From 8aa1b8f449d86618557442a08e0a0c6d7413a37f Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Sun, 15 Mar 2009 16:47:16 -0700 Subject: [PATCH 0001/1415] auto import from //branches/cupcake_rel/...@138607 --- tests/cts/net/Android.mk | 30 + tests/cts/net/AndroidManifest.xml | 30 + .../net/cts/ConnectivityManagerTest.java | 212 +++++ .../src/android/net/cts/CredentialsTest.java | 75 ++ .../net/src/android/net/cts/DhcpInfoTest.java | 80 ++ .../net/cts/LocalServerSocketTest.java | 107 +++ .../net/cts/LocalSocketAddressTest.java | 81 ++ .../cts/LocalSocketAddress_NamespaceTest.java | 59 ++ .../src/android/net/cts/LocalSocketTest.java | 342 ++++++++ .../net/src/android/net/cts/MailToTest.java | 167 ++++ .../src/android/net/cts/NetworkInfoTest.java | 171 ++++ .../cts/NetworkInfo_DetailedStateTest.java | 87 +++ .../net/cts/NetworkInfo_StateTest.java | 72 ++ .../net/src/android/net/cts/ProxyTest.java | 96 +++ .../cts/net/src/android/net/cts/UriTest.java | 727 ++++++++++++++++++ .../src/android/net/cts/Uri_BuilderTest.java | 174 +++++ .../net/http/cts/SslCertificateTest.java | 302 ++++++++ .../http/cts/SslCertificate_DNameTest.java | 83 ++ 18 files changed, 2895 insertions(+) create mode 100644 tests/cts/net/Android.mk create mode 100644 tests/cts/net/AndroidManifest.xml create mode 100644 tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java create mode 100644 tests/cts/net/src/android/net/cts/CredentialsTest.java create mode 100644 tests/cts/net/src/android/net/cts/DhcpInfoTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalServerSocketTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketTest.java create mode 100644 tests/cts/net/src/android/net/cts/MailToTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfoTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java create mode 100644 tests/cts/net/src/android/net/cts/ProxyTest.java create mode 100644 tests/cts/net/src/android/net/cts/UriTest.java create mode 100644 tests/cts/net/src/android/net/cts/Uri_BuilderTest.java create mode 100644 tests/cts/net/src/android/net/http/cts/SslCertificateTest.java create mode 100644 tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk new file mode 100644 index 0000000000..d1a459f0d3 --- /dev/null +++ b/tests/cts/net/Android.mk @@ -0,0 +1,30 @@ +# Copyright (C) 2008 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := ctstests_net + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := CtsNetTestCases + +LOCAL_INSTRUMENTATION_FOR := CtsTestStubs + +include $(BUILD_PACKAGE) + diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml new file mode 100644 index 0000000000..6c2dfbdf65 --- /dev/null +++ b/tests/cts/net/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java new file mode 100644 index 0000000000..201105f0a6 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2008 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 com.android.internal.telephony.Phone; + +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; +import android.test.AndroidTestCase; + +@TestTargetClass(ConnectivityManager.class) +public class ConnectivityManagerTest extends AndroidTestCase { + + private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 + private ConnectivityManager mCm; + @Override + protected void setUp() throws Exception { + super.setUp(); + mCm = (ConnectivityManager) getContext().getSystemService( + Context.CONNECTIVITY_SERVICE); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test getNetworkInfo(int networkType).", + method = "getNetworkInfo", + args = {int.class} + ) + public void testGetNetworkInfo() { + + // this test assumes that there are at least two network types. + assertTrue(mCm.getAllNetworkInfo().length >= 2); + NetworkInfo ni = mCm.getNetworkInfo(1); + State state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + + ni = mCm.getNetworkInfo(0); + state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + + ni = mCm.getNetworkInfo(-1); + assertNull(ni); + + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test isNetworkTypeValid(int networkType).", + method = "isNetworkTypeValid", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test isNetworkTypeValid(int networkType).", + method = "getAllNetworkInfo", + args = {} + ) + }) + public void testIsNetworkTypeValid() { + + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + + for (NetworkInfo n : ni) { + assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType())); + } + assertFalse(ConnectivityManager.isNetworkTypeValid(-1)); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "", + method = "getNetworkPreference", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "", + method = "setNetworkPreference", + args = {int.class} + ) + }) + public void testAccessNetworkPreference() { + + final int EXPECTED = 1; + int per = mCm.getNetworkPreference(); + mCm.setNetworkPreference(EXPECTED); + assertEquals(EXPECTED, mCm.getNetworkPreference()); + + mCm.setNetworkPreference(0); + assertEquals(0, mCm.getNetworkPreference()); + + mCm.setNetworkPreference(-1); + assertEquals(0, mCm.getNetworkPreference()); + + mCm.setNetworkPreference(2); + assertEquals(0, mCm.getNetworkPreference()); + + mCm.setNetworkPreference(1); + + assertEquals(1, mCm.getNetworkPreference()); + + mCm.setNetworkPreference(per); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test getAllNetworkInfo().", + method = "getAllNetworkInfo", + args = {} + ) + public void testGetAllNetworkInfo() { + + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + assertEquals(2, ni.length); + + assertTrue(ni[0].getType() >=0 && ni[0].getType() <= 1); + assertTrue(ni[1].getType() >=0 && ni[1].getType() <= 1); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test start and stop usingNetworkFeature(int networkType, String feature).", + method = "startUsingNetworkFeature", + args = {int.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test start and stop usingNetworkFeature(int networkType, String feature).", + method = "stopUsingNetworkFeature", + args = {int.class, java.lang.String.class} + ) + }) + public void testStartUsingNetworkFeature() { + + final String invalidateFeature = "invalidateFeature"; + assertEquals(-1, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + invalidateFeature)); + + assertEquals(-1, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + invalidateFeature)); + + assertEquals(-1, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, + Phone.FEATURE_ENABLE_MMS)); + assertEquals(-1, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, + Phone.FEATURE_ENABLE_MMS)); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test requestRouteToHost(int networkType, int hostAddress).", + method = "requestRouteToHost", + args = {int.class, int.class} + ) + public void testRequestRouteToHost() { + + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + for (NetworkInfo n : ni) { + assertTrue(mCm.requestRouteToHost(n.getType(), HOST_ADDRESS)); + } + + assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS)); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test getActiveNetworkInfo().", + method = "getActiveNetworkInfo", + args = {} + ) + public void testGetActiveNetworkInfo() { + + NetworkInfo ni = mCm.getActiveNetworkInfo(); + if (ni != null) { + assertTrue(ni.getType() >= 0); + } else { + fail("There is no active network connected, should be at least one kind of network"); + } + } + +} diff --git a/tests/cts/net/src/android/net/cts/CredentialsTest.java b/tests/cts/net/src/android/net/cts/CredentialsTest.java new file mode 100644 index 0000000000..0f6e49e00d --- /dev/null +++ b/tests/cts/net/src/android/net/cts/CredentialsTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 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 android.net.Credentials; +import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(android.net.Credentials.class) +public class CredentialsTest extends AndroidTestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", + method = "Credentials", + args = {int.class, int.class, int.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", + method = "getGid", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", + method = "getPid", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", + method = "getUid", + args = {} + ) + }) + public void testCredentials() { + // new the Credentials instance + // Test with zero inputs + Credentials cred = new Credentials(0, 0, 0); + assertEquals(0, cred.getGid()); + assertEquals(0, cred.getPid()); + assertEquals(0, cred.getUid()); + + // Test with big integer + cred = new Credentials(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + assertEquals(Integer.MAX_VALUE, cred.getGid()); + assertEquals(Integer.MAX_VALUE, cred.getPid()); + assertEquals(Integer.MAX_VALUE, cred.getUid()); + + // Test with big negative integer + cred = new Credentials(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); + assertEquals(Integer.MIN_VALUE, cred.getGid()); + assertEquals(Integer.MIN_VALUE, cred.getPid()); + assertEquals(Integer.MIN_VALUE, cred.getUid()); + } +} diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java new file mode 100644 index 0000000000..657d03c368 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2008 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 android.net.DhcpInfo; +import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(DhcpInfo.class) +public class DhcpInfoTest extends AndroidTestCase { + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test DhcpInfo's constructor.", + method = "DhcpInfo", + args = {} + ) + public void testConstructor() { + new DhcpInfo(); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test toString function.", + method = "toString", + args = {} + ) + public void testToString() { + String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 dns1 0.0.0.0 " + + "dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; + String STR_ADDR1 = "255.255.255.255"; + String STR_ADDR2 = "127.0.0.1"; + String STR_ADDR3 = "192.168.1.1"; + String STR_ADDR4 = "192.168.1.0"; + int leaseTime = 9999; + String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask " + + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server " + + STR_ADDR2 + " lease " + leaseTime + " seconds"; + + DhcpInfo dhcpInfo = new DhcpInfo(); + + // Test default string. + assertEquals(expectedDefault, dhcpInfo.toString()); + + dhcpInfo.ipAddress = ipToInteger(STR_ADDR1); + dhcpInfo.gateway = ipToInteger(STR_ADDR2); + dhcpInfo.netmask = ipToInteger(STR_ADDR3); + dhcpInfo.dns1 = ipToInteger(STR_ADDR4); + dhcpInfo.dns2 = ipToInteger(STR_ADDR4); + dhcpInfo.serverAddress = ipToInteger(STR_ADDR2); + dhcpInfo.leaseDuration = leaseTime; + + // Test with new values + assertEquals(expected, dhcpInfo.toString()); + } + + private int ipToInteger(String ipString) { + String ipSegs[] = ipString.split("[.]"); + int tmp = Integer.parseInt(ipSegs[3]) << 24 | Integer.parseInt(ipSegs[2]) << 16 | + Integer.parseInt(ipSegs[1]) << 8 | Integer.parseInt(ipSegs[0]); + return tmp; + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java new file mode 100644 index 0000000000..4fb8481674 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 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 java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import android.net.LocalServerSocket; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.os.ParcelFileDescriptor; +import android.test.AndroidTestCase; +import dalvik.annotation.TestInfo; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.ToBeFixed; + +@TestTargetClass(LocalServerSocket.class) +public class LocalServerSocketTest extends AndroidTestCase { + @TestInfo( + status = TestStatus.TBR, + notes = "test LocalServerSocket", + targets = { + @TestTarget( + methodName = "accept", + methodArgs = {} + ), + @TestTarget( + methodName = "close", + methodArgs = {} + ), + @TestTarget( + methodName = "getFileDescriptor", + methodArgs = {} + ), + @TestTarget( + methodName = "getLocalSocketAddress", + methodArgs = {} + ), + @TestTarget( + methodName = "LocalServerSocket", + methodArgs = {FileDescriptor.class} + ), + @TestTarget( + methodName = "LocalServerSocket", + methodArgs = {String.class} + ) + }) + @ToBeFixed(bug = "1520987", explanation = "Cannot find a proper FileDescriptor for " + + "android.net.LocalServerSocket constructor") + public void testLocalServerSocket() throws IOException { + LocalServerSocket localServerSocket = new LocalServerSocket(LocalSocketTest.mSockAddr); + assertNotNull(localServerSocket.getLocalSocketAddress()); + commonFunctions(localServerSocket); + + Socket socket = new Socket("www.google.com", 80); + ParcelFileDescriptor parcelFD = ParcelFileDescriptor.fromSocket(socket); + FileDescriptor fd = parcelFD.getFileDescriptor(); + + // enable the following after bug 1520987 fixed +// localServerSocket = new LocalServerSocket(fd); +// assertNull(localServerSocket.getLocalSocketAddress()); +// commonFunctions(localServerSocket); + } + + public void commonFunctions(LocalServerSocket localServerSocket) throws IOException { + // create client socket + LocalSocket clientSocket = new LocalSocket(); + + // establish connection between client and server + clientSocket.connect(new LocalSocketAddress(LocalSocketTest.mSockAddr)); + LocalSocket serverSocket = localServerSocket.accept(); + + // send data from client to server + OutputStream clientOutStream = clientSocket.getOutputStream(); + clientOutStream.write(12); + InputStream serverInStream = serverSocket.getInputStream(); + assertEquals(12, serverInStream.read()); + + // send data from server to client + OutputStream serverOutStream = serverSocket.getOutputStream(); + serverOutStream.write(3); + InputStream clientInStream = clientSocket.getInputStream(); + assertEquals(3, clientInStream.read()); + + // close server socket + assertNotNull(localServerSocket.getFileDescriptor()); + localServerSocket.close(); + assertNull(localServerSocket.getFileDescriptor()); + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java new file mode 100644 index 0000000000..cc3a1d38df --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008 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 android.net.LocalSocketAddress; +import android.net.LocalSocketAddress.Namespace; +import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(LocalSocketAddress.class) +public class LocalSocketAddressTest extends AndroidTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test LocalSocketAddress", + method = "LocalSocketAddress", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test LocalSocketAddress", + method = "LocalSocketAddress", + args = {java.lang.String.class, android.net.LocalSocketAddress.Namespace.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test LocalSocketAddress", + method = "getName", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test LocalSocketAddress", + method = "getNamespace", + args = {} + ) + }) + public void testNewLocalSocketAddressWithDefaultNamespace() { + // default namespace + LocalSocketAddress localSocketAddress = new LocalSocketAddress("name"); + assertEquals("name", localSocketAddress.getName()); + assertEquals(Namespace.ABSTRACT, localSocketAddress.getNamespace()); + + // specify the namespace + LocalSocketAddress localSocketAddress2 = new LocalSocketAddress("name2", Namespace.ABSTRACT); + assertEquals("name2", localSocketAddress2.getName()); + assertEquals(Namespace.ABSTRACT, localSocketAddress2.getNamespace()); + + LocalSocketAddress localSocketAddress3 = new LocalSocketAddress("name3", Namespace.FILESYSTEM); + assertEquals("name3", localSocketAddress3.getName()); + assertEquals(Namespace.FILESYSTEM, localSocketAddress3.getNamespace()); + + LocalSocketAddress localSocketAddress4 = new LocalSocketAddress("name4", Namespace.RESERVED); + assertEquals("name4", localSocketAddress4.getName()); + assertEquals(Namespace.RESERVED, localSocketAddress4.getNamespace()); + } +} + diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java new file mode 100644 index 0000000000..a9acaa357d --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 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 android.net.LocalSocketAddress.Namespace; +import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(Namespace.class) +public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) + public void testValueOf() { + assertEquals(Namespace.ABSTRACT, Namespace.valueOf("ABSTRACT")); + assertEquals(Namespace.RESERVED, Namespace.valueOf("RESERVED")); + assertEquals(Namespace.FILESYSTEM, Namespace.valueOf("FILESYSTEM")); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test values().", + method = "values", + args = {} + ) + public void testValues() { + Namespace[] expected = Namespace.values(); + assertEquals(Namespace.ABSTRACT, expected[0]); + assertEquals(Namespace.RESERVED, expected[1]); + assertEquals(Namespace.FILESYSTEM, expected[2]); + } +} + diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java new file mode 100644 index 0000000000..ae0b51c0ed --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2008 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 java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import android.net.Credentials; +import android.net.LocalServerSocket; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(LocalSocket.class) +public class LocalSocketTest extends AndroidTestCase{ + public final static String mSockAddr = "com.android.net.LocalSocketTest"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "LocalSocket", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "close", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "connect", + args = {android.net.LocalSocketAddress.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "getAncillaryFileDescriptors", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "getFileDescriptor", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "getInputStream", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "getOutputStream", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "getPeerCredentials", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "isConnected", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "setFileDescriptorsForSend", + args = {java.io.FileDescriptor[].class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "shutdownInput", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test core functions of LocalSocket", + method = "shutdownOutput", + args = {} + ) + }) + public void testLocalConnections() throws IOException{ + // create client and server socket + LocalServerSocket localServerSocket = new LocalServerSocket(mSockAddr); + LocalSocket clientSocket = new LocalSocket(); + + // establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(mSockAddr); + assertFalse(clientSocket.isConnected()); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + LocalSocket serverSocket = localServerSocket.accept(); + + Credentials credent = clientSocket.getPeerCredentials(); + assertTrue(0 != credent.getPid()); + + // send data from client to server + OutputStream clientOutStream = clientSocket.getOutputStream(); + clientOutStream.write(12); + InputStream serverInStream = serverSocket.getInputStream(); + assertEquals(12, serverInStream.read()); + + //send data from server to client + OutputStream serverOutStream = serverSocket.getOutputStream(); + serverOutStream.write(3); + InputStream clientInStream = clientSocket.getInputStream(); + assertEquals(3, clientInStream.read()); + + // Test sending and receiving file descriptors + clientSocket.setFileDescriptorsForSend(new FileDescriptor[]{FileDescriptor.in}); + clientOutStream.write(32); + assertEquals(32, serverInStream.read()); + + FileDescriptor[] out = serverSocket.getAncillaryFileDescriptors(); + assertEquals(1, out.length); + FileDescriptor fd = clientSocket.getFileDescriptor(); + assertTrue(fd.valid()); + + //shutdown input stream of client + clientSocket.shutdownInput(); + assertEquals(-1, clientInStream.read()); + + //shutdown output stream of client + clientSocket.shutdownOutput(); + try { + clientOutStream.write(10); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //shutdown input stream of server + serverSocket.shutdownInput(); + assertEquals(-1, serverInStream.read()); + + //shutdown output stream of server + serverSocket.shutdownOutput(); + try { + serverOutStream.write(10); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //close client socket + clientSocket.close(); + try { + clientInStream.read(); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //close server socket + serverSocket.close(); + try { + serverInStream.read(); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "bind", + args = {android.net.LocalSocketAddress.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "connect", + args = {android.net.LocalSocketAddress.class, int.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "getLocalSocketAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "getReceiveBufferSize", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "getRemoteSocketAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "getSendBufferSize", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "getSoTimeout", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "isBound", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "isClosed", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "isInputShutdown", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "isOutputShutdown", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "setReceiveBufferSize", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "setSendBufferSize", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "setSoTimeout", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "test secondary functions of LocalSocket", + method = "toString", + args = {} + ) + }) + public void testAccessors() throws IOException{ + LocalSocket socket = new LocalSocket(); + LocalSocketAddress addr = new LocalSocketAddress("secondary"); + + assertFalse(socket.isBound()); + socket.bind(addr); + assertTrue(socket.isBound()); + assertEquals(addr, socket.getLocalSocketAddress()); + + String str = socket.toString(); + assertTrue(str.contains("impl:android.net.LocalSocketImpl")); + + socket.setReceiveBufferSize(1999); + assertEquals(1999 << 1, socket.getReceiveBufferSize()); + + socket.setSendBufferSize(1998); + assertEquals(1998 << 1, socket.getSendBufferSize()); + + // Timeout is not support at present, so set is ignored + socket.setSoTimeout(1996); + assertEquals(0, socket.getSoTimeout()); + + try { + socket.getRemoteSocketAddress(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isClosed(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isInputShutdown(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isOutputShutdown(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.connect(addr, 2005); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + } +} diff --git a/tests/cts/net/src/android/net/cts/MailToTest.java b/tests/cts/net/src/android/net/cts/MailToTest.java new file mode 100644 index 0000000000..e419272517 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/MailToTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2008 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 android.net.MailTo; +import android.test.AndroidTestCase; +import android.util.Log; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(MailTo.class) +public class MailToTest extends AndroidTestCase { + private static final String MAILTOURI_1 = "mailto:chris@example.com"; + private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue"; + private static final String MAILTOURI_3 = "mailto:infobot@example.com?body=send%20current-issue"; + private static final String MAILTOURI_4 = "mailto:infobot@example.com?body=send%20current-" + + "issue%0D%0Asend%20index"; + private static final String MAILTOURI_5 = "mailto:joe@example.com?" + + "cc=bob@example.com&body=hello"; + private static final String MAILTOURI_6 = "mailto:?to=joe@example.com&" + + "cc=bob@example.com&body=hello"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test parse mailto URI.", + method = "parse", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test parse mailto URI.", + method = "isMailTo", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test parse mailto URI.", + method = "getTo", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test parse mailto URI.", + method = "getSubject", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test parse mailto URI.", + method = "getBody", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test parse mailto URI.", + method = "getCc", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test parse mailto URI.", + method = "toString", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test parse mailto URI.", + method = "getHeaders", + args = {} + ) + }) + public void testParseMailToURI() { + assertFalse(MailTo.isMailTo(null)); + assertFalse(MailTo.isMailTo("")); + assertFalse(MailTo.isMailTo("http://www.google.com")); + + assertTrue(MailTo.isMailTo(MAILTOURI_1)); + MailTo mailTo_1 = MailTo.parse(MAILTOURI_1); + Log.d("Trace", mailTo_1.toString()); + assertEquals("chris@example.com", mailTo_1.getTo()); + assertEquals(1, mailTo_1.getHeaders().size()); + assertNull(mailTo_1.getBody()); + assertNull(mailTo_1.getCc()); + assertNull(mailTo_1.getSubject()); + assertEquals("mailto:?to=chris%40example.com&", mailTo_1.toString()); + + assertTrue(MailTo.isMailTo(MAILTOURI_2)); + MailTo mailTo_2 = MailTo.parse(MAILTOURI_2); + Log.d("Trace", mailTo_2.toString()); + assertEquals(2, mailTo_2.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_2.getTo()); + assertEquals("current-issue", mailTo_2.getSubject()); + assertNull(mailTo_2.getBody()); + assertNull(mailTo_2.getCc()); + assertEquals("mailto:?to=infobot%40example.com&subject=current-issue&", + mailTo_2.toString()); + + assertTrue(MailTo.isMailTo(MAILTOURI_3)); + MailTo mailTo_3 = MailTo.parse(MAILTOURI_3); + Log.d("Trace", mailTo_3.toString()); + assertEquals(2, mailTo_3.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_3.getTo()); + assertEquals("send current-issue", mailTo_3.getBody()); + assertNull(mailTo_3.getCc()); + assertNull(mailTo_3.getSubject()); + assertEquals("mailto:?body=send%20current-issue&to=infobot%40example.com&", + mailTo_3.toString()); + + assertTrue(MailTo.isMailTo(MAILTOURI_4)); + MailTo mailTo_4 = MailTo.parse(MAILTOURI_4); + Log.d("Trace", mailTo_4.toString() + " " + mailTo_4.getBody()); + assertEquals(2, mailTo_4.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_4.getTo()); + assertEquals("send current-issue\r\nsend index", mailTo_4.getBody()); + assertNull(mailTo_4.getCc()); + assertNull(mailTo_4.getSubject()); + assertEquals("mailto:?body=send%20current-issue%0D%0Asend%20index&to=infobot%40example.com&", + mailTo_4.toString()); + + assertTrue(MailTo.isMailTo(MAILTOURI_5)); + MailTo mailTo_5 = MailTo.parse(MAILTOURI_5); + Log.d("Trace", mailTo_5.toString() + mailTo_5.getHeaders().toString() + + mailTo_5.getHeaders().size()); + assertEquals(3, mailTo_5.getHeaders().size()); + assertEquals("joe@example.com", mailTo_5.getTo()); + assertEquals("bob@example.com", mailTo_5.getCc()); + assertEquals("hello", mailTo_5.getBody()); + assertNull(mailTo_5.getSubject()); + assertEquals("mailto:?cc=bob%40example.com&body=hello&to=joe%40example.com&", + mailTo_5.toString()); + + assertTrue(MailTo.isMailTo(MAILTOURI_6)); + MailTo mailTo_6 = MailTo.parse(MAILTOURI_6); + Log.d("Trace", mailTo_6.toString() + mailTo_6.getHeaders().toString() + + mailTo_6.getHeaders().size()); + assertEquals(3, mailTo_6.getHeaders().size()); + assertEquals(", joe@example.com", mailTo_6.getTo()); + assertEquals("bob@example.com", mailTo_6.getCc()); + assertEquals("hello", mailTo_6.getBody()); + assertNull(mailTo_6.getSubject()); + assertEquals("mailto:?cc=bob%40example.com&body=hello&to=%2C%20joe%40example.com&", + mailTo_6.toString()); + } +} + diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java new file mode 100644 index 0000000000..248ef9a71f --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008 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 android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; +import android.os.Parcel; +import android.test.AndroidTestCase; +import dalvik.annotation.TestInfo; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(NetworkInfo.class) +public class NetworkInfoTest extends AndroidTestCase { + ConnectivityManager mConnectivityManager; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mConnectivityManager = (ConnectivityManager) mContext + .getSystemService(Context.CONNECTIVITY_SERVICE); + } + + @TestInfo( + status = TestStatus.TBR, + notes = "Test isConnectedOrConnecting().", + targets = { + @TestTarget( + methodName = "isConnectedOrConnecting", + methodArgs = {} + ), + @TestTarget( + methodName = "setFailover", + methodArgs = {boolean.class} + ), + @TestTarget( + methodName = "isFailover", + methodArgs = {} + ), + @TestTarget( + methodName = "getType", + methodArgs = {} + ), + @TestTarget( + methodName = "getTypeName", + methodArgs = {} + ), + @TestTarget( + methodName = "setIsAvailable", + methodArgs = {boolean.class} + ), + @TestTarget( + methodName = "isAvailable", + methodArgs = {} + ), + @TestTarget( + methodName = "isConnected", + methodArgs = {} + ), + @TestTarget( + methodName = "describeContents", + methodArgs = {} + ), + @TestTarget( + methodName = "getDetailedState", + methodArgs = {} + ), + @TestTarget( + methodName = "getState", + methodArgs = {} + ), + @TestTarget( + methodName = "getReason", + methodArgs = {} + ), + @TestTarget( + methodName = "getExtraInfo", + methodArgs = {} + ), + @TestTarget( + methodName = "toString", + methodArgs = {} + ) + }) + public void testAccessNetworkInfoProperties() { + NetworkInfo[] ni = mConnectivityManager.getAllNetworkInfo(); + assertTrue(ni.length >= 2); + assertFalse(ni[ConnectivityManager.TYPE_MOBILE].isFailover()); + assertFalse(ni[ConnectivityManager.TYPE_WIFI].isFailover()); + + // test environment:connect as TYPE_MOBILE, and connect to internet. + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getType(), + ConnectivityManager.TYPE_MOBILE); + assertEquals(ni[ConnectivityManager.TYPE_WIFI].getType(), + ConnectivityManager.TYPE_WIFI); + assertEquals("MOBILE",ni[ConnectivityManager.TYPE_MOBILE].getTypeName()); + assertEquals("WIFI",ni[ConnectivityManager.TYPE_WIFI].getTypeName()); + assertTrue(ni[ConnectivityManager.TYPE_MOBILE] + .isConnectedOrConnecting()); + assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnectedOrConnecting()); + assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isAvailable()); + assertFalse(ni[ConnectivityManager.TYPE_WIFI].isAvailable()); + assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isConnected()); + assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnected()); + + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].describeContents(), 0); + assertEquals(ni[ConnectivityManager.TYPE_WIFI].describeContents(), 0); + + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getState(), + State.CONNECTED); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getDetailedState(), + DetailedState.CONNECTED); + + assertNull(ni[ConnectivityManager.TYPE_MOBILE].getReason()); + assertNull(ni[ConnectivityManager.TYPE_WIFI].getReason()); + assertEquals("internet",ni[ConnectivityManager.TYPE_MOBILE].getExtraInfo()); + assertNull(ni[ConnectivityManager.TYPE_WIFI].getExtraInfo()); + + assertNotNull(ni[ConnectivityManager.TYPE_MOBILE].toString()); + assertNotNull(ni[ConnectivityManager.TYPE_WIFI].toString()); + } + + @TestInfo( + status = TestStatus.TBR, + notes = "Test writeToParcel(Parcel dest, int flags).", + targets = { + @TestTarget( + methodName = "writeToParcel", + methodArgs = {Parcel.class, Integer.class} + ) + }) + public void testWriteToParcel() { + NetworkInfo[] ni = mConnectivityManager.getAllNetworkInfo(); + Parcel p = Parcel.obtain(); + ni[ConnectivityManager.TYPE_MOBILE].writeToParcel(p, 1); + p.setDataPosition(0); + NetworkInfo mNetworkInfo = NetworkInfo.CREATOR.createFromParcel(p); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getExtraInfo(), + mNetworkInfo.getExtraInfo()); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getReason(), + mNetworkInfo.getReason()); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getType(), + mNetworkInfo.getType()); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getState(), + mNetworkInfo.getState()); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getDetailedState(), + mNetworkInfo.getDetailedState()); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].isAvailable(), + mNetworkInfo.isAvailable()); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].isFailover(), + mNetworkInfo.isFailover()); + } +} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java new file mode 100644 index 0000000000..64597242a7 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 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 android.net.NetworkInfo.DetailedState; +import android.test.AndroidTestCase; +import dalvik.annotation.TestInfo; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(DetailedState.class) +public class NetworkInfo_DetailedStateTest extends AndroidTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @TestInfo( + status = TestStatus.TBR, + notes = "Test valueOf(String name).", + targets = { + @TestTarget( + methodName = "valueOf", + methodArgs = {String.class} + ) + }) + public void testValueOf() { + assertEquals(DetailedState.AUTHENTICATING, DetailedState + .valueOf("AUTHENTICATING")); + assertEquals(DetailedState.CONNECTED, DetailedState + .valueOf("CONNECTED")); + assertEquals(DetailedState.CONNECTING, DetailedState + .valueOf("CONNECTING")); + assertEquals(DetailedState.DISCONNECTED, DetailedState + .valueOf("DISCONNECTED")); + assertEquals(DetailedState.DISCONNECTING, DetailedState + .valueOf("DISCONNECTING")); + assertEquals(DetailedState.FAILED, DetailedState.valueOf("FAILED")); + assertEquals(DetailedState.IDLE, DetailedState.valueOf("IDLE")); + assertEquals(DetailedState.OBTAINING_IPADDR, DetailedState + .valueOf("OBTAINING_IPADDR")); + assertEquals(DetailedState.SCANNING, DetailedState.valueOf("SCANNING")); + assertEquals(DetailedState.SUSPENDED, DetailedState + .valueOf("SUSPENDED")); + } + + @TestInfo( + status = TestStatus.TBR, + notes = "Test values().", + targets = { + @TestTarget( + methodName = "values", + methodArgs = {} + ) + }) + public void testValues() { + DetailedState[] expected = DetailedState.values(); + assertEquals(10, expected.length); + assertEquals(DetailedState.IDLE, expected[0]); + assertEquals(DetailedState.SCANNING, expected[1]); + assertEquals(DetailedState.CONNECTING, expected[2]); + assertEquals(DetailedState.AUTHENTICATING, expected[3]); + assertEquals(DetailedState.OBTAINING_IPADDR, expected[4]); + assertEquals(DetailedState.CONNECTED, expected[5]); + assertEquals(DetailedState.SUSPENDED, expected[6]); + assertEquals(DetailedState.DISCONNECTING, expected[7]); + assertEquals(DetailedState.DISCONNECTED, expected[8]); + assertEquals(DetailedState.FAILED, expected[9]); + } + +} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java new file mode 100644 index 0000000000..b03c3f0215 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 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 android.test.AndroidTestCase; +import dalvik.annotation.TestInfo; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetClass; +import android.net.NetworkInfo.State; + +@TestTargetClass(State.class) +public class NetworkInfo_StateTest extends AndroidTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @TestInfo( + status = TestStatus.TBR, + notes = "Test valueOf(String name).", + targets = { + @TestTarget( + methodName = "valueOf", + methodArgs = {String.class} + ) + }) + public void testValueOf() { + assertEquals(State.CONNECTED, State.valueOf("CONNECTED")); + assertEquals(State.CONNECTING, State.valueOf("CONNECTING")); + assertEquals(State.DISCONNECTED, State.valueOf("DISCONNECTED")); + assertEquals(State.DISCONNECTING, State.valueOf("DISCONNECTING")); + assertEquals(State.SUSPENDED, State.valueOf("SUSPENDED")); + assertEquals(State.UNKNOWN, State.valueOf("UNKNOWN")); + } + + @TestInfo( + status = TestStatus.TBR, + notes = "Test values().", + targets = { + @TestTarget( + methodName = "values", + methodArgs = {} + ) + }) + public void testValues() { + State[] expected = State.values(); + assertEquals(6, expected.length); + assertEquals(State.CONNECTING, expected[0]); + assertEquals(State.CONNECTED, expected[1]); + assertEquals(State.SUSPENDED, expected[2]); + assertEquals(State.DISCONNECTING, expected[3]); + assertEquals(State.DISCONNECTED, expected[4]); + assertEquals(State.UNKNOWN, expected[5]); + } + +} diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java new file mode 100644 index 0000000000..d9f7c1a942 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 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 android.content.Context; +import android.net.Proxy; +import android.provider.Settings; +import android.test.AndroidTestCase; +import dalvik.annotation.TestInfo; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(Proxy.class) +public class ProxyTest extends AndroidTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + + } + + @TestInfo( + status = TestStatus.TBR, + notes = "Test constructor(s) of Proxy.", + targets = { + @TestTarget( + methodName = "Proxy", + methodArgs = {} + ) + }) + public void testConstructor() { + + try { + Proxy proxy = new Proxy(); + } catch (Exception e) { + fail("shouldn't throw exception"); + } + } + + @TestInfo( + status = TestStatus.TBR, + notes = "Test getDefaultPort().", + targets = { + @TestTarget( + methodName = "getDefaultPort", + methodArgs = {} + ), + @TestTarget( + methodName = "getDefaultHost", + methodArgs = {} + ), + @TestTarget( + methodName = "getHost", + methodArgs = {Context.class} + ), + @TestTarget( + methodName = "getHost", + methodArgs = {Context.class} + ), + @TestTarget( + methodName = "getPort", + methodArgs = {Context.class} + ) + }) + public void testAccessProperties() { + String mHost = "www.google.com"; + int mPort = 8080; + String mHttpProxy = mHost + ":" + mPort; + + Settings.System.putString(mContext.getContentResolver(), + Settings.System.HTTP_PROXY, null); + assertNull(Proxy.getHost(mContext)); + assertEquals(-1,Proxy.getPort(mContext)); + + Settings.System.putString(mContext.getContentResolver(), + Settings.System.HTTP_PROXY, mHttpProxy); + assertEquals(mHost,Proxy.getHost(mContext)); + assertEquals(mPort,Proxy.getPort(mContext)); + } + +} + diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java new file mode 100644 index 0000000000..84b58c081a --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -0,0 +1,727 @@ +/* + * Copyright (C) 2008 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 dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import android.content.ContentUris; +import android.net.Uri; +import android.os.Parcel; +import android.test.AndroidTestCase; +import java.io.File; +import java.util.Arrays; + +@TestTargetClass(Uri.class) +public class UriTest extends AndroidTestCase { + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test write to and read frome parcel.", + method = "writeToParcel", + args = {android.os.Parcel.class, android.net.Uri.class} + ) + public void testParcelling() { + parcelAndUnparcel(Uri.parse("foo:bob%20lee")); + parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment")); + parcelAndUnparcel(new Uri.Builder() + .scheme("http") + .authority("crazybob.org") + .path("/rss/") + .encodedQuery("a=b") + .fragment("foo") + .build()); + } + + private void parcelAndUnparcel(Uri u) { + Parcel p = Parcel.obtain(); + Uri.writeToParcel(p, u); + p.setDataPosition(0); + assertEquals(u, Uri.CREATOR.createFromParcel(p)); + + p.setDataPosition(0); + u = u.buildUpon().build(); + Uri.writeToParcel(p, u); + p.setDataPosition(0); + assertEquals(u, Uri.CREATOR.createFromParcel(p)); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test buildUpon", + method = "buildUpon", + args = {} + ) + public void testBuildUpon() { + Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build(); + assertEquals("robert", u.getScheme()); + assertEquals("lee", u.getEncodedSchemeSpecificPart()); + assertEquals("lee", u.getSchemeSpecificPart()); + assertNull(u.getQuery()); + assertNull(u.getPath()); + assertNull(u.getAuthority()); + assertNull(u.getHost()); + + Uri a = Uri.fromParts("foo", "bar", "tee"); + Uri b = a.buildUpon().fragment("new").build(); + assertEquals("new", b.getFragment()); + assertEquals("bar", b.getSchemeSpecificPart()); + assertEquals("foo", b.getScheme()); + a = new Uri.Builder() + .scheme("foo") + .encodedOpaquePart("bar") + .fragment("tee") + .build(); + b = a.buildUpon().fragment("new").build(); + assertEquals("new", b.getFragment()); + assertEquals("bar", b.getSchemeSpecificPart()); + assertEquals("foo", b.getScheme()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getSchemeSpecificPart", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getEncodedSchemeSpecificPart", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getEncodedPath", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getPath", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getEncodedQuery", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getQuery", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getEncodedFragment", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getHost", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getPort", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getUserInfo", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "getEncodedUserInfo", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test string uri.", + method = "parse", + args = {java.lang.String.class} + ) + }) + public void testStringUri() { + assertEquals("bob lee", + Uri.parse("foo:bob%20lee").getSchemeSpecificPart()); + assertEquals("bob%20lee", + Uri.parse("foo:bob%20lee").getEncodedSchemeSpecificPart()); + + assertEquals("/bob%20lee", + Uri.parse("foo:/bob%20lee").getEncodedPath()); + assertNull(Uri.parse("foo:bob%20lee").getPath()); + + assertEquals("bob%20lee", + Uri.parse("foo:?bob%20lee").getEncodedQuery()); + assertNull(Uri.parse("foo:bob%20lee").getEncodedQuery()); + assertNull(Uri.parse("foo:bar#?bob%20lee").getQuery()); + + assertEquals("bob%20lee", + Uri.parse("foo:#bob%20lee").getEncodedFragment()); + + Uri uri = Uri.parse("http://localhost:42"); + assertEquals("localhost", uri.getHost()); + assertEquals(42, uri.getPort()); + + uri = Uri.parse("http://bob@localhost:42"); + assertEquals("bob", uri.getUserInfo()); + assertEquals("localhost", uri.getHost()); + assertEquals(42, uri.getPort()); + + uri = Uri.parse("http://bob%20lee@localhost:42"); + assertEquals("bob lee", uri.getUserInfo()); + assertEquals("bob%20lee", uri.getEncodedUserInfo()); + + uri = Uri.parse("http://localhost"); + assertEquals("localhost", uri.getHost()); + assertEquals(-1, uri.getPort()); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test compareTo", + method = "compareTo", + args = {android.net.Uri.class} + ) + public void testCompareTo() { + Uri a = Uri.parse("foo:a"); + Uri b = Uri.parse("foo:b"); + Uri b2 = Uri.parse("foo:b"); + + assertTrue(a.compareTo(b) < 0); + assertTrue(b.compareTo(a) > 0); + assertEquals(0, b.compareTo(b2)); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test equals and hashCode.", + method = "equals", + args = {java.lang.Object.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test equals and hashCode.", + method = "hashCode", + args = {} + ) + }) + public void testEqualsAndHashCode() { + Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee"); + + Uri b = new Uri.Builder() + .scheme("http") + .authority("crazybob.org") + .path("/test/") + .encodedQuery("foo=bar") + .fragment("tee") + .build(); + + // Try alternate builder methods. + Uri c = new Uri.Builder() + .scheme("http") + .encodedAuthority("crazybob.org") + .encodedPath("/test/") + .encodedQuery("foo=bar") + .encodedFragment("tee") + .build(); + + assertFalse(Uri.EMPTY.equals(null)); + assertEquals(a, b); + assertEquals(b, c); + assertEquals(c, a); + assertEquals(a.hashCode(), b.hashCode()); + assertEquals(b.hashCode(), c.hashCode()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test encode and decode.", + method = "encode", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test encode and decode.", + method = "encode", + args = {java.lang.String.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test encode and decode.", + method = "decode", + args = {java.lang.String.class} + ) + }) + public void testEncodeAndDecode() { + String encoded = Uri.encode("Bob:/", "/"); + assertEquals(-1, encoded.indexOf(':')); + assertTrue(encoded.indexOf('/') > -1); + assertDecode(null); + assertDecode(""); + assertDecode("Bob"); + assertDecode(":Bob"); + assertDecode("::Bob"); + assertDecode("Bob::Lee"); + assertDecode("Bob:Lee"); + assertDecode("Bob::"); + assertDecode("Bob:"); + assertDecode("::Bob::"); + } + + private void assertDecode(String s) { + assertEquals(s, Uri.decode(Uri.encode(s, null))); + } + + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test fromFile.", + method = "fromFile", + args = {java.io.File.class} + ) + public void testFromFile() { + File f = new File("/tmp/bob"); + Uri uri = Uri.fromFile(f); + assertEquals("file:///tmp/bob", uri.toString()); + try { + Uri.fromFile(null); + fail("testFile fail"); + } catch (NullPointerException e) {} + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test get query parameters.", + method = "getQueryParameter", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test get query parameters.", + method = "getQueryParameters", + args = {java.lang.String.class} + ) + }) + public void testQueryParameters() { + Uri uri = Uri.parse("content://user"); + assertEquals(null, uri.getQueryParameter("a")); + + uri = uri.buildUpon().appendQueryParameter("a", "b").build(); + assertEquals("b", uri.getQueryParameter("a")); + + uri = uri.buildUpon().appendQueryParameter("a", "b2").build(); + assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a")); + + uri = uri.buildUpon().appendQueryParameter("c", "d").build(); + assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a")); + assertEquals("d", uri.getQueryParameter("c")); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "", + method = "getPathSegments", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "", + method = "getLastPathSegment", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "", + method = "withAppendedPath", + args = {android.net.Uri.class, java.lang.String.class} + ) + }) + public void testPathOperations() { + Uri uri = Uri.parse("content://user/a/b"); + + assertEquals(2, uri.getPathSegments().size()); + assertEquals("a", uri.getPathSegments().get(0)); + assertEquals("b", uri.getPathSegments().get(1)); + assertEquals("b", uri.getLastPathSegment()); + + Uri first = uri; + uri = uri.buildUpon().appendPath("c").build(); + assertEquals(3, uri.getPathSegments().size()); + assertEquals("c", uri.getPathSegments().get(2)); + assertEquals("c", uri.getLastPathSegment()); + assertEquals("content://user/a/b/c", uri.toString()); + + uri = ContentUris.withAppendedId(uri, 100); + assertEquals(4, uri.getPathSegments().size()); + assertEquals("100", uri.getPathSegments().get(3)); + assertEquals("100", uri.getLastPathSegment()); + assertEquals(100, ContentUris.parseId(uri)); + assertEquals("content://user/a/b/c/100", uri.toString()); + + // Make sure the original URI is still intact. + assertEquals(2, first.getPathSegments().size()); + assertEquals("b", first.getLastPathSegment()); + + try { + first.getPathSegments().get(2); + fail("test path operations"); + } catch (IndexOutOfBoundsException e) {} + + assertEquals(null, Uri.EMPTY.getLastPathSegment()); + + Uri withC = Uri.parse("foo:/a/b/").buildUpon().appendPath("c").build(); + assertEquals("/a/b/c", withC.getPath()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "isAbsolute", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "isOpaque", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "isRelative", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "getHost", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "getPort", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "getScheme", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "getSchemeSpecificPart", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "fromParts", + args = {java.lang.String.class, java.lang.String.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test opaque uri.", + method = "toString", + args = {} + ) + }) + public void testOpaqueUri() { + Uri uri = Uri.parse("mailto:nobody"); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + + uri = Uri.fromParts("mailto", "nobody", null); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + + uri = new Uri.Builder() + .scheme("mailto") + .opaquePart("nobody") + .build(); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + } + + private void testOpaqueUri(Uri uri) { + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getSchemeSpecificPart()); + assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); + + assertNull(uri.getFragment()); + assertTrue(uri.isAbsolute()); + assertTrue(uri.isOpaque()); + assertFalse(uri.isRelative()); + assertFalse(uri.isHierarchical()); + + assertNull(uri.getAuthority()); + assertNull(uri.getEncodedAuthority()); + assertNull(uri.getPath()); + assertNull(uri.getEncodedPath()); + assertNull(uri.getUserInfo()); + assertNull(uri.getEncodedUserInfo()); + assertNull(uri.getQuery()); + assertNull(uri.getEncodedQuery()); + assertNull(uri.getHost()); + assertEquals(-1, uri.getPort()); + + assertTrue(uri.getPathSegments().isEmpty()); + assertNull(uri.getLastPathSegment()); + + assertEquals("mailto:nobody", uri.toString()); + + Uri withFragment = uri.buildUpon().fragment("top").build(); + assertEquals("mailto:nobody#top", withFragment.toString()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getAuthority", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getScheme", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getEncodedAuthority", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getPath", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getEncodedPath", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getQuery", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getEncodedQuery", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getFragment", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getEncodedFragment", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "getSchemeSpecificPart", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "isAbsolute", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "isHierarchical", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "isOpaque", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "isRelative", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test hierarchical uris.", + method = "toString", + args = {} + ) + }) + public void testHierarchicalUris() { + testHierarchical("http", "google.com", "/p1/p2", "query", "fragment"); + testHierarchical("file", null, "/p1/p2", null, null); + testHierarchical("content", "contact", "/p1/p2", null, null); + testHierarchical("http", "google.com", "/p1/p2", null, "fragment"); + testHierarchical("http", "google.com", "", null, "fragment"); + testHierarchical("http", "google.com", "", "query", "fragment"); + testHierarchical("http", "google.com", "", "query", null); + testHierarchical("http", null, "/", "query", null); + } + + private static void testHierarchical(String scheme, String authority, + String path, String query, String fragment) { + StringBuilder sb = new StringBuilder(); + + if (authority != null) { + sb.append("//").append(authority); + } + if (path != null) { + sb.append(path); + } + if (query != null) { + sb.append('?').append(query); + } + + String ssp = sb.toString(); + + if (scheme != null) { + sb.insert(0, scheme + ":"); + } + if (fragment != null) { + sb.append('#').append(fragment); + } + + String uriString = sb.toString(); + + Uri uri = Uri.parse(uriString); + + // Run these twice to test caching. + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + + // Test rebuilt version. + uri = uri.buildUpon().build(); + + // Run these twice to test caching. + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + + // The decoded and encoded versions of the inputs are all the same. + // We'll test the actual encoding decoding separately. + + // Test building with encoded versions. + Uri built = new Uri.Builder() + .scheme(scheme) + .encodedAuthority(authority) + .encodedPath(path) + .encodedQuery(query) + .encodedFragment(fragment) + .build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + + // Test building with decoded versions. + built = new Uri.Builder() + .scheme(scheme) + .authority(authority) + .path(path) + .query(query) + .fragment(fragment) + .build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + + // Rebuild. + built = built.buildUpon().build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + } + + private static void compareHierarchical(String uriString, String ssp, + Uri uri, + String scheme, String authority, String path, String query, + String fragment) { + assertEquals(scheme, uri.getScheme()); + assertEquals(authority, uri.getAuthority()); + assertEquals(authority, uri.getEncodedAuthority()); + assertEquals(path, uri.getPath()); + assertEquals(path, uri.getEncodedPath()); + assertEquals(query, uri.getQuery()); + assertEquals(query, uri.getEncodedQuery()); + assertEquals(fragment, uri.getFragment()); + assertEquals(fragment, uri.getEncodedFragment()); + assertEquals(ssp, uri.getSchemeSpecificPart()); + + if (scheme != null) { + assertTrue(uri.isAbsolute()); + assertFalse(uri.isRelative()); + } else { + assertFalse(uri.isAbsolute()); + assertTrue(uri.isRelative()); + } + + assertFalse(uri.isOpaque()); + assertTrue(uri.isHierarchical()); + assertEquals(uriString, uri.toString()); + } +} diff --git a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java new file mode 100644 index 0000000000..8a1b42341b --- /dev/null +++ b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2008 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 junit.framework.TestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; +import android.net.Uri.Builder; +import android.net.Uri; + +@TestTargetClass(Uri.Builder.class) +public class Uri_BuilderTest extends TestCase { + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "Uri.Builder", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "build", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "scheme", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "authority", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "path", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "query", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "opaquePart", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "fragment", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "appendEncodedPath", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "appendPath", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "appendQueryParameter", + args = {java.lang.String.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "encodedAuthority", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "encodedFragment", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "encodedPath", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "encodedQuery", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "encodedOpaquePart", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test Builder operations.", + method = "toString", + args = {} + ) + }) + public void testBuilderOperations() { + Uri uri = Uri.parse("http://google.com/p1?query#fragment"); + Builder builder = uri.buildUpon(); + uri = builder.appendPath("p2").build(); + assertEquals("http", uri.getScheme()); + assertEquals("google.com", uri.getAuthority()); + assertEquals("/p1/p2", uri.getPath()); + assertEquals("query", uri.getQuery()); + assertEquals("fragment", uri.getFragment()); + assertEquals(uri.toString(), builder.toString()); + + uri = Uri.parse("mailto:nobody"); + builder = uri.buildUpon(); + uri = builder.build(); + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getSchemeSpecificPart()); + assertEquals(uri.toString(), builder.toString()); + + uri = new Uri.Builder() + .scheme("http") + .encodedAuthority("google.com") + .encodedPath("/p1") + .appendEncodedPath("p2") + .encodedQuery("query") + .appendQueryParameter("query2", null) + .encodedFragment("fragment") + .build(); + assertEquals("http", uri.getScheme()); + assertEquals("google.com", uri.getEncodedAuthority()); + assertEquals("/p1/p2", uri.getEncodedPath()); + assertEquals("query&query2=null", uri.getEncodedQuery()); + assertEquals("fragment", uri.getEncodedFragment()); + + uri = new Uri.Builder() + .scheme("mailto") + .encodedOpaquePart("nobody") + .build(); + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); + } +} + diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java new file mode 100644 index 0000000000..6e23419de9 --- /dev/null +++ b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2008 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.http.cts; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.util.Date; +import java.util.Set; + +import junit.framework.TestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; +import android.net.http.SslCertificate; +import android.net.http.SslCertificate.DName; +import android.os.Bundle; + +@TestTargetClass(SslCertificate.class) +public class SslCertificateTest extends TestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test constructor(s) of SslCertificate.", + method = "SslCertificate", + args = {java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test constructor(s) of SslCertificate.", + method = "SslCertificate", + args = {java.security.cert.X509Certificate.class} + ) + }) + public void testConstructor() { + // new the SslCertificate instance + String date = DateFormat.getInstance().format(new Date()); + new SslCertificate("c=129", "e=weji", date, date); + + // new the SslCertificate instance + new SslCertificate(new MockX509Certificate()); + + } + + class MockX509Certificate extends X509Certificate { + + @Override + public void checkValidity() throws CertificateExpiredException, + CertificateNotYetValidException { + } + + @Override + public void checkValidity(Date date) throws CertificateExpiredException, + CertificateNotYetValidException { + } + + @Override + public int getBasicConstraints() { + return 0; + } + + @Override + public Principal getIssuerDN() { + return new MockPrincipal(); + } + + @Override + public boolean[] getIssuerUniqueID() { + return null; + } + + @Override + public boolean[] getKeyUsage() { + return null; + } + + @Override + public Date getNotAfter() { + return new Date(System.currentTimeMillis()); + } + + @Override + public Date getNotBefore() { + return new Date(System.currentTimeMillis() - 1000); + } + + @Override + public BigInteger getSerialNumber() { + return null; + } + + @Override + public String getSigAlgName() { + return null; + } + + @Override + public String getSigAlgOID() { + return null; + } + + @Override + public byte[] getSigAlgParams() { + return null; + } + + @Override + public byte[] getSignature() { + return null; + } + + @Override + public Principal getSubjectDN() { + return new MockPrincipal(); + } + + class MockPrincipal implements Principal { + public String getName() { + return null; + } + } + @Override + public boolean[] getSubjectUniqueID() { + return null; + } + + @Override + public byte[] getTBSCertificate() throws CertificateEncodingException { + return null; + } + + @Override + public int getVersion() { + return 0; + } + + @Override + public byte[] getEncoded() throws CertificateEncodingException { + return null; + } + + @Override + public PublicKey getPublicKey() { + return null; + } + + @Override + public String toString() { + return null; + } + + @Override + public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException { + } + + @Override + public void verify(PublicKey key, String sigProvider) throws CertificateException, + NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, + SignatureException { + } + + public Set getCriticalExtensionOIDs() { + return null; + } + + public byte[] getExtensionValue(String oid) { + return null; + } + + public Set getNonCriticalExtensionOIDs() { + return null; + } + + public boolean hasUnsupportedCriticalExtension() { + return false; + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test saveState and restoreState(SslCertificate certificate).", + method = "saveState", + args = {android.net.http.SslCertificate.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test saveState and restoreState(SslCertificate certificate).", + method = "restoreState", + args = {android.os.Bundle.class} + ) + }) + public void testState() { + // set the expected value + + Date date1 = new Date(System.currentTimeMillis() - 1000); + Date date2 = new Date(System.currentTimeMillis()); + SslCertificate ssl = new SslCertificate("c=129", "e=weji", DateFormat.getInstance().format( + date1), DateFormat.getInstance().format(date2)); + Bundle saved = SslCertificate.saveState(ssl); + assertTrue(saved.size() == 4); + + assertNotNull(saved.getString("issued-to")); + assertNotNull(saved.getString("issued-by")); + assertNotNull(saved.getString("valid-not-before")); + assertNotNull(saved.getString("valid-not-after")); + assertNull(SslCertificate.saveState(null)); + + SslCertificate restored = SslCertificate.restoreState(saved); + assertEquals(ssl.getValidNotAfter(), restored.getValidNotAfter()); + assertEquals(ssl.getValidNotBefore(), restored.getValidNotBefore()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test getIssuedTo().", + method = "getIssuedTo", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test getIssuedTo().", + method = "getIssuedBy", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test getIssuedTo().", + method = "getValidNotAfter", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test getIssuedTo().", + method = "getValidNotBefore", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test getIssuedTo().", + method = "toString", + args = {} + ) + }) + public void testSslCertificate() { + + final String TO = "c=ccc,o=testOName,ou=testUName,cn=testCName"; + final String BY = "e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName"; + // new the SslCertificate instance + Date date1 = new Date(System.currentTimeMillis() - 1000); + Date date2 = new Date(System.currentTimeMillis()); + SslCertificate ssl = new SslCertificate(TO, BY, DateFormat.getInstance().format( + date1), DateFormat.getInstance().format(date2)); + DName issuedTo = ssl.getIssuedTo(); + DName issuedBy = ssl.getIssuedBy(); + + assertEquals("testCName", issuedTo.getCName()); + assertEquals(TO, issuedTo.getDName()); + assertEquals("testOName", issuedTo.getOName()); + assertEquals("testUName", issuedTo.getUName()); + + assertEquals("testCName", issuedBy.getCName()); + assertEquals(BY, issuedBy.getDName()); + assertEquals("testOName", issuedBy.getOName()); + assertEquals("testUName", issuedBy.getUName()); + + assertEquals(DateFormat.getInstance().format(date1), ssl.getValidNotBefore()); + assertEquals(DateFormat.getInstance().format(date2), ssl.getValidNotAfter()); + final String EXPECTED = "Issued to: c=ccc,o=testOName,ou=testUName,cn=testCName;\n" + + "Issued by: e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName;\n"; + assertEquals(EXPECTED, ssl.toString()); + } + +} diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java new file mode 100644 index 0000000000..7562e3a847 --- /dev/null +++ b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 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.http.cts; + +import java.text.DateFormat; +import java.util.Date; + +import junit.framework.TestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; +import android.net.http.SslCertificate; +import android.net.http.SslCertificate.DName; + +@TestTargetClass(DName.class) +public class SslCertificate_DNameTest extends TestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test DName.", + method = "SslCertificate.DName", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test DName.", + method = "getCName", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test DName.", + method = "getDName", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test DName.", + method = "getOName", + args = {} + ), + @TestTargetNew( + level = TestLevel.TODO, + notes = "Test DName.", + method = "getUName", + args = {} + ) + }) + public void testDName() { + final String TO = "c=ccc,o=testOName,ou=testUName,cn=testCName"; + final String BY = "e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName"; + // new the SslCertificate instance + Date date1 = new Date(System.currentTimeMillis() - 1000); + Date date2 = new Date(System.currentTimeMillis()); + SslCertificate ssl = new SslCertificate(TO, BY, DateFormat.getInstance().format( + date1), DateFormat.getInstance().format(date2)); + DName issuedTo = ssl.getIssuedTo(); + + assertNotNull(issuedTo); + + assertEquals("testCName", issuedTo.getCName()); + assertEquals(TO, issuedTo.getDName()); + assertEquals("testOName", issuedTo.getOName()); + assertEquals("testUName", issuedTo.getUName()); + } + +} From 3cae4df32ad7dc766946b271fea7528d98a580a2 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 18 Mar 2009 17:39:42 -0700 Subject: [PATCH 0002/1415] auto import from //branches/cupcake_rel/...@140373 --- tests/cts/net/Android.mk | 2 + .../net/cts/ConnectivityManagerTest.java | 41 +++++++++------- .../src/android/net/cts/NetworkInfoTest.java | 49 +++++++------------ 3 files changed, 42 insertions(+), 50 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index d1a459f0d3..0a2a6f382b 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -26,5 +26,7 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_INSTRUMENTATION_FOR := CtsTestStubs +LOCAL_SDK_VERSION := current + include $(BUILD_PACKAGE) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 201105f0a6..f2ddd2143f 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,12 +16,11 @@ package android.net.cts; -import com.android.internal.telephony.Phone; - -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -112,10 +111,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { }) public void testAccessNetworkPreference() { - final int EXPECTED = 1; + final int expected = 1; int per = mCm.getNetworkPreference(); - mCm.setNetworkPreference(EXPECTED); - assertEquals(EXPECTED, mCm.getNetworkPreference()); + mCm.setNetworkPreference(expected); + assertEquals(expected, mCm.getNetworkPreference()); mCm.setNetworkPreference(0); assertEquals(0, mCm.getNetworkPreference()); @@ -144,20 +143,22 @@ public class ConnectivityManagerTest extends AndroidTestCase { NetworkInfo[] ni = mCm.getAllNetworkInfo(); assertEquals(2, ni.length); - assertTrue(ni[0].getType() >=0 && ni[0].getType() <= 1); - assertTrue(ni[1].getType() >=0 && ni[1].getType() <= 1); + assertTrue(ni[0].getType() >= 0 && ni[0].getType() <= 1); + assertTrue(ni[1].getType() >= 0 && ni[1].getType() <= 1); } @TestTargets({ @TestTargetNew( level = TestLevel.TODO, - notes = "Test start and stop usingNetworkFeature(int networkType, String feature).", + notes = "Test startUsingNetworkFeature(int networkType, String feature)." + + "Only test failure case.", method = "startUsingNetworkFeature", args = {int.class, java.lang.String.class} ), @TestTargetNew( level = TestLevel.TODO, - notes = "Test start and stop usingNetworkFeature(int networkType, String feature).", + notes = "Test stopUsingNetworkFeature(int networkType, String feature)." + + "Only test failure case.", method = "stopUsingNetworkFeature", args = {int.class, java.lang.String.class} ) @@ -165,16 +166,18 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testStartUsingNetworkFeature() { final String invalidateFeature = "invalidateFeature"; - assertEquals(-1, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + // TODO: MMS feature string is not public + final String mmsFeature = "enableMMS"; + final int failureCode = -1; + + assertEquals(failureCode, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + invalidateFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, invalidateFeature)); - assertEquals(-1, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - invalidateFeature)); - - assertEquals(-1, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, - Phone.FEATURE_ENABLE_MMS)); - assertEquals(-1, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, - Phone.FEATURE_ENABLE_MMS)); + // Should return failure(-1) because MMS is not supported on WIFI. + assertEquals(failureCode, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); } @TestTargetNew( diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 248ef9a71f..5036c4af60 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -16,6 +16,12 @@ package android.net.cts; +import dalvik.annotation.TestInfo; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.ToBeFixed; + import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -23,10 +29,6 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.os.Parcel; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; -import dalvik.annotation.TestTargetClass; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { @@ -109,12 +111,10 @@ public class NetworkInfoTest extends AndroidTestCase { // test environment:connect as TYPE_MOBILE, and connect to internet. assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getType(), ConnectivityManager.TYPE_MOBILE); - assertEquals(ni[ConnectivityManager.TYPE_WIFI].getType(), - ConnectivityManager.TYPE_WIFI); - assertEquals("MOBILE",ni[ConnectivityManager.TYPE_MOBILE].getTypeName()); - assertEquals("WIFI",ni[ConnectivityManager.TYPE_WIFI].getTypeName()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE] - .isConnectedOrConnecting()); + assertEquals(ni[ConnectivityManager.TYPE_WIFI].getType(), ConnectivityManager.TYPE_WIFI); + assertEquals("MOBILE", ni[ConnectivityManager.TYPE_MOBILE].getTypeName()); + assertEquals("WIFI", ni[ConnectivityManager.TYPE_WIFI].getTypeName()); + assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isConnectedOrConnecting()); assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnectedOrConnecting()); assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isAvailable()); assertFalse(ni[ConnectivityManager.TYPE_WIFI].isAvailable()); @@ -124,14 +124,13 @@ public class NetworkInfoTest extends AndroidTestCase { assertEquals(ni[ConnectivityManager.TYPE_MOBILE].describeContents(), 0); assertEquals(ni[ConnectivityManager.TYPE_WIFI].describeContents(), 0); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getState(), - State.CONNECTED); + assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getState(), State.CONNECTED); assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getDetailedState(), DetailedState.CONNECTED); assertNull(ni[ConnectivityManager.TYPE_MOBILE].getReason()); assertNull(ni[ConnectivityManager.TYPE_WIFI].getReason()); - assertEquals("internet",ni[ConnectivityManager.TYPE_MOBILE].getExtraInfo()); + assertEquals("internet", ni[ConnectivityManager.TYPE_MOBILE].getExtraInfo()); assertNull(ni[ConnectivityManager.TYPE_WIFI].getExtraInfo()); assertNotNull(ni[ConnectivityManager.TYPE_MOBILE].toString()); @@ -147,25 +146,13 @@ public class NetworkInfoTest extends AndroidTestCase { methodArgs = {Parcel.class, Integer.class} ) }) + @ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," + + " if build CTS against SDK.") public void testWriteToParcel() { - NetworkInfo[] ni = mConnectivityManager.getAllNetworkInfo(); + NetworkInfo[] networkInfos = mConnectivityManager.getAllNetworkInfo(); + NetworkInfo mobileInfo = networkInfos[ConnectivityManager.TYPE_MOBILE]; Parcel p = Parcel.obtain(); - ni[ConnectivityManager.TYPE_MOBILE].writeToParcel(p, 1); - p.setDataPosition(0); - NetworkInfo mNetworkInfo = NetworkInfo.CREATOR.createFromParcel(p); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getExtraInfo(), - mNetworkInfo.getExtraInfo()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getReason(), - mNetworkInfo.getReason()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getType(), - mNetworkInfo.getType()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getState(), - mNetworkInfo.getState()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getDetailedState(), - mNetworkInfo.getDetailedState()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].isAvailable(), - mNetworkInfo.isAvailable()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].isFailover(), - mNetworkInfo.isFailover()); + + mobileInfo.writeToParcel(p, 1); } } From c2af01c91d3d9faa1923db4936083e8a0e217670 Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Thu, 26 Mar 2009 01:42:37 -0700 Subject: [PATCH 0003/1415] Automated import from //branches/cupcake/...@142888,142888 --- .../net/cts/ConnectivityManagerTest.java | 26 ++-- .../src/android/net/cts/CredentialsTest.java | 8 +- .../net/src/android/net/cts/DhcpInfoTest.java | 4 +- .../net/cts/LocalServerSocketTest.java | 58 ++++--- .../net/cts/LocalSocketAddressTest.java | 18 ++- .../cts/LocalSocketAddress_NamespaceTest.java | 5 +- .../src/android/net/cts/LocalSocketTest.java | 56 +++---- .../net/src/android/net/cts/MailToTest.java | 23 +-- .../src/android/net/cts/NetworkInfoTest.java | 144 ++++++++++-------- .../cts/NetworkInfo_DetailedStateTest.java | 35 ++--- .../net/cts/NetworkInfo_StateTest.java | 35 ++--- .../cts/net/src/android/net/cts/UriTest.java | 100 ++++++------ .../src/android/net/cts/Uri_BuilderTest.java | 35 +++-- .../net/http/cts/SslCertificateTest.java | 21 +-- .../http/cts/SslCertificate_DNameTest.java | 10 +- 15 files changed, 302 insertions(+), 276 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index f2ddd2143f..e8697bebab 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -41,7 +41,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getNetworkInfo(int networkType).", method = "getNetworkInfo", args = {int.class} @@ -73,13 +73,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test isNetworkTypeValid(int networkType).", method = "isNetworkTypeValid", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test isNetworkTypeValid(int networkType).", method = "getAllNetworkInfo", args = {} @@ -97,13 +97,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getNetworkPreference", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "setNetworkPreference", args = {int.class} @@ -133,7 +133,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getAllNetworkInfo().", method = "getAllNetworkInfo", args = {} @@ -149,14 +149,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test startUsingNetworkFeature(int networkType, String feature)." + "Only test failure case.", method = "startUsingNetworkFeature", args = {int.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test stopUsingNetworkFeature(int networkType, String feature)." + "Only test failure case.", method = "stopUsingNetworkFeature", @@ -176,12 +176,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { invalidateFeature)); // Should return failure(-1) because MMS is not supported on WIFI. - assertEquals(failureCode, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, + mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, + mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test requestRouteToHost(int networkType, int hostAddress).", method = "requestRouteToHost", args = {int.class, int.class} @@ -197,7 +199,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getActiveNetworkInfo().", method = "getActiveNetworkInfo", args = {} diff --git a/tests/cts/net/src/android/net/cts/CredentialsTest.java b/tests/cts/net/src/android/net/cts/CredentialsTest.java index 0f6e49e00d..fe65805294 100644 --- a/tests/cts/net/src/android/net/cts/CredentialsTest.java +++ b/tests/cts/net/src/android/net/cts/CredentialsTest.java @@ -28,25 +28,25 @@ public class CredentialsTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "Credentials", args = {int.class, int.class, int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getGid", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getPid", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getUid", args = {} diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java index 657d03c368..1a1ad477fd 100644 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -27,7 +27,7 @@ import dalvik.annotation.TestTargetClass; public class DhcpInfoTest extends AndroidTestCase { @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DhcpInfo's constructor.", method = "DhcpInfo", args = {} @@ -37,7 +37,7 @@ public class DhcpInfoTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test toString function.", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index 4fb8481674..a6511e8521 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -25,41 +25,51 @@ import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.ParcelFileDescriptor; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.ToBeFixed; @TestTargetClass(LocalServerSocket.class) public class LocalServerSocketTest extends AndroidTestCase { - @TestInfo( - status = TestStatus.TBR, - notes = "test LocalServerSocket", - targets = { - @TestTarget( - methodName = "accept", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "accept", + args = {} ), - @TestTarget( - methodName = "close", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "close", + args = {} ), - @TestTarget( - methodName = "getFileDescriptor", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "getFileDescriptor", + args = {} ), - @TestTarget( - methodName = "getLocalSocketAddress", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "getLocalSocketAddress", + args = {} ), - @TestTarget( - methodName = "LocalServerSocket", - methodArgs = {FileDescriptor.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "LocalServerSocket", + args = {java.io.FileDescriptor.class} ), - @TestTarget( - methodName = "LocalServerSocket", - methodArgs = {String.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "LocalServerSocket", + args = {java.lang.String.class} ) }) @ToBeFixed(bug = "1520987", explanation = "Cannot find a proper FileDescriptor for " + diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java index cc3a1d38df..75232c4fff 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java @@ -34,25 +34,25 @@ public class LocalSocketAddressTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "LocalSocketAddress", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "LocalSocketAddress", args = {java.lang.String.class, android.net.LocalSocketAddress.Namespace.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "getName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "getNamespace", args = {} @@ -65,17 +65,19 @@ public class LocalSocketAddressTest extends AndroidTestCase { assertEquals(Namespace.ABSTRACT, localSocketAddress.getNamespace()); // specify the namespace - LocalSocketAddress localSocketAddress2 = new LocalSocketAddress("name2", Namespace.ABSTRACT); + LocalSocketAddress localSocketAddress2 = + new LocalSocketAddress("name2", Namespace.ABSTRACT); assertEquals("name2", localSocketAddress2.getName()); assertEquals(Namespace.ABSTRACT, localSocketAddress2.getNamespace()); - LocalSocketAddress localSocketAddress3 = new LocalSocketAddress("name3", Namespace.FILESYSTEM); + LocalSocketAddress localSocketAddress3 = + new LocalSocketAddress("name3", Namespace.FILESYSTEM); assertEquals("name3", localSocketAddress3.getName()); assertEquals(Namespace.FILESYSTEM, localSocketAddress3.getNamespace()); - LocalSocketAddress localSocketAddress4 = new LocalSocketAddress("name4", Namespace.RESERVED); + LocalSocketAddress localSocketAddress4 = + new LocalSocketAddress("name4", Namespace.RESERVED); assertEquals("name4", localSocketAddress4.getName()); assertEquals(Namespace.RESERVED, localSocketAddress4.getNamespace()); } } - diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java index a9acaa357d..5d29c81895 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java @@ -32,7 +32,7 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test valueOf(String name).", method = "valueOf", args = {java.lang.String.class} @@ -44,7 +44,7 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test values().", method = "values", args = {} @@ -56,4 +56,3 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { assertEquals(Namespace.FILESYSTEM, expected[2]); } } - diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index ae0b51c0ed..8e3cd6714b 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -36,73 +36,73 @@ public class LocalSocketTest extends AndroidTestCase{ @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "LocalSocket", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "close", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "connect", args = {android.net.LocalSocketAddress.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getAncillaryFileDescriptors", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getFileDescriptor", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getInputStream", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getOutputStream", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getPeerCredentials", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "isConnected", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "setFileDescriptorsForSend", args = {java.io.FileDescriptor[].class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "shutdownInput", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "shutdownOutput", args = {} @@ -192,91 +192,91 @@ public class LocalSocketTest extends AndroidTestCase{ @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "bind", args = {android.net.LocalSocketAddress.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "connect", args = {android.net.LocalSocketAddress.class, int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getLocalSocketAddress", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getReceiveBufferSize", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getRemoteSocketAddress", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getSendBufferSize", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getSoTimeout", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isBound", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isClosed", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isInputShutdown", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isOutputShutdown", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setReceiveBufferSize", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setSendBufferSize", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setSoTimeout", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "toString", args = {} @@ -285,7 +285,7 @@ public class LocalSocketTest extends AndroidTestCase{ public void testAccessors() throws IOException{ LocalSocket socket = new LocalSocket(); LocalSocketAddress addr = new LocalSocketAddress("secondary"); - + assertFalse(socket.isBound()); socket.bind(addr); assertTrue(socket.isBound()); diff --git a/tests/cts/net/src/android/net/cts/MailToTest.java b/tests/cts/net/src/android/net/cts/MailToTest.java index e419272517..e64aaf46e0 100644 --- a/tests/cts/net/src/android/net/cts/MailToTest.java +++ b/tests/cts/net/src/android/net/cts/MailToTest.java @@ -28,7 +28,8 @@ import dalvik.annotation.TestTargetClass; public class MailToTest extends AndroidTestCase { private static final String MAILTOURI_1 = "mailto:chris@example.com"; private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue"; - private static final String MAILTOURI_3 = "mailto:infobot@example.com?body=send%20current-issue"; + private static final String MAILTOURI_3 = + "mailto:infobot@example.com?body=send%20current-issue"; private static final String MAILTOURI_4 = "mailto:infobot@example.com?body=send%20current-" + "issue%0D%0Asend%20index"; private static final String MAILTOURI_5 = "mailto:joe@example.com?" + @@ -43,49 +44,49 @@ public class MailToTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "parse", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "isMailTo", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getTo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getSubject", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getBody", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getCc", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "toString", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getHeaders", args = {} @@ -136,7 +137,8 @@ public class MailToTest extends AndroidTestCase { assertEquals("send current-issue\r\nsend index", mailTo_4.getBody()); assertNull(mailTo_4.getCc()); assertNull(mailTo_4.getSubject()); - assertEquals("mailto:?body=send%20current-issue%0D%0Asend%20index&to=infobot%40example.com&", + assertEquals( + "mailto:?body=send%20current-issue%0D%0Asend%20index&to=infobot%40example.com&", mailTo_4.toString()); assertTrue(MailTo.isMailTo(MAILTOURI_5)); @@ -164,4 +166,3 @@ public class MailToTest extends AndroidTestCase { mailTo_6.toString()); } } - diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 5036c4af60..46da3ca74f 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -16,10 +16,6 @@ package android.net.cts; -import dalvik.annotation.TestInfo; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; -import dalvik.annotation.TestTargetClass; import dalvik.annotation.ToBeFixed; import android.content.Context; @@ -29,6 +25,11 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.os.Parcel; import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { @@ -41,65 +42,90 @@ public class NetworkInfoTest extends AndroidTestCase { .getSystemService(Context.CONNECTIVITY_SERVICE); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test isConnectedOrConnecting().", - targets = { - @TestTarget( - methodName = "isConnectedOrConnecting", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isConnectedOrConnecting", + args = {} ), - @TestTarget( - methodName = "setFailover", - methodArgs = {boolean.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "setFailover", + args = {boolean.class} ), - @TestTarget( - methodName = "isFailover", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isFailover", + args = {} ), - @TestTarget( - methodName = "getType", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getType", + args = {} ), - @TestTarget( - methodName = "getTypeName", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getTypeName", + args = {} ), - @TestTarget( - methodName = "setIsAvailable", - methodArgs = {boolean.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "setIsAvailable", + args = {boolean.class} ), - @TestTarget( - methodName = "isAvailable", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isAvailable", + args = {} ), - @TestTarget( - methodName = "isConnected", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isConnected", + args = {} ), - @TestTarget( - methodName = "describeContents", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "describeContents", + args = {} ), - @TestTarget( - methodName = "getDetailedState", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getDetailedState", + args = {} ), - @TestTarget( - methodName = "getState", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getState", + args = {} ), - @TestTarget( - methodName = "getReason", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getReason", + args = {} ), - @TestTarget( - methodName = "getExtraInfo", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getExtraInfo", + args = {} ), - @TestTarget( - methodName = "toString", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "toString", + args = {} ) }) public void testAccessNetworkInfoProperties() { @@ -137,17 +163,13 @@ public class NetworkInfoTest extends AndroidTestCase { assertNotNull(ni[ConnectivityManager.TYPE_WIFI].toString()); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test writeToParcel(Parcel dest, int flags).", - targets = { - @TestTarget( - methodName = "writeToParcel", - methodArgs = {Parcel.class, Integer.class} - ) - }) - @ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," - + " if build CTS against SDK.") + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test writeToParcel(Parcel dest, int flags).", + method = "writeToParcel", + args = {android.os.Parcel.class, java.lang.Integer.class} + ) + //@ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," public void testWriteToParcel() { NetworkInfo[] networkInfos = mConnectivityManager.getAllNetworkInfo(); NetworkInfo mobileInfo = networkInfos[ConnectivityManager.TYPE_MOBILE]; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 64597242a7..002adfecaf 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -18,9 +18,10 @@ package android.net.cts; import android.net.NetworkInfo.DetailedState; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; @TestTargetClass(DetailedState.class) @@ -31,15 +32,12 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { super.setUp(); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test valueOf(String name).", - targets = { - @TestTarget( - methodName = "valueOf", - methodArgs = {String.class} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) public void testValueOf() { assertEquals(DetailedState.AUTHENTICATING, DetailedState .valueOf("AUTHENTICATING")); @@ -60,15 +58,12 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { .valueOf("SUSPENDED")); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test values().", - targets = { - @TestTarget( - methodName = "values", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) public void testValues() { DetailedState[] expected = DetailedState.values(); assertEquals(10, expected.length); diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java index b03c3f0215..2f58784708 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -17,9 +17,10 @@ package android.net.cts; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import android.net.NetworkInfo.State; @@ -31,15 +32,12 @@ public class NetworkInfo_StateTest extends AndroidTestCase { super.setUp(); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test valueOf(String name).", - targets = { - @TestTarget( - methodName = "valueOf", - methodArgs = {String.class} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) public void testValueOf() { assertEquals(State.CONNECTED, State.valueOf("CONNECTED")); assertEquals(State.CONNECTING, State.valueOf("CONNECTING")); @@ -49,15 +47,12 @@ public class NetworkInfo_StateTest extends AndroidTestCase { assertEquals(State.UNKNOWN, State.valueOf("UNKNOWN")); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test values().", - targets = { - @TestTarget( - methodName = "values", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) public void testValues() { State[] expected = State.values(); assertEquals(6, expected.length); diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 84b58c081a..067ce52372 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -30,7 +30,7 @@ import java.util.Arrays; @TestTargetClass(Uri.class) public class UriTest extends AndroidTestCase { @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test write to and read frome parcel.", method = "writeToParcel", args = {android.os.Parcel.class, android.net.Uri.class} @@ -61,7 +61,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test buildUpon", method = "buildUpon", args = {} @@ -94,73 +94,73 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getHost", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getPort", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getUserInfo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedUserInfo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "parse", args = {java.lang.String.class} @@ -203,7 +203,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test compareTo", method = "compareTo", args = {android.net.Uri.class} @@ -220,13 +220,13 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test equals and hashCode.", method = "equals", args = {java.lang.Object.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test equals and hashCode.", method = "hashCode", args = {} @@ -262,19 +262,19 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "encode", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "encode", args = {java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "decode", args = {java.lang.String.class} @@ -301,7 +301,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test fromFile.", method = "fromFile", args = {java.io.File.class} @@ -318,13 +318,13 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test get query parameters.", method = "getQueryParameter", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test get query parameters.", method = "getQueryParameters", args = {java.lang.String.class} @@ -347,19 +347,19 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getPathSegments", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getLastPathSegment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "withAppendedPath", args = {android.net.Uri.class, java.lang.String.class} @@ -404,55 +404,55 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isAbsolute", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isOpaque", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isRelative", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getHost", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getPort", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getScheme", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "fromParts", args = {java.lang.String.class, java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "toString", args = {} @@ -514,91 +514,91 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getAuthority", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getScheme", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedAuthority", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isAbsolute", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isHierarchical", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isOpaque", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isRelative", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java index 8a1b42341b..66bdb074b0 100644 --- a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java +++ b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java @@ -28,103 +28,103 @@ import android.net.Uri; public class Uri_BuilderTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "Uri.Builder", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "build", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "scheme", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "authority", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "path", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "query", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "opaquePart", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "fragment", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendEncodedPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendQueryParameter", args = {java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedAuthority", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedFragment", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedQuery", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedOpaquePart", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "toString", args = {} @@ -171,4 +171,3 @@ public class Uri_BuilderTest extends TestCase { assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); } } - diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java index 6e23419de9..91ca876fda 100644 --- a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java @@ -46,13 +46,14 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor(s) of SslCertificate.", method = "SslCertificate", - args = {java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class} + args = {java.lang.String.class, java.lang.String.class, java.lang.String.class, + java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor(s) of SslCertificate.", method = "SslCertificate", args = {java.security.cert.X509Certificate.class} @@ -205,13 +206,13 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test saveState and restoreState(SslCertificate certificate).", method = "saveState", args = {android.net.http.SslCertificate.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test saveState and restoreState(SslCertificate certificate).", method = "restoreState", args = {android.os.Bundle.class} @@ -240,31 +241,31 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getIssuedTo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getIssuedBy", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getValidNotAfter", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getValidNotBefore", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java index 7562e3a847..848bf7b95a 100644 --- a/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java @@ -32,31 +32,31 @@ public class SslCertificate_DNameTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "SslCertificate.DName", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getCName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getDName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getOName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getUName", args = {} From 02051d27459011773f90e8796009fde63b9be863 Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Fri, 27 Mar 2009 16:24:28 -0700 Subject: [PATCH 0004/1415] AI 143176: am: CL 142888 CTS annotation update update wrong TestLevel values update tests that were still using the old annotations minor fixes to eliminate eclipse warnings style fixes Original author: sus Merged from: //branches/cupcake/... Automated import of CL 143176 --- .../net/cts/ConnectivityManagerTest.java | 26 ++-- .../src/android/net/cts/CredentialsTest.java | 8 +- .../net/src/android/net/cts/DhcpInfoTest.java | 4 +- .../net/cts/LocalServerSocketTest.java | 58 ++++--- .../net/cts/LocalSocketAddressTest.java | 18 ++- .../cts/LocalSocketAddress_NamespaceTest.java | 5 +- .../src/android/net/cts/LocalSocketTest.java | 56 +++---- .../net/src/android/net/cts/MailToTest.java | 23 +-- .../src/android/net/cts/NetworkInfoTest.java | 144 ++++++++++-------- .../cts/NetworkInfo_DetailedStateTest.java | 35 ++--- .../net/cts/NetworkInfo_StateTest.java | 35 ++--- .../cts/net/src/android/net/cts/UriTest.java | 100 ++++++------ .../src/android/net/cts/Uri_BuilderTest.java | 35 +++-- .../net/http/cts/SslCertificateTest.java | 21 +-- .../http/cts/SslCertificate_DNameTest.java | 10 +- 15 files changed, 302 insertions(+), 276 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index f2ddd2143f..e8697bebab 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -41,7 +41,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getNetworkInfo(int networkType).", method = "getNetworkInfo", args = {int.class} @@ -73,13 +73,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test isNetworkTypeValid(int networkType).", method = "isNetworkTypeValid", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test isNetworkTypeValid(int networkType).", method = "getAllNetworkInfo", args = {} @@ -97,13 +97,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getNetworkPreference", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "setNetworkPreference", args = {int.class} @@ -133,7 +133,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getAllNetworkInfo().", method = "getAllNetworkInfo", args = {} @@ -149,14 +149,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test startUsingNetworkFeature(int networkType, String feature)." + "Only test failure case.", method = "startUsingNetworkFeature", args = {int.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test stopUsingNetworkFeature(int networkType, String feature)." + "Only test failure case.", method = "stopUsingNetworkFeature", @@ -176,12 +176,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { invalidateFeature)); // Should return failure(-1) because MMS is not supported on WIFI. - assertEquals(failureCode, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, + mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, + mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test requestRouteToHost(int networkType, int hostAddress).", method = "requestRouteToHost", args = {int.class, int.class} @@ -197,7 +199,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getActiveNetworkInfo().", method = "getActiveNetworkInfo", args = {} diff --git a/tests/cts/net/src/android/net/cts/CredentialsTest.java b/tests/cts/net/src/android/net/cts/CredentialsTest.java index 0f6e49e00d..fe65805294 100644 --- a/tests/cts/net/src/android/net/cts/CredentialsTest.java +++ b/tests/cts/net/src/android/net/cts/CredentialsTest.java @@ -28,25 +28,25 @@ public class CredentialsTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "Credentials", args = {int.class, int.class, int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getGid", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getPid", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getUid", args = {} diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java index 657d03c368..1a1ad477fd 100644 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -27,7 +27,7 @@ import dalvik.annotation.TestTargetClass; public class DhcpInfoTest extends AndroidTestCase { @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DhcpInfo's constructor.", method = "DhcpInfo", args = {} @@ -37,7 +37,7 @@ public class DhcpInfoTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test toString function.", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index 4fb8481674..a6511e8521 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -25,41 +25,51 @@ import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.ParcelFileDescriptor; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.ToBeFixed; @TestTargetClass(LocalServerSocket.class) public class LocalServerSocketTest extends AndroidTestCase { - @TestInfo( - status = TestStatus.TBR, - notes = "test LocalServerSocket", - targets = { - @TestTarget( - methodName = "accept", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "accept", + args = {} ), - @TestTarget( - methodName = "close", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "close", + args = {} ), - @TestTarget( - methodName = "getFileDescriptor", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "getFileDescriptor", + args = {} ), - @TestTarget( - methodName = "getLocalSocketAddress", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "getLocalSocketAddress", + args = {} ), - @TestTarget( - methodName = "LocalServerSocket", - methodArgs = {FileDescriptor.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "LocalServerSocket", + args = {java.io.FileDescriptor.class} ), - @TestTarget( - methodName = "LocalServerSocket", - methodArgs = {String.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "LocalServerSocket", + args = {java.lang.String.class} ) }) @ToBeFixed(bug = "1520987", explanation = "Cannot find a proper FileDescriptor for " + diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java index cc3a1d38df..75232c4fff 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java @@ -34,25 +34,25 @@ public class LocalSocketAddressTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "LocalSocketAddress", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "LocalSocketAddress", args = {java.lang.String.class, android.net.LocalSocketAddress.Namespace.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "getName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "getNamespace", args = {} @@ -65,17 +65,19 @@ public class LocalSocketAddressTest extends AndroidTestCase { assertEquals(Namespace.ABSTRACT, localSocketAddress.getNamespace()); // specify the namespace - LocalSocketAddress localSocketAddress2 = new LocalSocketAddress("name2", Namespace.ABSTRACT); + LocalSocketAddress localSocketAddress2 = + new LocalSocketAddress("name2", Namespace.ABSTRACT); assertEquals("name2", localSocketAddress2.getName()); assertEquals(Namespace.ABSTRACT, localSocketAddress2.getNamespace()); - LocalSocketAddress localSocketAddress3 = new LocalSocketAddress("name3", Namespace.FILESYSTEM); + LocalSocketAddress localSocketAddress3 = + new LocalSocketAddress("name3", Namespace.FILESYSTEM); assertEquals("name3", localSocketAddress3.getName()); assertEquals(Namespace.FILESYSTEM, localSocketAddress3.getNamespace()); - LocalSocketAddress localSocketAddress4 = new LocalSocketAddress("name4", Namespace.RESERVED); + LocalSocketAddress localSocketAddress4 = + new LocalSocketAddress("name4", Namespace.RESERVED); assertEquals("name4", localSocketAddress4.getName()); assertEquals(Namespace.RESERVED, localSocketAddress4.getNamespace()); } } - diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java index a9acaa357d..5d29c81895 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java @@ -32,7 +32,7 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test valueOf(String name).", method = "valueOf", args = {java.lang.String.class} @@ -44,7 +44,7 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test values().", method = "values", args = {} @@ -56,4 +56,3 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { assertEquals(Namespace.FILESYSTEM, expected[2]); } } - diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index ae0b51c0ed..8e3cd6714b 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -36,73 +36,73 @@ public class LocalSocketTest extends AndroidTestCase{ @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "LocalSocket", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "close", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "connect", args = {android.net.LocalSocketAddress.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getAncillaryFileDescriptors", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getFileDescriptor", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getInputStream", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getOutputStream", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getPeerCredentials", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "isConnected", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "setFileDescriptorsForSend", args = {java.io.FileDescriptor[].class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "shutdownInput", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "shutdownOutput", args = {} @@ -192,91 +192,91 @@ public class LocalSocketTest extends AndroidTestCase{ @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "bind", args = {android.net.LocalSocketAddress.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "connect", args = {android.net.LocalSocketAddress.class, int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getLocalSocketAddress", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getReceiveBufferSize", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getRemoteSocketAddress", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getSendBufferSize", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getSoTimeout", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isBound", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isClosed", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isInputShutdown", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isOutputShutdown", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setReceiveBufferSize", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setSendBufferSize", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setSoTimeout", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "toString", args = {} @@ -285,7 +285,7 @@ public class LocalSocketTest extends AndroidTestCase{ public void testAccessors() throws IOException{ LocalSocket socket = new LocalSocket(); LocalSocketAddress addr = new LocalSocketAddress("secondary"); - + assertFalse(socket.isBound()); socket.bind(addr); assertTrue(socket.isBound()); diff --git a/tests/cts/net/src/android/net/cts/MailToTest.java b/tests/cts/net/src/android/net/cts/MailToTest.java index e419272517..e64aaf46e0 100644 --- a/tests/cts/net/src/android/net/cts/MailToTest.java +++ b/tests/cts/net/src/android/net/cts/MailToTest.java @@ -28,7 +28,8 @@ import dalvik.annotation.TestTargetClass; public class MailToTest extends AndroidTestCase { private static final String MAILTOURI_1 = "mailto:chris@example.com"; private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue"; - private static final String MAILTOURI_3 = "mailto:infobot@example.com?body=send%20current-issue"; + private static final String MAILTOURI_3 = + "mailto:infobot@example.com?body=send%20current-issue"; private static final String MAILTOURI_4 = "mailto:infobot@example.com?body=send%20current-" + "issue%0D%0Asend%20index"; private static final String MAILTOURI_5 = "mailto:joe@example.com?" + @@ -43,49 +44,49 @@ public class MailToTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "parse", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "isMailTo", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getTo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getSubject", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getBody", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getCc", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "toString", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getHeaders", args = {} @@ -136,7 +137,8 @@ public class MailToTest extends AndroidTestCase { assertEquals("send current-issue\r\nsend index", mailTo_4.getBody()); assertNull(mailTo_4.getCc()); assertNull(mailTo_4.getSubject()); - assertEquals("mailto:?body=send%20current-issue%0D%0Asend%20index&to=infobot%40example.com&", + assertEquals( + "mailto:?body=send%20current-issue%0D%0Asend%20index&to=infobot%40example.com&", mailTo_4.toString()); assertTrue(MailTo.isMailTo(MAILTOURI_5)); @@ -164,4 +166,3 @@ public class MailToTest extends AndroidTestCase { mailTo_6.toString()); } } - diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 5036c4af60..46da3ca74f 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -16,10 +16,6 @@ package android.net.cts; -import dalvik.annotation.TestInfo; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; -import dalvik.annotation.TestTargetClass; import dalvik.annotation.ToBeFixed; import android.content.Context; @@ -29,6 +25,11 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.os.Parcel; import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { @@ -41,65 +42,90 @@ public class NetworkInfoTest extends AndroidTestCase { .getSystemService(Context.CONNECTIVITY_SERVICE); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test isConnectedOrConnecting().", - targets = { - @TestTarget( - methodName = "isConnectedOrConnecting", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isConnectedOrConnecting", + args = {} ), - @TestTarget( - methodName = "setFailover", - methodArgs = {boolean.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "setFailover", + args = {boolean.class} ), - @TestTarget( - methodName = "isFailover", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isFailover", + args = {} ), - @TestTarget( - methodName = "getType", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getType", + args = {} ), - @TestTarget( - methodName = "getTypeName", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getTypeName", + args = {} ), - @TestTarget( - methodName = "setIsAvailable", - methodArgs = {boolean.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "setIsAvailable", + args = {boolean.class} ), - @TestTarget( - methodName = "isAvailable", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isAvailable", + args = {} ), - @TestTarget( - methodName = "isConnected", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isConnected", + args = {} ), - @TestTarget( - methodName = "describeContents", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "describeContents", + args = {} ), - @TestTarget( - methodName = "getDetailedState", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getDetailedState", + args = {} ), - @TestTarget( - methodName = "getState", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getState", + args = {} ), - @TestTarget( - methodName = "getReason", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getReason", + args = {} ), - @TestTarget( - methodName = "getExtraInfo", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getExtraInfo", + args = {} ), - @TestTarget( - methodName = "toString", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "toString", + args = {} ) }) public void testAccessNetworkInfoProperties() { @@ -137,17 +163,13 @@ public class NetworkInfoTest extends AndroidTestCase { assertNotNull(ni[ConnectivityManager.TYPE_WIFI].toString()); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test writeToParcel(Parcel dest, int flags).", - targets = { - @TestTarget( - methodName = "writeToParcel", - methodArgs = {Parcel.class, Integer.class} - ) - }) - @ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," - + " if build CTS against SDK.") + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test writeToParcel(Parcel dest, int flags).", + method = "writeToParcel", + args = {android.os.Parcel.class, java.lang.Integer.class} + ) + //@ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," public void testWriteToParcel() { NetworkInfo[] networkInfos = mConnectivityManager.getAllNetworkInfo(); NetworkInfo mobileInfo = networkInfos[ConnectivityManager.TYPE_MOBILE]; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 64597242a7..002adfecaf 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -18,9 +18,10 @@ package android.net.cts; import android.net.NetworkInfo.DetailedState; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; @TestTargetClass(DetailedState.class) @@ -31,15 +32,12 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { super.setUp(); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test valueOf(String name).", - targets = { - @TestTarget( - methodName = "valueOf", - methodArgs = {String.class} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) public void testValueOf() { assertEquals(DetailedState.AUTHENTICATING, DetailedState .valueOf("AUTHENTICATING")); @@ -60,15 +58,12 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { .valueOf("SUSPENDED")); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test values().", - targets = { - @TestTarget( - methodName = "values", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) public void testValues() { DetailedState[] expected = DetailedState.values(); assertEquals(10, expected.length); diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java index b03c3f0215..2f58784708 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -17,9 +17,10 @@ package android.net.cts; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import android.net.NetworkInfo.State; @@ -31,15 +32,12 @@ public class NetworkInfo_StateTest extends AndroidTestCase { super.setUp(); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test valueOf(String name).", - targets = { - @TestTarget( - methodName = "valueOf", - methodArgs = {String.class} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) public void testValueOf() { assertEquals(State.CONNECTED, State.valueOf("CONNECTED")); assertEquals(State.CONNECTING, State.valueOf("CONNECTING")); @@ -49,15 +47,12 @@ public class NetworkInfo_StateTest extends AndroidTestCase { assertEquals(State.UNKNOWN, State.valueOf("UNKNOWN")); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test values().", - targets = { - @TestTarget( - methodName = "values", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) public void testValues() { State[] expected = State.values(); assertEquals(6, expected.length); diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 84b58c081a..067ce52372 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -30,7 +30,7 @@ import java.util.Arrays; @TestTargetClass(Uri.class) public class UriTest extends AndroidTestCase { @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test write to and read frome parcel.", method = "writeToParcel", args = {android.os.Parcel.class, android.net.Uri.class} @@ -61,7 +61,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test buildUpon", method = "buildUpon", args = {} @@ -94,73 +94,73 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getHost", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getPort", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getUserInfo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedUserInfo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "parse", args = {java.lang.String.class} @@ -203,7 +203,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test compareTo", method = "compareTo", args = {android.net.Uri.class} @@ -220,13 +220,13 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test equals and hashCode.", method = "equals", args = {java.lang.Object.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test equals and hashCode.", method = "hashCode", args = {} @@ -262,19 +262,19 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "encode", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "encode", args = {java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "decode", args = {java.lang.String.class} @@ -301,7 +301,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test fromFile.", method = "fromFile", args = {java.io.File.class} @@ -318,13 +318,13 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test get query parameters.", method = "getQueryParameter", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test get query parameters.", method = "getQueryParameters", args = {java.lang.String.class} @@ -347,19 +347,19 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getPathSegments", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getLastPathSegment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "withAppendedPath", args = {android.net.Uri.class, java.lang.String.class} @@ -404,55 +404,55 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isAbsolute", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isOpaque", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isRelative", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getHost", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getPort", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getScheme", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "fromParts", args = {java.lang.String.class, java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "toString", args = {} @@ -514,91 +514,91 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getAuthority", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getScheme", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedAuthority", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isAbsolute", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isHierarchical", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isOpaque", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isRelative", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java index 8a1b42341b..66bdb074b0 100644 --- a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java +++ b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java @@ -28,103 +28,103 @@ import android.net.Uri; public class Uri_BuilderTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "Uri.Builder", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "build", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "scheme", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "authority", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "path", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "query", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "opaquePart", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "fragment", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendEncodedPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendQueryParameter", args = {java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedAuthority", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedFragment", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedQuery", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedOpaquePart", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "toString", args = {} @@ -171,4 +171,3 @@ public class Uri_BuilderTest extends TestCase { assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); } } - diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java index 6e23419de9..91ca876fda 100644 --- a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java @@ -46,13 +46,14 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor(s) of SslCertificate.", method = "SslCertificate", - args = {java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class} + args = {java.lang.String.class, java.lang.String.class, java.lang.String.class, + java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor(s) of SslCertificate.", method = "SslCertificate", args = {java.security.cert.X509Certificate.class} @@ -205,13 +206,13 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test saveState and restoreState(SslCertificate certificate).", method = "saveState", args = {android.net.http.SslCertificate.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test saveState and restoreState(SslCertificate certificate).", method = "restoreState", args = {android.os.Bundle.class} @@ -240,31 +241,31 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getIssuedTo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getIssuedBy", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getValidNotAfter", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getValidNotBefore", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java index 7562e3a847..848bf7b95a 100644 --- a/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java @@ -32,31 +32,31 @@ public class SslCertificate_DNameTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "SslCertificate.DName", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getCName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getDName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getOName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getUName", args = {} From ab7e18c924ed6b8e752ac9f8d53cc99eae178631 Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Fri, 27 Mar 2009 18:17:33 -0700 Subject: [PATCH 0005/1415] AI 143326: am: CL 143176 am: CL 142888 CTS annotation update update wrong TestLevel values update tests that were still using the old annotations minor fixes to eliminate eclipse warnings style fixes Original author: sus Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143326 --- .../net/cts/ConnectivityManagerTest.java | 26 ++-- .../src/android/net/cts/CredentialsTest.java | 8 +- .../net/src/android/net/cts/DhcpInfoTest.java | 4 +- .../net/cts/LocalServerSocketTest.java | 58 ++++--- .../net/cts/LocalSocketAddressTest.java | 18 ++- .../cts/LocalSocketAddress_NamespaceTest.java | 5 +- .../src/android/net/cts/LocalSocketTest.java | 56 +++---- .../net/src/android/net/cts/MailToTest.java | 23 +-- .../src/android/net/cts/NetworkInfoTest.java | 144 ++++++++++-------- .../cts/NetworkInfo_DetailedStateTest.java | 35 ++--- .../net/cts/NetworkInfo_StateTest.java | 35 ++--- .../cts/net/src/android/net/cts/UriTest.java | 100 ++++++------ .../src/android/net/cts/Uri_BuilderTest.java | 35 +++-- .../net/http/cts/SslCertificateTest.java | 21 +-- .../http/cts/SslCertificate_DNameTest.java | 10 +- 15 files changed, 302 insertions(+), 276 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index f2ddd2143f..e8697bebab 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -41,7 +41,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getNetworkInfo(int networkType).", method = "getNetworkInfo", args = {int.class} @@ -73,13 +73,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test isNetworkTypeValid(int networkType).", method = "isNetworkTypeValid", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test isNetworkTypeValid(int networkType).", method = "getAllNetworkInfo", args = {} @@ -97,13 +97,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getNetworkPreference", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "setNetworkPreference", args = {int.class} @@ -133,7 +133,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getAllNetworkInfo().", method = "getAllNetworkInfo", args = {} @@ -149,14 +149,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test startUsingNetworkFeature(int networkType, String feature)." + "Only test failure case.", method = "startUsingNetworkFeature", args = {int.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test stopUsingNetworkFeature(int networkType, String feature)." + "Only test failure case.", method = "stopUsingNetworkFeature", @@ -176,12 +176,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { invalidateFeature)); // Should return failure(-1) because MMS is not supported on WIFI. - assertEquals(failureCode, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, + mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, + mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test requestRouteToHost(int networkType, int hostAddress).", method = "requestRouteToHost", args = {int.class, int.class} @@ -197,7 +199,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getActiveNetworkInfo().", method = "getActiveNetworkInfo", args = {} diff --git a/tests/cts/net/src/android/net/cts/CredentialsTest.java b/tests/cts/net/src/android/net/cts/CredentialsTest.java index 0f6e49e00d..fe65805294 100644 --- a/tests/cts/net/src/android/net/cts/CredentialsTest.java +++ b/tests/cts/net/src/android/net/cts/CredentialsTest.java @@ -28,25 +28,25 @@ public class CredentialsTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "Credentials", args = {int.class, int.class, int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getGid", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getPid", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getUid", args = {} diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java index 657d03c368..1a1ad477fd 100644 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -27,7 +27,7 @@ import dalvik.annotation.TestTargetClass; public class DhcpInfoTest extends AndroidTestCase { @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DhcpInfo's constructor.", method = "DhcpInfo", args = {} @@ -37,7 +37,7 @@ public class DhcpInfoTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test toString function.", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index 4fb8481674..a6511e8521 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -25,41 +25,51 @@ import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.ParcelFileDescriptor; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.ToBeFixed; @TestTargetClass(LocalServerSocket.class) public class LocalServerSocketTest extends AndroidTestCase { - @TestInfo( - status = TestStatus.TBR, - notes = "test LocalServerSocket", - targets = { - @TestTarget( - methodName = "accept", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "accept", + args = {} ), - @TestTarget( - methodName = "close", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "close", + args = {} ), - @TestTarget( - methodName = "getFileDescriptor", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "getFileDescriptor", + args = {} ), - @TestTarget( - methodName = "getLocalSocketAddress", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "getLocalSocketAddress", + args = {} ), - @TestTarget( - methodName = "LocalServerSocket", - methodArgs = {FileDescriptor.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "LocalServerSocket", + args = {java.io.FileDescriptor.class} ), - @TestTarget( - methodName = "LocalServerSocket", - methodArgs = {String.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test LocalServerSocket", + method = "LocalServerSocket", + args = {java.lang.String.class} ) }) @ToBeFixed(bug = "1520987", explanation = "Cannot find a proper FileDescriptor for " + diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java index cc3a1d38df..75232c4fff 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java @@ -34,25 +34,25 @@ public class LocalSocketAddressTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "LocalSocketAddress", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "LocalSocketAddress", args = {java.lang.String.class, android.net.LocalSocketAddress.Namespace.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "getName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test LocalSocketAddress", method = "getNamespace", args = {} @@ -65,17 +65,19 @@ public class LocalSocketAddressTest extends AndroidTestCase { assertEquals(Namespace.ABSTRACT, localSocketAddress.getNamespace()); // specify the namespace - LocalSocketAddress localSocketAddress2 = new LocalSocketAddress("name2", Namespace.ABSTRACT); + LocalSocketAddress localSocketAddress2 = + new LocalSocketAddress("name2", Namespace.ABSTRACT); assertEquals("name2", localSocketAddress2.getName()); assertEquals(Namespace.ABSTRACT, localSocketAddress2.getNamespace()); - LocalSocketAddress localSocketAddress3 = new LocalSocketAddress("name3", Namespace.FILESYSTEM); + LocalSocketAddress localSocketAddress3 = + new LocalSocketAddress("name3", Namespace.FILESYSTEM); assertEquals("name3", localSocketAddress3.getName()); assertEquals(Namespace.FILESYSTEM, localSocketAddress3.getNamespace()); - LocalSocketAddress localSocketAddress4 = new LocalSocketAddress("name4", Namespace.RESERVED); + LocalSocketAddress localSocketAddress4 = + new LocalSocketAddress("name4", Namespace.RESERVED); assertEquals("name4", localSocketAddress4.getName()); assertEquals(Namespace.RESERVED, localSocketAddress4.getNamespace()); } } - diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java index a9acaa357d..5d29c81895 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java @@ -32,7 +32,7 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test valueOf(String name).", method = "valueOf", args = {java.lang.String.class} @@ -44,7 +44,7 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test values().", method = "values", args = {} @@ -56,4 +56,3 @@ public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { assertEquals(Namespace.FILESYSTEM, expected[2]); } } - diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index ae0b51c0ed..8e3cd6714b 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -36,73 +36,73 @@ public class LocalSocketTest extends AndroidTestCase{ @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "LocalSocket", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "close", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "connect", args = {android.net.LocalSocketAddress.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getAncillaryFileDescriptors", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getFileDescriptor", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getInputStream", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getOutputStream", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "getPeerCredentials", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "isConnected", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "setFileDescriptorsForSend", args = {java.io.FileDescriptor[].class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "shutdownInput", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test core functions of LocalSocket", method = "shutdownOutput", args = {} @@ -192,91 +192,91 @@ public class LocalSocketTest extends AndroidTestCase{ @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "bind", args = {android.net.LocalSocketAddress.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "connect", args = {android.net.LocalSocketAddress.class, int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getLocalSocketAddress", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getReceiveBufferSize", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getRemoteSocketAddress", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getSendBufferSize", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "getSoTimeout", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isBound", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isClosed", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isInputShutdown", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "isOutputShutdown", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setReceiveBufferSize", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setSendBufferSize", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "setSoTimeout", args = {int.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "test secondary functions of LocalSocket", method = "toString", args = {} @@ -285,7 +285,7 @@ public class LocalSocketTest extends AndroidTestCase{ public void testAccessors() throws IOException{ LocalSocket socket = new LocalSocket(); LocalSocketAddress addr = new LocalSocketAddress("secondary"); - + assertFalse(socket.isBound()); socket.bind(addr); assertTrue(socket.isBound()); diff --git a/tests/cts/net/src/android/net/cts/MailToTest.java b/tests/cts/net/src/android/net/cts/MailToTest.java index e419272517..e64aaf46e0 100644 --- a/tests/cts/net/src/android/net/cts/MailToTest.java +++ b/tests/cts/net/src/android/net/cts/MailToTest.java @@ -28,7 +28,8 @@ import dalvik.annotation.TestTargetClass; public class MailToTest extends AndroidTestCase { private static final String MAILTOURI_1 = "mailto:chris@example.com"; private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue"; - private static final String MAILTOURI_3 = "mailto:infobot@example.com?body=send%20current-issue"; + private static final String MAILTOURI_3 = + "mailto:infobot@example.com?body=send%20current-issue"; private static final String MAILTOURI_4 = "mailto:infobot@example.com?body=send%20current-" + "issue%0D%0Asend%20index"; private static final String MAILTOURI_5 = "mailto:joe@example.com?" + @@ -43,49 +44,49 @@ public class MailToTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "parse", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "isMailTo", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getTo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getSubject", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getBody", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getCc", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "toString", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test parse mailto URI.", method = "getHeaders", args = {} @@ -136,7 +137,8 @@ public class MailToTest extends AndroidTestCase { assertEquals("send current-issue\r\nsend index", mailTo_4.getBody()); assertNull(mailTo_4.getCc()); assertNull(mailTo_4.getSubject()); - assertEquals("mailto:?body=send%20current-issue%0D%0Asend%20index&to=infobot%40example.com&", + assertEquals( + "mailto:?body=send%20current-issue%0D%0Asend%20index&to=infobot%40example.com&", mailTo_4.toString()); assertTrue(MailTo.isMailTo(MAILTOURI_5)); @@ -164,4 +166,3 @@ public class MailToTest extends AndroidTestCase { mailTo_6.toString()); } } - diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 5036c4af60..46da3ca74f 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -16,10 +16,6 @@ package android.net.cts; -import dalvik.annotation.TestInfo; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; -import dalvik.annotation.TestTargetClass; import dalvik.annotation.ToBeFixed; import android.content.Context; @@ -29,6 +25,11 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.os.Parcel; import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestStatus; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { @@ -41,65 +42,90 @@ public class NetworkInfoTest extends AndroidTestCase { .getSystemService(Context.CONNECTIVITY_SERVICE); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test isConnectedOrConnecting().", - targets = { - @TestTarget( - methodName = "isConnectedOrConnecting", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isConnectedOrConnecting", + args = {} ), - @TestTarget( - methodName = "setFailover", - methodArgs = {boolean.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "setFailover", + args = {boolean.class} ), - @TestTarget( - methodName = "isFailover", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isFailover", + args = {} ), - @TestTarget( - methodName = "getType", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getType", + args = {} ), - @TestTarget( - methodName = "getTypeName", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getTypeName", + args = {} ), - @TestTarget( - methodName = "setIsAvailable", - methodArgs = {boolean.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "setIsAvailable", + args = {boolean.class} ), - @TestTarget( - methodName = "isAvailable", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isAvailable", + args = {} ), - @TestTarget( - methodName = "isConnected", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "isConnected", + args = {} ), - @TestTarget( - methodName = "describeContents", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "describeContents", + args = {} ), - @TestTarget( - methodName = "getDetailedState", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getDetailedState", + args = {} ), - @TestTarget( - methodName = "getState", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getState", + args = {} ), - @TestTarget( - methodName = "getReason", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getReason", + args = {} ), - @TestTarget( - methodName = "getExtraInfo", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "getExtraInfo", + args = {} ), - @TestTarget( - methodName = "toString", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test isConnectedOrConnecting().", + method = "toString", + args = {} ) }) public void testAccessNetworkInfoProperties() { @@ -137,17 +163,13 @@ public class NetworkInfoTest extends AndroidTestCase { assertNotNull(ni[ConnectivityManager.TYPE_WIFI].toString()); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test writeToParcel(Parcel dest, int flags).", - targets = { - @TestTarget( - methodName = "writeToParcel", - methodArgs = {Parcel.class, Integer.class} - ) - }) - @ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," - + " if build CTS against SDK.") + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test writeToParcel(Parcel dest, int flags).", + method = "writeToParcel", + args = {android.os.Parcel.class, java.lang.Integer.class} + ) + //@ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," public void testWriteToParcel() { NetworkInfo[] networkInfos = mConnectivityManager.getAllNetworkInfo(); NetworkInfo mobileInfo = networkInfos[ConnectivityManager.TYPE_MOBILE]; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 64597242a7..002adfecaf 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -18,9 +18,10 @@ package android.net.cts; import android.net.NetworkInfo.DetailedState; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; @TestTargetClass(DetailedState.class) @@ -31,15 +32,12 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { super.setUp(); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test valueOf(String name).", - targets = { - @TestTarget( - methodName = "valueOf", - methodArgs = {String.class} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) public void testValueOf() { assertEquals(DetailedState.AUTHENTICATING, DetailedState .valueOf("AUTHENTICATING")); @@ -60,15 +58,12 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { .valueOf("SUSPENDED")); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test values().", - targets = { - @TestTarget( - methodName = "values", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) public void testValues() { DetailedState[] expected = DetailedState.values(); assertEquals(10, expected.length); diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java index b03c3f0215..2f58784708 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -17,9 +17,10 @@ package android.net.cts; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import android.net.NetworkInfo.State; @@ -31,15 +32,12 @@ public class NetworkInfo_StateTest extends AndroidTestCase { super.setUp(); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test valueOf(String name).", - targets = { - @TestTarget( - methodName = "valueOf", - methodArgs = {String.class} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) public void testValueOf() { assertEquals(State.CONNECTED, State.valueOf("CONNECTED")); assertEquals(State.CONNECTING, State.valueOf("CONNECTING")); @@ -49,15 +47,12 @@ public class NetworkInfo_StateTest extends AndroidTestCase { assertEquals(State.UNKNOWN, State.valueOf("UNKNOWN")); } - @TestInfo( - status = TestStatus.TBR, - notes = "Test values().", - targets = { - @TestTarget( - methodName = "values", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) public void testValues() { State[] expected = State.values(); assertEquals(6, expected.length); diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 84b58c081a..067ce52372 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -30,7 +30,7 @@ import java.util.Arrays; @TestTargetClass(Uri.class) public class UriTest extends AndroidTestCase { @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test write to and read frome parcel.", method = "writeToParcel", args = {android.os.Parcel.class, android.net.Uri.class} @@ -61,7 +61,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test buildUpon", method = "buildUpon", args = {} @@ -94,73 +94,73 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getHost", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getPort", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getUserInfo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "getEncodedUserInfo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test string uri.", method = "parse", args = {java.lang.String.class} @@ -203,7 +203,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test compareTo", method = "compareTo", args = {android.net.Uri.class} @@ -220,13 +220,13 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test equals and hashCode.", method = "equals", args = {java.lang.Object.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test equals and hashCode.", method = "hashCode", args = {} @@ -262,19 +262,19 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "encode", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "encode", args = {java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test encode and decode.", method = "decode", args = {java.lang.String.class} @@ -301,7 +301,7 @@ public class UriTest extends AndroidTestCase { } @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test fromFile.", method = "fromFile", args = {java.io.File.class} @@ -318,13 +318,13 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test get query parameters.", method = "getQueryParameter", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test get query parameters.", method = "getQueryParameters", args = {java.lang.String.class} @@ -347,19 +347,19 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getPathSegments", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "getLastPathSegment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "", method = "withAppendedPath", args = {android.net.Uri.class, java.lang.String.class} @@ -404,55 +404,55 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isAbsolute", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isOpaque", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "isRelative", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getHost", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getPort", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getScheme", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "fromParts", args = {java.lang.String.class, java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test opaque uri.", method = "toString", args = {} @@ -514,91 +514,91 @@ public class UriTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getAuthority", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getScheme", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedAuthority", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedPath", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedQuery", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getEncodedFragment", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "getSchemeSpecificPart", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isAbsolute", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isHierarchical", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isOpaque", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "isRelative", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test hierarchical uris.", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java index 8a1b42341b..66bdb074b0 100644 --- a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java +++ b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java @@ -28,103 +28,103 @@ import android.net.Uri; public class Uri_BuilderTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "Uri.Builder", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "build", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "scheme", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "authority", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "path", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "query", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "opaquePart", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "fragment", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendEncodedPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "appendQueryParameter", args = {java.lang.String.class, java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedAuthority", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedFragment", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedPath", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedQuery", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "encodedOpaquePart", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test Builder operations.", method = "toString", args = {} @@ -171,4 +171,3 @@ public class Uri_BuilderTest extends TestCase { assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); } } - diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java index 6e23419de9..91ca876fda 100644 --- a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java @@ -46,13 +46,14 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor(s) of SslCertificate.", method = "SslCertificate", - args = {java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class} + args = {java.lang.String.class, java.lang.String.class, java.lang.String.class, + java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test constructor(s) of SslCertificate.", method = "SslCertificate", args = {java.security.cert.X509Certificate.class} @@ -205,13 +206,13 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test saveState and restoreState(SslCertificate certificate).", method = "saveState", args = {android.net.http.SslCertificate.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test saveState and restoreState(SslCertificate certificate).", method = "restoreState", args = {android.os.Bundle.class} @@ -240,31 +241,31 @@ public class SslCertificateTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getIssuedTo", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getIssuedBy", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getValidNotAfter", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "getValidNotBefore", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", method = "toString", args = {} diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java index 7562e3a847..848bf7b95a 100644 --- a/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java @@ -32,31 +32,31 @@ public class SslCertificate_DNameTest extends TestCase { @TestTargets({ @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "SslCertificate.DName", args = {java.lang.String.class} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getCName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getDName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getOName", args = {} ), @TestTargetNew( - level = TestLevel.TODO, + level = TestLevel.COMPLETE, notes = "Test DName.", method = "getUName", args = {} From c9ef937af0967fd7913c1ccbdaa79c4c45a4966b Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Thu, 9 Apr 2009 22:21:00 -0700 Subject: [PATCH 0006/1415] AI 145668: CTS: add test cases for net.UrlQuerySanitizer. Automated import of CL 145668 --- .../net/cts/UrlQuerySanitizerTest.java | 416 ++++++++++++++++++ ...er_IllegalCharacterValueSanitizerTest.java | 48 ++ ...QuerySanitizer_ParameterValuePairTest.java | 43 ++ 3 files changed, 507 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_ParameterValuePairTest.java diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java new file mode 100644 index 0000000000..e9ae95c303 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2009 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 java.util.List; +import java.util.Set; +import android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.net.UrlQuerySanitizer.ParameterValuePair; +import android.net.UrlQuerySanitizer.ValueSanitizer; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(UrlQuerySanitizer.class) +public class UrlQuerySanitizerTest extends AndroidTestCase { + private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; + + // URL for test. + private static final String TEST_URL = "http://example.com/?name=Joe+User&age=20&height=175"; + + // Default sanitizer's change when "+". + private static final String EXPECTED_UNDERLINE_NAME = "Joe_User"; + + // IllegalCharacterValueSanitizer sanitizer's change when "+". + private static final String EXPECTED_SPACE_NAME = "Joe User"; + private static final String EXPECTED_AGE = "20"; + private static final String EXPECTED_HEIGHT = "175"; + private static final String NAME = "name"; + private static final String AGE = "age"; + private static final String HEIGHT = "height"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link UrlQuerySanitizer}", + method = "UrlQuerySanitizer", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link UrlQuerySanitizer}", + method = "UrlQuerySanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseUrl", + method = "parseUrl", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseQuery", + method = "parseQuery", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseEntry", + method = "parseEntry", + args = {String.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getValue", + method = "getValue", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: addSanitizedEntry", + method = "addSanitizedEntry", + args = {String.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: hasParameter", + method = "hasParameter", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getParameterSet", + method = "getParameterSet", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getParameterList", + method = "getParameterList", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: setUnregisteredParameterValueSanitizer", + method = "setUnregisteredParameterValueSanitizer", + args = {ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUnregisteredParameterValueSanitizer", + method = "getUnregisteredParameterValueSanitizer", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButNulAndAngleBracketsLegal", + method = "getAllButNulAndAngleBracketsLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButNulLegal", + method = "getAllButNulLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButWhitespaceLegal", + method = "getAllButWhitespaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllIllegal", + method = "getAllIllegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAmpAndSpaceLegal", + method = "getAmpAndSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAmpLegal", + method = "getAmpLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getSpaceLegal", + method = "getSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUrlAndSpaceLegal", + method = "getUrlAndSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUrlLegal", + method = "getUrlLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: unescape", + method = "unescape", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: isHexDigit", + method = "isHexDigit", + args = {char.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: decodeHexDigit", + method = "decodeHexDigit", + args = {char.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: setAllowUnregisteredParamaters", + method = "setAllowUnregisteredParamaters", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllowUnregisteredParamaters", + method = "getAllowUnregisteredParamaters", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: registerParameter", + method = "registerParameter", + args = {String.class, ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: registerParameters", + method = "registerParameters", + args = {String[].class, ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getEffectiveValueSanitizer", + method = "getEffectiveValueSanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getValueSanitizer", + method = "getValueSanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: clear", + method = "clear", + args = {} + ) + }) + public void testUrlQuerySanitizer() { + MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer(); + assertFalse(uqs.getAllowUnregisteredParamaters()); + + final String query = "book=thinking in java&price=108"; + final String book = "book"; + final String bookName = "thinking in java"; + final String price = "price"; + final String bookPrice = "108"; + final String notExistPar = "notExistParameter"; + uqs.registerParameters(new String[]{book, price}, UrlQuerySanitizer.getSpaceLegal()); + uqs.parseQuery(query); + assertTrue(uqs.hasParameter(book)); + assertTrue(uqs.hasParameter(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertEquals(bookName, uqs.getValue(book)); + assertEquals(bookPrice, uqs.getValue(price)); + assertNull(uqs.getValue(notExistPar)); + uqs.clear(); + assertFalse(uqs.hasParameter(book)); + assertFalse(uqs.hasParameter(price)); + + uqs.parseEntry(book, bookName); + assertTrue(uqs.hasParameter(book)); + assertEquals(bookName, uqs.getValue(book)); + uqs.parseEntry(price, bookPrice); + assertTrue(uqs.hasParameter(price)); + assertEquals(bookPrice, uqs.getValue(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertNull(uqs.getValue(notExistPar)); + + uqs = new MockUrlQuerySanitizer(TEST_URL); + assertTrue(uqs.getAllowUnregisteredParamaters()); + + assertTrue(uqs.hasParameter(NAME)); + assertTrue(uqs.hasParameter(AGE)); + assertTrue(uqs.hasParameter(HEIGHT)); + assertFalse(uqs.hasParameter(notExistPar)); + + assertEquals(EXPECTED_UNDERLINE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertEquals(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + assertNull(uqs.getValue(notExistPar)); + + final int ContainerLen = 3; + Set urlSet = uqs.getParameterSet(); + assertEquals(ContainerLen, urlSet.size()); + assertTrue(urlSet.contains(NAME)); + assertTrue(urlSet.contains(AGE)); + assertTrue(urlSet.contains(HEIGHT)); + assertFalse(urlSet.contains(notExistPar)); + + List urlList = uqs.getParameterList(); + assertEquals(ContainerLen, urlList.size()); + ParameterValuePair pvp = urlList.get(0); + assertEquals(NAME, pvp.mParameter); + assertEquals(EXPECTED_UNDERLINE_NAME, pvp.mValue); + pvp = urlList.get(1); + assertEquals(AGE, pvp.mParameter); + assertEquals(EXPECTED_AGE, pvp.mValue); + pvp = urlList.get(2); + assertEquals(HEIGHT, pvp.mParameter); + assertEquals(EXPECTED_HEIGHT, pvp.mValue); + + assertFalse(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT + 1); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 1, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.setPreferFirstRepeatedParameter(true); + assertTrue(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 2, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.registerParameter(NAME, null); + assertNull(uqs.getValueSanitizer(NAME)); + assertNotNull(uqs.getEffectiveValueSanitizer(NAME)); + + uqs.setAllowUnregisteredParamaters(false); + assertFalse(uqs.getAllowUnregisteredParamaters()); + uqs.registerParameter(NAME, null); + assertNull(uqs.getEffectiveValueSanitizer(NAME)); + + ValueSanitizer vs = new IllegalCharacterValueSanitizer(ALL_OK); + uqs.registerParameter(NAME, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertNotSame(EXPECTED_AGE, uqs.getValue(AGE)); + + String[] register = {NAME, AGE}; + uqs.registerParameters(register, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertNotSame(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + + uqs.setUnregisteredParameterValueSanitizer(vs); + assertEquals(vs, uqs.getUnregisteredParameterValueSanitizer()); + + vs = UrlQuerySanitizer.getAllIllegal(); + assertEquals("Joe_User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButNulLegal(); + assertEquals("Joe User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButWhitespaceLegal(); + assertEquals("Joe_User", vs.sanitize("Joe User")); + vs = UrlQuerySanitizer.getAmpAndSpaceLegal(); + assertEquals("Joe User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getAmpLegal(); + assertEquals("Joe_User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getSpaceLegal(); + assertEquals("Joe User ", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getUrlAndSpaceLegal(); + assertEquals("Joe User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + vs = UrlQuerySanitizer.getUrlLegal(); + assertEquals("Joe_User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + + String escape = "Joe"; + assertEquals(escape, uqs.unescape(escape)); + String expectedPlus = "Joe User"; + String expectedPercentSignHex = "title=" + Character.toString((char)181); + String initialPlus = "Joe+User"; + String initialPercentSign = "title=%B5"; + assertEquals(expectedPlus, uqs.unescape(initialPlus)); + assertEquals(expectedPercentSignHex, uqs.unescape(initialPercentSign)); + + assertTrue(uqs.decodeHexDigit('0') >= 0); + assertTrue(uqs.decodeHexDigit('b') >= 0); + assertTrue(uqs.decodeHexDigit('F') >= 0); + assertTrue(uqs.decodeHexDigit('$') < 0); + + assertTrue(uqs.isHexDigit('0')); + assertTrue(uqs.isHexDigit('b')); + assertTrue(uqs.isHexDigit('F')); + assertFalse(uqs.isHexDigit('$')); + + uqs.clear(); + assertEquals(0, urlSet.size()); + assertEquals(0, urlList.size()); + } + + class MockUrlQuerySanitizer extends UrlQuerySanitizer { + public MockUrlQuerySanitizer() { + super(); + } + + public MockUrlQuerySanitizer(String url) { + super(url); + } + + @Override + protected void addSanitizedEntry(String parameter, String value) { + super.addSanitizedEntry(parameter, value); + } + + @Override + protected void clear() { + super.clear(); + } + + @Override + protected int decodeHexDigit(char c) { + return super.decodeHexDigit(c); + } + + @Override + protected boolean isHexDigit(char c) { + return super.isHexDigit(c); + } + + @Override + protected void parseEntry(String parameter, String value) { + super.parseEntry(parameter, value); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java new file mode 100644 index 0000000000..f85a5347e0 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 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 android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(UrlQuerySanitizer.IllegalCharacterValueSanitizer.class) +public class UrlQuerySanitizer_IllegalCharacterValueSanitizerTest extends AndroidTestCase { + static final int SPACE_OK = IllegalCharacterValueSanitizer.SPACE_OK; + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link IllegalCharacterValueSanitizer}", + method = "IllegalCharacterValueSanitizer", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: sanitize", + method = "sanitize", + args = {String.class} + ) + }) + public void testSanitize() { + IllegalCharacterValueSanitizer sanitizer = new IllegalCharacterValueSanitizer(SPACE_OK); + assertEquals("Joe User", sanitizer.sanitize("Joe Date: Thu, 9 Apr 2009 22:36:44 -0700 Subject: [PATCH 0007/1415] AI 145675: CTS: fixed the fail bug in android.net.cts.NetworkInfoTest Automated import of CL 145675 --- .../src/android/net/cts/NetworkInfoTest.java | 115 +++++++----------- 1 file changed, 46 insertions(+), 69 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 46da3ca74f..62a5f3fad9 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -16,72 +16,68 @@ package android.net.cts; -import dalvik.annotation.ToBeFixed; - import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; -import android.os.Parcel; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { - ConnectivityManager mConnectivityManager; - @Override - protected void setUp() throws Exception { - super.setUp(); - mConnectivityManager = (ConnectivityManager) mContext - .getSystemService(Context.CONNECTIVITY_SERVICE); + public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; + public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; + public static final String MOBILE_TYPE_NAME = "MOBILE"; + public static final String WIFI_TYPE_NAME = "WIFI"; + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of NetworkInfo.", + method = "NetworkInfo", + args = {int.class} + ) + public void testConstructor() { + new NetworkInfo(ConnectivityManager.TYPE_MOBILE); } @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isConnectedOrConnecting", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "setFailover", args = {boolean.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isFailover", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getType", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getTypeName", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "setIsAvailable", args = {boolean.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isAvailable", args = {} ), @@ -93,88 +89,69 @@ public class NetworkInfoTest extends AndroidTestCase { ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", - method = "describeContents", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getDetailedState", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getState", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getReason", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getExtraInfo", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "toString", args = {} ) }) public void testAccessNetworkInfoProperties() { - NetworkInfo[] ni = mConnectivityManager.getAllNetworkInfo(); + ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( + Context.CONNECTIVITY_SERVICE); + + NetworkInfo[] ni = cm.getAllNetworkInfo(); assertTrue(ni.length >= 2); - assertFalse(ni[ConnectivityManager.TYPE_MOBILE].isFailover()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isFailover()); + + assertFalse(ni[TYPE_MOBILE].isFailover()); + assertFalse(ni[TYPE_WIFI].isFailover()); // test environment:connect as TYPE_MOBILE, and connect to internet. - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getType(), - ConnectivityManager.TYPE_MOBILE); - assertEquals(ni[ConnectivityManager.TYPE_WIFI].getType(), ConnectivityManager.TYPE_WIFI); - assertEquals("MOBILE", ni[ConnectivityManager.TYPE_MOBILE].getTypeName()); - assertEquals("WIFI", ni[ConnectivityManager.TYPE_WIFI].getTypeName()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isConnectedOrConnecting()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnectedOrConnecting()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isAvailable()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isAvailable()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isConnected()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnected()); + assertEquals(ni[TYPE_MOBILE].getType(), TYPE_MOBILE); + assertEquals(ni[TYPE_WIFI].getType(), TYPE_WIFI); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].describeContents(), 0); - assertEquals(ni[ConnectivityManager.TYPE_WIFI].describeContents(), 0); + assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); + assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getState(), State.CONNECTED); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getDetailedState(), - DetailedState.CONNECTED); + assertTrue(ni[TYPE_MOBILE].isConnectedOrConnecting()); + assertFalse(ni[TYPE_WIFI].isConnectedOrConnecting()); - assertNull(ni[ConnectivityManager.TYPE_MOBILE].getReason()); - assertNull(ni[ConnectivityManager.TYPE_WIFI].getReason()); - assertEquals("internet", ni[ConnectivityManager.TYPE_MOBILE].getExtraInfo()); - assertNull(ni[ConnectivityManager.TYPE_WIFI].getExtraInfo()); + assertTrue(ni[TYPE_MOBILE].isAvailable()); + assertFalse(ni[TYPE_WIFI].isAvailable()); - assertNotNull(ni[ConnectivityManager.TYPE_MOBILE].toString()); - assertNotNull(ni[ConnectivityManager.TYPE_WIFI].toString()); - } + assertTrue(ni[TYPE_MOBILE].isConnected()); + assertFalse(ni[TYPE_WIFI].isConnected()); - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test writeToParcel(Parcel dest, int flags).", - method = "writeToParcel", - args = {android.os.Parcel.class, java.lang.Integer.class} - ) - //@ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," - public void testWriteToParcel() { - NetworkInfo[] networkInfos = mConnectivityManager.getAllNetworkInfo(); - NetworkInfo mobileInfo = networkInfos[ConnectivityManager.TYPE_MOBILE]; - Parcel p = Parcel.obtain(); + assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); + assertEquals(State.UNKNOWN, ni[TYPE_WIFI].getState()); - mobileInfo.writeToParcel(p, 1); + assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); + assertEquals(DetailedState.IDLE, ni[TYPE_WIFI].getDetailedState()); + + assertNotNull(ni[TYPE_MOBILE].getReason()); + assertNull(ni[TYPE_WIFI].getReason()); + + assertNotNull(ni[TYPE_MOBILE].getExtraInfo()); + assertNull(ni[TYPE_WIFI].getExtraInfo()); + + assertNotNull(ni[TYPE_MOBILE].toString()); + assertNotNull(ni[TYPE_WIFI].toString()); } } From d33eb60d31bb15df9635a173b0c3ca3d87db0f21 Mon Sep 17 00:00:00 2001 From: Eric Shienbrood <> Date: Mon, 13 Apr 2009 10:41:53 -0700 Subject: [PATCH 0008/1415] AI 145881: Adding on to CL 145383, unhiding some additional methods and constants that ought to be exposed. Hid and deprecated the single-arg public constructor for NetworkInfo, and modified a CTS test that was testing it. Ran the android.net test package to make sure it still works. BUG=1779439 Automated import of CL 145881 --- tests/cts/net/src/android/net/cts/NetworkInfoTest.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 62a5f3fad9..ea1e047d6a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -35,16 +35,6 @@ public class NetworkInfoTest extends AndroidTestCase { public static final String MOBILE_TYPE_NAME = "MOBILE"; public static final String WIFI_TYPE_NAME = "WIFI"; - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test constructor(s) of NetworkInfo.", - method = "NetworkInfo", - args = {int.class} - ) - public void testConstructor() { - new NetworkInfo(ConnectivityManager.TYPE_MOBILE); - } - @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, From 82bd6d83a231b947d690ad9a97db82729417cbdd Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Mon, 13 Apr 2009 15:37:58 -0700 Subject: [PATCH 0009/1415] AI 145953: am: CL 145668 CTS: add test cases for net.UrlQuerySanitizer. Original author: sus Merged from: //branches/cupcake/... Automated import of CL 145953 --- .../net/cts/UrlQuerySanitizerTest.java | 416 ++++++++++++++++++ ...er_IllegalCharacterValueSanitizerTest.java | 48 ++ ...QuerySanitizer_ParameterValuePairTest.java | 43 ++ 3 files changed, 507 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_ParameterValuePairTest.java diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java new file mode 100644 index 0000000000..e9ae95c303 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2009 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 java.util.List; +import java.util.Set; +import android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.net.UrlQuerySanitizer.ParameterValuePair; +import android.net.UrlQuerySanitizer.ValueSanitizer; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(UrlQuerySanitizer.class) +public class UrlQuerySanitizerTest extends AndroidTestCase { + private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; + + // URL for test. + private static final String TEST_URL = "http://example.com/?name=Joe+User&age=20&height=175"; + + // Default sanitizer's change when "+". + private static final String EXPECTED_UNDERLINE_NAME = "Joe_User"; + + // IllegalCharacterValueSanitizer sanitizer's change when "+". + private static final String EXPECTED_SPACE_NAME = "Joe User"; + private static final String EXPECTED_AGE = "20"; + private static final String EXPECTED_HEIGHT = "175"; + private static final String NAME = "name"; + private static final String AGE = "age"; + private static final String HEIGHT = "height"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link UrlQuerySanitizer}", + method = "UrlQuerySanitizer", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link UrlQuerySanitizer}", + method = "UrlQuerySanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseUrl", + method = "parseUrl", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseQuery", + method = "parseQuery", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseEntry", + method = "parseEntry", + args = {String.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getValue", + method = "getValue", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: addSanitizedEntry", + method = "addSanitizedEntry", + args = {String.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: hasParameter", + method = "hasParameter", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getParameterSet", + method = "getParameterSet", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getParameterList", + method = "getParameterList", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: setUnregisteredParameterValueSanitizer", + method = "setUnregisteredParameterValueSanitizer", + args = {ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUnregisteredParameterValueSanitizer", + method = "getUnregisteredParameterValueSanitizer", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButNulAndAngleBracketsLegal", + method = "getAllButNulAndAngleBracketsLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButNulLegal", + method = "getAllButNulLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButWhitespaceLegal", + method = "getAllButWhitespaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllIllegal", + method = "getAllIllegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAmpAndSpaceLegal", + method = "getAmpAndSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAmpLegal", + method = "getAmpLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getSpaceLegal", + method = "getSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUrlAndSpaceLegal", + method = "getUrlAndSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUrlLegal", + method = "getUrlLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: unescape", + method = "unescape", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: isHexDigit", + method = "isHexDigit", + args = {char.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: decodeHexDigit", + method = "decodeHexDigit", + args = {char.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: setAllowUnregisteredParamaters", + method = "setAllowUnregisteredParamaters", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllowUnregisteredParamaters", + method = "getAllowUnregisteredParamaters", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: registerParameter", + method = "registerParameter", + args = {String.class, ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: registerParameters", + method = "registerParameters", + args = {String[].class, ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getEffectiveValueSanitizer", + method = "getEffectiveValueSanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getValueSanitizer", + method = "getValueSanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: clear", + method = "clear", + args = {} + ) + }) + public void testUrlQuerySanitizer() { + MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer(); + assertFalse(uqs.getAllowUnregisteredParamaters()); + + final String query = "book=thinking in java&price=108"; + final String book = "book"; + final String bookName = "thinking in java"; + final String price = "price"; + final String bookPrice = "108"; + final String notExistPar = "notExistParameter"; + uqs.registerParameters(new String[]{book, price}, UrlQuerySanitizer.getSpaceLegal()); + uqs.parseQuery(query); + assertTrue(uqs.hasParameter(book)); + assertTrue(uqs.hasParameter(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertEquals(bookName, uqs.getValue(book)); + assertEquals(bookPrice, uqs.getValue(price)); + assertNull(uqs.getValue(notExistPar)); + uqs.clear(); + assertFalse(uqs.hasParameter(book)); + assertFalse(uqs.hasParameter(price)); + + uqs.parseEntry(book, bookName); + assertTrue(uqs.hasParameter(book)); + assertEquals(bookName, uqs.getValue(book)); + uqs.parseEntry(price, bookPrice); + assertTrue(uqs.hasParameter(price)); + assertEquals(bookPrice, uqs.getValue(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertNull(uqs.getValue(notExistPar)); + + uqs = new MockUrlQuerySanitizer(TEST_URL); + assertTrue(uqs.getAllowUnregisteredParamaters()); + + assertTrue(uqs.hasParameter(NAME)); + assertTrue(uqs.hasParameter(AGE)); + assertTrue(uqs.hasParameter(HEIGHT)); + assertFalse(uqs.hasParameter(notExistPar)); + + assertEquals(EXPECTED_UNDERLINE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertEquals(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + assertNull(uqs.getValue(notExistPar)); + + final int ContainerLen = 3; + Set urlSet = uqs.getParameterSet(); + assertEquals(ContainerLen, urlSet.size()); + assertTrue(urlSet.contains(NAME)); + assertTrue(urlSet.contains(AGE)); + assertTrue(urlSet.contains(HEIGHT)); + assertFalse(urlSet.contains(notExistPar)); + + List urlList = uqs.getParameterList(); + assertEquals(ContainerLen, urlList.size()); + ParameterValuePair pvp = urlList.get(0); + assertEquals(NAME, pvp.mParameter); + assertEquals(EXPECTED_UNDERLINE_NAME, pvp.mValue); + pvp = urlList.get(1); + assertEquals(AGE, pvp.mParameter); + assertEquals(EXPECTED_AGE, pvp.mValue); + pvp = urlList.get(2); + assertEquals(HEIGHT, pvp.mParameter); + assertEquals(EXPECTED_HEIGHT, pvp.mValue); + + assertFalse(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT + 1); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 1, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.setPreferFirstRepeatedParameter(true); + assertTrue(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 2, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.registerParameter(NAME, null); + assertNull(uqs.getValueSanitizer(NAME)); + assertNotNull(uqs.getEffectiveValueSanitizer(NAME)); + + uqs.setAllowUnregisteredParamaters(false); + assertFalse(uqs.getAllowUnregisteredParamaters()); + uqs.registerParameter(NAME, null); + assertNull(uqs.getEffectiveValueSanitizer(NAME)); + + ValueSanitizer vs = new IllegalCharacterValueSanitizer(ALL_OK); + uqs.registerParameter(NAME, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertNotSame(EXPECTED_AGE, uqs.getValue(AGE)); + + String[] register = {NAME, AGE}; + uqs.registerParameters(register, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertNotSame(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + + uqs.setUnregisteredParameterValueSanitizer(vs); + assertEquals(vs, uqs.getUnregisteredParameterValueSanitizer()); + + vs = UrlQuerySanitizer.getAllIllegal(); + assertEquals("Joe_User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButNulLegal(); + assertEquals("Joe User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButWhitespaceLegal(); + assertEquals("Joe_User", vs.sanitize("Joe User")); + vs = UrlQuerySanitizer.getAmpAndSpaceLegal(); + assertEquals("Joe User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getAmpLegal(); + assertEquals("Joe_User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getSpaceLegal(); + assertEquals("Joe User ", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getUrlAndSpaceLegal(); + assertEquals("Joe User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + vs = UrlQuerySanitizer.getUrlLegal(); + assertEquals("Joe_User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + + String escape = "Joe"; + assertEquals(escape, uqs.unescape(escape)); + String expectedPlus = "Joe User"; + String expectedPercentSignHex = "title=" + Character.toString((char)181); + String initialPlus = "Joe+User"; + String initialPercentSign = "title=%B5"; + assertEquals(expectedPlus, uqs.unescape(initialPlus)); + assertEquals(expectedPercentSignHex, uqs.unescape(initialPercentSign)); + + assertTrue(uqs.decodeHexDigit('0') >= 0); + assertTrue(uqs.decodeHexDigit('b') >= 0); + assertTrue(uqs.decodeHexDigit('F') >= 0); + assertTrue(uqs.decodeHexDigit('$') < 0); + + assertTrue(uqs.isHexDigit('0')); + assertTrue(uqs.isHexDigit('b')); + assertTrue(uqs.isHexDigit('F')); + assertFalse(uqs.isHexDigit('$')); + + uqs.clear(); + assertEquals(0, urlSet.size()); + assertEquals(0, urlList.size()); + } + + class MockUrlQuerySanitizer extends UrlQuerySanitizer { + public MockUrlQuerySanitizer() { + super(); + } + + public MockUrlQuerySanitizer(String url) { + super(url); + } + + @Override + protected void addSanitizedEntry(String parameter, String value) { + super.addSanitizedEntry(parameter, value); + } + + @Override + protected void clear() { + super.clear(); + } + + @Override + protected int decodeHexDigit(char c) { + return super.decodeHexDigit(c); + } + + @Override + protected boolean isHexDigit(char c) { + return super.isHexDigit(c); + } + + @Override + protected void parseEntry(String parameter, String value) { + super.parseEntry(parameter, value); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java new file mode 100644 index 0000000000..f85a5347e0 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 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 android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(UrlQuerySanitizer.IllegalCharacterValueSanitizer.class) +public class UrlQuerySanitizer_IllegalCharacterValueSanitizerTest extends AndroidTestCase { + static final int SPACE_OK = IllegalCharacterValueSanitizer.SPACE_OK; + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link IllegalCharacterValueSanitizer}", + method = "IllegalCharacterValueSanitizer", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: sanitize", + method = "sanitize", + args = {String.class} + ) + }) + public void testSanitize() { + IllegalCharacterValueSanitizer sanitizer = new IllegalCharacterValueSanitizer(SPACE_OK); + assertEquals("Joe User", sanitizer.sanitize("Joe Date: Mon, 13 Apr 2009 15:47:21 -0700 Subject: [PATCH 0010/1415] AI 145956: am: CL 145675 CTS: fixed the fail bug in android.net.cts.NetworkInfoTest Original author: sus Merged from: //branches/cupcake/... Automated import of CL 145956 --- .../src/android/net/cts/NetworkInfoTest.java | 115 +++++++----------- 1 file changed, 46 insertions(+), 69 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 46da3ca74f..62a5f3fad9 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -16,72 +16,68 @@ package android.net.cts; -import dalvik.annotation.ToBeFixed; - import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; -import android.os.Parcel; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { - ConnectivityManager mConnectivityManager; - @Override - protected void setUp() throws Exception { - super.setUp(); - mConnectivityManager = (ConnectivityManager) mContext - .getSystemService(Context.CONNECTIVITY_SERVICE); + public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; + public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; + public static final String MOBILE_TYPE_NAME = "MOBILE"; + public static final String WIFI_TYPE_NAME = "WIFI"; + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of NetworkInfo.", + method = "NetworkInfo", + args = {int.class} + ) + public void testConstructor() { + new NetworkInfo(ConnectivityManager.TYPE_MOBILE); } @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isConnectedOrConnecting", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "setFailover", args = {boolean.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isFailover", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getType", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getTypeName", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "setIsAvailable", args = {boolean.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isAvailable", args = {} ), @@ -93,88 +89,69 @@ public class NetworkInfoTest extends AndroidTestCase { ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", - method = "describeContents", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getDetailedState", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getState", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getReason", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getExtraInfo", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "toString", args = {} ) }) public void testAccessNetworkInfoProperties() { - NetworkInfo[] ni = mConnectivityManager.getAllNetworkInfo(); + ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( + Context.CONNECTIVITY_SERVICE); + + NetworkInfo[] ni = cm.getAllNetworkInfo(); assertTrue(ni.length >= 2); - assertFalse(ni[ConnectivityManager.TYPE_MOBILE].isFailover()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isFailover()); + + assertFalse(ni[TYPE_MOBILE].isFailover()); + assertFalse(ni[TYPE_WIFI].isFailover()); // test environment:connect as TYPE_MOBILE, and connect to internet. - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getType(), - ConnectivityManager.TYPE_MOBILE); - assertEquals(ni[ConnectivityManager.TYPE_WIFI].getType(), ConnectivityManager.TYPE_WIFI); - assertEquals("MOBILE", ni[ConnectivityManager.TYPE_MOBILE].getTypeName()); - assertEquals("WIFI", ni[ConnectivityManager.TYPE_WIFI].getTypeName()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isConnectedOrConnecting()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnectedOrConnecting()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isAvailable()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isAvailable()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isConnected()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnected()); + assertEquals(ni[TYPE_MOBILE].getType(), TYPE_MOBILE); + assertEquals(ni[TYPE_WIFI].getType(), TYPE_WIFI); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].describeContents(), 0); - assertEquals(ni[ConnectivityManager.TYPE_WIFI].describeContents(), 0); + assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); + assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getState(), State.CONNECTED); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getDetailedState(), - DetailedState.CONNECTED); + assertTrue(ni[TYPE_MOBILE].isConnectedOrConnecting()); + assertFalse(ni[TYPE_WIFI].isConnectedOrConnecting()); - assertNull(ni[ConnectivityManager.TYPE_MOBILE].getReason()); - assertNull(ni[ConnectivityManager.TYPE_WIFI].getReason()); - assertEquals("internet", ni[ConnectivityManager.TYPE_MOBILE].getExtraInfo()); - assertNull(ni[ConnectivityManager.TYPE_WIFI].getExtraInfo()); + assertTrue(ni[TYPE_MOBILE].isAvailable()); + assertFalse(ni[TYPE_WIFI].isAvailable()); - assertNotNull(ni[ConnectivityManager.TYPE_MOBILE].toString()); - assertNotNull(ni[ConnectivityManager.TYPE_WIFI].toString()); - } + assertTrue(ni[TYPE_MOBILE].isConnected()); + assertFalse(ni[TYPE_WIFI].isConnected()); - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test writeToParcel(Parcel dest, int flags).", - method = "writeToParcel", - args = {android.os.Parcel.class, java.lang.Integer.class} - ) - //@ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," - public void testWriteToParcel() { - NetworkInfo[] networkInfos = mConnectivityManager.getAllNetworkInfo(); - NetworkInfo mobileInfo = networkInfos[ConnectivityManager.TYPE_MOBILE]; - Parcel p = Parcel.obtain(); + assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); + assertEquals(State.UNKNOWN, ni[TYPE_WIFI].getState()); - mobileInfo.writeToParcel(p, 1); + assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); + assertEquals(DetailedState.IDLE, ni[TYPE_WIFI].getDetailedState()); + + assertNotNull(ni[TYPE_MOBILE].getReason()); + assertNull(ni[TYPE_WIFI].getReason()); + + assertNotNull(ni[TYPE_MOBILE].getExtraInfo()); + assertNull(ni[TYPE_WIFI].getExtraInfo()); + + assertNotNull(ni[TYPE_MOBILE].toString()); + assertNotNull(ni[TYPE_WIFI].toString()); } } From 537a83c57a505b23dfc5a6b6635b8fc9ad891cb8 Mon Sep 17 00:00:00 2001 From: Eric Shienbrood <> Date: Mon, 13 Apr 2009 18:12:46 -0700 Subject: [PATCH 0011/1415] AI 145980: am: CL 145881 Adding on to CL 145383, unhiding some additional methods and constants that ought to be exposed. Hid and deprecated the single-arg public constructor for NetworkInfo, and modified a CTS test that was testing it. Ran the android.net test package to make sure it still works. Original author: ers Merged from: //branches/cupcake/... Automated import of CL 145980 --- tests/cts/net/src/android/net/cts/NetworkInfoTest.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 62a5f3fad9..ea1e047d6a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -35,16 +35,6 @@ public class NetworkInfoTest extends AndroidTestCase { public static final String MOBILE_TYPE_NAME = "MOBILE"; public static final String WIFI_TYPE_NAME = "WIFI"; - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test constructor(s) of NetworkInfo.", - method = "NetworkInfo", - args = {int.class} - ) - public void testConstructor() { - new NetworkInfo(ConnectivityManager.TYPE_MOBILE); - } - @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, From 316ee5f68ba3bbd3df43b67848219e45df4e83e1 Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Mon, 13 Apr 2009 23:23:32 -0700 Subject: [PATCH 0012/1415] AI 146071: CTS: Clean up test annotations BUG=1654276 Automated import of CL 146071 --- .../net/cts/LocalServerSocketTest.java | 1 - .../cts/NetworkInfo_DetailedStateTest.java | 1 - .../net/cts/NetworkInfo_StateTest.java | 1 - .../net/src/android/net/cts/ProxyTest.java | 57 ++++++++----------- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index a6511e8521..07f29c6783 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -26,7 +26,6 @@ import android.net.LocalSocketAddress; import android.os.ParcelFileDescriptor; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 002adfecaf..0e05b28119 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -19,7 +19,6 @@ package android.net.cts; import android.net.NetworkInfo.DetailedState; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java index 2f58784708..249df4b588 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -18,7 +18,6 @@ package android.net.cts; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index d9f7c1a942..9345ac2485 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -20,9 +20,9 @@ import android.content.Context; import android.net.Proxy; import android.provider.Settings; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; @TestTargetClass(Proxy.class) @@ -33,15 +33,11 @@ public class ProxyTest extends AndroidTestCase { } - @TestInfo( - status = TestStatus.TBR, - notes = "Test constructor(s) of Proxy.", - targets = { - @TestTarget( - methodName = "Proxy", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "Proxy", + args = {} + ) public void testConstructor() { try { @@ -51,29 +47,26 @@ public class ProxyTest extends AndroidTestCase { } } - @TestInfo( - status = TestStatus.TBR, - notes = "Test getDefaultPort().", - targets = { - @TestTarget( - methodName = "getDefaultPort", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefaultPort", + args = {} ), - @TestTarget( - methodName = "getDefaultHost", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefaultHost", + args = {} ), - @TestTarget( - methodName = "getHost", - methodArgs = {Context.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getHost", + args = {Context.class} ), - @TestTarget( - methodName = "getHost", - methodArgs = {Context.class} - ), - @TestTarget( - methodName = "getPort", - methodArgs = {Context.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPort", + args = {Context.class} ) }) public void testAccessProperties() { From 3ae3101a2aeded72922213669e25345658c3d2b4 Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Mon, 13 Apr 2009 23:24:06 -0700 Subject: [PATCH 0013/1415] AI 146072: am: CL 146071 CTS: Clean up test annotations Original author: sus Merged from: //branches/cupcake/... Automated import of CL 146072 --- .../net/cts/LocalServerSocketTest.java | 1 - .../cts/NetworkInfo_DetailedStateTest.java | 1 - .../net/cts/NetworkInfo_StateTest.java | 1 - .../net/src/android/net/cts/ProxyTest.java | 57 ++++++++----------- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index a6511e8521..07f29c6783 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -26,7 +26,6 @@ import android.net.LocalSocketAddress; import android.os.ParcelFileDescriptor; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 002adfecaf..0e05b28119 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -19,7 +19,6 @@ package android.net.cts; import android.net.NetworkInfo.DetailedState; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java index 2f58784708..249df4b588 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -18,7 +18,6 @@ package android.net.cts; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index d9f7c1a942..9345ac2485 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -20,9 +20,9 @@ import android.content.Context; import android.net.Proxy; import android.provider.Settings; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; @TestTargetClass(Proxy.class) @@ -33,15 +33,11 @@ public class ProxyTest extends AndroidTestCase { } - @TestInfo( - status = TestStatus.TBR, - notes = "Test constructor(s) of Proxy.", - targets = { - @TestTarget( - methodName = "Proxy", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "Proxy", + args = {} + ) public void testConstructor() { try { @@ -51,29 +47,26 @@ public class ProxyTest extends AndroidTestCase { } } - @TestInfo( - status = TestStatus.TBR, - notes = "Test getDefaultPort().", - targets = { - @TestTarget( - methodName = "getDefaultPort", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefaultPort", + args = {} ), - @TestTarget( - methodName = "getDefaultHost", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefaultHost", + args = {} ), - @TestTarget( - methodName = "getHost", - methodArgs = {Context.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getHost", + args = {Context.class} ), - @TestTarget( - methodName = "getHost", - methodArgs = {Context.class} - ), - @TestTarget( - methodName = "getPort", - methodArgs = {Context.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPort", + args = {Context.class} ) }) public void testAccessProperties() { From 871df54abaca97ff4bc26d70449a9621bcfae2b6 Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Tue, 14 Apr 2009 12:15:18 -0700 Subject: [PATCH 0014/1415] AI 146168: am: CL 145953 am: CL 145668 CTS: add test cases for net.UrlQuerySanitizer. Original author: sus Merged from: //branches/cupcake/... Original author: android-build Automated import of CL 146168 --- .../net/cts/UrlQuerySanitizerTest.java | 416 ++++++++++++++++++ ...er_IllegalCharacterValueSanitizerTest.java | 48 ++ ...QuerySanitizer_ParameterValuePairTest.java | 43 ++ 3 files changed, 507 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_ParameterValuePairTest.java diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java new file mode 100644 index 0000000000..e9ae95c303 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2009 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 java.util.List; +import java.util.Set; +import android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.net.UrlQuerySanitizer.ParameterValuePair; +import android.net.UrlQuerySanitizer.ValueSanitizer; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(UrlQuerySanitizer.class) +public class UrlQuerySanitizerTest extends AndroidTestCase { + private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; + + // URL for test. + private static final String TEST_URL = "http://example.com/?name=Joe+User&age=20&height=175"; + + // Default sanitizer's change when "+". + private static final String EXPECTED_UNDERLINE_NAME = "Joe_User"; + + // IllegalCharacterValueSanitizer sanitizer's change when "+". + private static final String EXPECTED_SPACE_NAME = "Joe User"; + private static final String EXPECTED_AGE = "20"; + private static final String EXPECTED_HEIGHT = "175"; + private static final String NAME = "name"; + private static final String AGE = "age"; + private static final String HEIGHT = "height"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link UrlQuerySanitizer}", + method = "UrlQuerySanitizer", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link UrlQuerySanitizer}", + method = "UrlQuerySanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseUrl", + method = "parseUrl", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseQuery", + method = "parseQuery", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: parseEntry", + method = "parseEntry", + args = {String.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getValue", + method = "getValue", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: addSanitizedEntry", + method = "addSanitizedEntry", + args = {String.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: hasParameter", + method = "hasParameter", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getParameterSet", + method = "getParameterSet", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getParameterList", + method = "getParameterList", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: setUnregisteredParameterValueSanitizer", + method = "setUnregisteredParameterValueSanitizer", + args = {ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUnregisteredParameterValueSanitizer", + method = "getUnregisteredParameterValueSanitizer", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButNulAndAngleBracketsLegal", + method = "getAllButNulAndAngleBracketsLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButNulLegal", + method = "getAllButNulLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllButWhitespaceLegal", + method = "getAllButWhitespaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllIllegal", + method = "getAllIllegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAmpAndSpaceLegal", + method = "getAmpAndSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAmpLegal", + method = "getAmpLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getSpaceLegal", + method = "getSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUrlAndSpaceLegal", + method = "getUrlAndSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getUrlLegal", + method = "getUrlLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: unescape", + method = "unescape", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: isHexDigit", + method = "isHexDigit", + args = {char.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test mehtod: decodeHexDigit", + method = "decodeHexDigit", + args = {char.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: setAllowUnregisteredParamaters", + method = "setAllowUnregisteredParamaters", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getAllowUnregisteredParamaters", + method = "getAllowUnregisteredParamaters", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: registerParameter", + method = "registerParameter", + args = {String.class, ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: registerParameters", + method = "registerParameters", + args = {String[].class, ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getEffectiveValueSanitizer", + method = "getEffectiveValueSanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: getValueSanitizer", + method = "getValueSanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: clear", + method = "clear", + args = {} + ) + }) + public void testUrlQuerySanitizer() { + MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer(); + assertFalse(uqs.getAllowUnregisteredParamaters()); + + final String query = "book=thinking in java&price=108"; + final String book = "book"; + final String bookName = "thinking in java"; + final String price = "price"; + final String bookPrice = "108"; + final String notExistPar = "notExistParameter"; + uqs.registerParameters(new String[]{book, price}, UrlQuerySanitizer.getSpaceLegal()); + uqs.parseQuery(query); + assertTrue(uqs.hasParameter(book)); + assertTrue(uqs.hasParameter(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertEquals(bookName, uqs.getValue(book)); + assertEquals(bookPrice, uqs.getValue(price)); + assertNull(uqs.getValue(notExistPar)); + uqs.clear(); + assertFalse(uqs.hasParameter(book)); + assertFalse(uqs.hasParameter(price)); + + uqs.parseEntry(book, bookName); + assertTrue(uqs.hasParameter(book)); + assertEquals(bookName, uqs.getValue(book)); + uqs.parseEntry(price, bookPrice); + assertTrue(uqs.hasParameter(price)); + assertEquals(bookPrice, uqs.getValue(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertNull(uqs.getValue(notExistPar)); + + uqs = new MockUrlQuerySanitizer(TEST_URL); + assertTrue(uqs.getAllowUnregisteredParamaters()); + + assertTrue(uqs.hasParameter(NAME)); + assertTrue(uqs.hasParameter(AGE)); + assertTrue(uqs.hasParameter(HEIGHT)); + assertFalse(uqs.hasParameter(notExistPar)); + + assertEquals(EXPECTED_UNDERLINE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertEquals(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + assertNull(uqs.getValue(notExistPar)); + + final int ContainerLen = 3; + Set urlSet = uqs.getParameterSet(); + assertEquals(ContainerLen, urlSet.size()); + assertTrue(urlSet.contains(NAME)); + assertTrue(urlSet.contains(AGE)); + assertTrue(urlSet.contains(HEIGHT)); + assertFalse(urlSet.contains(notExistPar)); + + List urlList = uqs.getParameterList(); + assertEquals(ContainerLen, urlList.size()); + ParameterValuePair pvp = urlList.get(0); + assertEquals(NAME, pvp.mParameter); + assertEquals(EXPECTED_UNDERLINE_NAME, pvp.mValue); + pvp = urlList.get(1); + assertEquals(AGE, pvp.mParameter); + assertEquals(EXPECTED_AGE, pvp.mValue); + pvp = urlList.get(2); + assertEquals(HEIGHT, pvp.mParameter); + assertEquals(EXPECTED_HEIGHT, pvp.mValue); + + assertFalse(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT + 1); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 1, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.setPreferFirstRepeatedParameter(true); + assertTrue(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 2, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.registerParameter(NAME, null); + assertNull(uqs.getValueSanitizer(NAME)); + assertNotNull(uqs.getEffectiveValueSanitizer(NAME)); + + uqs.setAllowUnregisteredParamaters(false); + assertFalse(uqs.getAllowUnregisteredParamaters()); + uqs.registerParameter(NAME, null); + assertNull(uqs.getEffectiveValueSanitizer(NAME)); + + ValueSanitizer vs = new IllegalCharacterValueSanitizer(ALL_OK); + uqs.registerParameter(NAME, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertNotSame(EXPECTED_AGE, uqs.getValue(AGE)); + + String[] register = {NAME, AGE}; + uqs.registerParameters(register, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertNotSame(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + + uqs.setUnregisteredParameterValueSanitizer(vs); + assertEquals(vs, uqs.getUnregisteredParameterValueSanitizer()); + + vs = UrlQuerySanitizer.getAllIllegal(); + assertEquals("Joe_User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButNulLegal(); + assertEquals("Joe User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButWhitespaceLegal(); + assertEquals("Joe_User", vs.sanitize("Joe User")); + vs = UrlQuerySanitizer.getAmpAndSpaceLegal(); + assertEquals("Joe User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getAmpLegal(); + assertEquals("Joe_User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getSpaceLegal(); + assertEquals("Joe User ", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getUrlAndSpaceLegal(); + assertEquals("Joe User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + vs = UrlQuerySanitizer.getUrlLegal(); + assertEquals("Joe_User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + + String escape = "Joe"; + assertEquals(escape, uqs.unescape(escape)); + String expectedPlus = "Joe User"; + String expectedPercentSignHex = "title=" + Character.toString((char)181); + String initialPlus = "Joe+User"; + String initialPercentSign = "title=%B5"; + assertEquals(expectedPlus, uqs.unescape(initialPlus)); + assertEquals(expectedPercentSignHex, uqs.unescape(initialPercentSign)); + + assertTrue(uqs.decodeHexDigit('0') >= 0); + assertTrue(uqs.decodeHexDigit('b') >= 0); + assertTrue(uqs.decodeHexDigit('F') >= 0); + assertTrue(uqs.decodeHexDigit('$') < 0); + + assertTrue(uqs.isHexDigit('0')); + assertTrue(uqs.isHexDigit('b')); + assertTrue(uqs.isHexDigit('F')); + assertFalse(uqs.isHexDigit('$')); + + uqs.clear(); + assertEquals(0, urlSet.size()); + assertEquals(0, urlList.size()); + } + + class MockUrlQuerySanitizer extends UrlQuerySanitizer { + public MockUrlQuerySanitizer() { + super(); + } + + public MockUrlQuerySanitizer(String url) { + super(url); + } + + @Override + protected void addSanitizedEntry(String parameter, String value) { + super.addSanitizedEntry(parameter, value); + } + + @Override + protected void clear() { + super.clear(); + } + + @Override + protected int decodeHexDigit(char c) { + return super.decodeHexDigit(c); + } + + @Override + protected boolean isHexDigit(char c) { + return super.isHexDigit(c); + } + + @Override + protected void parseEntry(String parameter, String value) { + super.parseEntry(parameter, value); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java new file mode 100644 index 0000000000..f85a5347e0 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 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 android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(UrlQuerySanitizer.IllegalCharacterValueSanitizer.class) +public class UrlQuerySanitizer_IllegalCharacterValueSanitizerTest extends AndroidTestCase { + static final int SPACE_OK = IllegalCharacterValueSanitizer.SPACE_OK; + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link IllegalCharacterValueSanitizer}", + method = "IllegalCharacterValueSanitizer", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: sanitize", + method = "sanitize", + args = {String.class} + ) + }) + public void testSanitize() { + IllegalCharacterValueSanitizer sanitizer = new IllegalCharacterValueSanitizer(SPACE_OK); + assertEquals("Joe User", sanitizer.sanitize("Joe Date: Tue, 14 Apr 2009 12:23:31 -0700 Subject: [PATCH 0015/1415] AI 146171: am: CL 145956 am: CL 145675 CTS: fixed the fail bug in android.net.cts.NetworkInfoTest Original author: sus Merged from: //branches/cupcake/... Original author: android-build Automated import of CL 146171 --- .../src/android/net/cts/NetworkInfoTest.java | 115 +++++++----------- 1 file changed, 46 insertions(+), 69 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 46da3ca74f..62a5f3fad9 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -16,72 +16,68 @@ package android.net.cts; -import dalvik.annotation.ToBeFixed; - import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; -import android.os.Parcel; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { - ConnectivityManager mConnectivityManager; - @Override - protected void setUp() throws Exception { - super.setUp(); - mConnectivityManager = (ConnectivityManager) mContext - .getSystemService(Context.CONNECTIVITY_SERVICE); + public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; + public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; + public static final String MOBILE_TYPE_NAME = "MOBILE"; + public static final String WIFI_TYPE_NAME = "WIFI"; + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of NetworkInfo.", + method = "NetworkInfo", + args = {int.class} + ) + public void testConstructor() { + new NetworkInfo(ConnectivityManager.TYPE_MOBILE); } @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isConnectedOrConnecting", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "setFailover", args = {boolean.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isFailover", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getType", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getTypeName", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "setIsAvailable", args = {boolean.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isAvailable", args = {} ), @@ -93,88 +89,69 @@ public class NetworkInfoTest extends AndroidTestCase { ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", - method = "describeContents", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getDetailedState", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getState", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getReason", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "getExtraInfo", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "toString", args = {} ) }) public void testAccessNetworkInfoProperties() { - NetworkInfo[] ni = mConnectivityManager.getAllNetworkInfo(); + ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( + Context.CONNECTIVITY_SERVICE); + + NetworkInfo[] ni = cm.getAllNetworkInfo(); assertTrue(ni.length >= 2); - assertFalse(ni[ConnectivityManager.TYPE_MOBILE].isFailover()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isFailover()); + + assertFalse(ni[TYPE_MOBILE].isFailover()); + assertFalse(ni[TYPE_WIFI].isFailover()); // test environment:connect as TYPE_MOBILE, and connect to internet. - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getType(), - ConnectivityManager.TYPE_MOBILE); - assertEquals(ni[ConnectivityManager.TYPE_WIFI].getType(), ConnectivityManager.TYPE_WIFI); - assertEquals("MOBILE", ni[ConnectivityManager.TYPE_MOBILE].getTypeName()); - assertEquals("WIFI", ni[ConnectivityManager.TYPE_WIFI].getTypeName()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isConnectedOrConnecting()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnectedOrConnecting()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isAvailable()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isAvailable()); - assertTrue(ni[ConnectivityManager.TYPE_MOBILE].isConnected()); - assertFalse(ni[ConnectivityManager.TYPE_WIFI].isConnected()); + assertEquals(ni[TYPE_MOBILE].getType(), TYPE_MOBILE); + assertEquals(ni[TYPE_WIFI].getType(), TYPE_WIFI); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].describeContents(), 0); - assertEquals(ni[ConnectivityManager.TYPE_WIFI].describeContents(), 0); + assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); + assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getState(), State.CONNECTED); - assertEquals(ni[ConnectivityManager.TYPE_MOBILE].getDetailedState(), - DetailedState.CONNECTED); + assertTrue(ni[TYPE_MOBILE].isConnectedOrConnecting()); + assertFalse(ni[TYPE_WIFI].isConnectedOrConnecting()); - assertNull(ni[ConnectivityManager.TYPE_MOBILE].getReason()); - assertNull(ni[ConnectivityManager.TYPE_WIFI].getReason()); - assertEquals("internet", ni[ConnectivityManager.TYPE_MOBILE].getExtraInfo()); - assertNull(ni[ConnectivityManager.TYPE_WIFI].getExtraInfo()); + assertTrue(ni[TYPE_MOBILE].isAvailable()); + assertFalse(ni[TYPE_WIFI].isAvailable()); - assertNotNull(ni[ConnectivityManager.TYPE_MOBILE].toString()); - assertNotNull(ni[ConnectivityManager.TYPE_WIFI].toString()); - } + assertTrue(ni[TYPE_MOBILE].isConnected()); + assertFalse(ni[TYPE_WIFI].isConnected()); - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test writeToParcel(Parcel dest, int flags).", - method = "writeToParcel", - args = {android.os.Parcel.class, java.lang.Integer.class} - ) - //@ToBeFixed(bug = "1703933", explanation = "Cannot test if the data was written correctly," - public void testWriteToParcel() { - NetworkInfo[] networkInfos = mConnectivityManager.getAllNetworkInfo(); - NetworkInfo mobileInfo = networkInfos[ConnectivityManager.TYPE_MOBILE]; - Parcel p = Parcel.obtain(); + assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); + assertEquals(State.UNKNOWN, ni[TYPE_WIFI].getState()); - mobileInfo.writeToParcel(p, 1); + assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); + assertEquals(DetailedState.IDLE, ni[TYPE_WIFI].getDetailedState()); + + assertNotNull(ni[TYPE_MOBILE].getReason()); + assertNull(ni[TYPE_WIFI].getReason()); + + assertNotNull(ni[TYPE_MOBILE].getExtraInfo()); + assertNull(ni[TYPE_WIFI].getExtraInfo()); + + assertNotNull(ni[TYPE_MOBILE].toString()); + assertNotNull(ni[TYPE_WIFI].toString()); } } From f4c5ba485607468d90d277cff08c3a70347edc7e Mon Sep 17 00:00:00 2001 From: Eric Shienbrood <> Date: Tue, 14 Apr 2009 15:40:19 -0700 Subject: [PATCH 0016/1415] AI 146222: Manual merge of 145980 from donutburger => master. Automated import of CL 146222 --- tests/cts/net/src/android/net/cts/NetworkInfoTest.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 62a5f3fad9..ea1e047d6a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -35,16 +35,6 @@ public class NetworkInfoTest extends AndroidTestCase { public static final String MOBILE_TYPE_NAME = "MOBILE"; public static final String WIFI_TYPE_NAME = "WIFI"; - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test constructor(s) of NetworkInfo.", - method = "NetworkInfo", - args = {int.class} - ) - public void testConstructor() { - new NetworkInfo(ConnectivityManager.TYPE_MOBILE); - } - @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, From 71f2c4fa150cc7bb8c80f1c155e5f3c6abab7c9f Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Tue, 14 Apr 2009 23:34:23 -0700 Subject: [PATCH 0017/1415] AI 146287: CTS: fixed failed problem in ProxyTest Automated import of CL 146287 --- .../net/src/android/net/cts/ProxyTest.java | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index 9345ac2485..fd25084eb6 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -18,33 +18,49 @@ package android.net.cts; import android.content.Context; import android.net.Proxy; -import android.provider.Settings; +import android.provider.Settings.Secure; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; @TestTargetClass(Proxy.class) public class ProxyTest extends AndroidTestCase { + + private Context mContext; + private String mOriginHost; + private int mOriginPort; + @Override protected void setUp() throws Exception { super.setUp(); + mContext = getContext(); + mOriginHost = Proxy.getHost(mContext); + mOriginPort = Proxy.getPort(mContext); + } + + @Override + protected void tearDown() throws Exception { + // Secure.putString should run only on device + Secure.putString(mContext.getContentResolver(), + Secure.HTTP_PROXY, + mOriginHost + ":" + mOriginPort); + + super.tearDown(); } @TestTargetNew( level = TestLevel.COMPLETE, + notes = "Test constructor(s) of Proxy.", method = "Proxy", args = {} ) public void testConstructor() { - - try { - Proxy proxy = new Proxy(); - } catch (Exception e) { - fail("shouldn't throw exception"); - } + new Proxy(); } @TestTargets({ @@ -60,30 +76,31 @@ public class ProxyTest extends AndroidTestCase { ), @TestTargetNew( level = TestLevel.COMPLETE, - method = "getHost", + method = "getPort", args = {Context.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - method = "getPort", + method = "getHost", args = {Context.class} ) }) public void testAccessProperties() { - String mHost = "www.google.com"; - int mPort = 8080; - String mHttpProxy = mHost + ":" + mPort; + final int minValidPort = 0; + final int maxValidPort = 65535; + int defaultPort = Proxy.getDefaultPort(); + if(null == Proxy.getDefaultHost()) { + assertEquals(-1, defaultPort); + } else { + assertTrue(defaultPort >= minValidPort && defaultPort <= maxValidPort); + } - Settings.System.putString(mContext.getContentResolver(), - Settings.System.HTTP_PROXY, null); - assertNull(Proxy.getHost(mContext)); - assertEquals(-1,Proxy.getPort(mContext)); + final String host = "proxy.example.com"; + final int port = 2008; - Settings.System.putString(mContext.getContentResolver(), - Settings.System.HTTP_PROXY, mHttpProxy); - assertEquals(mHost,Proxy.getHost(mContext)); - assertEquals(mPort,Proxy.getPort(mContext)); + // Secure.putString should run only on device + Secure.putString(mContext.getContentResolver(), Secure.HTTP_PROXY, host + ":" + port); + assertEquals(host, Proxy.getHost(mContext)); + assertEquals(port, Proxy.getPort(mContext)); } - } - From 9c2e78b1284855cde87c4139e11028d79dcb52ca Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Tue, 14 Apr 2009 23:34:43 -0700 Subject: [PATCH 0018/1415] AI 146288: am: CL 146287 CTS: fixed failed problem in ProxyTest Original author: sus Merged from: //branches/cupcake/... Automated import of CL 146288 --- .../net/src/android/net/cts/ProxyTest.java | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index 9345ac2485..fd25084eb6 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -18,33 +18,49 @@ package android.net.cts; import android.content.Context; import android.net.Proxy; -import android.provider.Settings; +import android.provider.Settings.Secure; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; @TestTargetClass(Proxy.class) public class ProxyTest extends AndroidTestCase { + + private Context mContext; + private String mOriginHost; + private int mOriginPort; + @Override protected void setUp() throws Exception { super.setUp(); + mContext = getContext(); + mOriginHost = Proxy.getHost(mContext); + mOriginPort = Proxy.getPort(mContext); + } + + @Override + protected void tearDown() throws Exception { + // Secure.putString should run only on device + Secure.putString(mContext.getContentResolver(), + Secure.HTTP_PROXY, + mOriginHost + ":" + mOriginPort); + + super.tearDown(); } @TestTargetNew( level = TestLevel.COMPLETE, + notes = "Test constructor(s) of Proxy.", method = "Proxy", args = {} ) public void testConstructor() { - - try { - Proxy proxy = new Proxy(); - } catch (Exception e) { - fail("shouldn't throw exception"); - } + new Proxy(); } @TestTargets({ @@ -60,30 +76,31 @@ public class ProxyTest extends AndroidTestCase { ), @TestTargetNew( level = TestLevel.COMPLETE, - method = "getHost", + method = "getPort", args = {Context.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - method = "getPort", + method = "getHost", args = {Context.class} ) }) public void testAccessProperties() { - String mHost = "www.google.com"; - int mPort = 8080; - String mHttpProxy = mHost + ":" + mPort; + final int minValidPort = 0; + final int maxValidPort = 65535; + int defaultPort = Proxy.getDefaultPort(); + if(null == Proxy.getDefaultHost()) { + assertEquals(-1, defaultPort); + } else { + assertTrue(defaultPort >= minValidPort && defaultPort <= maxValidPort); + } - Settings.System.putString(mContext.getContentResolver(), - Settings.System.HTTP_PROXY, null); - assertNull(Proxy.getHost(mContext)); - assertEquals(-1,Proxy.getPort(mContext)); + final String host = "proxy.example.com"; + final int port = 2008; - Settings.System.putString(mContext.getContentResolver(), - Settings.System.HTTP_PROXY, mHttpProxy); - assertEquals(mHost,Proxy.getHost(mContext)); - assertEquals(mPort,Proxy.getPort(mContext)); + // Secure.putString should run only on device + Secure.putString(mContext.getContentResolver(), Secure.HTTP_PROXY, host + ":" + port); + assertEquals(host, Proxy.getHost(mContext)); + assertEquals(port, Proxy.getPort(mContext)); } - } - From daff20c5e615e1fdc547538b7b5b64f2b79003e9 Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Thu, 16 Apr 2009 12:01:02 -0700 Subject: [PATCH 0019/1415] AI 146516: am: CL 146072 am: CL 146071 CTS: Clean up test annotations Original author: sus Merged from: //branches/cupcake/... Original author: android-build Automated import of CL 146516 --- .../net/cts/LocalServerSocketTest.java | 1 - .../cts/NetworkInfo_DetailedStateTest.java | 1 - .../net/cts/NetworkInfo_StateTest.java | 1 - .../net/src/android/net/cts/ProxyTest.java | 57 ++++++++----------- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index a6511e8521..07f29c6783 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -26,7 +26,6 @@ import android.net.LocalSocketAddress; import android.os.ParcelFileDescriptor; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 002adfecaf..0e05b28119 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -19,7 +19,6 @@ package android.net.cts; import android.net.NetworkInfo.DetailedState; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java index 2f58784708..249df4b588 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -18,7 +18,6 @@ package android.net.cts; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; -import dalvik.annotation.TestStatus; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index d9f7c1a942..9345ac2485 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -20,9 +20,9 @@ import android.content.Context; import android.net.Proxy; import android.provider.Settings; import android.test.AndroidTestCase; -import dalvik.annotation.TestInfo; -import dalvik.annotation.TestStatus; -import dalvik.annotation.TestTarget; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; @TestTargetClass(Proxy.class) @@ -33,15 +33,11 @@ public class ProxyTest extends AndroidTestCase { } - @TestInfo( - status = TestStatus.TBR, - notes = "Test constructor(s) of Proxy.", - targets = { - @TestTarget( - methodName = "Proxy", - methodArgs = {} - ) - }) + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "Proxy", + args = {} + ) public void testConstructor() { try { @@ -51,29 +47,26 @@ public class ProxyTest extends AndroidTestCase { } } - @TestInfo( - status = TestStatus.TBR, - notes = "Test getDefaultPort().", - targets = { - @TestTarget( - methodName = "getDefaultPort", - methodArgs = {} + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefaultPort", + args = {} ), - @TestTarget( - methodName = "getDefaultHost", - methodArgs = {} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefaultHost", + args = {} ), - @TestTarget( - methodName = "getHost", - methodArgs = {Context.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getHost", + args = {Context.class} ), - @TestTarget( - methodName = "getHost", - methodArgs = {Context.class} - ), - @TestTarget( - methodName = "getPort", - methodArgs = {Context.class} + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPort", + args = {Context.class} ) }) public void testAccessProperties() { From 0a30b3a77ee56edb925b0c42137585dde859956f Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Sat, 18 Apr 2009 20:48:00 -0700 Subject: [PATCH 0020/1415] AI 146564: am: CL 146288 am: CL 146287 CTS: fixed failed problem in ProxyTest Original author: sus Merged from: //branches/cupcake/... Original author: android-build Automated import of CL 146564 --- .../net/src/android/net/cts/ProxyTest.java | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index 9345ac2485..fd25084eb6 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -18,33 +18,49 @@ package android.net.cts; import android.content.Context; import android.net.Proxy; -import android.provider.Settings; +import android.provider.Settings.Secure; import android.test.AndroidTestCase; import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; @TestTargetClass(Proxy.class) public class ProxyTest extends AndroidTestCase { + + private Context mContext; + private String mOriginHost; + private int mOriginPort; + @Override protected void setUp() throws Exception { super.setUp(); + mContext = getContext(); + mOriginHost = Proxy.getHost(mContext); + mOriginPort = Proxy.getPort(mContext); + } + + @Override + protected void tearDown() throws Exception { + // Secure.putString should run only on device + Secure.putString(mContext.getContentResolver(), + Secure.HTTP_PROXY, + mOriginHost + ":" + mOriginPort); + + super.tearDown(); } @TestTargetNew( level = TestLevel.COMPLETE, + notes = "Test constructor(s) of Proxy.", method = "Proxy", args = {} ) public void testConstructor() { - - try { - Proxy proxy = new Proxy(); - } catch (Exception e) { - fail("shouldn't throw exception"); - } + new Proxy(); } @TestTargets({ @@ -60,30 +76,31 @@ public class ProxyTest extends AndroidTestCase { ), @TestTargetNew( level = TestLevel.COMPLETE, - method = "getHost", + method = "getPort", args = {Context.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - method = "getPort", + method = "getHost", args = {Context.class} ) }) public void testAccessProperties() { - String mHost = "www.google.com"; - int mPort = 8080; - String mHttpProxy = mHost + ":" + mPort; + final int minValidPort = 0; + final int maxValidPort = 65535; + int defaultPort = Proxy.getDefaultPort(); + if(null == Proxy.getDefaultHost()) { + assertEquals(-1, defaultPort); + } else { + assertTrue(defaultPort >= minValidPort && defaultPort <= maxValidPort); + } - Settings.System.putString(mContext.getContentResolver(), - Settings.System.HTTP_PROXY, null); - assertNull(Proxy.getHost(mContext)); - assertEquals(-1,Proxy.getPort(mContext)); + final String host = "proxy.example.com"; + final int port = 2008; - Settings.System.putString(mContext.getContentResolver(), - Settings.System.HTTP_PROXY, mHttpProxy); - assertEquals(mHost,Proxy.getHost(mContext)); - assertEquals(mPort,Proxy.getPort(mContext)); + // Secure.putString should run only on device + Secure.putString(mContext.getContentResolver(), Secure.HTTP_PROXY, host + ":" + port); + assertEquals(host, Proxy.getHost(mContext)); + assertEquals(port, Proxy.getPort(mContext)); } - } - From 3165096c2d71aa3cb13d7d739df49a8abf5ec52a Mon Sep 17 00:00:00 2001 From: Phil Dubach <> Date: Mon, 20 Apr 2009 17:57:22 -0700 Subject: [PATCH 0021/1415] AI 147059: CTS: Fix LOCAL_MODULE_TAGS for CTS tests CTS tests should use local module tag 'tests' such that they are not built and included in the image by default. BUG=1778334 Automated import of CL 147059 --- tests/cts/net/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 0a2a6f382b..a2bbc9c316 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -16,7 +16,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := ctstests_net +LOCAL_MODULE_TAGS := tests LOCAL_JAVA_LIBRARIES := android.test.runner From 2774b0fab0e6d7c910baa997d12e65b7fa65d886 Mon Sep 17 00:00:00 2001 From: Phil Dubach <> Date: Mon, 20 Apr 2009 18:00:20 -0700 Subject: [PATCH 0022/1415] AI 147064: am: CL 147060 am: CL 147059 CTS: Fix LOCAL_MODULE_TAGS for CTS tests CTS tests should use local module tag 'tests' such that they are not built and included in the image by default. Original author: phillipd Merged from: //branches/cupcake/... Original author: android-build Automated import of CL 147064 --- tests/cts/net/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 0a2a6f382b..a2bbc9c316 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -16,7 +16,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := ctstests_net +LOCAL_MODULE_TAGS := tests LOCAL_JAVA_LIBRARIES := android.test.runner From 3da72df1599b6ae9c20dca66ddfb11954643d200 Mon Sep 17 00:00:00 2001 From: Phil Dubach <> Date: Tue, 21 Apr 2009 01:02:54 -0700 Subject: [PATCH 0023/1415] AI 147060: am: CL 147059 CTS: Fix LOCAL_MODULE_TAGS for CTS tests CTS tests should use local module tag 'tests' such that they are not built and included in the image by default. Original author: phillipd Merged from: //branches/cupcake/... Automated import of CL 147060 --- tests/cts/net/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 0a2a6f382b..a2bbc9c316 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -16,7 +16,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := ctstests_net +LOCAL_MODULE_TAGS := tests LOCAL_JAVA_LIBRARIES := android.test.runner From 0f009ffc55bf3404f43dba000031d2293a14e061 Mon Sep 17 00:00:00 2001 From: Scott Su <> Date: Wed, 29 Apr 2009 03:12:14 -0700 Subject: [PATCH 0024/1415] AI 147986: Change CTS tests to use InstrumentationCoreTestRunner, which has handled the @BrokenTest Automated import of CL 147986 --- tests/cts/net/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 6c2dfbdf65..f6db2feb70 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -22,7 +22,7 @@ - From 68b8cda17af0cb88732ddbc264cfbeab86304d9b Mon Sep 17 00:00:00 2001 From: Scott Su Date: Thu, 30 Apr 2009 16:53:23 -0700 Subject: [PATCH 0025/1415] AI 148053: CTS: fixed failed testcases Automated import of CL 148053 --- .../net/cts/ConnectivityManagerTest.java | 29 ++++------- .../src/android/net/cts/NetworkInfoTest.java | 50 ++++++++++++------- .../net/src/android/net/cts/ProxyTest.java | 21 ++------ 3 files changed, 46 insertions(+), 54 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index e8697bebab..abcfb2261c 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -16,6 +16,7 @@ package android.net.cts; +import dalvik.annotation.BrokenTest; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; @@ -31,13 +32,15 @@ import android.test.AndroidTestCase; @TestTargetClass(ConnectivityManager.class) public class ConnectivityManagerTest extends AndroidTestCase { + public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; + public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 private ConnectivityManager mCm; + @Override protected void setUp() throws Exception { super.setUp(); - mCm = (ConnectivityManager) getContext().getSystemService( - Context.CONNECTIVITY_SERVICE); + mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); } @TestTargetNew( @@ -98,17 +101,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "", method = "getNetworkPreference", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "", method = "setNetworkPreference", args = {int.class} ) }) + @BrokenTest("Cannot write secure settings table") public void testAccessNetworkPreference() { final int expected = 1; @@ -150,15 +152,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test startUsingNetworkFeature(int networkType, String feature)." - + "Only test failure case.", method = "startUsingNetworkFeature", args = {int.class, java.lang.String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test stopUsingNetworkFeature(int networkType, String feature)." - + "Only test failure case.", method = "stopUsingNetworkFeature", args = {int.class, java.lang.String.class} ) @@ -166,20 +164,15 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testStartUsingNetworkFeature() { final String invalidateFeature = "invalidateFeature"; - // TODO: MMS feature string is not public final String mmsFeature = "enableMMS"; final int failureCode = -1; - assertEquals(failureCode, mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - invalidateFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - invalidateFeature)); + assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); // Should return failure(-1) because MMS is not supported on WIFI. - assertEquals(failureCode, - mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); - assertEquals(failureCode, - mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI, mmsFeature)); } @TestTargetNew( diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index ea1e047d6a..2c3d73c75a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -73,7 +73,6 @@ public class NetworkInfoTest extends AndroidTestCase { ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isConnectedOrConnecting().", method = "isConnected", args = {} ), @@ -114,32 +113,47 @@ public class NetworkInfoTest extends AndroidTestCase { assertFalse(ni[TYPE_WIFI].isFailover()); // test environment:connect as TYPE_MOBILE, and connect to internet. - assertEquals(ni[TYPE_MOBILE].getType(), TYPE_MOBILE); - assertEquals(ni[TYPE_WIFI].getType(), TYPE_WIFI); + assertEquals(TYPE_MOBILE, ni[TYPE_MOBILE].getType()); + assertEquals(TYPE_WIFI, ni[TYPE_WIFI].getType()); assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); - assertTrue(ni[TYPE_MOBILE].isConnectedOrConnecting()); - assertFalse(ni[TYPE_WIFI].isConnectedOrConnecting()); + if(ni[TYPE_MOBILE].isConnectedOrConnecting()) { + assertTrue(ni[TYPE_MOBILE].isAvailable()); + assertTrue(ni[TYPE_MOBILE].isConnected()); + assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); + assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); + assertNotNull(ni[TYPE_MOBILE].getReason()); + assertNotNull(ni[TYPE_MOBILE].getExtraInfo()); + } else { + assertFalse(ni[TYPE_MOBILE].isAvailable()); + assertFalse(ni[TYPE_MOBILE].isConnected()); - assertTrue(ni[TYPE_MOBILE].isAvailable()); - assertFalse(ni[TYPE_WIFI].isAvailable()); + // mobile state is undefined - assertTrue(ni[TYPE_MOBILE].isConnected()); - assertFalse(ni[TYPE_WIFI].isConnected()); + assertEquals(DetailedState.IDLE, ni[TYPE_MOBILE].getDetailedState()); + assertNull(ni[TYPE_MOBILE].getReason()); + assertNull(ni[TYPE_MOBILE].getExtraInfo()); + } - assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); - assertEquals(State.UNKNOWN, ni[TYPE_WIFI].getState()); + if(ni[TYPE_WIFI].isConnectedOrConnecting()) { + assertTrue(ni[TYPE_WIFI].isAvailable()); + assertTrue(ni[TYPE_WIFI].isConnected()); + assertEquals(State.CONNECTED, ni[TYPE_WIFI].getState()); + assertEquals(DetailedState.CONNECTED, ni[TYPE_WIFI].getDetailedState()); + assertNotNull(ni[TYPE_WIFI].getReason()); + assertNotNull(ni[TYPE_WIFI].getExtraInfo()); + } else { + assertFalse(ni[TYPE_WIFI].isAvailable()); + assertFalse(ni[TYPE_WIFI].isConnected()); - assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); - assertEquals(DetailedState.IDLE, ni[TYPE_WIFI].getDetailedState()); + // wifi state is undefined - assertNotNull(ni[TYPE_MOBILE].getReason()); - assertNull(ni[TYPE_WIFI].getReason()); - - assertNotNull(ni[TYPE_MOBILE].getExtraInfo()); - assertNull(ni[TYPE_WIFI].getExtraInfo()); + assertEquals(DetailedState.IDLE, ni[TYPE_WIFI].getDetailedState()); + assertNull(ni[TYPE_WIFI].getReason()); + assertNull(ni[TYPE_WIFI].getExtraInfo()); + } assertNotNull(ni[TYPE_MOBILE].toString()); assertNotNull(ni[TYPE_WIFI].toString()); diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index fd25084eb6..357935adb0 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -20,9 +20,9 @@ import android.content.Context; import android.net.Proxy; import android.provider.Settings.Secure; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; + +import dalvik.annotation.BrokenTest; import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargets; @@ -31,31 +31,16 @@ import dalvik.annotation.TestTargets; public class ProxyTest extends AndroidTestCase { private Context mContext; - private String mOriginHost; - private int mOriginPort; @Override protected void setUp() throws Exception { super.setUp(); mContext = getContext(); - mOriginHost = Proxy.getHost(mContext); - mOriginPort = Proxy.getPort(mContext); - } - - @Override - protected void tearDown() throws Exception { - // Secure.putString should run only on device - Secure.putString(mContext.getContentResolver(), - Secure.HTTP_PROXY, - mOriginHost + ":" + mOriginPort); - - super.tearDown(); } @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test constructor(s) of Proxy.", method = "Proxy", args = {} ) @@ -85,6 +70,7 @@ public class ProxyTest extends AndroidTestCase { args = {Context.class} ) }) + @BrokenTest("Cannot write secure settings table") public void testAccessProperties() { final int minValidPort = 0; final int maxValidPort = 65535; @@ -98,7 +84,6 @@ public class ProxyTest extends AndroidTestCase { final String host = "proxy.example.com"; final int port = 2008; - // Secure.putString should run only on device Secure.putString(mContext.getContentResolver(), Secure.HTTP_PROXY, host + ":" + port); assertEquals(host, Proxy.getHost(mContext)); assertEquals(port, Proxy.getPort(mContext)); From e480582d829a87e2d7097cb79b7afb9e4ccbf74a Mon Sep 17 00:00:00 2001 From: Phil Dubach Date: Thu, 7 May 2009 10:34:41 -0700 Subject: [PATCH 0026/1415] AI 148455: CTS: Change tests in Android plan to use new InstrumentationCtsTestRunner BUG=1537738 Automated import of CL 148455 --- tests/cts/net/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index f6db2feb70..a1f632effb 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -22,7 +22,7 @@ - From 665f512ebc9b376e8ca503bdfa77d656c914b0f0 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Thu, 14 May 2009 15:55:21 -0700 Subject: [PATCH 0027/1415] Change cts tests to use InstrumentationTestRunner. --- tests/cts/net/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index a1f632effb..6c2dfbdf65 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -22,7 +22,7 @@ - From e7a02b243e27420df5273e0276442225dd50839e Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Tue, 19 May 2009 18:08:05 -0700 Subject: [PATCH 0028/1415] Revert "Change cts tests to use InstrumentationTestRunner." This reverts commit 665f512ebc9b376e8ca503bdfa77d656c914b0f0. --- tests/cts/net/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 6c2dfbdf65..a1f632effb 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -22,7 +22,7 @@ - From a87bf95576ef45a304447e55172373049a0350fe Mon Sep 17 00:00:00 2001 From: Phil Dubach Date: Tue, 19 May 2009 11:43:39 -0700 Subject: [PATCH 0029/1415] Integrate unsubmitted cupcake change 131139: CTS: add test cases for net.wifi.ScanResult, SupplicantState, WifiConfiguration, WifiInfo and WifiManager. Added new tests as per mondrian comments. Cleaned code to get rid of eclipse warnings. --- .../android/net/wifi/cts/ScanResultTest.java | 126 ++++++ .../net/wifi/cts/SupplicantStateTest.java | 50 ++ .../net/wifi/cts/WifiConfigurationTest.java | 60 +++ .../android/net/wifi/cts/WifiInfoTest.java | 194 ++++++++ .../android/net/wifi/cts/WifiManagerTest.java | 427 ++++++++++++++++++ .../wifi/cts/WifiManager_WifiLockTest.java | 107 +++++ 6 files changed, 964 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java new file mode 100644 index 0000000000..0ab71c70e4 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import java.util.List; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; + +@TestTargetClass(ScanResult.class) +public class ScanResultTest extends AndroidTestCase { + private static class MySync { + int expectedState = STATE_NULL; + } + + private WifiManager mWifiManager; + private WifiLock mWifiLock; + private static MySync mMySync; + + private static final int STATE_NULL = 0; + private static final int STATE_WIFI_CHANGING = 1; + private static final int STATE_WIFI_CHANGED = 2; + + private static final String TAG = "WifiInfoTest"; + private static final int TIMEOUT_MSEC = 6000; + private static final int WAIT_MSEC = 60; + private static final int DURATION = 10000; + private IntentFilter mIntentFilter; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGED; + mMySync.notify(); + } + } + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mMySync = new MySync(); + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); + + mContext.registerReceiver(mReceiver, mIntentFilter); + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + assertNotNull(mWifiManager); + mWifiLock = mWifiManager.createWifiLock(TAG); + mWifiLock.acquire(); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + assertTrue(mWifiManager.isWifiEnabled()); + mMySync.expectedState = STATE_NULL; + } + + @Override + protected void tearDown() throws Exception { + mWifiLock.release(); + mContext.unregisterReceiver(mReceiver); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + super.tearDown(); + } + + private void setWifiEnabled(boolean enable) throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGING; + assertTrue(mWifiManager.setWifiEnabled(enable)); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mMySync.expectedState == STATE_WIFI_CHANGING) + mMySync.wait(WAIT_MSEC); + } + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "toString", + args = {} + ) + public void testScanResultProperties() { + List scanResults = mWifiManager.getScanResults(); + // this test case should in Wifi environment + for (int i = 0; i < scanResults.size(); i++) { + ScanResult mScanResult = scanResults.get(i); + assertNotNull(mScanResult.toString()); + } + } + +} diff --git a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java new file mode 100644 index 0000000000..4e03f5e9ce --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import android.net.wifi.SupplicantState; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(SupplicantState.class) +public class SupplicantStateTest extends AndroidTestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isValidState", + args = {android.net.wifi.SupplicantState.class} + ) + }) + public void testIsValidState() { + assertTrue(SupplicantState.isValidState(SupplicantState.DISCONNECTED)); + assertTrue(SupplicantState.isValidState(SupplicantState.INACTIVE)); + assertTrue(SupplicantState.isValidState(SupplicantState.SCANNING)); + assertTrue(SupplicantState.isValidState(SupplicantState.ASSOCIATING)); + assertTrue(SupplicantState.isValidState(SupplicantState.ASSOCIATED)); + assertTrue(SupplicantState.isValidState(SupplicantState.FOUR_WAY_HANDSHAKE)); + assertTrue(SupplicantState.isValidState(SupplicantState.GROUP_HANDSHAKE)); + assertTrue(SupplicantState.isValidState(SupplicantState.COMPLETED)); + assertTrue(SupplicantState.isValidState(SupplicantState.DORMANT)); + assertFalse(SupplicantState.isValidState(SupplicantState.UNINITIALIZED)); + assertFalse(SupplicantState.isValidState(SupplicantState.INVALID)); + } + +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java new file mode 100644 index 0000000000..3018907092 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import java.util.List; + +import android.content.Context; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(WifiConfiguration.class) +public class WifiConfigurationTest extends AndroidTestCase { + private WifiManager mWifiManager; + @Override + protected void setUp() throws Exception { + super.setUp(); + mWifiManager = (WifiManager) mContext + .getSystemService(Context.WIFI_SERVICE); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "WifiConfiguration", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "toString", + args = {} + ) + }) + public void testWifiConfiguration() { + List wifiConfigurations = mWifiManager.getConfiguredNetworks(); + for (int i = 0; i < wifiConfigurations.size(); i++) { + WifiConfiguration wifiConfiguration = wifiConfigurations.get(i); + assertNotNull(wifiConfiguration); + assertNotNull(wifiConfiguration.toString()); + } + } +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java new file mode 100644 index 0000000000..42243c890d --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; +import dalvik.annotation.ToBeFixed; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.SupplicantState; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.test.AndroidTestCase; + +@TestTargetClass(WifiInfo.class) +public class WifiInfoTest extends AndroidTestCase { + private static class MySync { + int expectedState = STATE_NULL; + } + + private WifiManager mWifiManager; + private WifiLock mWifiLock; + private static MySync mMySync; + + private static final int STATE_NULL = 0; + private static final int STATE_WIFI_CHANGING = 1; + private static final int STATE_WIFI_CHANGED = 2; + + private static final String TAG = "WifiInfoTest"; + private static final int TIMEOUT_MSEC = 6000; + private static final int WAIT_MSEC = 60; + private static final int DURATION = 10000; + private IntentFilter mIntentFilter; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGED; + mMySync.notify(); + } + } + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mMySync = new MySync(); + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); + + mContext.registerReceiver(mReceiver, mIntentFilter); + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + assertNotNull(mWifiManager); + mWifiLock = mWifiManager.createWifiLock(TAG); + mWifiLock.acquire(); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + assertTrue(mWifiManager.isWifiEnabled()); + mMySync.expectedState = STATE_NULL; + } + + @Override + protected void tearDown() throws Exception { + mWifiLock.release(); + mContext.unregisterReceiver(mReceiver); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + super.tearDown(); + } + + private void setWifiEnabled(boolean enable) throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGING; + assertTrue(mWifiManager.setWifiEnabled(enable)); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mMySync.expectedState == STATE_WIFI_CHANGING) + mMySync.wait(WAIT_MSEC); + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getMacAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getIpAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getDetailedStateOf", + args = {android.net.wifi.SupplicantState.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getNetworkId", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getSSID", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getBSSID", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getSupplicantState", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getLinkSpeed", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "toString", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getRssi", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getHiddenSSID", + args = {} + ) + }) + @ToBeFixed(bug="1871573", explanation="android.net.wifi.WifiInfo#getNetworkId() return -1 when" + + " there is wifi connection") + public void testWifiInfoProperties() throws Exception { + // this test case should in Wifi environment + WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + + assertNotNull(wifiInfo); + assertNotNull(wifiInfo.toString()); + SupplicantState.isValidState(wifiInfo.getSupplicantState()); + WifiInfo.getDetailedStateOf(SupplicantState.DISCONNECTED); + wifiInfo.getSSID(); + wifiInfo.getBSSID(); + wifiInfo.getIpAddress(); + wifiInfo.getLinkSpeed(); + wifiInfo.getRssi(); + wifiInfo.getHiddenSSID(); + wifiInfo.getMacAddress(); + setWifiEnabled(false); + Thread.sleep(DURATION); + wifiInfo = mWifiManager.getConnectionInfo(); + assertEquals(-1, wifiInfo.getNetworkId()); + } + +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java new file mode 100644 index 0000000000..132ca9247d --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2009 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.wifi.cts; + +import java.util.List; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiConfiguration.Status; +import android.net.wifi.WifiManager.WifiLock; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(WifiManager.class) +public class WifiManagerTest extends AndroidTestCase { + private static class MySync { + int expectedState = STATE_NULL; + } + + private WifiManager mWifiManager; + private WifiLock mWifiLock; + private static MySync mMySync; + private List mScanResult = null; + + // Please refer to WifiManager + private static final int MIN_RSSI = -100; + private static final int MAX_RSSI = -55; + + private static final int STATE_NULL = 0; + private static final int STATE_WIFI_CHANGING = 1; + private static final int STATE_WIFI_CHANGED = 2; + private static final int STATE_SCANING = 3; + private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; + + private static final String TAG = "WifiManagerTest"; + private static final String SSID1 = "\"WifiManagerTest\""; + private static final String SSID2 = "\"WifiManagerTestModified\""; + private static final int TIMEOUT_MSEC = 6000; + private static final int WAIT_MSEC = 60; + private static final int DURATION = 10000; + private IntentFilter mIntentFilter; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { + synchronized (mMySync) { + if (mWifiManager.getScanResults() != null) { + mScanResult = mWifiManager.getScanResults(); + mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; + mScanResult = mWifiManager.getScanResults(); + mMySync.notify(); + } + } + } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGED; + mMySync.notify(); + } + } + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mMySync = new MySync(); + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); + + mContext.registerReceiver(mReceiver, mIntentFilter); + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + assertNotNull(mWifiManager); + mWifiLock = mWifiManager.createWifiLock(TAG); + mWifiLock.acquire(); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + assertTrue(mWifiManager.isWifiEnabled()); + mMySync.expectedState = STATE_NULL; + } + + @Override + protected void tearDown() throws Exception { + mWifiLock.release(); + mContext.unregisterReceiver(mReceiver); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + super.tearDown(); + } + + private void setWifiEnabled(boolean enable) throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGING; + assertTrue(mWifiManager.setWifiEnabled(enable)); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mMySync.expectedState == STATE_WIFI_CHANGING) + mMySync.wait(WAIT_MSEC); + } + } + + private void startScan() throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_SCANING; + assertTrue(mWifiManager.startScan()); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANING) + mMySync.wait(WAIT_MSEC); + } + } + + private boolean existSSID(String ssid) { + for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { + if (w.SSID.equals(ssid)) + return true; + } + return false; + } + + private int findConfiguredNetworks(String SSID, List networks) { + for (final WifiConfiguration w : networks) { + if (w.SSID.equals(SSID)) + return networks.indexOf(w); + } + return -1; + } + + private void assertDisableOthers(WifiConfiguration wifiConfiguration, boolean disableOthers) { + for (WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { + if ((!w.SSID.equals(wifiConfiguration.SSID)) && w.status != Status.CURRENT) { + if (disableOthers) + assertEquals(Status.DISABLED, w.status); + } + } + } + + /** + * test point of wifiManager actions: + * 1.reconnect + * 2.reassociate + * 3.disconnect + * 4.pingSupplicant + * 5.satrtScan + */ + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isWifiEnabled", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setWifiEnabled", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "startScan", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getScanResults", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "pingSupplicant", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "reassociate", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "reconnect", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "disconnect", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createWifiLock", + args = {int.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createWifiLock", + args = {String.class} + ) + }) + public void testWifiManagerActions() throws Exception { + assertTrue(mWifiManager.reconnect()); + assertTrue(mWifiManager.reassociate()); + assertTrue(mWifiManager.disconnect()); + assertTrue(mWifiManager.pingSupplicant()); + startScan(); + setWifiEnabled(false); + Thread.sleep(DURATION); + assertFalse(mWifiManager.pingSupplicant()); + final String TAG = "Test"; + assertNotNull(mWifiManager.createWifiLock(TAG)); + assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); + } + + /** + * test point of wifiManager properties: + * 1.enable properties + * 2.DhcpInfo properties + * 3.wifi state + * 4.ConnectionInfo + */ + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isWifiEnabled", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getWifiState", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setWifiEnabled", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getConnectionInfo", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDhcpInfo", + args = {} + ) + }) + public void testWifiManagerProperties() throws Exception { + setWifiEnabled(true); + assertTrue(mWifiManager.isWifiEnabled()); + assertNotNull(mWifiManager.getDhcpInfo()); + assertEquals(WifiManager.WIFI_STATE_ENABLED, mWifiManager.getWifiState()); + mWifiManager.getConnectionInfo(); + setWifiEnabled(false); + assertFalse(mWifiManager.isWifiEnabled()); + } + + /** + * test point of wifiManager NetWork: + * 1.add NetWork + * 2.update NetWork + * 3.remove NetWork + * 4.enable NetWork + * 5.disable NetWork + * 6.configured Networks + * 7.save configure; + */ + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isWifiEnabled", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setWifiEnabled", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getConfiguredNetworks", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "addNetwork", + args = {android.net.wifi.WifiConfiguration.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "updateNetwork", + args = {android.net.wifi.WifiConfiguration.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "removeNetwork", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "enableNetwork", + args = {int.class, boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "disableNetwork", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "saveConfiguration", + args = {} + ) + }) + public void testWifiManagerNetWork() throws Exception { + WifiConfiguration wifiConfiguration; + // add a WifiConfig + final int notExist = -1; + List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + if (notExist != pos) { + wifiConfiguration = wifiConfiguredNetworks.get(pos); + mWifiManager.removeNetwork(wifiConfiguration.networkId); + } + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertEquals(notExist, pos); + final int size = wifiConfiguredNetworks.size(); + + wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = SSID1; + int netId = mWifiManager.addNetwork(wifiConfiguration); + assertTrue(existSSID(SSID1)); + + wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + assertEquals(size + 1, wifiConfiguredNetworks.size()); + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertTrue(notExist != pos); + + // Enable & disable network + boolean disableOthers = false; + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + assertEquals(Status.ENABLED, wifiConfiguration.status); + disableOthers = true; + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + + assertTrue(mWifiManager.disableNetwork(netId)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertEquals(Status.DISABLED, wifiConfiguration.status); + + // Update a WifiConfig + wifiConfiguration = wifiConfiguredNetworks.get(pos); + wifiConfiguration.SSID = SSID2; + netId = mWifiManager.updateNetwork(wifiConfiguration); + assertFalse(existSSID(SSID1)); + assertTrue(existSSID(SSID2)); + + // Remove a WifiConfig + assertTrue(mWifiManager.removeNetwork(netId)); + assertFalse(mWifiManager.removeNetwork(notExist)); + assertFalse(existSSID(SSID1)); + assertFalse(existSSID(SSID2)); + + assertTrue(mWifiManager.saveConfiguration()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "compareSignalLevel", + args = {int.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "calculateSignalLevel", + args = {int.class, int.class} + ) + }) + public void testSignal() { + final int numLevels = 9; + int expectLevel = 0; + assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels)); + assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels)); + expectLevel = 4; + assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2, + numLevels)); + int rssiA = 4; + int rssiB = 5; + assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0); + rssiB = 4; + assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0); + rssiA = 5; + rssiB = 4; + assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0); + } +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java new file mode 100644 index 0000000000..53150c9650 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(WifiManager.WifiLock.class) +public class WifiManager_WifiLockTest extends AndroidTestCase { + + private static final String WIFI_TAG = "WifiManager_WifiLockTest"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "acquire", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "finalize", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isHeld", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "release", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setReferenceCounted", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "toString", + args = {} + ) + }) + public void testWifiLock() { + WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + WifiLock wl = wm.createWifiLock(WIFI_TAG); + + wl.setReferenceCounted(true); + assertFalse(wl.isHeld()); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + wl.acquire(); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + assertNotNull(wl.toString()); + try { + wl.release(); + fail("should throw out exception because release is called" + +" a greater number of times than acquire"); + } catch (RuntimeException e) { + // expected + } + + wl = wm.createWifiLock(WIFI_TAG); + wl.setReferenceCounted(false); + assertFalse(wl.isHeld()); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + wl.acquire(); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + assertNotNull(wl.toString()); + // should be ignored + wl.release(); + } +} From 1c52e1c796e81a9947b044ed4c64760bf740eff5 Mon Sep 17 00:00:00 2001 From: Phil Dubach Date: Tue, 2 Jun 2009 14:46:51 -0700 Subject: [PATCH 0030/1415] Integrate unsubmitted cupcake change 123653: CTS: add test cases for net.SSLCertificateSocketFactory --- .../cts/SSLCertificateSocketFactoryTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java new file mode 100644 index 0000000000..b81dd37007 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2008 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 java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; + +import javax.net.SocketFactory; + +import android.net.SSLCertificateSocketFactory; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; +import dalvik.annotation.ToBeFixed; + +@TestTargetClass(SSLCertificateSocketFactory.class) +public class SSLCertificateSocketFactoryTest extends AndroidTestCase { + private SSLCertificateSocketFactory mFactory; + private int mTimeout; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTimeout = 1000; + mFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(mTimeout); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getSupportedCipherSuites", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefault", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getDefaultCipherSuites", + args = {} + ) + }) + @ToBeFixed(bug="1695243", explanation="Android API javadocs are incomplete") + public void testAccessProperties() throws Exception { + mFactory.getSupportedCipherSuites(); + mFactory.getDefaultCipherSuites(); + SocketFactory sf = SSLCertificateSocketFactory.getDefault(mTimeout); + assertNotNull(sf); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {java.net.InetAddress.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {java.net.Socket.class, java.lang.String.class, int.class, boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {java.lang.String.class, int.class} + ), + @TestTargetNew( + level = TestLevel.NOT_FEASIBLE, + method = "createSocket", + args = {java.lang.String.class, int.class, java.net.InetAddress.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {java.net.InetAddress.class, int.class, java.net.InetAddress.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "SSLCertificateSocketFactory", + args = {int.class} + ) + }) + public void testCreateSocket() throws Exception { + new SSLCertificateSocketFactory(100); + int port = 443; + String host = "www.fortify.net"; + InetAddress inetAddress = null; + inetAddress = InetAddress.getLocalHost(); + try { + mFactory.createSocket(inetAddress, port); + fail("should throw exception!"); + } catch (IOException e) { + // expected + } + + try { + InetAddress inetAddress1 = InetAddress.getLocalHost(); + InetAddress inetAddress2 = InetAddress.getLocalHost(); + mFactory.createSocket(inetAddress1, port, inetAddress2, port); + fail("should throw exception!"); + } catch (IOException e) { + // expected + } + + try { + Socket socket = new Socket(); + mFactory.createSocket(socket, host, port, true); + fail("should throw exception!"); + } catch (IOException e) { + // expected + } + Socket socket = null; + socket = mFactory.createSocket(host, port); + assertNotNull(socket); + assertNotNull(socket.getOutputStream()); + assertNotNull(socket.getInputStream()); + + // it throw exception when calling createSocket(String, int, InetAddress, int) + // The socket level is invalid. + } + +} From 8b360f568a040e1452dfa0e4c89009435d57c2c7 Mon Sep 17 00:00:00 2001 From: Phil Dubach Date: Thu, 11 Jun 2009 14:02:10 -0700 Subject: [PATCH 0031/1415] Integrate unsubmitted cupcake change 147342: CTS: clean up code in android.net package --- .../net/cts/ConnectivityManagerTest.java | 81 ++++++++++++------- .../src/android/net/cts/CredentialsTest.java | 4 - .../net/src/android/net/cts/DhcpInfoTest.java | 5 +- .../net/cts/LocalServerSocketTest.java | 27 ++----- .../net/cts/LocalSocketAddressTest.java | 11 +-- .../cts/LocalSocketAddress_NamespaceTest.java | 10 +-- .../src/android/net/cts/NetworkInfoTest.java | 52 +++++++----- .../cts/NetworkInfo_DetailedStateTest.java | 31 +++---- .../net/cts/NetworkInfo_StateTest.java | 13 +-- .../net/cts/UrlQuerySanitizerTest.java | 65 ++++++++------- 10 files changed, 142 insertions(+), 157 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index abcfb2261c..a8a149f250 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,11 +16,11 @@ package android.net.cts; -import dalvik.annotation.BrokenTest; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargets; +import dalvik.annotation.ToBeFixed; import android.content.Context; import android.net.ConnectivityManager; @@ -45,7 +45,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test getNetworkInfo(int networkType).", method = "getNetworkInfo", args = {int.class} ) @@ -77,13 +76,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isNetworkTypeValid(int networkType).", method = "isNetworkTypeValid", args = {int.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test isNetworkTypeValid(int networkType).", method = "getAllNetworkInfo", args = {} ) @@ -105,33 +102,58 @@ public class ConnectivityManagerTest extends AndroidTestCase { args = {} ), @TestTargetNew( - level = TestLevel.COMPLETE, + level = TestLevel.SUFFICIENT, method = "setNetworkPreference", args = {int.class} ) }) - @BrokenTest("Cannot write secure settings table") public void testAccessNetworkPreference() { + int initialSetting = mCm.getNetworkPreference(); - final int expected = 1; - int per = mCm.getNetworkPreference(); - mCm.setNetworkPreference(expected); - assertEquals(expected, mCm.getNetworkPreference()); + // Changing the network preference requires android.permission.WRITE_SECURE_SETTINGS, + // which is only available to signed or system applications. - mCm.setNetworkPreference(0); - assertEquals(0, mCm.getNetworkPreference()); + // Setting the same preference that is already set is a no-op and does not throw + // a SecurityException. + mCm.setNetworkPreference(initialSetting); + assertEquals(initialSetting, mCm.getNetworkPreference()); + // find a valid setting that is different from the initial setting + int validSetting = -1; + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + for (NetworkInfo n : ni) { + int type = n.getType(); + if (type != initialSetting) { + validSetting = type; + break; + } + } + if (validSetting >= 0) { + try { + mCm.setNetworkPreference(validSetting); + fail("Trying to change the network preference should throw SecurityException"); + } catch (SecurityException expected) { + // expected + } + } + + // find an invalid setting + int invalidSetting = -1; + for (int i = 0; i < 10; i++) { + if (!ConnectivityManager.isNetworkTypeValid(i)) { + invalidSetting = i; + break; + } + } + if (invalidSetting >= 0) { + // illegal setting should be ignored + mCm.setNetworkPreference(invalidSetting); + assertEquals(initialSetting, mCm.getNetworkPreference()); + } + + // illegal setting should be ignored mCm.setNetworkPreference(-1); - assertEquals(0, mCm.getNetworkPreference()); - - mCm.setNetworkPreference(2); - assertEquals(0, mCm.getNetworkPreference()); - - mCm.setNetworkPreference(1); - - assertEquals(1, mCm.getNetworkPreference()); - - mCm.setNetworkPreference(per); + assertEquals(initialSetting, mCm.getNetworkPreference()); } @TestTargetNew( @@ -177,7 +199,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test requestRouteToHost(int networkType, int hostAddress).", method = "requestRouteToHost", args = {int.class, int.class} ) @@ -193,18 +214,24 @@ public class ConnectivityManagerTest extends AndroidTestCase { @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test getActiveNetworkInfo().", method = "getActiveNetworkInfo", args = {} ) + @ToBeFixed(bug="1695243", explanation="No Javadoc") public void testGetActiveNetworkInfo() { - NetworkInfo ni = mCm.getActiveNetworkInfo(); + if (ni != null) { assertTrue(ni.getType() >= 0); - } else { - fail("There is no active network connected, should be at least one kind of network"); } } + @TestTargetNew( + level = TestLevel.SUFFICIENT, + method = "getBackgroundDataSetting", + args = {} + ) + public void testTest() { + mCm.getBackgroundDataSetting(); + } } diff --git a/tests/cts/net/src/android/net/cts/CredentialsTest.java b/tests/cts/net/src/android/net/cts/CredentialsTest.java index fe65805294..6cf8c2351e 100644 --- a/tests/cts/net/src/android/net/cts/CredentialsTest.java +++ b/tests/cts/net/src/android/net/cts/CredentialsTest.java @@ -29,25 +29,21 @@ public class CredentialsTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "Credentials", args = {int.class, int.class, int.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getGid", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getPid", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test constructor of Credentials, and test getGid, getPid, getUid.", method = "getUid", args = {} ) diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java index 1a1ad477fd..97bd27a970 100644 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -18,10 +18,9 @@ package android.net.cts; import android.net.DhcpInfo; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; @TestTargetClass(DhcpInfo.class) public class DhcpInfoTest extends AndroidTestCase { diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index 07f29c6783..21c7d5e299 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -15,58 +15,50 @@ */ package android.net.cts; -import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.Socket; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; -import android.os.ParcelFileDescriptor; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; import dalvik.annotation.ToBeFixed; @TestTargetClass(LocalServerSocket.class) public class LocalServerSocketTest extends AndroidTestCase { + @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "test LocalServerSocket", method = "accept", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "test LocalServerSocket", method = "close", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "test LocalServerSocket", method = "getFileDescriptor", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "test LocalServerSocket", method = "getLocalSocketAddress", args = {} ), @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test LocalServerSocket", + level = TestLevel.NOT_FEASIBLE, method = "LocalServerSocket", args = {java.io.FileDescriptor.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "test LocalServerSocket", method = "LocalServerSocket", args = {java.lang.String.class} ) @@ -77,15 +69,6 @@ public class LocalServerSocketTest extends AndroidTestCase { LocalServerSocket localServerSocket = new LocalServerSocket(LocalSocketTest.mSockAddr); assertNotNull(localServerSocket.getLocalSocketAddress()); commonFunctions(localServerSocket); - - Socket socket = new Socket("www.google.com", 80); - ParcelFileDescriptor parcelFD = ParcelFileDescriptor.fromSocket(socket); - FileDescriptor fd = parcelFD.getFileDescriptor(); - - // enable the following after bug 1520987 fixed -// localServerSocket = new LocalServerSocket(fd); -// assertNull(localServerSocket.getLocalSocketAddress()); -// commonFunctions(localServerSocket); } public void commonFunctions(LocalServerSocket localServerSocket) throws IOException { diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java index 75232c4fff..e3141d57e5 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java @@ -27,11 +27,6 @@ import dalvik.annotation.TestTargetClass; @TestTargetClass(LocalSocketAddress.class) public class LocalSocketAddressTest extends AndroidTestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, @@ -65,17 +60,17 @@ public class LocalSocketAddressTest extends AndroidTestCase { assertEquals(Namespace.ABSTRACT, localSocketAddress.getNamespace()); // specify the namespace - LocalSocketAddress localSocketAddress2 = + LocalSocketAddress localSocketAddress2 = new LocalSocketAddress("name2", Namespace.ABSTRACT); assertEquals("name2", localSocketAddress2.getName()); assertEquals(Namespace.ABSTRACT, localSocketAddress2.getNamespace()); - LocalSocketAddress localSocketAddress3 = + LocalSocketAddress localSocketAddress3 = new LocalSocketAddress("name3", Namespace.FILESYSTEM); assertEquals("name3", localSocketAddress3.getName()); assertEquals(Namespace.FILESYSTEM, localSocketAddress3.getNamespace()); - LocalSocketAddress localSocketAddress4 = + LocalSocketAddress localSocketAddress4 = new LocalSocketAddress("name4", Namespace.RESERVED); assertEquals("name4", localSocketAddress4.getName()); assertEquals(Namespace.RESERVED, localSocketAddress4.getNamespace()); diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java index 5d29c81895..fc9de5b14c 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -18,19 +18,13 @@ package android.net.cts; import android.net.LocalSocketAddress.Namespace; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; @TestTargetClass(Namespace.class) public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - @TestTargetNew( level = TestLevel.COMPLETE, notes = "Test valueOf(String name).", diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 2c3d73c75a..d2de4e4be2 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -51,16 +51,31 @@ public class NetworkInfoTest extends AndroidTestCase { method = "isFailover", args = {} ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isRoaming", + args = {} + ), @TestTargetNew( level = TestLevel.COMPLETE, method = "getType", args = {} ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getSubtype", + args = {} + ), @TestTargetNew( level = TestLevel.COMPLETE, method = "getTypeName", args = {} ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getSubtypeName", + args = {} + ), @TestTargetNew( level = TestLevel.COMPLETE, method = "setIsAvailable", @@ -116,25 +131,24 @@ public class NetworkInfoTest extends AndroidTestCase { assertEquals(TYPE_MOBILE, ni[TYPE_MOBILE].getType()); assertEquals(TYPE_WIFI, ni[TYPE_WIFI].getType()); + // don't know the return value + ni[TYPE_MOBILE].getSubtype(); + ni[TYPE_WIFI].getSubtype(); + assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); + // don't know the return value + ni[TYPE_MOBILE].getSubtypeName(); + ni[TYPE_WIFI].getSubtypeName(); + if(ni[TYPE_MOBILE].isConnectedOrConnecting()) { assertTrue(ni[TYPE_MOBILE].isAvailable()); assertTrue(ni[TYPE_MOBILE].isConnected()); assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); - assertNotNull(ni[TYPE_MOBILE].getReason()); - assertNotNull(ni[TYPE_MOBILE].getExtraInfo()); - } else { - assertFalse(ni[TYPE_MOBILE].isAvailable()); - assertFalse(ni[TYPE_MOBILE].isConnected()); - - // mobile state is undefined - - assertEquals(DetailedState.IDLE, ni[TYPE_MOBILE].getDetailedState()); - assertNull(ni[TYPE_MOBILE].getReason()); - assertNull(ni[TYPE_MOBILE].getExtraInfo()); + ni[TYPE_MOBILE].getReason(); + ni[TYPE_MOBILE].getExtraInfo(); } if(ni[TYPE_WIFI].isConnectedOrConnecting()) { @@ -142,19 +156,13 @@ public class NetworkInfoTest extends AndroidTestCase { assertTrue(ni[TYPE_WIFI].isConnected()); assertEquals(State.CONNECTED, ni[TYPE_WIFI].getState()); assertEquals(DetailedState.CONNECTED, ni[TYPE_WIFI].getDetailedState()); - assertNotNull(ni[TYPE_WIFI].getReason()); - assertNotNull(ni[TYPE_WIFI].getExtraInfo()); - } else { - assertFalse(ni[TYPE_WIFI].isAvailable()); - assertFalse(ni[TYPE_WIFI].isConnected()); - - // wifi state is undefined - - assertEquals(DetailedState.IDLE, ni[TYPE_WIFI].getDetailedState()); - assertNull(ni[TYPE_WIFI].getReason()); - assertNull(ni[TYPE_WIFI].getExtraInfo()); + ni[TYPE_WIFI].getReason(); + ni[TYPE_WIFI].getExtraInfo(); } + assertFalse(ni[TYPE_MOBILE].isRoaming()); + assertFalse(ni[TYPE_WIFI].isRoaming()); + assertNotNull(ni[TYPE_MOBILE].toString()); assertNotNull(ni[TYPE_WIFI].toString()); } diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 0e05b28119..196e102dee 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -18,19 +18,13 @@ package android.net.cts; import android.net.NetworkInfo.DetailedState; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; @TestTargetClass(DetailedState.class) public class NetworkInfo_DetailedStateTest extends AndroidTestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - @TestTargetNew( level = TestLevel.COMPLETE, notes = "Test valueOf(String name).", @@ -38,23 +32,16 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { args = {java.lang.String.class} ) public void testValueOf() { - assertEquals(DetailedState.AUTHENTICATING, DetailedState - .valueOf("AUTHENTICATING")); - assertEquals(DetailedState.CONNECTED, DetailedState - .valueOf("CONNECTED")); - assertEquals(DetailedState.CONNECTING, DetailedState - .valueOf("CONNECTING")); - assertEquals(DetailedState.DISCONNECTED, DetailedState - .valueOf("DISCONNECTED")); - assertEquals(DetailedState.DISCONNECTING, DetailedState - .valueOf("DISCONNECTING")); + assertEquals(DetailedState.AUTHENTICATING, DetailedState.valueOf("AUTHENTICATING")); + assertEquals(DetailedState.CONNECTED, DetailedState.valueOf("CONNECTED")); + assertEquals(DetailedState.CONNECTING, DetailedState.valueOf("CONNECTING")); + assertEquals(DetailedState.DISCONNECTED, DetailedState.valueOf("DISCONNECTED")); + assertEquals(DetailedState.DISCONNECTING, DetailedState.valueOf("DISCONNECTING")); assertEquals(DetailedState.FAILED, DetailedState.valueOf("FAILED")); assertEquals(DetailedState.IDLE, DetailedState.valueOf("IDLE")); - assertEquals(DetailedState.OBTAINING_IPADDR, DetailedState - .valueOf("OBTAINING_IPADDR")); + assertEquals(DetailedState.OBTAINING_IPADDR, DetailedState.valueOf("OBTAINING_IPADDR")); assertEquals(DetailedState.SCANNING, DetailedState.valueOf("SCANNING")); - assertEquals(DetailedState.SUSPENDED, DetailedState - .valueOf("SUSPENDED")); + assertEquals(DetailedState.SUSPENDED, DetailedState.valueOf("SUSPENDED")); } @TestTargetNew( diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java index 249df4b588..1a51acd091 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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. @@ -16,21 +16,15 @@ package android.net.cts; +import android.net.NetworkInfo.State; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; -import android.net.NetworkInfo.State; +import dalvik.annotation.TestTargetNew; @TestTargetClass(State.class) public class NetworkInfo_StateTest extends AndroidTestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - @TestTargetNew( level = TestLevel.COMPLETE, notes = "Test valueOf(String name).", @@ -62,5 +56,4 @@ public class NetworkInfo_StateTest extends AndroidTestCase { assertEquals(State.DISCONNECTED, expected[4]); assertEquals(State.UNKNOWN, expected[5]); } - } diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java index e9ae95c303..0dd5db1886 100644 --- a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -49,189 +49,168 @@ public class UrlQuerySanitizerTest extends AndroidTestCase { @TestTargets({ @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test constructor(s) of {@link UrlQuerySanitizer}", method = "UrlQuerySanitizer", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test constructor(s) of {@link UrlQuerySanitizer}", method = "UrlQuerySanitizer", args = {String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: parseUrl", method = "parseUrl", args = {String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: parseQuery", method = "parseQuery", args = {String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: parseEntry", method = "parseEntry", args = {String.class, String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getValue", method = "getValue", args = {String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: addSanitizedEntry", method = "addSanitizedEntry", args = {String.class, String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: hasParameter", method = "hasParameter", args = {String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getParameterSet", method = "getParameterSet", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getParameterList", method = "getParameterList", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: setUnregisteredParameterValueSanitizer", method = "setUnregisteredParameterValueSanitizer", args = {ValueSanitizer.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getUnregisteredParameterValueSanitizer", method = "getUnregisteredParameterValueSanitizer", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getAllButNulAndAngleBracketsLegal", method = "getAllButNulAndAngleBracketsLegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getAllButNulLegal", method = "getAllButNulLegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getAllButWhitespaceLegal", method = "getAllButWhitespaceLegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getAllIllegal", method = "getAllIllegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getAmpAndSpaceLegal", method = "getAmpAndSpaceLegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getAmpLegal", method = "getAmpLegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getSpaceLegal", method = "getSpaceLegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getUrlAndSpaceLegal", method = "getUrlAndSpaceLegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getUrlLegal", method = "getUrlLegal", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test mehtod: unescape", method = "unescape", args = {String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test mehtod: isHexDigit", method = "isHexDigit", args = {char.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test mehtod: decodeHexDigit", method = "decodeHexDigit", args = {char.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: setAllowUnregisteredParamaters", method = "setAllowUnregisteredParamaters", args = {boolean.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getAllowUnregisteredParamaters", method = "getAllowUnregisteredParamaters", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: registerParameter", method = "registerParameter", args = {String.class, ValueSanitizer.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: registerParameters", method = "registerParameters", args = {String[].class, ValueSanitizer.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getEffectiveValueSanitizer", method = "getEffectiveValueSanitizer", args = {String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: getValueSanitizer", method = "getValueSanitizer", args = {String.class} ), @TestTargetNew( level = TestLevel.COMPLETE, - notes = "Test method: clear", method = "clear", args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setPreferFirstRepeatedParameter", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPreferFirstRepeatedParameter", + args = {} ) }) public void testUrlQuerySanitizer() { @@ -377,6 +356,30 @@ public class UrlQuerySanitizerTest extends AndroidTestCase { uqs.clear(); assertEquals(0, urlSet.size()); assertEquals(0, urlList.size()); + + uqs.setPreferFirstRepeatedParameter(true); + assertTrue(uqs.getPreferFirstRepeatedParameter()); + uqs.setPreferFirstRepeatedParameter(false); + assertFalse(uqs.getPreferFirstRepeatedParameter()); + + UrlQuerySanitizer uq = new UrlQuerySanitizer(); + uq.setPreferFirstRepeatedParameter(true); + final String PARA_ANSWER = "answer"; + uq.registerParameter(PARA_ANSWER, new MockValueSanitizer()); + uq.parseUrl("http://www.google.com/question?answer=13&answer=42"); + assertEquals("13", uq.getValue(PARA_ANSWER)); + + uq.setPreferFirstRepeatedParameter(false); + uq.parseQuery("http://www.google.com/question?answer=13&answer=42"); + assertEquals("42", uq.getValue(PARA_ANSWER)); + + } + + private static class MockValueSanitizer implements ValueSanitizer{ + + public String sanitize(String value) { + return value; + } } class MockUrlQuerySanitizer extends UrlQuerySanitizer { From bda6b58510265c32453985bc49624786fca56e64 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Thu, 13 Aug 2009 21:23:28 -0700 Subject: [PATCH 0032/1415] More CTS cleanup - Mark currently failing CTS tests as BrokenTests. - Fix race condition in LocationManagerTest - tweak host config to run tests in batch mode - fix genDefaultTestPlan and rename java package so permission2 tests get included properly, BUG 2053939 --- .../src/android/net/cts/SSLCertificateSocketFactoryTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index b81dd37007..6cd5d6f10b 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -24,6 +24,8 @@ import javax.net.SocketFactory; import android.net.SSLCertificateSocketFactory; import android.test.AndroidTestCase; + +import dalvik.annotation.BrokenTest; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; @@ -99,6 +101,7 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { args = {int.class} ) }) + @BrokenTest("flaky") public void testCreateSocket() throws Exception { new SSLCertificateSocketFactory(100); int port = 443; From f4ffdb9732bd8640606fa96569eef09b535ae0be Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Thu, 13 Aug 2009 20:55:28 -0700 Subject: [PATCH 0033/1415] Remove a bunch of unused CTS tests from continuous test build to save space. BUG 2053298 --- tests/cts/net/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index a2bbc9c316..26188afcfc 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -16,7 +16,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_TAGS := optional LOCAL_JAVA_LIBRARIES := android.test.runner From 1505142f7b42e606562eeb51ed1879c70a67d150 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Fri, 28 Aug 2009 12:22:23 -0700 Subject: [PATCH 0034/1415] Change CTS makefiles so apps are built in data not system partition. BUG 2053298 Change-Id: I2c541c03f7c33c69cde7b0567b080710658c8d28 --- tests/cts/net/Android.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 26188afcfc..d23cee81cc 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -16,7 +16,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +# don't include this package in any target LOCAL_MODULE_TAGS := optional +# and when built explicitly put it in the data partition +LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) LOCAL_JAVA_LIBRARIES := android.test.runner From dcccc5488842ec9fe70106d6bff616d04270656b Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Fri, 11 Sep 2009 15:26:23 -0700 Subject: [PATCH 0035/1415] Change CTS tests to not build against SDK. Most CTS test packages reference test related annotations in dalvik.annotation which are not part of SDK. This was previously allowed due to bug in build build system. For now, temporarily change CTS makefiles so they are not built against SDK. BUG 2114936 --- tests/cts/net/Android.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index d23cee81cc..1fd9ba0c40 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -29,7 +29,8 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_INSTRUMENTATION_FOR := CtsTestStubs -LOCAL_SDK_VERSION := current +# uncomment when dalvik.annotation.Test* are removed or part of SDK +#LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) From 1bf60c89bbe02b33fd6977ec85eae2035e1aad37 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Tue, 3 Nov 2009 15:57:26 -0800 Subject: [PATCH 0036/1415] Fix MailToTest. Changed the toString assertions to be parameter order independent. --- .../net/src/android/net/cts/MailToTest.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/MailToTest.java b/tests/cts/net/src/android/net/cts/MailToTest.java index e64aaf46e0..01ede1aea0 100644 --- a/tests/cts/net/src/android/net/cts/MailToTest.java +++ b/tests/cts/net/src/android/net/cts/MailToTest.java @@ -28,7 +28,7 @@ import dalvik.annotation.TestTargetClass; public class MailToTest extends AndroidTestCase { private static final String MAILTOURI_1 = "mailto:chris@example.com"; private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue"; - private static final String MAILTOURI_3 = + private static final String MAILTOURI_3 = "mailto:infobot@example.com?body=send%20current-issue"; private static final String MAILTOURI_4 = "mailto:infobot@example.com?body=send%20current-" + "issue%0D%0Asend%20index"; @@ -115,8 +115,10 @@ public class MailToTest extends AndroidTestCase { assertEquals("current-issue", mailTo_2.getSubject()); assertNull(mailTo_2.getBody()); assertNull(mailTo_2.getCc()); - assertEquals("mailto:?to=infobot%40example.com&subject=current-issue&", - mailTo_2.toString()); + String stringUrl = mailTo_2.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("subject=current-issue&")); assertTrue(MailTo.isMailTo(MAILTOURI_3)); MailTo mailTo_3 = MailTo.parse(MAILTOURI_3); @@ -126,8 +128,10 @@ public class MailToTest extends AndroidTestCase { assertEquals("send current-issue", mailTo_3.getBody()); assertNull(mailTo_3.getCc()); assertNull(mailTo_3.getSubject()); - assertEquals("mailto:?body=send%20current-issue&to=infobot%40example.com&", - mailTo_3.toString()); + stringUrl = mailTo_3.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("body=send%20current-issue&")); assertTrue(MailTo.isMailTo(MAILTOURI_4)); MailTo mailTo_4 = MailTo.parse(MAILTOURI_4); @@ -137,9 +141,11 @@ public class MailToTest extends AndroidTestCase { assertEquals("send current-issue\r\nsend index", mailTo_4.getBody()); assertNull(mailTo_4.getCc()); assertNull(mailTo_4.getSubject()); - assertEquals( - "mailto:?body=send%20current-issue%0D%0Asend%20index&to=infobot%40example.com&", - mailTo_4.toString()); + stringUrl = mailTo_4.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("body=send%20current-issue%0D%0Asend%20index&")); + assertTrue(MailTo.isMailTo(MAILTOURI_5)); MailTo mailTo_5 = MailTo.parse(MAILTOURI_5); @@ -150,8 +156,11 @@ public class MailToTest extends AndroidTestCase { assertEquals("bob@example.com", mailTo_5.getCc()); assertEquals("hello", mailTo_5.getBody()); assertNull(mailTo_5.getSubject()); - assertEquals("mailto:?cc=bob%40example.com&body=hello&to=joe%40example.com&", - mailTo_5.toString()); + stringUrl = mailTo_5.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("cc=bob%40example.com&")); + assertTrue(stringUrl.contains("body=hello&")); + assertTrue(stringUrl.contains("to=joe%40example.com&")); assertTrue(MailTo.isMailTo(MAILTOURI_6)); MailTo mailTo_6 = MailTo.parse(MAILTOURI_6); @@ -162,7 +171,10 @@ public class MailToTest extends AndroidTestCase { assertEquals("bob@example.com", mailTo_6.getCc()); assertEquals("hello", mailTo_6.getBody()); assertNull(mailTo_6.getSubject()); - assertEquals("mailto:?cc=bob%40example.com&body=hello&to=%2C%20joe%40example.com&", - mailTo_6.toString()); + stringUrl = mailTo_6.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("cc=bob%40example.com&")); + assertTrue(stringUrl.contains("body=hello&")); + assertTrue(stringUrl.contains("to=%2C%20joe%40example.com&")); } } From 7aa0090ef51543318399afa9a9a3d6065ae7cfdd Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Tue, 8 Dec 2009 19:52:35 -0800 Subject: [PATCH 0037/1415] Fix ConnectivityManagerTest testRequestRouteToHost and testGetAllNetworkInfo. Bugs 2138046 and 2138034. Change-Id: I2c3973be9166892caaf2deb07bc15344b897b552 --- .../android/net/cts/ConnectivityManagerTest.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index a8a149f250..edcea9a24e 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -36,6 +36,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 private ConnectivityManager mCm; + // must include both mobile data + wifi + private static final int MIN_NUM_NETWORK_TYPES = 2; @Override protected void setUp() throws Exception { @@ -51,7 +53,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testGetNetworkInfo() { // this test assumes that there are at least two network types. - assertTrue(mCm.getAllNetworkInfo().length >= 2); + assertTrue(mCm.getAllNetworkInfo().length >= MIN_NUM_NETWORK_TYPES); NetworkInfo ni = mCm.getNetworkInfo(1); State state = ni.getState(); assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() @@ -163,12 +165,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { args = {} ) public void testGetAllNetworkInfo() { - NetworkInfo[] ni = mCm.getAllNetworkInfo(); - assertEquals(2, ni.length); - - assertTrue(ni[0].getType() >= 0 && ni[0].getType() <= 1); - assertTrue(ni[1].getType() >= 0 && ni[1].getType() <= 1); + assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); } @TestTargets({ @@ -206,7 +204,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { NetworkInfo[] ni = mCm.getAllNetworkInfo(); for (NetworkInfo n : ni) { - assertTrue(mCm.requestRouteToHost(n.getType(), HOST_ADDRESS)); + // make sure network is up + if (n.isConnected()) { + assertTrue(mCm.requestRouteToHost(n.getType(), HOST_ADDRESS)); + } } assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS)); From 16a5fa3ce2d3585d3f15b316e40262f3fa38f54f Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Mon, 11 Jan 2010 14:33:36 -0800 Subject: [PATCH 0038/1415] empty initial commit From 8c81965feba9036e62bac2c21ba19b902ac2e615 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 12 Jan 2010 15:18:07 -0800 Subject: [PATCH 0039/1415] android-2.1_r1 snapshot --- tests/cts/net/Android.mk | 36 + tests/cts/net/AndroidManifest.xml | 30 + .../net/cts/ConnectivityManagerTest.java | 238 ++++++ .../src/android/net/cts/CredentialsTest.java | 71 ++ .../net/src/android/net/cts/DhcpInfoTest.java | 79 ++ .../net/cts/LocalServerSocketTest.java | 99 +++ .../net/cts/LocalSocketAddressTest.java | 78 ++ .../cts/LocalSocketAddress_NamespaceTest.java | 52 ++ .../src/android/net/cts/LocalSocketTest.java | 342 ++++++++ .../net/src/android/net/cts/MailToTest.java | 180 +++++ .../src/android/net/cts/NetworkInfoTest.java | 169 ++++ .../cts/NetworkInfo_DetailedStateTest.java | 68 ++ .../net/cts/NetworkInfo_StateTest.java | 59 ++ .../net/src/android/net/cts/ProxyTest.java | 91 +++ .../cts/SSLCertificateSocketFactoryTest.java | 144 ++++ .../cts/net/src/android/net/cts/UriTest.java | 727 ++++++++++++++++++ .../src/android/net/cts/Uri_BuilderTest.java | 173 +++++ .../net/cts/UrlQuerySanitizerTest.java | 419 ++++++++++ ...er_IllegalCharacterValueSanitizerTest.java | 48 ++ ...QuerySanitizer_ParameterValuePairTest.java | 43 ++ .../net/http/cts/SslCertificateTest.java | 303 ++++++++ .../http/cts/SslCertificate_DNameTest.java | 83 ++ .../android/net/wifi/cts/ScanResultTest.java | 126 +++ .../net/wifi/cts/SupplicantStateTest.java | 50 ++ .../net/wifi/cts/WifiConfigurationTest.java | 60 ++ .../android/net/wifi/cts/WifiInfoTest.java | 194 +++++ .../android/net/wifi/cts/WifiManagerTest.java | 427 ++++++++++ .../wifi/cts/WifiManager_WifiLockTest.java | 107 +++ 28 files changed, 4496 insertions(+) create mode 100644 tests/cts/net/Android.mk create mode 100644 tests/cts/net/AndroidManifest.xml create mode 100644 tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java create mode 100644 tests/cts/net/src/android/net/cts/CredentialsTest.java create mode 100644 tests/cts/net/src/android/net/cts/DhcpInfoTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalServerSocketTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketTest.java create mode 100644 tests/cts/net/src/android/net/cts/MailToTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfoTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java create mode 100644 tests/cts/net/src/android/net/cts/ProxyTest.java create mode 100644 tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java create mode 100644 tests/cts/net/src/android/net/cts/UriTest.java create mode 100644 tests/cts/net/src/android/net/cts/Uri_BuilderTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_ParameterValuePairTest.java create mode 100644 tests/cts/net/src/android/net/http/cts/SslCertificateTest.java create mode 100644 tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk new file mode 100644 index 0000000000..1fd9ba0c40 --- /dev/null +++ b/tests/cts/net/Android.mk @@ -0,0 +1,36 @@ +# Copyright (C) 2008 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +# don't include this package in any target +LOCAL_MODULE_TAGS := optional +# and when built explicitly put it in the data partition +LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := CtsNetTestCases + +LOCAL_INSTRUMENTATION_FOR := CtsTestStubs + +# uncomment when dalvik.annotation.Test* are removed or part of SDK +#LOCAL_SDK_VERSION := current + +include $(BUILD_PACKAGE) + diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml new file mode 100644 index 0000000000..a1f632effb --- /dev/null +++ b/tests/cts/net/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java new file mode 100644 index 0000000000..edcea9a24e --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2009 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 dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; +import dalvik.annotation.ToBeFixed; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; +import android.test.AndroidTestCase; + +@TestTargetClass(ConnectivityManager.class) +public class ConnectivityManagerTest extends AndroidTestCase { + + public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; + public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; + private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 + private ConnectivityManager mCm; + // must include both mobile data + wifi + private static final int MIN_NUM_NETWORK_TYPES = 2; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getNetworkInfo", + args = {int.class} + ) + public void testGetNetworkInfo() { + + // this test assumes that there are at least two network types. + assertTrue(mCm.getAllNetworkInfo().length >= MIN_NUM_NETWORK_TYPES); + NetworkInfo ni = mCm.getNetworkInfo(1); + State state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + + ni = mCm.getNetworkInfo(0); + state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + + ni = mCm.getNetworkInfo(-1); + assertNull(ni); + + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isNetworkTypeValid", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getAllNetworkInfo", + args = {} + ) + }) + public void testIsNetworkTypeValid() { + + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + + for (NetworkInfo n : ni) { + assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType())); + } + assertFalse(ConnectivityManager.isNetworkTypeValid(-1)); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getNetworkPreference", + args = {} + ), + @TestTargetNew( + level = TestLevel.SUFFICIENT, + method = "setNetworkPreference", + args = {int.class} + ) + }) + public void testAccessNetworkPreference() { + int initialSetting = mCm.getNetworkPreference(); + + // Changing the network preference requires android.permission.WRITE_SECURE_SETTINGS, + // which is only available to signed or system applications. + + // Setting the same preference that is already set is a no-op and does not throw + // a SecurityException. + mCm.setNetworkPreference(initialSetting); + assertEquals(initialSetting, mCm.getNetworkPreference()); + + // find a valid setting that is different from the initial setting + int validSetting = -1; + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + for (NetworkInfo n : ni) { + int type = n.getType(); + if (type != initialSetting) { + validSetting = type; + break; + } + } + if (validSetting >= 0) { + try { + mCm.setNetworkPreference(validSetting); + fail("Trying to change the network preference should throw SecurityException"); + } catch (SecurityException expected) { + // expected + } + } + + // find an invalid setting + int invalidSetting = -1; + for (int i = 0; i < 10; i++) { + if (!ConnectivityManager.isNetworkTypeValid(i)) { + invalidSetting = i; + break; + } + } + if (invalidSetting >= 0) { + // illegal setting should be ignored + mCm.setNetworkPreference(invalidSetting); + assertEquals(initialSetting, mCm.getNetworkPreference()); + } + + // illegal setting should be ignored + mCm.setNetworkPreference(-1); + assertEquals(initialSetting, mCm.getNetworkPreference()); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test getAllNetworkInfo().", + method = "getAllNetworkInfo", + args = {} + ) + public void testGetAllNetworkInfo() { + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "startUsingNetworkFeature", + args = {int.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "stopUsingNetworkFeature", + args = {int.class, java.lang.String.class} + ) + }) + public void testStartUsingNetworkFeature() { + + final String invalidateFeature = "invalidateFeature"; + final String mmsFeature = "enableMMS"; + final int failureCode = -1; + + assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); + + // Should return failure(-1) because MMS is not supported on WIFI. + assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_WIFI, mmsFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI, mmsFeature)); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "requestRouteToHost", + args = {int.class, int.class} + ) + public void testRequestRouteToHost() { + + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + for (NetworkInfo n : ni) { + // make sure network is up + if (n.isConnected()) { + assertTrue(mCm.requestRouteToHost(n.getType(), HOST_ADDRESS)); + } + } + + assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS)); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getActiveNetworkInfo", + args = {} + ) + @ToBeFixed(bug="1695243", explanation="No Javadoc") + public void testGetActiveNetworkInfo() { + NetworkInfo ni = mCm.getActiveNetworkInfo(); + + if (ni != null) { + assertTrue(ni.getType() >= 0); + } + } + + @TestTargetNew( + level = TestLevel.SUFFICIENT, + method = "getBackgroundDataSetting", + args = {} + ) + public void testTest() { + mCm.getBackgroundDataSetting(); + } +} diff --git a/tests/cts/net/src/android/net/cts/CredentialsTest.java b/tests/cts/net/src/android/net/cts/CredentialsTest.java new file mode 100644 index 0000000000..6cf8c2351e --- /dev/null +++ b/tests/cts/net/src/android/net/cts/CredentialsTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 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 android.net.Credentials; +import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(android.net.Credentials.class) +public class CredentialsTest extends AndroidTestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "Credentials", + args = {int.class, int.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getGid", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPid", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getUid", + args = {} + ) + }) + public void testCredentials() { + // new the Credentials instance + // Test with zero inputs + Credentials cred = new Credentials(0, 0, 0); + assertEquals(0, cred.getGid()); + assertEquals(0, cred.getPid()); + assertEquals(0, cred.getUid()); + + // Test with big integer + cred = new Credentials(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + assertEquals(Integer.MAX_VALUE, cred.getGid()); + assertEquals(Integer.MAX_VALUE, cred.getPid()); + assertEquals(Integer.MAX_VALUE, cred.getUid()); + + // Test with big negative integer + cred = new Credentials(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); + assertEquals(Integer.MIN_VALUE, cred.getGid()); + assertEquals(Integer.MIN_VALUE, cred.getPid()); + assertEquals(Integer.MIN_VALUE, cred.getUid()); + } +} diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java new file mode 100644 index 0000000000..97bd27a970 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009 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 android.net.DhcpInfo; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; + +@TestTargetClass(DhcpInfo.class) +public class DhcpInfoTest extends AndroidTestCase { + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test DhcpInfo's constructor.", + method = "DhcpInfo", + args = {} + ) + public void testConstructor() { + new DhcpInfo(); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test toString function.", + method = "toString", + args = {} + ) + public void testToString() { + String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 dns1 0.0.0.0 " + + "dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; + String STR_ADDR1 = "255.255.255.255"; + String STR_ADDR2 = "127.0.0.1"; + String STR_ADDR3 = "192.168.1.1"; + String STR_ADDR4 = "192.168.1.0"; + int leaseTime = 9999; + String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask " + + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server " + + STR_ADDR2 + " lease " + leaseTime + " seconds"; + + DhcpInfo dhcpInfo = new DhcpInfo(); + + // Test default string. + assertEquals(expectedDefault, dhcpInfo.toString()); + + dhcpInfo.ipAddress = ipToInteger(STR_ADDR1); + dhcpInfo.gateway = ipToInteger(STR_ADDR2); + dhcpInfo.netmask = ipToInteger(STR_ADDR3); + dhcpInfo.dns1 = ipToInteger(STR_ADDR4); + dhcpInfo.dns2 = ipToInteger(STR_ADDR4); + dhcpInfo.serverAddress = ipToInteger(STR_ADDR2); + dhcpInfo.leaseDuration = leaseTime; + + // Test with new values + assertEquals(expected, dhcpInfo.toString()); + } + + private int ipToInteger(String ipString) { + String ipSegs[] = ipString.split("[.]"); + int tmp = Integer.parseInt(ipSegs[3]) << 24 | Integer.parseInt(ipSegs[2]) << 16 | + Integer.parseInt(ipSegs[1]) << 8 | Integer.parseInt(ipSegs[0]); + return tmp; + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java new file mode 100644 index 0000000000..21c7d5e299 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2009 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 java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import android.net.LocalServerSocket; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; +import dalvik.annotation.ToBeFixed; + +@TestTargetClass(LocalServerSocket.class) +public class LocalServerSocketTest extends AndroidTestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "accept", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "close", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getFileDescriptor", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getLocalSocketAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.NOT_FEASIBLE, + method = "LocalServerSocket", + args = {java.io.FileDescriptor.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "LocalServerSocket", + args = {java.lang.String.class} + ) + }) + @ToBeFixed(bug = "1520987", explanation = "Cannot find a proper FileDescriptor for " + + "android.net.LocalServerSocket constructor") + public void testLocalServerSocket() throws IOException { + LocalServerSocket localServerSocket = new LocalServerSocket(LocalSocketTest.mSockAddr); + assertNotNull(localServerSocket.getLocalSocketAddress()); + commonFunctions(localServerSocket); + } + + public void commonFunctions(LocalServerSocket localServerSocket) throws IOException { + // create client socket + LocalSocket clientSocket = new LocalSocket(); + + // establish connection between client and server + clientSocket.connect(new LocalSocketAddress(LocalSocketTest.mSockAddr)); + LocalSocket serverSocket = localServerSocket.accept(); + + // send data from client to server + OutputStream clientOutStream = clientSocket.getOutputStream(); + clientOutStream.write(12); + InputStream serverInStream = serverSocket.getInputStream(); + assertEquals(12, serverInStream.read()); + + // send data from server to client + OutputStream serverOutStream = serverSocket.getOutputStream(); + serverOutStream.write(3); + InputStream clientInStream = clientSocket.getInputStream(); + assertEquals(3, clientInStream.read()); + + // close server socket + assertNotNull(localServerSocket.getFileDescriptor()); + localServerSocket.close(); + assertNull(localServerSocket.getFileDescriptor()); + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java new file mode 100644 index 0000000000..e3141d57e5 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2008 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 android.net.LocalSocketAddress; +import android.net.LocalSocketAddress.Namespace; +import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(LocalSocketAddress.class) +public class LocalSocketAddressTest extends AndroidTestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test LocalSocketAddress", + method = "LocalSocketAddress", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test LocalSocketAddress", + method = "LocalSocketAddress", + args = {java.lang.String.class, android.net.LocalSocketAddress.Namespace.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test LocalSocketAddress", + method = "getName", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test LocalSocketAddress", + method = "getNamespace", + args = {} + ) + }) + public void testNewLocalSocketAddressWithDefaultNamespace() { + // default namespace + LocalSocketAddress localSocketAddress = new LocalSocketAddress("name"); + assertEquals("name", localSocketAddress.getName()); + assertEquals(Namespace.ABSTRACT, localSocketAddress.getNamespace()); + + // specify the namespace + LocalSocketAddress localSocketAddress2 = + new LocalSocketAddress("name2", Namespace.ABSTRACT); + assertEquals("name2", localSocketAddress2.getName()); + assertEquals(Namespace.ABSTRACT, localSocketAddress2.getNamespace()); + + LocalSocketAddress localSocketAddress3 = + new LocalSocketAddress("name3", Namespace.FILESYSTEM); + assertEquals("name3", localSocketAddress3.getName()); + assertEquals(Namespace.FILESYSTEM, localSocketAddress3.getNamespace()); + + LocalSocketAddress localSocketAddress4 = + new LocalSocketAddress("name4", Namespace.RESERVED); + assertEquals("name4", localSocketAddress4.getName()); + assertEquals(Namespace.RESERVED, localSocketAddress4.getNamespace()); + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java new file mode 100644 index 0000000000..fc9de5b14c --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 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 android.net.LocalSocketAddress.Namespace; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; + +@TestTargetClass(Namespace.class) +public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) + public void testValueOf() { + assertEquals(Namespace.ABSTRACT, Namespace.valueOf("ABSTRACT")); + assertEquals(Namespace.RESERVED, Namespace.valueOf("RESERVED")); + assertEquals(Namespace.FILESYSTEM, Namespace.valueOf("FILESYSTEM")); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) + public void testValues() { + Namespace[] expected = Namespace.values(); + assertEquals(Namespace.ABSTRACT, expected[0]); + assertEquals(Namespace.RESERVED, expected[1]); + assertEquals(Namespace.FILESYSTEM, expected[2]); + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java new file mode 100644 index 0000000000..8e3cd6714b --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2008 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 java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import android.net.Credentials; +import android.net.LocalServerSocket; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.test.AndroidTestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(LocalSocket.class) +public class LocalSocketTest extends AndroidTestCase{ + public final static String mSockAddr = "com.android.net.LocalSocketTest"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "LocalSocket", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "close", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "connect", + args = {android.net.LocalSocketAddress.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "getAncillaryFileDescriptors", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "getFileDescriptor", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "getInputStream", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "getOutputStream", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "getPeerCredentials", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "isConnected", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "setFileDescriptorsForSend", + args = {java.io.FileDescriptor[].class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "shutdownInput", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test core functions of LocalSocket", + method = "shutdownOutput", + args = {} + ) + }) + public void testLocalConnections() throws IOException{ + // create client and server socket + LocalServerSocket localServerSocket = new LocalServerSocket(mSockAddr); + LocalSocket clientSocket = new LocalSocket(); + + // establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(mSockAddr); + assertFalse(clientSocket.isConnected()); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + LocalSocket serverSocket = localServerSocket.accept(); + + Credentials credent = clientSocket.getPeerCredentials(); + assertTrue(0 != credent.getPid()); + + // send data from client to server + OutputStream clientOutStream = clientSocket.getOutputStream(); + clientOutStream.write(12); + InputStream serverInStream = serverSocket.getInputStream(); + assertEquals(12, serverInStream.read()); + + //send data from server to client + OutputStream serverOutStream = serverSocket.getOutputStream(); + serverOutStream.write(3); + InputStream clientInStream = clientSocket.getInputStream(); + assertEquals(3, clientInStream.read()); + + // Test sending and receiving file descriptors + clientSocket.setFileDescriptorsForSend(new FileDescriptor[]{FileDescriptor.in}); + clientOutStream.write(32); + assertEquals(32, serverInStream.read()); + + FileDescriptor[] out = serverSocket.getAncillaryFileDescriptors(); + assertEquals(1, out.length); + FileDescriptor fd = clientSocket.getFileDescriptor(); + assertTrue(fd.valid()); + + //shutdown input stream of client + clientSocket.shutdownInput(); + assertEquals(-1, clientInStream.read()); + + //shutdown output stream of client + clientSocket.shutdownOutput(); + try { + clientOutStream.write(10); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //shutdown input stream of server + serverSocket.shutdownInput(); + assertEquals(-1, serverInStream.read()); + + //shutdown output stream of server + serverSocket.shutdownOutput(); + try { + serverOutStream.write(10); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //close client socket + clientSocket.close(); + try { + clientInStream.read(); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //close server socket + serverSocket.close(); + try { + serverInStream.read(); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "bind", + args = {android.net.LocalSocketAddress.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "connect", + args = {android.net.LocalSocketAddress.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "getLocalSocketAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "getReceiveBufferSize", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "getRemoteSocketAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "getSendBufferSize", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "getSoTimeout", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "isBound", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "isClosed", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "isInputShutdown", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "isOutputShutdown", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "setReceiveBufferSize", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "setSendBufferSize", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "setSoTimeout", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "test secondary functions of LocalSocket", + method = "toString", + args = {} + ) + }) + public void testAccessors() throws IOException{ + LocalSocket socket = new LocalSocket(); + LocalSocketAddress addr = new LocalSocketAddress("secondary"); + + assertFalse(socket.isBound()); + socket.bind(addr); + assertTrue(socket.isBound()); + assertEquals(addr, socket.getLocalSocketAddress()); + + String str = socket.toString(); + assertTrue(str.contains("impl:android.net.LocalSocketImpl")); + + socket.setReceiveBufferSize(1999); + assertEquals(1999 << 1, socket.getReceiveBufferSize()); + + socket.setSendBufferSize(1998); + assertEquals(1998 << 1, socket.getSendBufferSize()); + + // Timeout is not support at present, so set is ignored + socket.setSoTimeout(1996); + assertEquals(0, socket.getSoTimeout()); + + try { + socket.getRemoteSocketAddress(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isClosed(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isInputShutdown(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isOutputShutdown(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.connect(addr, 2005); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + } +} diff --git a/tests/cts/net/src/android/net/cts/MailToTest.java b/tests/cts/net/src/android/net/cts/MailToTest.java new file mode 100644 index 0000000000..01ede1aea0 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/MailToTest.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2008 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 android.net.MailTo; +import android.test.AndroidTestCase; +import android.util.Log; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(MailTo.class) +public class MailToTest extends AndroidTestCase { + private static final String MAILTOURI_1 = "mailto:chris@example.com"; + private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue"; + private static final String MAILTOURI_3 = + "mailto:infobot@example.com?body=send%20current-issue"; + private static final String MAILTOURI_4 = "mailto:infobot@example.com?body=send%20current-" + + "issue%0D%0Asend%20index"; + private static final String MAILTOURI_5 = "mailto:joe@example.com?" + + "cc=bob@example.com&body=hello"; + private static final String MAILTOURI_6 = "mailto:?to=joe@example.com&" + + "cc=bob@example.com&body=hello"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test parse mailto URI.", + method = "parse", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test parse mailto URI.", + method = "isMailTo", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test parse mailto URI.", + method = "getTo", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test parse mailto URI.", + method = "getSubject", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test parse mailto URI.", + method = "getBody", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test parse mailto URI.", + method = "getCc", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test parse mailto URI.", + method = "toString", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test parse mailto URI.", + method = "getHeaders", + args = {} + ) + }) + public void testParseMailToURI() { + assertFalse(MailTo.isMailTo(null)); + assertFalse(MailTo.isMailTo("")); + assertFalse(MailTo.isMailTo("http://www.google.com")); + + assertTrue(MailTo.isMailTo(MAILTOURI_1)); + MailTo mailTo_1 = MailTo.parse(MAILTOURI_1); + Log.d("Trace", mailTo_1.toString()); + assertEquals("chris@example.com", mailTo_1.getTo()); + assertEquals(1, mailTo_1.getHeaders().size()); + assertNull(mailTo_1.getBody()); + assertNull(mailTo_1.getCc()); + assertNull(mailTo_1.getSubject()); + assertEquals("mailto:?to=chris%40example.com&", mailTo_1.toString()); + + assertTrue(MailTo.isMailTo(MAILTOURI_2)); + MailTo mailTo_2 = MailTo.parse(MAILTOURI_2); + Log.d("Trace", mailTo_2.toString()); + assertEquals(2, mailTo_2.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_2.getTo()); + assertEquals("current-issue", mailTo_2.getSubject()); + assertNull(mailTo_2.getBody()); + assertNull(mailTo_2.getCc()); + String stringUrl = mailTo_2.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("subject=current-issue&")); + + assertTrue(MailTo.isMailTo(MAILTOURI_3)); + MailTo mailTo_3 = MailTo.parse(MAILTOURI_3); + Log.d("Trace", mailTo_3.toString()); + assertEquals(2, mailTo_3.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_3.getTo()); + assertEquals("send current-issue", mailTo_3.getBody()); + assertNull(mailTo_3.getCc()); + assertNull(mailTo_3.getSubject()); + stringUrl = mailTo_3.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("body=send%20current-issue&")); + + assertTrue(MailTo.isMailTo(MAILTOURI_4)); + MailTo mailTo_4 = MailTo.parse(MAILTOURI_4); + Log.d("Trace", mailTo_4.toString() + " " + mailTo_4.getBody()); + assertEquals(2, mailTo_4.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_4.getTo()); + assertEquals("send current-issue\r\nsend index", mailTo_4.getBody()); + assertNull(mailTo_4.getCc()); + assertNull(mailTo_4.getSubject()); + stringUrl = mailTo_4.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("body=send%20current-issue%0D%0Asend%20index&")); + + + assertTrue(MailTo.isMailTo(MAILTOURI_5)); + MailTo mailTo_5 = MailTo.parse(MAILTOURI_5); + Log.d("Trace", mailTo_5.toString() + mailTo_5.getHeaders().toString() + + mailTo_5.getHeaders().size()); + assertEquals(3, mailTo_5.getHeaders().size()); + assertEquals("joe@example.com", mailTo_5.getTo()); + assertEquals("bob@example.com", mailTo_5.getCc()); + assertEquals("hello", mailTo_5.getBody()); + assertNull(mailTo_5.getSubject()); + stringUrl = mailTo_5.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("cc=bob%40example.com&")); + assertTrue(stringUrl.contains("body=hello&")); + assertTrue(stringUrl.contains("to=joe%40example.com&")); + + assertTrue(MailTo.isMailTo(MAILTOURI_6)); + MailTo mailTo_6 = MailTo.parse(MAILTOURI_6); + Log.d("Trace", mailTo_6.toString() + mailTo_6.getHeaders().toString() + + mailTo_6.getHeaders().size()); + assertEquals(3, mailTo_6.getHeaders().size()); + assertEquals(", joe@example.com", mailTo_6.getTo()); + assertEquals("bob@example.com", mailTo_6.getCc()); + assertEquals("hello", mailTo_6.getBody()); + assertNull(mailTo_6.getSubject()); + stringUrl = mailTo_6.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("cc=bob%40example.com&")); + assertTrue(stringUrl.contains("body=hello&")); + assertTrue(stringUrl.contains("to=%2C%20joe%40example.com&")); + } +} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java new file mode 100644 index 0000000000..d2de4e4be2 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2009 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 android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(NetworkInfo.class) +public class NetworkInfoTest extends AndroidTestCase { + + public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; + public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; + public static final String MOBILE_TYPE_NAME = "MOBILE"; + public static final String WIFI_TYPE_NAME = "WIFI"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isConnectedOrConnecting", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setFailover", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isFailover", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isRoaming", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getType", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getSubtype", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getTypeName", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getSubtypeName", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setIsAvailable", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isAvailable", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isConnected", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDetailedState", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getState", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getReason", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getExtraInfo", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "toString", + args = {} + ) + }) + public void testAccessNetworkInfoProperties() { + ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( + Context.CONNECTIVITY_SERVICE); + + NetworkInfo[] ni = cm.getAllNetworkInfo(); + assertTrue(ni.length >= 2); + + assertFalse(ni[TYPE_MOBILE].isFailover()); + assertFalse(ni[TYPE_WIFI].isFailover()); + + // test environment:connect as TYPE_MOBILE, and connect to internet. + assertEquals(TYPE_MOBILE, ni[TYPE_MOBILE].getType()); + assertEquals(TYPE_WIFI, ni[TYPE_WIFI].getType()); + + // don't know the return value + ni[TYPE_MOBILE].getSubtype(); + ni[TYPE_WIFI].getSubtype(); + + assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); + assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); + + // don't know the return value + ni[TYPE_MOBILE].getSubtypeName(); + ni[TYPE_WIFI].getSubtypeName(); + + if(ni[TYPE_MOBILE].isConnectedOrConnecting()) { + assertTrue(ni[TYPE_MOBILE].isAvailable()); + assertTrue(ni[TYPE_MOBILE].isConnected()); + assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); + assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); + ni[TYPE_MOBILE].getReason(); + ni[TYPE_MOBILE].getExtraInfo(); + } + + if(ni[TYPE_WIFI].isConnectedOrConnecting()) { + assertTrue(ni[TYPE_WIFI].isAvailable()); + assertTrue(ni[TYPE_WIFI].isConnected()); + assertEquals(State.CONNECTED, ni[TYPE_WIFI].getState()); + assertEquals(DetailedState.CONNECTED, ni[TYPE_WIFI].getDetailedState()); + ni[TYPE_WIFI].getReason(); + ni[TYPE_WIFI].getExtraInfo(); + } + + assertFalse(ni[TYPE_MOBILE].isRoaming()); + assertFalse(ni[TYPE_WIFI].isRoaming()); + + assertNotNull(ni[TYPE_MOBILE].toString()); + assertNotNull(ni[TYPE_WIFI].toString()); + } +} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java new file mode 100644 index 0000000000..196e102dee --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 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 android.net.NetworkInfo.DetailedState; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; + +@TestTargetClass(DetailedState.class) +public class NetworkInfo_DetailedStateTest extends AndroidTestCase { + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) + public void testValueOf() { + assertEquals(DetailedState.AUTHENTICATING, DetailedState.valueOf("AUTHENTICATING")); + assertEquals(DetailedState.CONNECTED, DetailedState.valueOf("CONNECTED")); + assertEquals(DetailedState.CONNECTING, DetailedState.valueOf("CONNECTING")); + assertEquals(DetailedState.DISCONNECTED, DetailedState.valueOf("DISCONNECTED")); + assertEquals(DetailedState.DISCONNECTING, DetailedState.valueOf("DISCONNECTING")); + assertEquals(DetailedState.FAILED, DetailedState.valueOf("FAILED")); + assertEquals(DetailedState.IDLE, DetailedState.valueOf("IDLE")); + assertEquals(DetailedState.OBTAINING_IPADDR, DetailedState.valueOf("OBTAINING_IPADDR")); + assertEquals(DetailedState.SCANNING, DetailedState.valueOf("SCANNING")); + assertEquals(DetailedState.SUSPENDED, DetailedState.valueOf("SUSPENDED")); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) + public void testValues() { + DetailedState[] expected = DetailedState.values(); + assertEquals(10, expected.length); + assertEquals(DetailedState.IDLE, expected[0]); + assertEquals(DetailedState.SCANNING, expected[1]); + assertEquals(DetailedState.CONNECTING, expected[2]); + assertEquals(DetailedState.AUTHENTICATING, expected[3]); + assertEquals(DetailedState.OBTAINING_IPADDR, expected[4]); + assertEquals(DetailedState.CONNECTED, expected[5]); + assertEquals(DetailedState.SUSPENDED, expected[6]); + assertEquals(DetailedState.DISCONNECTING, expected[7]); + assertEquals(DetailedState.DISCONNECTED, expected[8]); + assertEquals(DetailedState.FAILED, expected[9]); + } + +} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java new file mode 100644 index 0000000000..1a51acd091 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009 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 android.net.NetworkInfo.State; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; + +@TestTargetClass(State.class) +public class NetworkInfo_StateTest extends AndroidTestCase { + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test valueOf(String name).", + method = "valueOf", + args = {java.lang.String.class} + ) + public void testValueOf() { + assertEquals(State.CONNECTED, State.valueOf("CONNECTED")); + assertEquals(State.CONNECTING, State.valueOf("CONNECTING")); + assertEquals(State.DISCONNECTED, State.valueOf("DISCONNECTED")); + assertEquals(State.DISCONNECTING, State.valueOf("DISCONNECTING")); + assertEquals(State.SUSPENDED, State.valueOf("SUSPENDED")); + assertEquals(State.UNKNOWN, State.valueOf("UNKNOWN")); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test values().", + method = "values", + args = {} + ) + public void testValues() { + State[] expected = State.values(); + assertEquals(6, expected.length); + assertEquals(State.CONNECTING, expected[0]); + assertEquals(State.CONNECTED, expected[1]); + assertEquals(State.SUSPENDED, expected[2]); + assertEquals(State.DISCONNECTING, expected[3]); + assertEquals(State.DISCONNECTED, expected[4]); + assertEquals(State.UNKNOWN, expected[5]); + } +} diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java new file mode 100644 index 0000000000..357935adb0 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009 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 android.content.Context; +import android.net.Proxy; +import android.provider.Settings.Secure; +import android.test.AndroidTestCase; + +import dalvik.annotation.BrokenTest; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(Proxy.class) +public class ProxyTest extends AndroidTestCase { + + private Context mContext; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mContext = getContext(); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "Proxy", + args = {} + ) + public void testConstructor() { + new Proxy(); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefaultPort", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefaultHost", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPort", + args = {Context.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getHost", + args = {Context.class} + ) + }) + @BrokenTest("Cannot write secure settings table") + public void testAccessProperties() { + final int minValidPort = 0; + final int maxValidPort = 65535; + int defaultPort = Proxy.getDefaultPort(); + if(null == Proxy.getDefaultHost()) { + assertEquals(-1, defaultPort); + } else { + assertTrue(defaultPort >= minValidPort && defaultPort <= maxValidPort); + } + + final String host = "proxy.example.com"; + final int port = 2008; + + Secure.putString(mContext.getContentResolver(), Secure.HTTP_PROXY, host + ":" + port); + assertEquals(host, Proxy.getHost(mContext)); + assertEquals(port, Proxy.getPort(mContext)); + } +} diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java new file mode 100644 index 0000000000..6cd5d6f10b --- /dev/null +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2008 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 java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; + +import javax.net.SocketFactory; + +import android.net.SSLCertificateSocketFactory; +import android.test.AndroidTestCase; + +import dalvik.annotation.BrokenTest; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; +import dalvik.annotation.ToBeFixed; + +@TestTargetClass(SSLCertificateSocketFactory.class) +public class SSLCertificateSocketFactoryTest extends AndroidTestCase { + private SSLCertificateSocketFactory mFactory; + private int mTimeout; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTimeout = 1000; + mFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(mTimeout); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getSupportedCipherSuites", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDefault", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getDefaultCipherSuites", + args = {} + ) + }) + @ToBeFixed(bug="1695243", explanation="Android API javadocs are incomplete") + public void testAccessProperties() throws Exception { + mFactory.getSupportedCipherSuites(); + mFactory.getDefaultCipherSuites(); + SocketFactory sf = SSLCertificateSocketFactory.getDefault(mTimeout); + assertNotNull(sf); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {java.net.InetAddress.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {java.net.Socket.class, java.lang.String.class, int.class, boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {java.lang.String.class, int.class} + ), + @TestTargetNew( + level = TestLevel.NOT_FEASIBLE, + method = "createSocket", + args = {java.lang.String.class, int.class, java.net.InetAddress.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {java.net.InetAddress.class, int.class, java.net.InetAddress.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "SSLCertificateSocketFactory", + args = {int.class} + ) + }) + @BrokenTest("flaky") + public void testCreateSocket() throws Exception { + new SSLCertificateSocketFactory(100); + int port = 443; + String host = "www.fortify.net"; + InetAddress inetAddress = null; + inetAddress = InetAddress.getLocalHost(); + try { + mFactory.createSocket(inetAddress, port); + fail("should throw exception!"); + } catch (IOException e) { + // expected + } + + try { + InetAddress inetAddress1 = InetAddress.getLocalHost(); + InetAddress inetAddress2 = InetAddress.getLocalHost(); + mFactory.createSocket(inetAddress1, port, inetAddress2, port); + fail("should throw exception!"); + } catch (IOException e) { + // expected + } + + try { + Socket socket = new Socket(); + mFactory.createSocket(socket, host, port, true); + fail("should throw exception!"); + } catch (IOException e) { + // expected + } + Socket socket = null; + socket = mFactory.createSocket(host, port); + assertNotNull(socket); + assertNotNull(socket.getOutputStream()); + assertNotNull(socket.getInputStream()); + + // it throw exception when calling createSocket(String, int, InetAddress, int) + // The socket level is invalid. + } + +} diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java new file mode 100644 index 0000000000..067ce52372 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -0,0 +1,727 @@ +/* + * Copyright (C) 2008 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 dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import android.content.ContentUris; +import android.net.Uri; +import android.os.Parcel; +import android.test.AndroidTestCase; +import java.io.File; +import java.util.Arrays; + +@TestTargetClass(Uri.class) +public class UriTest extends AndroidTestCase { + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test write to and read frome parcel.", + method = "writeToParcel", + args = {android.os.Parcel.class, android.net.Uri.class} + ) + public void testParcelling() { + parcelAndUnparcel(Uri.parse("foo:bob%20lee")); + parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment")); + parcelAndUnparcel(new Uri.Builder() + .scheme("http") + .authority("crazybob.org") + .path("/rss/") + .encodedQuery("a=b") + .fragment("foo") + .build()); + } + + private void parcelAndUnparcel(Uri u) { + Parcel p = Parcel.obtain(); + Uri.writeToParcel(p, u); + p.setDataPosition(0); + assertEquals(u, Uri.CREATOR.createFromParcel(p)); + + p.setDataPosition(0); + u = u.buildUpon().build(); + Uri.writeToParcel(p, u); + p.setDataPosition(0); + assertEquals(u, Uri.CREATOR.createFromParcel(p)); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test buildUpon", + method = "buildUpon", + args = {} + ) + public void testBuildUpon() { + Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build(); + assertEquals("robert", u.getScheme()); + assertEquals("lee", u.getEncodedSchemeSpecificPart()); + assertEquals("lee", u.getSchemeSpecificPart()); + assertNull(u.getQuery()); + assertNull(u.getPath()); + assertNull(u.getAuthority()); + assertNull(u.getHost()); + + Uri a = Uri.fromParts("foo", "bar", "tee"); + Uri b = a.buildUpon().fragment("new").build(); + assertEquals("new", b.getFragment()); + assertEquals("bar", b.getSchemeSpecificPart()); + assertEquals("foo", b.getScheme()); + a = new Uri.Builder() + .scheme("foo") + .encodedOpaquePart("bar") + .fragment("tee") + .build(); + b = a.buildUpon().fragment("new").build(); + assertEquals("new", b.getFragment()); + assertEquals("bar", b.getSchemeSpecificPart()); + assertEquals("foo", b.getScheme()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getSchemeSpecificPart", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getEncodedSchemeSpecificPart", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getEncodedPath", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getPath", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getEncodedQuery", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getQuery", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getEncodedFragment", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getHost", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getPort", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getUserInfo", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "getEncodedUserInfo", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test string uri.", + method = "parse", + args = {java.lang.String.class} + ) + }) + public void testStringUri() { + assertEquals("bob lee", + Uri.parse("foo:bob%20lee").getSchemeSpecificPart()); + assertEquals("bob%20lee", + Uri.parse("foo:bob%20lee").getEncodedSchemeSpecificPart()); + + assertEquals("/bob%20lee", + Uri.parse("foo:/bob%20lee").getEncodedPath()); + assertNull(Uri.parse("foo:bob%20lee").getPath()); + + assertEquals("bob%20lee", + Uri.parse("foo:?bob%20lee").getEncodedQuery()); + assertNull(Uri.parse("foo:bob%20lee").getEncodedQuery()); + assertNull(Uri.parse("foo:bar#?bob%20lee").getQuery()); + + assertEquals("bob%20lee", + Uri.parse("foo:#bob%20lee").getEncodedFragment()); + + Uri uri = Uri.parse("http://localhost:42"); + assertEquals("localhost", uri.getHost()); + assertEquals(42, uri.getPort()); + + uri = Uri.parse("http://bob@localhost:42"); + assertEquals("bob", uri.getUserInfo()); + assertEquals("localhost", uri.getHost()); + assertEquals(42, uri.getPort()); + + uri = Uri.parse("http://bob%20lee@localhost:42"); + assertEquals("bob lee", uri.getUserInfo()); + assertEquals("bob%20lee", uri.getEncodedUserInfo()); + + uri = Uri.parse("http://localhost"); + assertEquals("localhost", uri.getHost()); + assertEquals(-1, uri.getPort()); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test compareTo", + method = "compareTo", + args = {android.net.Uri.class} + ) + public void testCompareTo() { + Uri a = Uri.parse("foo:a"); + Uri b = Uri.parse("foo:b"); + Uri b2 = Uri.parse("foo:b"); + + assertTrue(a.compareTo(b) < 0); + assertTrue(b.compareTo(a) > 0); + assertEquals(0, b.compareTo(b2)); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test equals and hashCode.", + method = "equals", + args = {java.lang.Object.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test equals and hashCode.", + method = "hashCode", + args = {} + ) + }) + public void testEqualsAndHashCode() { + Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee"); + + Uri b = new Uri.Builder() + .scheme("http") + .authority("crazybob.org") + .path("/test/") + .encodedQuery("foo=bar") + .fragment("tee") + .build(); + + // Try alternate builder methods. + Uri c = new Uri.Builder() + .scheme("http") + .encodedAuthority("crazybob.org") + .encodedPath("/test/") + .encodedQuery("foo=bar") + .encodedFragment("tee") + .build(); + + assertFalse(Uri.EMPTY.equals(null)); + assertEquals(a, b); + assertEquals(b, c); + assertEquals(c, a); + assertEquals(a.hashCode(), b.hashCode()); + assertEquals(b.hashCode(), c.hashCode()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test encode and decode.", + method = "encode", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test encode and decode.", + method = "encode", + args = {java.lang.String.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test encode and decode.", + method = "decode", + args = {java.lang.String.class} + ) + }) + public void testEncodeAndDecode() { + String encoded = Uri.encode("Bob:/", "/"); + assertEquals(-1, encoded.indexOf(':')); + assertTrue(encoded.indexOf('/') > -1); + assertDecode(null); + assertDecode(""); + assertDecode("Bob"); + assertDecode(":Bob"); + assertDecode("::Bob"); + assertDecode("Bob::Lee"); + assertDecode("Bob:Lee"); + assertDecode("Bob::"); + assertDecode("Bob:"); + assertDecode("::Bob::"); + } + + private void assertDecode(String s) { + assertEquals(s, Uri.decode(Uri.encode(s, null))); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test fromFile.", + method = "fromFile", + args = {java.io.File.class} + ) + public void testFromFile() { + File f = new File("/tmp/bob"); + Uri uri = Uri.fromFile(f); + assertEquals("file:///tmp/bob", uri.toString()); + try { + Uri.fromFile(null); + fail("testFile fail"); + } catch (NullPointerException e) {} + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test get query parameters.", + method = "getQueryParameter", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test get query parameters.", + method = "getQueryParameters", + args = {java.lang.String.class} + ) + }) + public void testQueryParameters() { + Uri uri = Uri.parse("content://user"); + assertEquals(null, uri.getQueryParameter("a")); + + uri = uri.buildUpon().appendQueryParameter("a", "b").build(); + assertEquals("b", uri.getQueryParameter("a")); + + uri = uri.buildUpon().appendQueryParameter("a", "b2").build(); + assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a")); + + uri = uri.buildUpon().appendQueryParameter("c", "d").build(); + assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a")); + assertEquals("d", uri.getQueryParameter("c")); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getPathSegments", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getLastPathSegment", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "withAppendedPath", + args = {android.net.Uri.class, java.lang.String.class} + ) + }) + public void testPathOperations() { + Uri uri = Uri.parse("content://user/a/b"); + + assertEquals(2, uri.getPathSegments().size()); + assertEquals("a", uri.getPathSegments().get(0)); + assertEquals("b", uri.getPathSegments().get(1)); + assertEquals("b", uri.getLastPathSegment()); + + Uri first = uri; + uri = uri.buildUpon().appendPath("c").build(); + assertEquals(3, uri.getPathSegments().size()); + assertEquals("c", uri.getPathSegments().get(2)); + assertEquals("c", uri.getLastPathSegment()); + assertEquals("content://user/a/b/c", uri.toString()); + + uri = ContentUris.withAppendedId(uri, 100); + assertEquals(4, uri.getPathSegments().size()); + assertEquals("100", uri.getPathSegments().get(3)); + assertEquals("100", uri.getLastPathSegment()); + assertEquals(100, ContentUris.parseId(uri)); + assertEquals("content://user/a/b/c/100", uri.toString()); + + // Make sure the original URI is still intact. + assertEquals(2, first.getPathSegments().size()); + assertEquals("b", first.getLastPathSegment()); + + try { + first.getPathSegments().get(2); + fail("test path operations"); + } catch (IndexOutOfBoundsException e) {} + + assertEquals(null, Uri.EMPTY.getLastPathSegment()); + + Uri withC = Uri.parse("foo:/a/b/").buildUpon().appendPath("c").build(); + assertEquals("/a/b/c", withC.getPath()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "isAbsolute", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "isOpaque", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "isRelative", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "getHost", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "getPort", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "getScheme", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "getSchemeSpecificPart", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "fromParts", + args = {java.lang.String.class, java.lang.String.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test opaque uri.", + method = "toString", + args = {} + ) + }) + public void testOpaqueUri() { + Uri uri = Uri.parse("mailto:nobody"); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + + uri = Uri.fromParts("mailto", "nobody", null); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + + uri = new Uri.Builder() + .scheme("mailto") + .opaquePart("nobody") + .build(); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + } + + private void testOpaqueUri(Uri uri) { + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getSchemeSpecificPart()); + assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); + + assertNull(uri.getFragment()); + assertTrue(uri.isAbsolute()); + assertTrue(uri.isOpaque()); + assertFalse(uri.isRelative()); + assertFalse(uri.isHierarchical()); + + assertNull(uri.getAuthority()); + assertNull(uri.getEncodedAuthority()); + assertNull(uri.getPath()); + assertNull(uri.getEncodedPath()); + assertNull(uri.getUserInfo()); + assertNull(uri.getEncodedUserInfo()); + assertNull(uri.getQuery()); + assertNull(uri.getEncodedQuery()); + assertNull(uri.getHost()); + assertEquals(-1, uri.getPort()); + + assertTrue(uri.getPathSegments().isEmpty()); + assertNull(uri.getLastPathSegment()); + + assertEquals("mailto:nobody", uri.toString()); + + Uri withFragment = uri.buildUpon().fragment("top").build(); + assertEquals("mailto:nobody#top", withFragment.toString()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getAuthority", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getScheme", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getEncodedAuthority", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getPath", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getEncodedPath", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getQuery", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getEncodedQuery", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getFragment", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getEncodedFragment", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "getSchemeSpecificPart", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "isAbsolute", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "isHierarchical", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "isOpaque", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "isRelative", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test hierarchical uris.", + method = "toString", + args = {} + ) + }) + public void testHierarchicalUris() { + testHierarchical("http", "google.com", "/p1/p2", "query", "fragment"); + testHierarchical("file", null, "/p1/p2", null, null); + testHierarchical("content", "contact", "/p1/p2", null, null); + testHierarchical("http", "google.com", "/p1/p2", null, "fragment"); + testHierarchical("http", "google.com", "", null, "fragment"); + testHierarchical("http", "google.com", "", "query", "fragment"); + testHierarchical("http", "google.com", "", "query", null); + testHierarchical("http", null, "/", "query", null); + } + + private static void testHierarchical(String scheme, String authority, + String path, String query, String fragment) { + StringBuilder sb = new StringBuilder(); + + if (authority != null) { + sb.append("//").append(authority); + } + if (path != null) { + sb.append(path); + } + if (query != null) { + sb.append('?').append(query); + } + + String ssp = sb.toString(); + + if (scheme != null) { + sb.insert(0, scheme + ":"); + } + if (fragment != null) { + sb.append('#').append(fragment); + } + + String uriString = sb.toString(); + + Uri uri = Uri.parse(uriString); + + // Run these twice to test caching. + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + + // Test rebuilt version. + uri = uri.buildUpon().build(); + + // Run these twice to test caching. + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + + // The decoded and encoded versions of the inputs are all the same. + // We'll test the actual encoding decoding separately. + + // Test building with encoded versions. + Uri built = new Uri.Builder() + .scheme(scheme) + .encodedAuthority(authority) + .encodedPath(path) + .encodedQuery(query) + .encodedFragment(fragment) + .build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + + // Test building with decoded versions. + built = new Uri.Builder() + .scheme(scheme) + .authority(authority) + .path(path) + .query(query) + .fragment(fragment) + .build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + + // Rebuild. + built = built.buildUpon().build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + } + + private static void compareHierarchical(String uriString, String ssp, + Uri uri, + String scheme, String authority, String path, String query, + String fragment) { + assertEquals(scheme, uri.getScheme()); + assertEquals(authority, uri.getAuthority()); + assertEquals(authority, uri.getEncodedAuthority()); + assertEquals(path, uri.getPath()); + assertEquals(path, uri.getEncodedPath()); + assertEquals(query, uri.getQuery()); + assertEquals(query, uri.getEncodedQuery()); + assertEquals(fragment, uri.getFragment()); + assertEquals(fragment, uri.getEncodedFragment()); + assertEquals(ssp, uri.getSchemeSpecificPart()); + + if (scheme != null) { + assertTrue(uri.isAbsolute()); + assertFalse(uri.isRelative()); + } else { + assertFalse(uri.isAbsolute()); + assertTrue(uri.isRelative()); + } + + assertFalse(uri.isOpaque()); + assertTrue(uri.isHierarchical()); + assertEquals(uriString, uri.toString()); + } +} diff --git a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java new file mode 100644 index 0000000000..66bdb074b0 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008 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 junit.framework.TestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; +import android.net.Uri.Builder; +import android.net.Uri; + +@TestTargetClass(Uri.Builder.class) +public class Uri_BuilderTest extends TestCase { + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "Uri.Builder", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "build", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "scheme", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "authority", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "path", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "query", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "opaquePart", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "fragment", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "appendEncodedPath", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "appendPath", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "appendQueryParameter", + args = {java.lang.String.class, java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "encodedAuthority", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "encodedFragment", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "encodedPath", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "encodedQuery", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "encodedOpaquePart", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test Builder operations.", + method = "toString", + args = {} + ) + }) + public void testBuilderOperations() { + Uri uri = Uri.parse("http://google.com/p1?query#fragment"); + Builder builder = uri.buildUpon(); + uri = builder.appendPath("p2").build(); + assertEquals("http", uri.getScheme()); + assertEquals("google.com", uri.getAuthority()); + assertEquals("/p1/p2", uri.getPath()); + assertEquals("query", uri.getQuery()); + assertEquals("fragment", uri.getFragment()); + assertEquals(uri.toString(), builder.toString()); + + uri = Uri.parse("mailto:nobody"); + builder = uri.buildUpon(); + uri = builder.build(); + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getSchemeSpecificPart()); + assertEquals(uri.toString(), builder.toString()); + + uri = new Uri.Builder() + .scheme("http") + .encodedAuthority("google.com") + .encodedPath("/p1") + .appendEncodedPath("p2") + .encodedQuery("query") + .appendQueryParameter("query2", null) + .encodedFragment("fragment") + .build(); + assertEquals("http", uri.getScheme()); + assertEquals("google.com", uri.getEncodedAuthority()); + assertEquals("/p1/p2", uri.getEncodedPath()); + assertEquals("query&query2=null", uri.getEncodedQuery()); + assertEquals("fragment", uri.getEncodedFragment()); + + uri = new Uri.Builder() + .scheme("mailto") + .encodedOpaquePart("nobody") + .build(); + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); + } +} diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java new file mode 100644 index 0000000000..0dd5db1886 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2009 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 java.util.List; +import java.util.Set; +import android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.net.UrlQuerySanitizer.ParameterValuePair; +import android.net.UrlQuerySanitizer.ValueSanitizer; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(UrlQuerySanitizer.class) +public class UrlQuerySanitizerTest extends AndroidTestCase { + private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; + + // URL for test. + private static final String TEST_URL = "http://example.com/?name=Joe+User&age=20&height=175"; + + // Default sanitizer's change when "+". + private static final String EXPECTED_UNDERLINE_NAME = "Joe_User"; + + // IllegalCharacterValueSanitizer sanitizer's change when "+". + private static final String EXPECTED_SPACE_NAME = "Joe User"; + private static final String EXPECTED_AGE = "20"; + private static final String EXPECTED_HEIGHT = "175"; + private static final String NAME = "name"; + private static final String AGE = "age"; + private static final String HEIGHT = "height"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "UrlQuerySanitizer", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "UrlQuerySanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "parseUrl", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "parseQuery", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "parseEntry", + args = {String.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getValue", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "addSanitizedEntry", + args = {String.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "hasParameter", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getParameterSet", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getParameterList", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setUnregisteredParameterValueSanitizer", + args = {ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getUnregisteredParameterValueSanitizer", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getAllButNulAndAngleBracketsLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getAllButNulLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getAllButWhitespaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getAllIllegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getAmpAndSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getAmpLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getUrlAndSpaceLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getUrlLegal", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "unescape", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isHexDigit", + args = {char.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "decodeHexDigit", + args = {char.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setAllowUnregisteredParamaters", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getAllowUnregisteredParamaters", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "registerParameter", + args = {String.class, ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "registerParameters", + args = {String[].class, ValueSanitizer.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getEffectiveValueSanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getValueSanitizer", + args = {String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "clear", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setPreferFirstRepeatedParameter", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPreferFirstRepeatedParameter", + args = {} + ) + }) + public void testUrlQuerySanitizer() { + MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer(); + assertFalse(uqs.getAllowUnregisteredParamaters()); + + final String query = "book=thinking in java&price=108"; + final String book = "book"; + final String bookName = "thinking in java"; + final String price = "price"; + final String bookPrice = "108"; + final String notExistPar = "notExistParameter"; + uqs.registerParameters(new String[]{book, price}, UrlQuerySanitizer.getSpaceLegal()); + uqs.parseQuery(query); + assertTrue(uqs.hasParameter(book)); + assertTrue(uqs.hasParameter(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertEquals(bookName, uqs.getValue(book)); + assertEquals(bookPrice, uqs.getValue(price)); + assertNull(uqs.getValue(notExistPar)); + uqs.clear(); + assertFalse(uqs.hasParameter(book)); + assertFalse(uqs.hasParameter(price)); + + uqs.parseEntry(book, bookName); + assertTrue(uqs.hasParameter(book)); + assertEquals(bookName, uqs.getValue(book)); + uqs.parseEntry(price, bookPrice); + assertTrue(uqs.hasParameter(price)); + assertEquals(bookPrice, uqs.getValue(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertNull(uqs.getValue(notExistPar)); + + uqs = new MockUrlQuerySanitizer(TEST_URL); + assertTrue(uqs.getAllowUnregisteredParamaters()); + + assertTrue(uqs.hasParameter(NAME)); + assertTrue(uqs.hasParameter(AGE)); + assertTrue(uqs.hasParameter(HEIGHT)); + assertFalse(uqs.hasParameter(notExistPar)); + + assertEquals(EXPECTED_UNDERLINE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertEquals(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + assertNull(uqs.getValue(notExistPar)); + + final int ContainerLen = 3; + Set urlSet = uqs.getParameterSet(); + assertEquals(ContainerLen, urlSet.size()); + assertTrue(urlSet.contains(NAME)); + assertTrue(urlSet.contains(AGE)); + assertTrue(urlSet.contains(HEIGHT)); + assertFalse(urlSet.contains(notExistPar)); + + List urlList = uqs.getParameterList(); + assertEquals(ContainerLen, urlList.size()); + ParameterValuePair pvp = urlList.get(0); + assertEquals(NAME, pvp.mParameter); + assertEquals(EXPECTED_UNDERLINE_NAME, pvp.mValue); + pvp = urlList.get(1); + assertEquals(AGE, pvp.mParameter); + assertEquals(EXPECTED_AGE, pvp.mValue); + pvp = urlList.get(2); + assertEquals(HEIGHT, pvp.mParameter); + assertEquals(EXPECTED_HEIGHT, pvp.mValue); + + assertFalse(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT + 1); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 1, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.setPreferFirstRepeatedParameter(true); + assertTrue(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 2, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.registerParameter(NAME, null); + assertNull(uqs.getValueSanitizer(NAME)); + assertNotNull(uqs.getEffectiveValueSanitizer(NAME)); + + uqs.setAllowUnregisteredParamaters(false); + assertFalse(uqs.getAllowUnregisteredParamaters()); + uqs.registerParameter(NAME, null); + assertNull(uqs.getEffectiveValueSanitizer(NAME)); + + ValueSanitizer vs = new IllegalCharacterValueSanitizer(ALL_OK); + uqs.registerParameter(NAME, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertNotSame(EXPECTED_AGE, uqs.getValue(AGE)); + + String[] register = {NAME, AGE}; + uqs.registerParameters(register, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertNotSame(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + + uqs.setUnregisteredParameterValueSanitizer(vs); + assertEquals(vs, uqs.getUnregisteredParameterValueSanitizer()); + + vs = UrlQuerySanitizer.getAllIllegal(); + assertEquals("Joe_User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButNulLegal(); + assertEquals("Joe User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButWhitespaceLegal(); + assertEquals("Joe_User", vs.sanitize("Joe User")); + vs = UrlQuerySanitizer.getAmpAndSpaceLegal(); + assertEquals("Joe User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getAmpLegal(); + assertEquals("Joe_User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getSpaceLegal(); + assertEquals("Joe User ", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getUrlAndSpaceLegal(); + assertEquals("Joe User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + vs = UrlQuerySanitizer.getUrlLegal(); + assertEquals("Joe_User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + + String escape = "Joe"; + assertEquals(escape, uqs.unescape(escape)); + String expectedPlus = "Joe User"; + String expectedPercentSignHex = "title=" + Character.toString((char)181); + String initialPlus = "Joe+User"; + String initialPercentSign = "title=%B5"; + assertEquals(expectedPlus, uqs.unescape(initialPlus)); + assertEquals(expectedPercentSignHex, uqs.unescape(initialPercentSign)); + + assertTrue(uqs.decodeHexDigit('0') >= 0); + assertTrue(uqs.decodeHexDigit('b') >= 0); + assertTrue(uqs.decodeHexDigit('F') >= 0); + assertTrue(uqs.decodeHexDigit('$') < 0); + + assertTrue(uqs.isHexDigit('0')); + assertTrue(uqs.isHexDigit('b')); + assertTrue(uqs.isHexDigit('F')); + assertFalse(uqs.isHexDigit('$')); + + uqs.clear(); + assertEquals(0, urlSet.size()); + assertEquals(0, urlList.size()); + + uqs.setPreferFirstRepeatedParameter(true); + assertTrue(uqs.getPreferFirstRepeatedParameter()); + uqs.setPreferFirstRepeatedParameter(false); + assertFalse(uqs.getPreferFirstRepeatedParameter()); + + UrlQuerySanitizer uq = new UrlQuerySanitizer(); + uq.setPreferFirstRepeatedParameter(true); + final String PARA_ANSWER = "answer"; + uq.registerParameter(PARA_ANSWER, new MockValueSanitizer()); + uq.parseUrl("http://www.google.com/question?answer=13&answer=42"); + assertEquals("13", uq.getValue(PARA_ANSWER)); + + uq.setPreferFirstRepeatedParameter(false); + uq.parseQuery("http://www.google.com/question?answer=13&answer=42"); + assertEquals("42", uq.getValue(PARA_ANSWER)); + + } + + private static class MockValueSanitizer implements ValueSanitizer{ + + public String sanitize(String value) { + return value; + } + } + + class MockUrlQuerySanitizer extends UrlQuerySanitizer { + public MockUrlQuerySanitizer() { + super(); + } + + public MockUrlQuerySanitizer(String url) { + super(url); + } + + @Override + protected void addSanitizedEntry(String parameter, String value) { + super.addSanitizedEntry(parameter, value); + } + + @Override + protected void clear() { + super.clear(); + } + + @Override + protected int decodeHexDigit(char c) { + return super.decodeHexDigit(c); + } + + @Override + protected boolean isHexDigit(char c) { + return super.isHexDigit(c); + } + + @Override + protected void parseEntry(String parameter, String value) { + super.parseEntry(parameter, value); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java new file mode 100644 index 0000000000..f85a5347e0 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 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 android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(UrlQuerySanitizer.IllegalCharacterValueSanitizer.class) +public class UrlQuerySanitizer_IllegalCharacterValueSanitizerTest extends AndroidTestCase { + static final int SPACE_OK = IllegalCharacterValueSanitizer.SPACE_OK; + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test constructor(s) of {@link IllegalCharacterValueSanitizer}", + method = "IllegalCharacterValueSanitizer", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test method: sanitize", + method = "sanitize", + args = {String.class} + ) + }) + public void testSanitize() { + IllegalCharacterValueSanitizer sanitizer = new IllegalCharacterValueSanitizer(SPACE_OK); + assertEquals("Joe User", sanitizer.sanitize("Joe getCriticalExtensionOIDs() { + return null; + } + + public byte[] getExtensionValue(String oid) { + return null; + } + + public Set getNonCriticalExtensionOIDs() { + return null; + } + + public boolean hasUnsupportedCriticalExtension() { + return false; + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test saveState and restoreState(SslCertificate certificate).", + method = "saveState", + args = {android.net.http.SslCertificate.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test saveState and restoreState(SslCertificate certificate).", + method = "restoreState", + args = {android.os.Bundle.class} + ) + }) + public void testState() { + // set the expected value + + Date date1 = new Date(System.currentTimeMillis() - 1000); + Date date2 = new Date(System.currentTimeMillis()); + SslCertificate ssl = new SslCertificate("c=129", "e=weji", DateFormat.getInstance().format( + date1), DateFormat.getInstance().format(date2)); + Bundle saved = SslCertificate.saveState(ssl); + assertTrue(saved.size() == 4); + + assertNotNull(saved.getString("issued-to")); + assertNotNull(saved.getString("issued-by")); + assertNotNull(saved.getString("valid-not-before")); + assertNotNull(saved.getString("valid-not-after")); + assertNull(SslCertificate.saveState(null)); + + SslCertificate restored = SslCertificate.restoreState(saved); + assertEquals(ssl.getValidNotAfter(), restored.getValidNotAfter()); + assertEquals(ssl.getValidNotBefore(), restored.getValidNotBefore()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test getIssuedTo().", + method = "getIssuedTo", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test getIssuedTo().", + method = "getIssuedBy", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test getIssuedTo().", + method = "getValidNotAfter", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test getIssuedTo().", + method = "getValidNotBefore", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test getIssuedTo().", + method = "toString", + args = {} + ) + }) + public void testSslCertificate() { + + final String TO = "c=ccc,o=testOName,ou=testUName,cn=testCName"; + final String BY = "e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName"; + // new the SslCertificate instance + Date date1 = new Date(System.currentTimeMillis() - 1000); + Date date2 = new Date(System.currentTimeMillis()); + SslCertificate ssl = new SslCertificate(TO, BY, DateFormat.getInstance().format( + date1), DateFormat.getInstance().format(date2)); + DName issuedTo = ssl.getIssuedTo(); + DName issuedBy = ssl.getIssuedBy(); + + assertEquals("testCName", issuedTo.getCName()); + assertEquals(TO, issuedTo.getDName()); + assertEquals("testOName", issuedTo.getOName()); + assertEquals("testUName", issuedTo.getUName()); + + assertEquals("testCName", issuedBy.getCName()); + assertEquals(BY, issuedBy.getDName()); + assertEquals("testOName", issuedBy.getOName()); + assertEquals("testUName", issuedBy.getUName()); + + assertEquals(DateFormat.getInstance().format(date1), ssl.getValidNotBefore()); + assertEquals(DateFormat.getInstance().format(date2), ssl.getValidNotAfter()); + final String EXPECTED = "Issued to: c=ccc,o=testOName,ou=testUName,cn=testCName;\n" + + "Issued by: e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName;\n"; + assertEquals(EXPECTED, ssl.toString()); + } + +} diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java new file mode 100644 index 0000000000..848bf7b95a --- /dev/null +++ b/tests/cts/net/src/android/net/http/cts/SslCertificate_DNameTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 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.http.cts; + +import java.text.DateFormat; +import java.util.Date; + +import junit.framework.TestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; +import android.net.http.SslCertificate; +import android.net.http.SslCertificate.DName; + +@TestTargetClass(DName.class) +public class SslCertificate_DNameTest extends TestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test DName.", + method = "SslCertificate.DName", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test DName.", + method = "getCName", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test DName.", + method = "getDName", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test DName.", + method = "getOName", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test DName.", + method = "getUName", + args = {} + ) + }) + public void testDName() { + final String TO = "c=ccc,o=testOName,ou=testUName,cn=testCName"; + final String BY = "e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName"; + // new the SslCertificate instance + Date date1 = new Date(System.currentTimeMillis() - 1000); + Date date2 = new Date(System.currentTimeMillis()); + SslCertificate ssl = new SslCertificate(TO, BY, DateFormat.getInstance().format( + date1), DateFormat.getInstance().format(date2)); + DName issuedTo = ssl.getIssuedTo(); + + assertNotNull(issuedTo); + + assertEquals("testCName", issuedTo.getCName()); + assertEquals(TO, issuedTo.getDName()); + assertEquals("testOName", issuedTo.getOName()); + assertEquals("testUName", issuedTo.getUName()); + } + +} diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java new file mode 100644 index 0000000000..0ab71c70e4 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import java.util.List; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; + +@TestTargetClass(ScanResult.class) +public class ScanResultTest extends AndroidTestCase { + private static class MySync { + int expectedState = STATE_NULL; + } + + private WifiManager mWifiManager; + private WifiLock mWifiLock; + private static MySync mMySync; + + private static final int STATE_NULL = 0; + private static final int STATE_WIFI_CHANGING = 1; + private static final int STATE_WIFI_CHANGED = 2; + + private static final String TAG = "WifiInfoTest"; + private static final int TIMEOUT_MSEC = 6000; + private static final int WAIT_MSEC = 60; + private static final int DURATION = 10000; + private IntentFilter mIntentFilter; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGED; + mMySync.notify(); + } + } + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mMySync = new MySync(); + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); + + mContext.registerReceiver(mReceiver, mIntentFilter); + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + assertNotNull(mWifiManager); + mWifiLock = mWifiManager.createWifiLock(TAG); + mWifiLock.acquire(); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + assertTrue(mWifiManager.isWifiEnabled()); + mMySync.expectedState = STATE_NULL; + } + + @Override + protected void tearDown() throws Exception { + mWifiLock.release(); + mContext.unregisterReceiver(mReceiver); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + super.tearDown(); + } + + private void setWifiEnabled(boolean enable) throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGING; + assertTrue(mWifiManager.setWifiEnabled(enable)); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mMySync.expectedState == STATE_WIFI_CHANGING) + mMySync.wait(WAIT_MSEC); + } + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "toString", + args = {} + ) + public void testScanResultProperties() { + List scanResults = mWifiManager.getScanResults(); + // this test case should in Wifi environment + for (int i = 0; i < scanResults.size(); i++) { + ScanResult mScanResult = scanResults.get(i); + assertNotNull(mScanResult.toString()); + } + } + +} diff --git a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java new file mode 100644 index 0000000000..4e03f5e9ce --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import android.net.wifi.SupplicantState; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(SupplicantState.class) +public class SupplicantStateTest extends AndroidTestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isValidState", + args = {android.net.wifi.SupplicantState.class} + ) + }) + public void testIsValidState() { + assertTrue(SupplicantState.isValidState(SupplicantState.DISCONNECTED)); + assertTrue(SupplicantState.isValidState(SupplicantState.INACTIVE)); + assertTrue(SupplicantState.isValidState(SupplicantState.SCANNING)); + assertTrue(SupplicantState.isValidState(SupplicantState.ASSOCIATING)); + assertTrue(SupplicantState.isValidState(SupplicantState.ASSOCIATED)); + assertTrue(SupplicantState.isValidState(SupplicantState.FOUR_WAY_HANDSHAKE)); + assertTrue(SupplicantState.isValidState(SupplicantState.GROUP_HANDSHAKE)); + assertTrue(SupplicantState.isValidState(SupplicantState.COMPLETED)); + assertTrue(SupplicantState.isValidState(SupplicantState.DORMANT)); + assertFalse(SupplicantState.isValidState(SupplicantState.UNINITIALIZED)); + assertFalse(SupplicantState.isValidState(SupplicantState.INVALID)); + } + +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java new file mode 100644 index 0000000000..3018907092 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import java.util.List; + +import android.content.Context; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(WifiConfiguration.class) +public class WifiConfigurationTest extends AndroidTestCase { + private WifiManager mWifiManager; + @Override + protected void setUp() throws Exception { + super.setUp(); + mWifiManager = (WifiManager) mContext + .getSystemService(Context.WIFI_SERVICE); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "WifiConfiguration", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "toString", + args = {} + ) + }) + public void testWifiConfiguration() { + List wifiConfigurations = mWifiManager.getConfiguredNetworks(); + for (int i = 0; i < wifiConfigurations.size(); i++) { + WifiConfiguration wifiConfiguration = wifiConfigurations.get(i); + assertNotNull(wifiConfiguration); + assertNotNull(wifiConfiguration.toString()); + } + } +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java new file mode 100644 index 0000000000..42243c890d --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; +import dalvik.annotation.ToBeFixed; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.SupplicantState; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.test.AndroidTestCase; + +@TestTargetClass(WifiInfo.class) +public class WifiInfoTest extends AndroidTestCase { + private static class MySync { + int expectedState = STATE_NULL; + } + + private WifiManager mWifiManager; + private WifiLock mWifiLock; + private static MySync mMySync; + + private static final int STATE_NULL = 0; + private static final int STATE_WIFI_CHANGING = 1; + private static final int STATE_WIFI_CHANGED = 2; + + private static final String TAG = "WifiInfoTest"; + private static final int TIMEOUT_MSEC = 6000; + private static final int WAIT_MSEC = 60; + private static final int DURATION = 10000; + private IntentFilter mIntentFilter; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGED; + mMySync.notify(); + } + } + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mMySync = new MySync(); + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); + + mContext.registerReceiver(mReceiver, mIntentFilter); + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + assertNotNull(mWifiManager); + mWifiLock = mWifiManager.createWifiLock(TAG); + mWifiLock.acquire(); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + assertTrue(mWifiManager.isWifiEnabled()); + mMySync.expectedState = STATE_NULL; + } + + @Override + protected void tearDown() throws Exception { + mWifiLock.release(); + mContext.unregisterReceiver(mReceiver); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + super.tearDown(); + } + + private void setWifiEnabled(boolean enable) throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGING; + assertTrue(mWifiManager.setWifiEnabled(enable)); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mMySync.expectedState == STATE_WIFI_CHANGING) + mMySync.wait(WAIT_MSEC); + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getMacAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getIpAddress", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getDetailedStateOf", + args = {android.net.wifi.SupplicantState.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getNetworkId", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getSSID", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getBSSID", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getSupplicantState", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getLinkSpeed", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "toString", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getRssi", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL, + method = "getHiddenSSID", + args = {} + ) + }) + @ToBeFixed(bug="1871573", explanation="android.net.wifi.WifiInfo#getNetworkId() return -1 when" + + " there is wifi connection") + public void testWifiInfoProperties() throws Exception { + // this test case should in Wifi environment + WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + + assertNotNull(wifiInfo); + assertNotNull(wifiInfo.toString()); + SupplicantState.isValidState(wifiInfo.getSupplicantState()); + WifiInfo.getDetailedStateOf(SupplicantState.DISCONNECTED); + wifiInfo.getSSID(); + wifiInfo.getBSSID(); + wifiInfo.getIpAddress(); + wifiInfo.getLinkSpeed(); + wifiInfo.getRssi(); + wifiInfo.getHiddenSSID(); + wifiInfo.getMacAddress(); + setWifiEnabled(false); + Thread.sleep(DURATION); + wifiInfo = mWifiManager.getConnectionInfo(); + assertEquals(-1, wifiInfo.getNetworkId()); + } + +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java new file mode 100644 index 0000000000..132ca9247d --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2009 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.wifi.cts; + +import java.util.List; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiConfiguration.Status; +import android.net.wifi.WifiManager.WifiLock; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(WifiManager.class) +public class WifiManagerTest extends AndroidTestCase { + private static class MySync { + int expectedState = STATE_NULL; + } + + private WifiManager mWifiManager; + private WifiLock mWifiLock; + private static MySync mMySync; + private List mScanResult = null; + + // Please refer to WifiManager + private static final int MIN_RSSI = -100; + private static final int MAX_RSSI = -55; + + private static final int STATE_NULL = 0; + private static final int STATE_WIFI_CHANGING = 1; + private static final int STATE_WIFI_CHANGED = 2; + private static final int STATE_SCANING = 3; + private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; + + private static final String TAG = "WifiManagerTest"; + private static final String SSID1 = "\"WifiManagerTest\""; + private static final String SSID2 = "\"WifiManagerTestModified\""; + private static final int TIMEOUT_MSEC = 6000; + private static final int WAIT_MSEC = 60; + private static final int DURATION = 10000; + private IntentFilter mIntentFilter; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { + synchronized (mMySync) { + if (mWifiManager.getScanResults() != null) { + mScanResult = mWifiManager.getScanResults(); + mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; + mScanResult = mWifiManager.getScanResults(); + mMySync.notify(); + } + } + } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGED; + mMySync.notify(); + } + } + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mMySync = new MySync(); + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); + + mContext.registerReceiver(mReceiver, mIntentFilter); + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + assertNotNull(mWifiManager); + mWifiLock = mWifiManager.createWifiLock(TAG); + mWifiLock.acquire(); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + assertTrue(mWifiManager.isWifiEnabled()); + mMySync.expectedState = STATE_NULL; + } + + @Override + protected void tearDown() throws Exception { + mWifiLock.release(); + mContext.unregisterReceiver(mReceiver); + if (!mWifiManager.isWifiEnabled()) + setWifiEnabled(true); + Thread.sleep(DURATION); + super.tearDown(); + } + + private void setWifiEnabled(boolean enable) throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_WIFI_CHANGING; + assertTrue(mWifiManager.setWifiEnabled(enable)); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mMySync.expectedState == STATE_WIFI_CHANGING) + mMySync.wait(WAIT_MSEC); + } + } + + private void startScan() throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_SCANING; + assertTrue(mWifiManager.startScan()); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANING) + mMySync.wait(WAIT_MSEC); + } + } + + private boolean existSSID(String ssid) { + for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { + if (w.SSID.equals(ssid)) + return true; + } + return false; + } + + private int findConfiguredNetworks(String SSID, List networks) { + for (final WifiConfiguration w : networks) { + if (w.SSID.equals(SSID)) + return networks.indexOf(w); + } + return -1; + } + + private void assertDisableOthers(WifiConfiguration wifiConfiguration, boolean disableOthers) { + for (WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { + if ((!w.SSID.equals(wifiConfiguration.SSID)) && w.status != Status.CURRENT) { + if (disableOthers) + assertEquals(Status.DISABLED, w.status); + } + } + } + + /** + * test point of wifiManager actions: + * 1.reconnect + * 2.reassociate + * 3.disconnect + * 4.pingSupplicant + * 5.satrtScan + */ + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isWifiEnabled", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setWifiEnabled", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "startScan", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getScanResults", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "pingSupplicant", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "reassociate", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "reconnect", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "disconnect", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createWifiLock", + args = {int.class, String.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createWifiLock", + args = {String.class} + ) + }) + public void testWifiManagerActions() throws Exception { + assertTrue(mWifiManager.reconnect()); + assertTrue(mWifiManager.reassociate()); + assertTrue(mWifiManager.disconnect()); + assertTrue(mWifiManager.pingSupplicant()); + startScan(); + setWifiEnabled(false); + Thread.sleep(DURATION); + assertFalse(mWifiManager.pingSupplicant()); + final String TAG = "Test"; + assertNotNull(mWifiManager.createWifiLock(TAG)); + assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); + } + + /** + * test point of wifiManager properties: + * 1.enable properties + * 2.DhcpInfo properties + * 3.wifi state + * 4.ConnectionInfo + */ + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isWifiEnabled", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getWifiState", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setWifiEnabled", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getConnectionInfo", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getDhcpInfo", + args = {} + ) + }) + public void testWifiManagerProperties() throws Exception { + setWifiEnabled(true); + assertTrue(mWifiManager.isWifiEnabled()); + assertNotNull(mWifiManager.getDhcpInfo()); + assertEquals(WifiManager.WIFI_STATE_ENABLED, mWifiManager.getWifiState()); + mWifiManager.getConnectionInfo(); + setWifiEnabled(false); + assertFalse(mWifiManager.isWifiEnabled()); + } + + /** + * test point of wifiManager NetWork: + * 1.add NetWork + * 2.update NetWork + * 3.remove NetWork + * 4.enable NetWork + * 5.disable NetWork + * 6.configured Networks + * 7.save configure; + */ + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isWifiEnabled", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setWifiEnabled", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getConfiguredNetworks", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "addNetwork", + args = {android.net.wifi.WifiConfiguration.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "updateNetwork", + args = {android.net.wifi.WifiConfiguration.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "removeNetwork", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "enableNetwork", + args = {int.class, boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "disableNetwork", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "saveConfiguration", + args = {} + ) + }) + public void testWifiManagerNetWork() throws Exception { + WifiConfiguration wifiConfiguration; + // add a WifiConfig + final int notExist = -1; + List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + if (notExist != pos) { + wifiConfiguration = wifiConfiguredNetworks.get(pos); + mWifiManager.removeNetwork(wifiConfiguration.networkId); + } + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertEquals(notExist, pos); + final int size = wifiConfiguredNetworks.size(); + + wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = SSID1; + int netId = mWifiManager.addNetwork(wifiConfiguration); + assertTrue(existSSID(SSID1)); + + wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + assertEquals(size + 1, wifiConfiguredNetworks.size()); + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertTrue(notExist != pos); + + // Enable & disable network + boolean disableOthers = false; + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + assertEquals(Status.ENABLED, wifiConfiguration.status); + disableOthers = true; + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + + assertTrue(mWifiManager.disableNetwork(netId)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertEquals(Status.DISABLED, wifiConfiguration.status); + + // Update a WifiConfig + wifiConfiguration = wifiConfiguredNetworks.get(pos); + wifiConfiguration.SSID = SSID2; + netId = mWifiManager.updateNetwork(wifiConfiguration); + assertFalse(existSSID(SSID1)); + assertTrue(existSSID(SSID2)); + + // Remove a WifiConfig + assertTrue(mWifiManager.removeNetwork(netId)); + assertFalse(mWifiManager.removeNetwork(notExist)); + assertFalse(existSSID(SSID1)); + assertFalse(existSSID(SSID2)); + + assertTrue(mWifiManager.saveConfiguration()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "compareSignalLevel", + args = {int.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "calculateSignalLevel", + args = {int.class, int.class} + ) + }) + public void testSignal() { + final int numLevels = 9; + int expectLevel = 0; + assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels)); + assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels)); + expectLevel = 4; + assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2, + numLevels)); + int rssiA = 4; + int rssiB = 5; + assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0); + rssiB = 4; + assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0); + rssiA = 5; + rssiB = 4; + assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0); + } +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java new file mode 100644 index 0000000000..53150c9650 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 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.wifi.cts; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass(WifiManager.WifiLock.class) +public class WifiManager_WifiLockTest extends AndroidTestCase { + + private static final String WIFI_TAG = "WifiManager_WifiLockTest"; + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "acquire", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "finalize", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "isHeld", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "release", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "setReferenceCounted", + args = {boolean.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "toString", + args = {} + ) + }) + public void testWifiLock() { + WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + WifiLock wl = wm.createWifiLock(WIFI_TAG); + + wl.setReferenceCounted(true); + assertFalse(wl.isHeld()); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + wl.acquire(); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + assertNotNull(wl.toString()); + try { + wl.release(); + fail("should throw out exception because release is called" + +" a greater number of times than acquire"); + } catch (RuntimeException e) { + // expected + } + + wl = wm.createWifiLock(WIFI_TAG); + wl.setReferenceCounted(false); + assertFalse(wl.isHeld()); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + wl.acquire(); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + assertNotNull(wl.toString()); + // should be ignored + wl.release(); + } +} From cd7a8fa37379f557cec738963f2d20db9c2b85c4 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Tue, 2 Mar 2010 10:01:45 -0800 Subject: [PATCH 0040/1415] SslCertificate should provide Date interface While working on out openssl code, I found a Y2k bug that the dates from invalidate certificates could be shown as 1909 instead of 2009. The reason was because SslCertificate/BrowserActivity passed the values around as Strings even though the started as Dates (from X509Certificate) and were converted backed to Dates before presentation by BrowserActivity's reformatCertificateDate. SslCertificate now maintains date fields internally as Date objects without converting them to Strings. The constructor and String accessors, which are now @deprecated, now specify the format as an ISO 8601 date string which uses 4 digit years. BrowserActivity now reformatCertificateDate is now simply formatCertificateDate and no longer has to convert from String to Date and back to String to get proper Locale formatting. CTS SslCertificateTest also updated. --- .../android/net/http/cts/SslCertificateTest.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java index 91ca876fda..8bc84989ec 100644 --- a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java @@ -223,8 +223,7 @@ public class SslCertificateTest extends TestCase { Date date1 = new Date(System.currentTimeMillis() - 1000); Date date2 = new Date(System.currentTimeMillis()); - SslCertificate ssl = new SslCertificate("c=129", "e=weji", DateFormat.getInstance().format( - date1), DateFormat.getInstance().format(date2)); + SslCertificate ssl = new SslCertificate("c=129", "e=weji", date1, date2); Bundle saved = SslCertificate.saveState(ssl); assertTrue(saved.size() == 4); @@ -255,13 +254,13 @@ public class SslCertificateTest extends TestCase { @TestTargetNew( level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", - method = "getValidNotAfter", + method = "getValidNotAfterDate", args = {} ), @TestTargetNew( level = TestLevel.COMPLETE, notes = "Test getIssuedTo().", - method = "getValidNotBefore", + method = "getValidNotBeforeDate", args = {} ), @TestTargetNew( @@ -278,8 +277,7 @@ public class SslCertificateTest extends TestCase { // new the SslCertificate instance Date date1 = new Date(System.currentTimeMillis() - 1000); Date date2 = new Date(System.currentTimeMillis()); - SslCertificate ssl = new SslCertificate(TO, BY, DateFormat.getInstance().format( - date1), DateFormat.getInstance().format(date2)); + SslCertificate ssl = new SslCertificate(TO, BY, date1, date2); DName issuedTo = ssl.getIssuedTo(); DName issuedBy = ssl.getIssuedBy(); @@ -293,8 +291,8 @@ public class SslCertificateTest extends TestCase { assertEquals("testOName", issuedBy.getOName()); assertEquals("testUName", issuedBy.getUName()); - assertEquals(DateFormat.getInstance().format(date1), ssl.getValidNotBefore()); - assertEquals(DateFormat.getInstance().format(date2), ssl.getValidNotAfter()); + assertEquals(date1, ssl.getValidNotBeforeDate()); + assertEquals(date2, ssl.getValidNotAfterDate()); final String EXPECTED = "Issued to: c=ccc,o=testOName,ou=testUName,cn=testCName;\n" + "Issued by: e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName;\n"; assertEquals(EXPECTED, ssl.toString()); From c4b56b887f2c3b0e7565f59d06a717718202b44e Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Wed, 3 Mar 2010 19:16:18 -0800 Subject: [PATCH 0041/1415] Fix NetworkInfoTest#testAccessNetworkInfoProperties Bug 2483701 Change-Id: I98c0fc74471d9a7a9511c224d5eaa52542a8d68f --- tests/cts/net/src/android/net/cts/NetworkInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index d2de4e4be2..99e8e15169 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -32,7 +32,7 @@ public class NetworkInfoTest extends AndroidTestCase { public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; - public static final String MOBILE_TYPE_NAME = "MOBILE"; + public static final String MOBILE_TYPE_NAME = "mobile"; public static final String WIFI_TYPE_NAME = "WIFI"; @TestTargets({ From 4706a3af1558331a5870c160c52039c77d8bf1c8 Mon Sep 17 00:00:00 2001 From: Dan Egnor Date: Thu, 8 Apr 2010 14:02:54 -0700 Subject: [PATCH 0042/1415] CTS test for android.net.TrafficStats Change-Id: I35fecea2a343fe2483d8c723b7f3a2d9916d47f2 --- .../src/android/net/cts/TrafficStatsTest.java | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/TrafficStatsTest.java diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java new file mode 100644 index 0000000000..ee37244792 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2010 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 android.os.Process; +import android.net.TrafficStats; +import android.test.AndroidTestCase; + +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.Random; + +@TestTargetClass(TrafficStats.class) +public class TrafficStatsTest extends AndroidTestCase { + @TestTargets({ + @TestTargetNew(level = TestLevel.SUFFICIENT, method = "getMobileTxPackets"), + @TestTargetNew(level = TestLevel.SUFFICIENT, method = "getMobileRxPackets"), + @TestTargetNew(level = TestLevel.SUFFICIENT, method = "getMobileTxBytes"), + @TestTargetNew(level = TestLevel.SUFFICIENT, method = "getMobileRxBytes") + }) + public void testGetMobileStats() { + // We can't assume a mobile network is even present in this test, so + // we simply assert that a valid value is returned. + + assertTrue(TrafficStats.getMobileTxPackets() == TrafficStats.UNSUPPORTED || + TrafficStats.getMobileTxPackets() >= 0); + assertTrue(TrafficStats.getMobileRxPackets() == TrafficStats.UNSUPPORTED || + TrafficStats.getMobileRxPackets() >= 0); + assertTrue(TrafficStats.getMobileTxBytes() == TrafficStats.UNSUPPORTED || + TrafficStats.getMobileTxBytes() >= 0); + assertTrue(TrafficStats.getMobileRxBytes() == TrafficStats.UNSUPPORTED || + TrafficStats.getMobileRxBytes() >= 0); + } + + @TestTargets({ + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalTxPackets"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalRxPackets"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalTxBytes"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalRxBytes"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getUidTxBytes"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getUidRxBytes") + }) + public void testTrafficStatsWithHostLookup() { + long txPacketsBefore = TrafficStats.getTotalTxPackets(); + long rxPacketsBefore = TrafficStats.getTotalRxPackets(); + long txBytesBefore = TrafficStats.getTotalTxBytes(); + long rxBytesBefore = TrafficStats.getTotalRxBytes(); + long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid()); + long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); + + // Look up random hostnames in a wildcard domain owned by Google. + // This will require a DNS request, which should generate traffic. + + int found = 0; + Random r = new Random(); + for (int i = 0; i < 10; i++) { + try { + String host = "test" + r.nextInt(100000) + ".clients.google.com"; + InetAddress[] addr = InetAddress.getAllByName(host); + if (addr.length > 0) found++; + } catch (UnknownHostException e) { + // Ignore -- our purpose is not to test network connectivity, + // and we'd rather have false positives than a flaky test. + } + } + + long txPacketsAfter = TrafficStats.getTotalTxPackets(); + long rxPacketsAfter = TrafficStats.getTotalRxPackets(); + long txBytesAfter = TrafficStats.getTotalTxBytes(); + long rxBytesAfter = TrafficStats.getTotalRxBytes(); + long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid()); + long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid()); + + // Make some conservative assertions about the data used: + // each successful resolution should exchange at least one packet, + // and at least 20 bytes in each direction. + + assertTrue("txp: " + txPacketsBefore + " [" + found + "] " + txPacketsAfter, + txPacketsAfter >= txPacketsBefore + found); + assertTrue("rxp: " + rxPacketsBefore + " [" + found + "] " + rxPacketsAfter, + rxPacketsAfter >= rxPacketsBefore + found); + assertTrue("txb: " + txBytesBefore + " [" + found + "] " + txBytesAfter, + txBytesAfter >= txBytesBefore + found * 20); + assertTrue("rxb: " + rxBytesBefore + " [" + found + "] " + rxBytesAfter, + rxBytesAfter >= rxBytesBefore + found * 20); + assertTrue("uidtxb: " + uidTxBytesBefore + " [" + found + "] " + uidTxBytesAfter, + uidTxBytesAfter >= uidTxBytesBefore + found * 20); + assertTrue("uidrxb: " + uidRxBytesBefore + " [" + found + "] " + uidRxBytesAfter, + uidRxBytesAfter >= uidRxBytesBefore + found * 20); + } + + @TestTargets({ + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileTxPackets"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileRxPackets"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileTxBytes"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileRxBytes"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalTxPackets"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalRxPackets"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalTxBytes"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalRxBytes"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getUidTxBytes"), + @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getUidRxBytes") + }) + public void testTrafficStatsForLocalhost() throws IOException { + long mobileTxPacketsBefore = TrafficStats.getTotalTxPackets(); + long mobileRxPacketsBefore = TrafficStats.getTotalRxPackets(); + long mobileTxBytesBefore = TrafficStats.getTotalTxBytes(); + long mobileRxBytesBefore = TrafficStats.getTotalRxBytes(); + long totalTxPacketsBefore = TrafficStats.getTotalTxPackets(); + long totalRxPacketsBefore = TrafficStats.getTotalRxPackets(); + long totalTxBytesBefore = TrafficStats.getTotalTxBytes(); + long totalRxBytesBefore = TrafficStats.getTotalRxBytes(); + long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid()); + long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); + + // Transfer 1MB of data across an explicitly localhost socket. + + final ServerSocket server = new ServerSocket(0); + new Thread("TrafficStatsTest.testTrafficStatsForLocalhost") { + @Override + public void run() { + try { + Socket socket = new Socket("localhost", server.getLocalPort()); + OutputStream out = socket.getOutputStream(); + byte[] buf = new byte[1024]; + for (int i = 0; i < 1024; i++) out.write(buf); + out.close(); + socket.close(); + } catch (IOException e) { + } + } + }.start(); + + try { + Socket socket = server.accept(); + InputStream in = socket.getInputStream(); + byte[] buf = new byte[1024]; + int read = 0; + while (read < 1048576) { + int n = in.read(buf); + assertTrue("Unexpected EOF", n > 0); + read += n; + } + } finally { + server.close(); + } + + long mobileTxPacketsAfter = TrafficStats.getTotalTxPackets(); + long mobileRxPacketsAfter = TrafficStats.getTotalRxPackets(); + long mobileTxBytesAfter = TrafficStats.getTotalTxBytes(); + long mobileRxBytesAfter = TrafficStats.getTotalRxBytes(); + long totalTxPacketsAfter = TrafficStats.getTotalTxPackets(); + long totalRxPacketsAfter = TrafficStats.getTotalRxPackets(); + long totalTxBytesAfter = TrafficStats.getTotalTxBytes(); + long totalRxBytesAfter = TrafficStats.getTotalRxBytes(); + long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid()); + long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid()); + + // Localhost traffic should *not* count against mobile or total stats. + // There might be some other traffic, but nowhere near 1MB. + + assertTrue("mtxp: " + mobileTxPacketsBefore + " -> " + mobileTxPacketsAfter, + mobileTxPacketsAfter >= mobileTxPacketsBefore && + mobileTxPacketsAfter <= mobileTxPacketsBefore + 500); + assertTrue("mrxp: " + mobileRxPacketsBefore + " -> " + mobileRxPacketsAfter, + mobileRxPacketsAfter >= mobileRxPacketsBefore && + mobileRxPacketsAfter <= mobileRxPacketsBefore + 500); + assertTrue("mtxb: " + mobileTxBytesBefore + " -> " + mobileTxBytesAfter, + mobileTxBytesAfter >= mobileTxBytesBefore && + mobileTxBytesAfter <= mobileTxBytesBefore + 200000); + assertTrue("mrxb: " + mobileRxBytesBefore + " -> " + mobileRxBytesAfter, + mobileRxBytesAfter >= mobileRxBytesBefore && + mobileRxBytesAfter <= mobileRxBytesBefore + 200000); + + assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, + totalTxPacketsAfter >= totalTxPacketsBefore && + totalTxPacketsAfter <= totalTxPacketsBefore + 500); + assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, + totalRxPacketsAfter >= totalRxPacketsBefore && + totalRxPacketsAfter <= totalRxPacketsBefore + 500); + assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, + totalTxBytesAfter >= totalTxBytesBefore && + totalTxBytesAfter <= totalTxBytesBefore + 200000); + assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, + totalRxBytesAfter >= totalRxBytesBefore && + totalRxBytesAfter <= totalRxBytesBefore + 200000); + + // Localhost traffic *does* count against per-UID stats. + assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter, + uidTxBytesAfter >= uidTxBytesBefore + 1048576); + assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter, + uidRxBytesAfter >= uidRxBytesBefore + 1048576); + } +} From 20a98ac150770c7316392a8c7ac73bec63b0e1b7 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Wed, 2 Jun 2010 16:12:05 -0700 Subject: [PATCH 0043/1415] Prohibit Listening Ports on Devices Bug 2732034 Check that devices do not have any listening ports open by scanning files in the /proc/net directory. Change-Id: Ic6204667809b3a0c136e38f35fe536bc6d79dcad --- .../android/net/cts/ListeningPortsTest.java | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/ListeningPortsTest.java diff --git a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java new file mode 100644 index 0000000000..ff6b4e9d94 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2010 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 java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.regex.Pattern; + +import junit.framework.TestCase; + +public class ListeningPortsTest extends TestCase { + + /** Address patterns used to check whether we're checking the right column in /proc/net. */ + private static final List ADDRESS_PATTERNS = new ArrayList(2); + + static { + ADDRESS_PATTERNS.add("[0-9A-F]{8}:[0-9A-F]{4}"); + ADDRESS_PATTERNS.add("[0-9A-F]{32}:[0-9A-F]{4}"); + } + + /** Ports that are allowed to be listening on the emulator. */ + private static final List EXCEPTION_PATTERNS = new ArrayList(6); + + static { + // IPv4 exceptions + EXCEPTION_PATTERNS.add("00000000:15B3"); // 0.0.0.0:5555 - emulator port + EXCEPTION_PATTERNS.add("0F02000A:15B3"); // 10.0.2.15:5555 - net forwarding for emulator + EXCEPTION_PATTERNS.add("[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4 Loopback + + // IPv6 exceptions + EXCEPTION_PATTERNS.add("[0]{31}1:[0-9A-F]{4}"); // IPv6 Loopback + EXCEPTION_PATTERNS.add("[0]{16}[0]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion + EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion + } + + public static void testNoListeningPorts() { + final boolean isTcp = true; + assertNoListeningPorts("/proc/net/tcp", isTcp); + assertNoListeningPorts("/proc/net/tcp6", isTcp); + assertNoListeningPorts("/proc/net/udp", !isTcp); + assertNoListeningPorts("/proc/net/udp6", !isTcp); + } + + private static void assertNoListeningPorts(String procFilePath, boolean isTcp) { + + /* + * Sample output of "cat /proc/net/tcp" on emulator: + * + * sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid ... + * 0: 0100007F:13AD 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 ... + * 1: 00000000:15B3 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 ... + * 2: 0F02000A:15B3 0202000A:CE8A 01 00000000:00000000 00:00000000 00000000 0 ... + * + */ + + File procFile = new File(procFilePath); + Scanner scanner = null; + try { + scanner = new Scanner(procFile); + while (scanner.hasNextLine()) { + String line = scanner.nextLine().trim(); + + // Skip column headers + if (line.startsWith("sl")) { + continue; + } + + String[] fields = line.split("\\s+"); + final int expectedNumColumns = 12; + assertTrue(procFilePath + " should have at least " + expectedNumColumns + + " columns of output " + fields, fields.length >= expectedNumColumns); + + String localAddress = fields[1]; + String state = fields[3]; + + assertTrue(procFilePath + " should have an IP address in the second column", + isAddress(localAddress)); + + if (!isException(localAddress) && isPortListening(state, isTcp)) { + fail("Found port listening on " + localAddress + " in " + procFilePath); + } + } + } catch (FileNotFoundException notFound) { + fail("Could not open file " + procFilePath + " to check for listening ports."); + } finally { + if (scanner != null) { + scanner.close(); + } + } + } + + private static boolean isAddress(String localAddress) { + return isPatternMatch(ADDRESS_PATTERNS, localAddress); + } + + private static boolean isException(String localAddress) { + return isPatternMatch(EXCEPTION_PATTERNS, localAddress); + } + + private static boolean isPatternMatch(List patterns, String input) { + for (String pattern : patterns) { + if (Pattern.matches(pattern, input)) { + return true; + } + } + return false; + } + + private static boolean isPortListening(String state, boolean isTcp) { + // 0A = TCP_LISTEN from include/net/tcp_states.h + String listeningState = isTcp ? "0A" : "07"; + return listeningState.equals(state); + } +} From 878dd15dce911a6346b767169054a7c4546149ad Mon Sep 17 00:00:00 2001 From: DongseokYi Date: Thu, 16 Sep 2010 11:44:04 +0900 Subject: [PATCH 0044/1415] Need enough time (1 sec) to read amounts of packet from /proc/stat_uid/[uid]/tcp_snd. Change-Id: I93fdd1bc383e8b944a76e211166e2c5fdb9707cd --- tests/cts/net/src/android/net/cts/TrafficStatsTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index ee37244792..9d23a874da 100644 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -170,6 +170,12 @@ public class TrafficStatsTest extends AndroidTestCase { server.close(); } + // It's too fast to call getUidTxBytes function. + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + long mobileTxPacketsAfter = TrafficStats.getTotalTxPackets(); long mobileRxPacketsAfter = TrafficStats.getTotalRxPackets(); long mobileTxBytesAfter = TrafficStats.getTotalTxBytes(); From bf0563335889cb898963324192870878042b9b29 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Wed, 22 Sep 2010 17:13:29 -0700 Subject: [PATCH 0045/1415] Create CTS test for SSL hostname checks Bug: 2807618 Change-Id: I05b051d779850e51eabea0880400273cdcc2f748 --- .../cts/SSLCertificateSocketFactoryTest.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 6cd5d6f10b..258ac4db1c 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -21,6 +21,7 @@ import java.net.InetAddress; import java.net.Socket; import javax.net.SocketFactory; +import javax.net.ssl.SSLPeerUnverifiedException; import android.net.SSLCertificateSocketFactory; import android.test.AndroidTestCase; @@ -141,4 +142,73 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { // The socket level is invalid. } + // a host and port that are expected to be available but have + // a cert with a different CN, in this case CN=mtalk.google.com + private static String TEST_CREATE_SOCKET_HOST = "mobile-gtalk.l.google.com"; + private static int TEST_CREATE_SOCKET_PORT = 5228; + + /** + * b/2807618 Make sure that hostname verifcation in cases were it + * is documented to be included by various + * SSLCertificateSocketFactory.createSocket messages. + * + * NOTE: Test will fail if external server is not available. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {String.class, int.class} + ) + public void test_createSocket_simple() throws Exception { + try { + mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } + + /** + * b/2807618 Make sure that hostname verifcation in cases were it + * is documented to be included by various + * SSLCertificateSocketFactory.createSocket messages. + * + * NOTE: Test will fail if external server is not available. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {Socket.class, String.class, int.class, boolean.class} + ) + public void test_createSocket_wrapping() throws Exception { + try { + Socket underlying = new Socket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT); + mFactory.createSocket( + underlying, TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT, true); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } + + /** + * b/2807618 Make sure that hostname verifcation in cases were it + * is documented to be included by various + * SSLCertificateSocketFactory.createSocket messages. + * + * NOTE: Test will fail if external server is not available. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "createSocket", + args = {String.class, int.class, InetAddress.class, int.class} + ) + public void test_createSocket_bind() throws Exception { + try { + mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT, null, 0); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } } From 5ff0ab314c7af98e2ab81dde3fc7d03450cc1ab9 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Wed, 20 Oct 2010 15:04:28 -0700 Subject: [PATCH 0046/1415] Delete CM#testAccessNetworkPreference Test Bug 3106981 ConnectivityManager#setNetworkPreference used to be synchronous, but now it merely sends a handler message. As a result, the method won't throw any SecurityExceptions, because it will throw it in the handler instead when trying to write to System.Secure settings. The test tries to write invalid settings or the same settings value to test that it won't throw a SecurityException. Since the method won't throw the exceptions anymore and its not clear how long to wait to confirm that the settings weren't going to be changed, just delete these tests. Change-Id: I9e754bb0e026656511512b17108c42c37d84b069 --- .../net/cts/ConnectivityManagerTest.java | 61 ------------------- 1 file changed, 61 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index edcea9a24e..cfe087227c 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -97,67 +97,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertFalse(ConnectivityManager.isNetworkTypeValid(-1)); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getNetworkPreference", - args = {} - ), - @TestTargetNew( - level = TestLevel.SUFFICIENT, - method = "setNetworkPreference", - args = {int.class} - ) - }) - public void testAccessNetworkPreference() { - int initialSetting = mCm.getNetworkPreference(); - - // Changing the network preference requires android.permission.WRITE_SECURE_SETTINGS, - // which is only available to signed or system applications. - - // Setting the same preference that is already set is a no-op and does not throw - // a SecurityException. - mCm.setNetworkPreference(initialSetting); - assertEquals(initialSetting, mCm.getNetworkPreference()); - - // find a valid setting that is different from the initial setting - int validSetting = -1; - NetworkInfo[] ni = mCm.getAllNetworkInfo(); - for (NetworkInfo n : ni) { - int type = n.getType(); - if (type != initialSetting) { - validSetting = type; - break; - } - } - if (validSetting >= 0) { - try { - mCm.setNetworkPreference(validSetting); - fail("Trying to change the network preference should throw SecurityException"); - } catch (SecurityException expected) { - // expected - } - } - - // find an invalid setting - int invalidSetting = -1; - for (int i = 0; i < 10; i++) { - if (!ConnectivityManager.isNetworkTypeValid(i)) { - invalidSetting = i; - break; - } - } - if (invalidSetting >= 0) { - // illegal setting should be ignored - mCm.setNetworkPreference(invalidSetting); - assertEquals(initialSetting, mCm.getNetworkPreference()); - } - - // illegal setting should be ignored - mCm.setNetworkPreference(-1); - assertEquals(initialSetting, mCm.getNetworkPreference()); - } - @TestTargetNew( level = TestLevel.COMPLETE, notes = "Test getAllNetworkInfo().", From bfc98683699ac45dc0cc787bace8e64dc4c5909c Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Fri, 12 Nov 2010 17:20:23 -0800 Subject: [PATCH 0047/1415] Stop WifiManagerTest from disabling current network. Bug 3181376 Change-Id: I93fa28f20a36b2cc90fbe0a59bbfbac758855c3a --- .../android/net/wifi/cts/WifiManagerTest.java | 139 +++++++++++------- 1 file changed, 86 insertions(+), 53 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 132ca9247d..e2a583b6ef 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -16,7 +16,10 @@ package android.net.wifi.cts; -import java.util.List; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; import android.content.BroadcastReceiver; import android.content.Context; @@ -28,10 +31,11 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiConfiguration.Status; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; +import android.util.Log; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; @TestTargetClass(WifiManager.class) public class WifiManagerTest extends AndroidTestCase { @@ -341,58 +345,87 @@ public class WifiManagerTest extends AndroidTestCase { ) }) public void testWifiManagerNetWork() throws Exception { - WifiConfiguration wifiConfiguration; - // add a WifiConfig - final int notExist = -1; - List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - if (notExist != pos) { + // store the list of enabled networks, so they can be re-enabled after test completes + Set enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); + try { + WifiConfiguration wifiConfiguration; + // add a WifiConfig + final int notExist = -1; + List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + if (notExist != pos) { + wifiConfiguration = wifiConfiguredNetworks.get(pos); + mWifiManager.removeNetwork(wifiConfiguration.networkId); + } + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertEquals(notExist, pos); + final int size = wifiConfiguredNetworks.size(); + + wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = SSID1; + int netId = mWifiManager.addNetwork(wifiConfiguration); + assertTrue(existSSID(SSID1)); + + wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + assertEquals(size + 1, wifiConfiguredNetworks.size()); + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertTrue(notExist != pos); + + // Enable & disable network + boolean disableOthers = false; + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + assertEquals(Status.ENABLED, wifiConfiguration.status); + disableOthers = true; + + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + + assertTrue(mWifiManager.disableNetwork(netId)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertEquals(Status.DISABLED, wifiConfiguration.status); + + // Update a WifiConfig wifiConfiguration = wifiConfiguredNetworks.get(pos); - mWifiManager.removeNetwork(wifiConfiguration.networkId); + wifiConfiguration.SSID = SSID2; + netId = mWifiManager.updateNetwork(wifiConfiguration); + assertFalse(existSSID(SSID1)); + assertTrue(existSSID(SSID2)); + + // Remove a WifiConfig + assertTrue(mWifiManager.removeNetwork(netId)); + assertFalse(mWifiManager.removeNetwork(notExist)); + assertFalse(existSSID(SSID1)); + assertFalse(existSSID(SSID2)); + + assertTrue(mWifiManager.saveConfiguration()); + } finally { + reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks()); + mWifiManager.saveConfiguration(); } - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertEquals(notExist, pos); - final int size = wifiConfiguredNetworks.size(); + } - wifiConfiguration = new WifiConfiguration(); - wifiConfiguration.SSID = SSID1; - int netId = mWifiManager.addNetwork(wifiConfiguration); - assertTrue(existSSID(SSID1)); + private Set getEnabledNetworks(List configuredNetworks) { + Set ssids = new HashSet(); + for (WifiConfiguration wifiConfig : configuredNetworks) { + if (Status.ENABLED == wifiConfig.status || Status.CURRENT == wifiConfig.status) { + ssids.add(wifiConfig.SSID); + Log.i(TAG, String.format("remembering enabled network %s", wifiConfig.SSID)); + } + } + return ssids; + } - wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - assertEquals(size + 1, wifiConfiguredNetworks.size()); - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertTrue(notExist != pos); - - // Enable & disable network - boolean disableOthers = false; - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertDisableOthers(wifiConfiguration, disableOthers); - assertEquals(Status.ENABLED, wifiConfiguration.status); - disableOthers = true; - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertDisableOthers(wifiConfiguration, disableOthers); - - assertTrue(mWifiManager.disableNetwork(netId)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertEquals(Status.DISABLED, wifiConfiguration.status); - - // Update a WifiConfig - wifiConfiguration = wifiConfiguredNetworks.get(pos); - wifiConfiguration.SSID = SSID2; - netId = mWifiManager.updateNetwork(wifiConfiguration); - assertFalse(existSSID(SSID1)); - assertTrue(existSSID(SSID2)); - - // Remove a WifiConfig - assertTrue(mWifiManager.removeNetwork(netId)); - assertFalse(mWifiManager.removeNetwork(notExist)); - assertFalse(existSSID(SSID1)); - assertFalse(existSSID(SSID2)); - - assertTrue(mWifiManager.saveConfiguration()); + private void reEnableNetworks(Set enabledSsids, + List configuredNetworks) { + for (WifiConfiguration wifiConfig : configuredNetworks) { + if (enabledSsids.contains(wifiConfig.SSID)) { + mWifiManager.enableNetwork(wifiConfig.networkId, false); + Log.i(TAG, String.format("re-enabling network %s", wifiConfig.SSID)); + } + } } @TestTargets({ From c97dbae9d4b05eb98ad1e170196ba3cef7724993 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Fri, 12 Nov 2010 17:20:23 -0800 Subject: [PATCH 0048/1415] Stop WifiManagerTest from disabling current network. Bug 3181376 Change-Id: I7dad90ba830678357b900709359f10319070c96e --- .../android/net/wifi/cts/WifiManagerTest.java | 139 +++++++++++------- 1 file changed, 86 insertions(+), 53 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 132ca9247d..e2a583b6ef 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -16,7 +16,10 @@ package android.net.wifi.cts; -import java.util.List; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; import android.content.BroadcastReceiver; import android.content.Context; @@ -28,10 +31,11 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiConfiguration.Status; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; +import android.util.Log; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; @TestTargetClass(WifiManager.class) public class WifiManagerTest extends AndroidTestCase { @@ -341,58 +345,87 @@ public class WifiManagerTest extends AndroidTestCase { ) }) public void testWifiManagerNetWork() throws Exception { - WifiConfiguration wifiConfiguration; - // add a WifiConfig - final int notExist = -1; - List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - if (notExist != pos) { + // store the list of enabled networks, so they can be re-enabled after test completes + Set enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); + try { + WifiConfiguration wifiConfiguration; + // add a WifiConfig + final int notExist = -1; + List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + if (notExist != pos) { + wifiConfiguration = wifiConfiguredNetworks.get(pos); + mWifiManager.removeNetwork(wifiConfiguration.networkId); + } + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertEquals(notExist, pos); + final int size = wifiConfiguredNetworks.size(); + + wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = SSID1; + int netId = mWifiManager.addNetwork(wifiConfiguration); + assertTrue(existSSID(SSID1)); + + wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + assertEquals(size + 1, wifiConfiguredNetworks.size()); + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertTrue(notExist != pos); + + // Enable & disable network + boolean disableOthers = false; + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + assertEquals(Status.ENABLED, wifiConfiguration.status); + disableOthers = true; + + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + + assertTrue(mWifiManager.disableNetwork(netId)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertEquals(Status.DISABLED, wifiConfiguration.status); + + // Update a WifiConfig wifiConfiguration = wifiConfiguredNetworks.get(pos); - mWifiManager.removeNetwork(wifiConfiguration.networkId); + wifiConfiguration.SSID = SSID2; + netId = mWifiManager.updateNetwork(wifiConfiguration); + assertFalse(existSSID(SSID1)); + assertTrue(existSSID(SSID2)); + + // Remove a WifiConfig + assertTrue(mWifiManager.removeNetwork(netId)); + assertFalse(mWifiManager.removeNetwork(notExist)); + assertFalse(existSSID(SSID1)); + assertFalse(existSSID(SSID2)); + + assertTrue(mWifiManager.saveConfiguration()); + } finally { + reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks()); + mWifiManager.saveConfiguration(); } - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertEquals(notExist, pos); - final int size = wifiConfiguredNetworks.size(); + } - wifiConfiguration = new WifiConfiguration(); - wifiConfiguration.SSID = SSID1; - int netId = mWifiManager.addNetwork(wifiConfiguration); - assertTrue(existSSID(SSID1)); + private Set getEnabledNetworks(List configuredNetworks) { + Set ssids = new HashSet(); + for (WifiConfiguration wifiConfig : configuredNetworks) { + if (Status.ENABLED == wifiConfig.status || Status.CURRENT == wifiConfig.status) { + ssids.add(wifiConfig.SSID); + Log.i(TAG, String.format("remembering enabled network %s", wifiConfig.SSID)); + } + } + return ssids; + } - wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - assertEquals(size + 1, wifiConfiguredNetworks.size()); - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertTrue(notExist != pos); - - // Enable & disable network - boolean disableOthers = false; - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertDisableOthers(wifiConfiguration, disableOthers); - assertEquals(Status.ENABLED, wifiConfiguration.status); - disableOthers = true; - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertDisableOthers(wifiConfiguration, disableOthers); - - assertTrue(mWifiManager.disableNetwork(netId)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertEquals(Status.DISABLED, wifiConfiguration.status); - - // Update a WifiConfig - wifiConfiguration = wifiConfiguredNetworks.get(pos); - wifiConfiguration.SSID = SSID2; - netId = mWifiManager.updateNetwork(wifiConfiguration); - assertFalse(existSSID(SSID1)); - assertTrue(existSSID(SSID2)); - - // Remove a WifiConfig - assertTrue(mWifiManager.removeNetwork(netId)); - assertFalse(mWifiManager.removeNetwork(notExist)); - assertFalse(existSSID(SSID1)); - assertFalse(existSSID(SSID2)); - - assertTrue(mWifiManager.saveConfiguration()); + private void reEnableNetworks(Set enabledSsids, + List configuredNetworks) { + for (WifiConfiguration wifiConfig : configuredNetworks) { + if (enabledSsids.contains(wifiConfig.SSID)) { + mWifiManager.enableNetwork(wifiConfig.networkId, false); + Log.i(TAG, String.format("re-enabling network %s", wifiConfig.SSID)); + } + } } @TestTargets({ From 9e410175ba43c445caaf67652ae0eaee9a1a188a Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Fri, 12 Nov 2010 17:20:23 -0800 Subject: [PATCH 0049/1415] Stop WifiManagerTest from disabling current network. Bug 3181376 Change-Id: Ia8d12a10f4ed0c46325e76f1dffeef93412a55e5 --- .../android/net/wifi/cts/WifiManagerTest.java | 139 +++++++++++------- 1 file changed, 86 insertions(+), 53 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 132ca9247d..e2a583b6ef 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -16,7 +16,10 @@ package android.net.wifi.cts; -import java.util.List; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; import android.content.BroadcastReceiver; import android.content.Context; @@ -28,10 +31,11 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiConfiguration.Status; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; +import android.util.Log; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; @TestTargetClass(WifiManager.class) public class WifiManagerTest extends AndroidTestCase { @@ -341,58 +345,87 @@ public class WifiManagerTest extends AndroidTestCase { ) }) public void testWifiManagerNetWork() throws Exception { - WifiConfiguration wifiConfiguration; - // add a WifiConfig - final int notExist = -1; - List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - if (notExist != pos) { + // store the list of enabled networks, so they can be re-enabled after test completes + Set enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); + try { + WifiConfiguration wifiConfiguration; + // add a WifiConfig + final int notExist = -1; + List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + if (notExist != pos) { + wifiConfiguration = wifiConfiguredNetworks.get(pos); + mWifiManager.removeNetwork(wifiConfiguration.networkId); + } + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertEquals(notExist, pos); + final int size = wifiConfiguredNetworks.size(); + + wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = SSID1; + int netId = mWifiManager.addNetwork(wifiConfiguration); + assertTrue(existSSID(SSID1)); + + wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); + assertEquals(size + 1, wifiConfiguredNetworks.size()); + pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); + assertTrue(notExist != pos); + + // Enable & disable network + boolean disableOthers = false; + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + assertEquals(Status.ENABLED, wifiConfiguration.status); + disableOthers = true; + + assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertDisableOthers(wifiConfiguration, disableOthers); + + assertTrue(mWifiManager.disableNetwork(netId)); + wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); + assertEquals(Status.DISABLED, wifiConfiguration.status); + + // Update a WifiConfig wifiConfiguration = wifiConfiguredNetworks.get(pos); - mWifiManager.removeNetwork(wifiConfiguration.networkId); + wifiConfiguration.SSID = SSID2; + netId = mWifiManager.updateNetwork(wifiConfiguration); + assertFalse(existSSID(SSID1)); + assertTrue(existSSID(SSID2)); + + // Remove a WifiConfig + assertTrue(mWifiManager.removeNetwork(netId)); + assertFalse(mWifiManager.removeNetwork(notExist)); + assertFalse(existSSID(SSID1)); + assertFalse(existSSID(SSID2)); + + assertTrue(mWifiManager.saveConfiguration()); + } finally { + reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks()); + mWifiManager.saveConfiguration(); } - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertEquals(notExist, pos); - final int size = wifiConfiguredNetworks.size(); + } - wifiConfiguration = new WifiConfiguration(); - wifiConfiguration.SSID = SSID1; - int netId = mWifiManager.addNetwork(wifiConfiguration); - assertTrue(existSSID(SSID1)); + private Set getEnabledNetworks(List configuredNetworks) { + Set ssids = new HashSet(); + for (WifiConfiguration wifiConfig : configuredNetworks) { + if (Status.ENABLED == wifiConfig.status || Status.CURRENT == wifiConfig.status) { + ssids.add(wifiConfig.SSID); + Log.i(TAG, String.format("remembering enabled network %s", wifiConfig.SSID)); + } + } + return ssids; + } - wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - assertEquals(size + 1, wifiConfiguredNetworks.size()); - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertTrue(notExist != pos); - - // Enable & disable network - boolean disableOthers = false; - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertDisableOthers(wifiConfiguration, disableOthers); - assertEquals(Status.ENABLED, wifiConfiguration.status); - disableOthers = true; - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertDisableOthers(wifiConfiguration, disableOthers); - - assertTrue(mWifiManager.disableNetwork(netId)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertEquals(Status.DISABLED, wifiConfiguration.status); - - // Update a WifiConfig - wifiConfiguration = wifiConfiguredNetworks.get(pos); - wifiConfiguration.SSID = SSID2; - netId = mWifiManager.updateNetwork(wifiConfiguration); - assertFalse(existSSID(SSID1)); - assertTrue(existSSID(SSID2)); - - // Remove a WifiConfig - assertTrue(mWifiManager.removeNetwork(netId)); - assertFalse(mWifiManager.removeNetwork(notExist)); - assertFalse(existSSID(SSID1)); - assertFalse(existSSID(SSID2)); - - assertTrue(mWifiManager.saveConfiguration()); + private void reEnableNetworks(Set enabledSsids, + List configuredNetworks) { + for (WifiConfiguration wifiConfig : configuredNetworks) { + if (enabledSsids.contains(wifiConfig.SSID)) { + mWifiManager.enableNetwork(wifiConfig.networkId, false); + Log.i(TAG, String.format("re-enabling network %s", wifiConfig.SSID)); + } + } } @TestTargets({ From 5f78c57fc5a82e2f0d34668f0885654019993a2a Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Mon, 29 Nov 2010 12:54:45 -0800 Subject: [PATCH 0050/1415] Fix android.net.cts.ProxyTest Bug 3188260 Remove the code that was trying to write to secure settings and take off the BrokenTest annotation. Change-Id: I0759db38225a9822b25c987e66a7590c555b5e9e --- .../net/src/android/net/cts/ProxyTest.java | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index 357935adb0..184a07c483 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -16,29 +16,17 @@ package android.net.cts; -import android.content.Context; -import android.net.Proxy; -import android.provider.Settings.Secure; -import android.test.AndroidTestCase; - -import dalvik.annotation.BrokenTest; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargets; +import android.net.Proxy; +import android.test.AndroidTestCase; + @TestTargetClass(Proxy.class) public class ProxyTest extends AndroidTestCase { - private Context mContext; - - @Override - protected void setUp() throws Exception { - super.setUp(); - - mContext = getContext(); - } - @TestTargetNew( level = TestLevel.COMPLETE, method = "Proxy", @@ -59,18 +47,7 @@ public class ProxyTest extends AndroidTestCase { method = "getDefaultHost", args = {} ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getPort", - args = {Context.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getHost", - args = {Context.class} - ) }) - @BrokenTest("Cannot write secure settings table") public void testAccessProperties() { final int minValidPort = 0; final int maxValidPort = 65535; @@ -80,12 +57,5 @@ public class ProxyTest extends AndroidTestCase { } else { assertTrue(defaultPort >= minValidPort && defaultPort <= maxValidPort); } - - final String host = "proxy.example.com"; - final int port = 2008; - - Secure.putString(mContext.getContentResolver(), Secure.HTTP_PROXY, host + ":" + port); - assertEquals(host, Proxy.getHost(mContext)); - assertEquals(port, Proxy.getPort(mContext)); } } From 5822cf4427886b8fbe1cfc51d4d87c5c9a6464a3 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Mon, 29 Nov 2010 14:28:39 -0800 Subject: [PATCH 0051/1415] Fix Build Didn't have the right javac set in my environment... :-( Change-Id: I951a11460eafeb75c081a4a07787aaf320b48b31 --- tests/cts/net/src/android/net/cts/ProxyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index 184a07c483..0c0586ea84 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -46,7 +46,7 @@ public class ProxyTest extends AndroidTestCase { level = TestLevel.COMPLETE, method = "getDefaultHost", args = {} - ), + ) }) public void testAccessProperties() { final int minValidPort = 0; From 26c4fe935fc14fc9661d5dccc04e0d190037f42f Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Mon, 13 Dec 2010 12:50:29 -0800 Subject: [PATCH 0052/1415] Make ListeningPortsTest less flaky. When a DNS lookup occurs, a new listening UDP socket will be created to receive the DNS response. This listening socket is only temporary, and shouldn't count as a permanent open socket. Bug: 3276283 Change-Id: I45090c0e07d9b360cc26f4bce23833db8c399507 --- .../android/net/cts/ListeningPortsTest.java | 50 ++++++++++++++++--- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java index ff6b4e9d94..0a32bd7f7f 100644 --- a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java +++ b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Scanner; import java.util.regex.Pattern; +import junit.framework.AssertionFailedError; import junit.framework.TestCase; public class ListeningPortsTest extends TestCase { @@ -50,12 +51,40 @@ public class ListeningPortsTest extends TestCase { EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion } - public static void testNoListeningPorts() { - final boolean isTcp = true; - assertNoListeningPorts("/proc/net/tcp", isTcp); - assertNoListeningPorts("/proc/net/tcp6", isTcp); - assertNoListeningPorts("/proc/net/udp", !isTcp); - assertNoListeningPorts("/proc/net/udp6", !isTcp); + public void testNoListeningTcpPorts() { + assertNoListeningPorts("/proc/net/tcp", true); + } + + public void testNoListeningTcp6Ports() { + assertNoListeningPorts("/proc/net/tcp6", true); + } + + public void testNoListeningUdpPorts() throws Exception { + assertNoListeningUdpPorts("/proc/net/udp"); + } + + public void testNoListeningUdp6Ports() throws Exception { + assertNoListeningUdpPorts("/proc/net/udp6"); + } + + private static final int RETRIES_MAX = 4; + + /** + * UDP tests can be flaky due to DNS lookups. Compensate. + */ + private static void assertNoListeningUdpPorts(String procFilePath) throws Exception { + for (int i = 0; i < RETRIES_MAX; i++) { + try { + assertNoListeningPorts(procFilePath, false); + return; + } catch (ListeningPortsAssertionError e) { + if (i == RETRIES_MAX - 1) { + throw e; + } + Thread.sleep(2 * 1000 * i); + } + } + throw new IllegalStateException("unreachable"); } private static void assertNoListeningPorts(String procFilePath, boolean isTcp) { @@ -94,7 +123,8 @@ public class ListeningPortsTest extends TestCase { isAddress(localAddress)); if (!isException(localAddress) && isPortListening(state, isTcp)) { - fail("Found port listening on " + localAddress + " in " + procFilePath); + throw new ListeningPortsAssertionError( + "Found port listening on " + localAddress + " in " + procFilePath); } } } catch (FileNotFoundException notFound) { @@ -128,4 +158,10 @@ public class ListeningPortsTest extends TestCase { String listeningState = isTcp ? "0A" : "07"; return listeningState.equals(state); } + + private static class ListeningPortsAssertionError extends AssertionFailedError { + private ListeningPortsAssertionError(String msg) { + super(msg); + } + } } From 553ae9a71ac044abf9df5027a41b6a0cffe4d042 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Mon, 13 Dec 2010 14:02:45 -0800 Subject: [PATCH 0053/1415] still seeing flakyness. Increase retries. Change-Id: I988afa2922dc503bcdff455822088ad22c854d97 --- tests/cts/net/src/android/net/cts/ListeningPortsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java index 0a32bd7f7f..b6e6efbc71 100644 --- a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java +++ b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java @@ -67,7 +67,7 @@ public class ListeningPortsTest extends TestCase { assertNoListeningUdpPorts("/proc/net/udp6"); } - private static final int RETRIES_MAX = 4; + private static final int RETRIES_MAX = 6; /** * UDP tests can be flaky due to DNS lookups. Compensate. From b511c888ec8d115a751bf46b24ed0b5ed24454f0 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Mon, 20 Dec 2010 13:57:14 -0800 Subject: [PATCH 0054/1415] Nuke TrafficStatsTest#testTrafficStatsWithHost... Bug 3189208 Removing this test due to potential problems with GB. This will need to be brought back and investigated. Change-Id: Ifeafdf44464c652b063edfb51c5f7931624b6973 --- .../src/android/net/cts/TrafficStatsTest.java | 73 ++----------------- 1 file changed, 6 insertions(+), 67 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 9d23a874da..183f891637 100644 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -16,24 +16,20 @@ package android.net.cts; -import android.os.Process; -import android.net.TrafficStats; -import android.test.AndroidTestCase; - -import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +import android.net.TrafficStats; +import android.os.Process; +import android.test.AndroidTestCase; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; -import java.net.UnknownHostException; -import java.util.Random; @TestTargetClass(TrafficStats.class) public class TrafficStatsTest extends AndroidTestCase { @@ -57,63 +53,6 @@ public class TrafficStatsTest extends AndroidTestCase { TrafficStats.getMobileRxBytes() >= 0); } - @TestTargets({ - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalTxPackets"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalRxPackets"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalTxBytes"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalRxBytes"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getUidTxBytes"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getUidRxBytes") - }) - public void testTrafficStatsWithHostLookup() { - long txPacketsBefore = TrafficStats.getTotalTxPackets(); - long rxPacketsBefore = TrafficStats.getTotalRxPackets(); - long txBytesBefore = TrafficStats.getTotalTxBytes(); - long rxBytesBefore = TrafficStats.getTotalRxBytes(); - long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid()); - long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); - - // Look up random hostnames in a wildcard domain owned by Google. - // This will require a DNS request, which should generate traffic. - - int found = 0; - Random r = new Random(); - for (int i = 0; i < 10; i++) { - try { - String host = "test" + r.nextInt(100000) + ".clients.google.com"; - InetAddress[] addr = InetAddress.getAllByName(host); - if (addr.length > 0) found++; - } catch (UnknownHostException e) { - // Ignore -- our purpose is not to test network connectivity, - // and we'd rather have false positives than a flaky test. - } - } - - long txPacketsAfter = TrafficStats.getTotalTxPackets(); - long rxPacketsAfter = TrafficStats.getTotalRxPackets(); - long txBytesAfter = TrafficStats.getTotalTxBytes(); - long rxBytesAfter = TrafficStats.getTotalRxBytes(); - long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid()); - long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid()); - - // Make some conservative assertions about the data used: - // each successful resolution should exchange at least one packet, - // and at least 20 bytes in each direction. - - assertTrue("txp: " + txPacketsBefore + " [" + found + "] " + txPacketsAfter, - txPacketsAfter >= txPacketsBefore + found); - assertTrue("rxp: " + rxPacketsBefore + " [" + found + "] " + rxPacketsAfter, - rxPacketsAfter >= rxPacketsBefore + found); - assertTrue("txb: " + txBytesBefore + " [" + found + "] " + txBytesAfter, - txBytesAfter >= txBytesBefore + found * 20); - assertTrue("rxb: " + rxBytesBefore + " [" + found + "] " + rxBytesAfter, - rxBytesAfter >= rxBytesBefore + found * 20); - assertTrue("uidtxb: " + uidTxBytesBefore + " [" + found + "] " + uidTxBytesAfter, - uidTxBytesAfter >= uidTxBytesBefore + found * 20); - assertTrue("uidrxb: " + uidRxBytesBefore + " [" + found + "] " + uidRxBytesAfter, - uidRxBytesAfter >= uidRxBytesBefore + found * 20); - } - @TestTargets({ @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileTxPackets"), @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileRxPackets"), From d2488d6ffd7b1a789150abd8d7488764af9c085e Mon Sep 17 00:00:00 2001 From: Masanori Ogino Date: Thu, 13 Jan 2011 15:52:34 +0900 Subject: [PATCH 0055/1415] Test requestRouteToHost() except TYPE_WIFI If the device is set Wifi-ON, then testRequestRouteToHost always fails. Change-Id: Ie487773552e8f6f1d4838755cc39e23c5aa57c1d --- .../cts/net/src/android/net/cts/ConnectivityManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index edcea9a24e..354428b8e9 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -204,8 +204,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { NetworkInfo[] ni = mCm.getAllNetworkInfo(); for (NetworkInfo n : ni) { - // make sure network is up - if (n.isConnected()) { + // make sure network is up (except WIFI due to always fail) + if (n.isConnected() && (n.getType() != TYPE_WIFI)) { assertTrue(mCm.requestRouteToHost(n.getType(), HOST_ADDRESS)); } } From 328b217e5823e47e54b077c43bc8fab91763cb06 Mon Sep 17 00:00:00 2001 From: Madan Ankapura Date: Thu, 11 Nov 2010 18:31:24 -0800 Subject: [PATCH 0056/1415] DO NOT MERGE fix failing test testWifiInfoProperties for non-telephony devices Device can still have a valid networkId even after disconnection if it was associated with AP, getWifiState is a better check to get valid state. Change-Id: I31a8ca38f304fbf639e1f3111be4b5ed406e3b3c --- tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 42243c890d..d6d7d8e47c 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -20,7 +20,6 @@ import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargets; -import dalvik.annotation.ToBeFixed; import android.content.BroadcastReceiver; import android.content.Context; @@ -168,8 +167,6 @@ public class WifiInfoTest extends AndroidTestCase { args = {} ) }) - @ToBeFixed(bug="1871573", explanation="android.net.wifi.WifiInfo#getNetworkId() return -1 when" - + " there is wifi connection") public void testWifiInfoProperties() throws Exception { // this test case should in Wifi environment WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); @@ -187,8 +184,7 @@ public class WifiInfoTest extends AndroidTestCase { wifiInfo.getMacAddress(); setWifiEnabled(false); Thread.sleep(DURATION); - wifiInfo = mWifiManager.getConnectionInfo(); - assertEquals(-1, wifiInfo.getNetworkId()); + assertEquals(WifiManager.WIFI_STATE_DISABLED, mWifiManager.getWifiState()); } } From 3bd4323ce4d90a2051010a8f9e2880140d5b2ec4 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Wed, 9 Feb 2011 16:07:14 -0800 Subject: [PATCH 0057/1415] Change SSLCertificateSocketFactoryTest.testCreateSocket host The test may be flaky because it depends on a live server. Switch to a different server that may be more reliable. Bug: 3188260 Change-Id: Ibba872489650914db8ddd9a117529556787f66ec --- .../src/android/net/cts/SSLCertificateSocketFactoryTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 258ac4db1c..f125550a8b 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -102,11 +102,10 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { args = {int.class} ) }) - @BrokenTest("flaky") public void testCreateSocket() throws Exception { new SSLCertificateSocketFactory(100); int port = 443; - String host = "www.fortify.net"; + String host = "www.google.com"; InetAddress inetAddress = null; inetAddress = InetAddress.getLocalHost(); try { From 76e1414be8d472827d510785d5529b8e5607141a Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Fri, 14 Jan 2011 17:38:16 -0800 Subject: [PATCH 0058/1415] Test startUsingNetworkFeature TYPE_MOBILE_HIPRI Bug 3307293 Change-Id: I03b3e11e1de20333ece772e3448937c61ca0fe91 --- .../net/cts/ConnectivityManagerTest.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 354428b8e9..dcb4e1d992 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,26 +16,43 @@ package android.net.cts; +import com.android.internal.telephony.Phone; + import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargets; import dalvik.annotation.ToBeFixed; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; +import android.net.wifi.WifiManager; import android.test.AndroidTestCase; +import android.util.Log; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; @TestTargetClass(ConnectivityManager.class) public class ConnectivityManagerTest extends AndroidTestCase { + private static final String TAG = ConnectivityManagerTest.class.getSimpleName(); + + private static final String FEATURE_ENABLE_HIPRI = "enableHIPRI"; + public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 private ConnectivityManager mCm; + private WifiManager mWifiManager; + private PackageManager mPackageManager; // must include both mobile data + wifi private static final int MIN_NUM_NETWORK_TYPES = 2; @@ -43,6 +60,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + mPackageManager = getContext().getPackageManager(); } @TestTargetNew( @@ -235,4 +254,91 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testTest() { mCm.getBackgroundDataSetting(); } + + /** Test that hipri can be brought up when Wifi is enabled. */ + public void testStartUsingNetworkFeature_enableHipri() throws Exception { + if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) + || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { + // This test requires a mobile data connection and WiFi. + return; + } + + boolean isWifiConnected = mWifiManager.isWifiEnabled() + && mWifiManager.getConnectionInfo().getSSID() != null; + + try { + // Make sure WiFi is connected to an access point. + if (!isWifiConnected) { + connectToWifi(); + } + + // Register a receiver that will capture the connectivity change for hipri. + ConnectivityActionReceiver receiver = + new ConnectivityActionReceiver(ConnectivityManager.TYPE_MOBILE_HIPRI); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + // Try to start using the hipri feature... + int result = mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + FEATURE_ENABLE_HIPRI); + assertTrue("Couldn't start using the HIPRI feature.", result != -1); + + // Check that the ConnectivityManager reported that it connected using hipri... + assertTrue("Couldn't connect using hipri...", receiver.waitForConnection()); + + assertTrue("Couldn't requestRouteToHost using HIPRI.", + mCm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, HOST_ADDRESS)); + + } catch (InterruptedException e) { + fail("Broadcast receiver waiting for ConnectivityManager interrupted."); + } finally { + mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + Phone.FEATURE_ENABLE_HIPRI); + if (!isWifiConnected) { + mWifiManager.setWifiEnabled(false); + } + } + } + + private void connectToWifi() throws InterruptedException { + ConnectivityActionReceiver receiver = + new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + assertTrue(mWifiManager.setWifiEnabled(true)); + assertTrue("Wifi must be configured to connect to an access point for this test.", + receiver.waitForConnection()); + + mContext.unregisterReceiver(receiver); + } + + /** Receiver that captures the last connectivity change's network type and state. */ + private class ConnectivityActionReceiver extends BroadcastReceiver { + + private final CountDownLatch mReceiveLatch = new CountDownLatch(1); + + private final int mNetworkType; + + ConnectivityActionReceiver(int networkType) { + mNetworkType = networkType; + } + + public void onReceive(Context context, Intent intent) { + NetworkInfo networkInfo = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); + int networkType = networkInfo.getType(); + State networkState = networkInfo.getState(); + Log.i(TAG, "Network type: " + networkType + " state: " + networkState); + if (networkType == mNetworkType && networkInfo.getState() == State.CONNECTED) { + mReceiveLatch.countDown(); + } + } + + public boolean waitForConnection() throws InterruptedException { + return mReceiveLatch.await(10, TimeUnit.SECONDS); + } + } } From f3336d71e9928e044f8d43aa2ac07191cdcc7fc9 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Mon, 28 Feb 2011 15:21:42 -0800 Subject: [PATCH 0059/1415] Remove Reference to Internal Phone Constant Use the constant defined in the test instead. Change-Id: Ia4c85a56663df0c79910395aaae534407952aaf6 --- .../cts/net/src/android/net/cts/ConnectivityManagerTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index dcb4e1d992..3b85e9f92e 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,8 +16,6 @@ package android.net.cts; -import com.android.internal.telephony.Phone; - import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; @@ -294,7 +292,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { fail("Broadcast receiver waiting for ConnectivityManager interrupted."); } finally { mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - Phone.FEATURE_ENABLE_HIPRI); + FEATURE_ENABLE_HIPRI); if (!isWifiConnected) { mWifiManager.setWifiEnabled(false); } From a89c9170d2b0b20410aa96cee7a43b38035564b6 Mon Sep 17 00:00:00 2001 From: Xia Wang Date: Fri, 4 Mar 2011 22:11:29 -0800 Subject: [PATCH 0060/1415] Fix cts tests for Wi-Fi only devices. For Wi-Fi only device, startUsingNetworkFeature() returns Phone.APN_TYPE_NOT_AVAILABLE stopUsingNetworkFeature() return 1; In NetworkInfoTest: cm.getAllNetworkInfo() returns an array of NetworkInfo. But the index is not based on network type. bug#: 3513630 Change-Id: Ied0684a9fe2152dae242d779efe3dffd6c9c0609 --- .../net/cts/ConnectivityManagerTest.java | 57 +++++++------ .../src/android/net/cts/NetworkInfoTest.java | 79 +++++++++---------- 2 files changed, 72 insertions(+), 64 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 17a3ac16c8..b69bffd669 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -36,8 +36,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 private ConnectivityManager mCm; - // must include both mobile data + wifi - private static final int MIN_NUM_NETWORK_TYPES = 2; + // device could have only one interface: data, wifi. + private static final int MIN_NUM_NETWORK_TYPES = 1; @Override protected void setUp() throws Exception { @@ -51,28 +51,27 @@ public class ConnectivityManagerTest extends AndroidTestCase { args = {int.class} ) public void testGetNetworkInfo() { - - // this test assumes that there are at least two network types. assertTrue(mCm.getAllNetworkInfo().length >= MIN_NUM_NETWORK_TYPES); - NetworkInfo ni = mCm.getNetworkInfo(1); - State state = ni.getState(); - assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() - && state.ordinal() >= State.CONNECTING.ordinal()); - DetailedState ds = ni.getDetailedState(); - assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() - && ds.ordinal() >= DetailedState.IDLE.ordinal()); - - ni = mCm.getNetworkInfo(0); - state = ni.getState(); - assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() - && state.ordinal() >= State.CONNECTING.ordinal()); - ds = ni.getDetailedState(); - assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() - && ds.ordinal() >= DetailedState.IDLE.ordinal()); - + NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI); + if (ni != null) { + State state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + } + ni = mCm.getNetworkInfo(TYPE_MOBILE); + if (ni != null) { + State state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + } ni = mCm.getNetworkInfo(-1); assertNull(ni); - } @TestTargets({ @@ -125,9 +124,21 @@ public class ConnectivityManagerTest extends AndroidTestCase { final String invalidateFeature = "invalidateFeature"; final String mmsFeature = "enableMMS"; final int failureCode = -1; + final int wifiOnlyStartFailureCode = 3; + final int wifiOnlyStopFailureCode = 1; - assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); + NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE); + if (ni != null) { + assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + } else { + assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + } // Should return failure(-1) because MMS is not supported on WIFI. assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_WIFI, mmsFeature)); diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 99e8e15169..b333be747e 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -120,50 +120,47 @@ public class NetworkInfoTest extends AndroidTestCase { public void testAccessNetworkInfoProperties() { ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( Context.CONNECTIVITY_SERVICE); - NetworkInfo[] ni = cm.getAllNetworkInfo(); assertTrue(ni.length >= 2); - assertFalse(ni[TYPE_MOBILE].isFailover()); - assertFalse(ni[TYPE_WIFI].isFailover()); - - // test environment:connect as TYPE_MOBILE, and connect to internet. - assertEquals(TYPE_MOBILE, ni[TYPE_MOBILE].getType()); - assertEquals(TYPE_WIFI, ni[TYPE_WIFI].getType()); - - // don't know the return value - ni[TYPE_MOBILE].getSubtype(); - ni[TYPE_WIFI].getSubtype(); - - assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); - assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); - - // don't know the return value - ni[TYPE_MOBILE].getSubtypeName(); - ni[TYPE_WIFI].getSubtypeName(); - - if(ni[TYPE_MOBILE].isConnectedOrConnecting()) { - assertTrue(ni[TYPE_MOBILE].isAvailable()); - assertTrue(ni[TYPE_MOBILE].isConnected()); - assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); - assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); - ni[TYPE_MOBILE].getReason(); - ni[TYPE_MOBILE].getExtraInfo(); + for (NetworkInfo netInfo: ni) { + switch (netInfo.getType()) { + case TYPE_MOBILE: + // don't know the return value + netInfo.getSubtype(); + assertEquals(MOBILE_TYPE_NAME, netInfo.getTypeName()); + // don't know the return value + netInfo.getSubtypeName(); + if(netInfo.isConnectedOrConnecting()) { + assertTrue(netInfo.isAvailable()); + assertTrue(netInfo.isConnected()); + assertEquals(State.CONNECTED, netInfo.getState()); + assertEquals(DetailedState.CONNECTED, netInfo.getDetailedState()); + netInfo.getReason(); + netInfo.getExtraInfo(); + } + assertFalse(netInfo.isRoaming()); + assertNotNull(netInfo.toString()); + break; + case TYPE_WIFI: + netInfo.getSubtype(); + assertEquals(WIFI_TYPE_NAME, netInfo.getTypeName()); + netInfo.getSubtypeName(); + if(netInfo.isConnectedOrConnecting()) { + assertTrue(netInfo.isAvailable()); + assertTrue(netInfo.isConnected()); + assertEquals(State.CONNECTED, netInfo.getState()); + assertEquals(DetailedState.CONNECTED, netInfo.getDetailedState()); + netInfo.getReason(); + netInfo.getExtraInfo(); + } + assertFalse(netInfo.isRoaming()); + assertNotNull(netInfo.toString()); + break; + // TODO: Add BLUETOOTH_TETHER testing + default: + break; + } } - - if(ni[TYPE_WIFI].isConnectedOrConnecting()) { - assertTrue(ni[TYPE_WIFI].isAvailable()); - assertTrue(ni[TYPE_WIFI].isConnected()); - assertEquals(State.CONNECTED, ni[TYPE_WIFI].getState()); - assertEquals(DetailedState.CONNECTED, ni[TYPE_WIFI].getDetailedState()); - ni[TYPE_WIFI].getReason(); - ni[TYPE_WIFI].getExtraInfo(); - } - - assertFalse(ni[TYPE_MOBILE].isRoaming()); - assertFalse(ni[TYPE_WIFI].isRoaming()); - - assertNotNull(ni[TYPE_MOBILE].toString()); - assertNotNull(ni[TYPE_WIFI].toString()); } } From f108edaa630a5d808328fe892cba7ebbefb26ce0 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Wed, 6 Apr 2011 10:21:51 -0700 Subject: [PATCH 0061/1415] Fix WifiInfoTest Do not listen to supplicant state change for wifi disable action, instead depend on wifi state changed action Bug: 4242273 Change-Id: Ie53ff42d5e51bbc9f28d93a435fa3315611d342e --- tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 3b1a6c1ab3..44189cd13a 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -54,7 +54,7 @@ public class WifiInfoTest extends AndroidTestCase { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { synchronized (mMySync) { mMySync.expectedState = STATE_WIFI_CHANGED; mMySync.notify(); @@ -68,14 +68,7 @@ public class WifiInfoTest extends AndroidTestCase { super.setUp(); mMySync = new MySync(); mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); mContext.registerReceiver(mReceiver, mIntentFilter); mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); From 5c990cd7145803b20368097d3f4514e23177a3c8 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Wed, 6 Apr 2011 10:21:51 -0700 Subject: [PATCH 0062/1415] Fix WifiInfoTest Do not listen to supplicant state change for wifi disable action, instead depend on wifi state changed action Bug: 4242273 Change-Id: Ie53ff42d5e51bbc9f28d93a435fa3315611d342e --- tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 3b1a6c1ab3..44189cd13a 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -54,7 +54,7 @@ public class WifiInfoTest extends AndroidTestCase { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { synchronized (mMySync) { mMySync.expectedState = STATE_WIFI_CHANGED; mMySync.notify(); @@ -68,14 +68,7 @@ public class WifiInfoTest extends AndroidTestCase { super.setUp(); mMySync = new MySync(); mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); mContext.registerReceiver(mReceiver, mIntentFilter); mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); From 4a88b709cc18156f25055de26025857bef9f5e2f Mon Sep 17 00:00:00 2001 From: Xia Wang Date: Fri, 4 Mar 2011 22:11:29 -0800 Subject: [PATCH 0063/1415] Backport from HC to Fix NetworkInfoTest Bug 4322307 Fixed some other assertions that didn't check for either CONNECTING or CONNECTED. Cleaned up some code and removed some extraneous checks. Original description: "Fix cts tests for Wi-Fi only devices. For Wi-Fi only device, startUsingNetworkFeature() returns Phone.APN_TYPE_NOT_AVAILABLE stopUsingNetworkFeature() return 1; In NetworkInfoTest: cm.getAllNetworkInfo() returns an array of NetworkInfo. But the index is not based on network type." Change-Id: I0b5e3d0cfe5fac18bca0a5ca2ce4cc73bc4dfa16 --- .../net/cts/ConnectivityManagerTest.java | 58 ++++--- .../src/android/net/cts/NetworkInfoTest.java | 156 ++++-------------- 2 files changed, 65 insertions(+), 149 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 12cc21e053..96a935b549 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -51,8 +51,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { private ConnectivityManager mCm; private WifiManager mWifiManager; private PackageManager mPackageManager; - // must include both mobile data + wifi - private static final int MIN_NUM_NETWORK_TYPES = 2; + + // device could have only one interface: data, wifi. + private static final int MIN_NUM_NETWORK_TYPES = 1; @Override protected void setUp() throws Exception { @@ -68,28 +69,27 @@ public class ConnectivityManagerTest extends AndroidTestCase { args = {int.class} ) public void testGetNetworkInfo() { - - // this test assumes that there are at least two network types. assertTrue(mCm.getAllNetworkInfo().length >= MIN_NUM_NETWORK_TYPES); - NetworkInfo ni = mCm.getNetworkInfo(1); - State state = ni.getState(); - assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() - && state.ordinal() >= State.CONNECTING.ordinal()); - DetailedState ds = ni.getDetailedState(); - assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() - && ds.ordinal() >= DetailedState.IDLE.ordinal()); - - ni = mCm.getNetworkInfo(0); - state = ni.getState(); - assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() - && state.ordinal() >= State.CONNECTING.ordinal()); - ds = ni.getDetailedState(); - assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() - && ds.ordinal() >= DetailedState.IDLE.ordinal()); - + NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI); + if (ni != null) { + State state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + } + ni = mCm.getNetworkInfo(TYPE_MOBILE); + if (ni != null) { + State state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + } ni = mCm.getNetworkInfo(-1); assertNull(ni); - } @TestTargets({ @@ -142,9 +142,21 @@ public class ConnectivityManagerTest extends AndroidTestCase { final String invalidateFeature = "invalidateFeature"; final String mmsFeature = "enableMMS"; final int failureCode = -1; + final int wifiOnlyStartFailureCode = 3; + final int wifiOnlyStopFailureCode = 1; - assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); + NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE); + if (ni != null) { + assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + } else { + assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + } // Should return failure(-1) because MMS is not supported on WIFI. assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_WIFI, mmsFeature)); diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 99e8e15169..6800c43b0a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -16,16 +16,14 @@ package android.net.cts; +import dalvik.annotation.TestTargetClass; + import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { @@ -35,135 +33,41 @@ public class NetworkInfoTest extends AndroidTestCase { public static final String MOBILE_TYPE_NAME = "mobile"; public static final String WIFI_TYPE_NAME = "WIFI"; - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isConnectedOrConnecting", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setFailover", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isFailover", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isRoaming", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getType", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getSubtype", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getTypeName", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getSubtypeName", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setIsAvailable", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isAvailable", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isConnected", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getDetailedState", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getState", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getReason", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getExtraInfo", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "toString", - args = {} - ) - }) public void testAccessNetworkInfoProperties() { ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( Context.CONNECTIVITY_SERVICE); - NetworkInfo[] ni = cm.getAllNetworkInfo(); - assertTrue(ni.length >= 2); + assertTrue(ni.length >= 1); - assertFalse(ni[TYPE_MOBILE].isFailover()); - assertFalse(ni[TYPE_WIFI].isFailover()); - - // test environment:connect as TYPE_MOBILE, and connect to internet. - assertEquals(TYPE_MOBILE, ni[TYPE_MOBILE].getType()); - assertEquals(TYPE_WIFI, ni[TYPE_WIFI].getType()); - - // don't know the return value - ni[TYPE_MOBILE].getSubtype(); - ni[TYPE_WIFI].getSubtype(); - - assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); - assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); - - // don't know the return value - ni[TYPE_MOBILE].getSubtypeName(); - ni[TYPE_WIFI].getSubtypeName(); - - if(ni[TYPE_MOBILE].isConnectedOrConnecting()) { - assertTrue(ni[TYPE_MOBILE].isAvailable()); - assertTrue(ni[TYPE_MOBILE].isConnected()); - assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); - assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); - ni[TYPE_MOBILE].getReason(); - ni[TYPE_MOBILE].getExtraInfo(); + for (NetworkInfo netInfo: ni) { + switch (netInfo.getType()) { + case TYPE_MOBILE: + assertNetworkInfo(netInfo, MOBILE_TYPE_NAME); + break; + case TYPE_WIFI: + assertNetworkInfo(netInfo, WIFI_TYPE_NAME); + break; + // TODO: Add BLUETOOTH_TETHER testing + default: + break; + } } + } - if(ni[TYPE_WIFI].isConnectedOrConnecting()) { - assertTrue(ni[TYPE_WIFI].isAvailable()); - assertTrue(ni[TYPE_WIFI].isConnected()); - assertEquals(State.CONNECTED, ni[TYPE_WIFI].getState()); - assertEquals(DetailedState.CONNECTED, ni[TYPE_WIFI].getDetailedState()); - ni[TYPE_WIFI].getReason(); - ni[TYPE_WIFI].getExtraInfo(); + private void assertNetworkInfo(NetworkInfo netInfo, String expectedTypeName) { + assertEquals(expectedTypeName, netInfo.getTypeName()); + if(netInfo.isConnectedOrConnecting()) { + assertTrue(netInfo.isAvailable()); + if (State.CONNECTED == netInfo.getState()) { + assertTrue(netInfo.isConnected()); + } + assertTrue(State.CONNECTING == netInfo.getState() + || State.CONNECTED == netInfo.getState()); + assertTrue(DetailedState.SCANNING == netInfo.getDetailedState() + || DetailedState.CONNECTING == netInfo.getDetailedState() + || DetailedState.AUTHENTICATING == netInfo.getDetailedState() + || DetailedState.CONNECTED == netInfo.getDetailedState()); } - - assertFalse(ni[TYPE_MOBILE].isRoaming()); - assertFalse(ni[TYPE_WIFI].isRoaming()); - - assertNotNull(ni[TYPE_MOBILE].toString()); - assertNotNull(ni[TYPE_WIFI].toString()); + assertNotNull(netInfo.toString()); } } From cf5f6fa087810445801f5da1223ed0c9b1e4bea3 Mon Sep 17 00:00:00 2001 From: Xia Wang Date: Fri, 4 Mar 2011 22:11:29 -0800 Subject: [PATCH 0064/1415] Backport from HC to Fix NetworkInfoTest Bug 4322307 Fixed some other assertions that didn't check for either CONNECTING or CONNECTED. Cleaned up some code and removed some extraneous checks. Original description: "Fix cts tests for Wi-Fi only devices. For Wi-Fi only device, startUsingNetworkFeature() returns Phone.APN_TYPE_NOT_AVAILABLE stopUsingNetworkFeature() return 1; In NetworkInfoTest: cm.getAllNetworkInfo() returns an array of NetworkInfo. But the index is not based on network type." Change-Id: I0b5e3d0cfe5fac18bca0a5ca2ce4cc73bc4dfa16 --- .../net/cts/ConnectivityManagerTest.java | 58 ++++--- .../src/android/net/cts/NetworkInfoTest.java | 156 ++++-------------- 2 files changed, 65 insertions(+), 149 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 12cc21e053..96a935b549 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -51,8 +51,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { private ConnectivityManager mCm; private WifiManager mWifiManager; private PackageManager mPackageManager; - // must include both mobile data + wifi - private static final int MIN_NUM_NETWORK_TYPES = 2; + + // device could have only one interface: data, wifi. + private static final int MIN_NUM_NETWORK_TYPES = 1; @Override protected void setUp() throws Exception { @@ -68,28 +69,27 @@ public class ConnectivityManagerTest extends AndroidTestCase { args = {int.class} ) public void testGetNetworkInfo() { - - // this test assumes that there are at least two network types. assertTrue(mCm.getAllNetworkInfo().length >= MIN_NUM_NETWORK_TYPES); - NetworkInfo ni = mCm.getNetworkInfo(1); - State state = ni.getState(); - assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() - && state.ordinal() >= State.CONNECTING.ordinal()); - DetailedState ds = ni.getDetailedState(); - assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() - && ds.ordinal() >= DetailedState.IDLE.ordinal()); - - ni = mCm.getNetworkInfo(0); - state = ni.getState(); - assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() - && state.ordinal() >= State.CONNECTING.ordinal()); - ds = ni.getDetailedState(); - assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() - && ds.ordinal() >= DetailedState.IDLE.ordinal()); - + NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI); + if (ni != null) { + State state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + } + ni = mCm.getNetworkInfo(TYPE_MOBILE); + if (ni != null) { + State state = ni.getState(); + assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + } ni = mCm.getNetworkInfo(-1); assertNull(ni); - } @TestTargets({ @@ -142,9 +142,21 @@ public class ConnectivityManagerTest extends AndroidTestCase { final String invalidateFeature = "invalidateFeature"; final String mmsFeature = "enableMMS"; final int failureCode = -1; + final int wifiOnlyStartFailureCode = 3; + final int wifiOnlyStopFailureCode = 1; - assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); + NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE); + if (ni != null) { + assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + } else { + assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, + invalidateFeature)); + } // Should return failure(-1) because MMS is not supported on WIFI. assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_WIFI, mmsFeature)); diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 99e8e15169..6800c43b0a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -16,16 +16,14 @@ package android.net.cts; +import dalvik.annotation.TestTargetClass; + import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; @TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { @@ -35,135 +33,41 @@ public class NetworkInfoTest extends AndroidTestCase { public static final String MOBILE_TYPE_NAME = "mobile"; public static final String WIFI_TYPE_NAME = "WIFI"; - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isConnectedOrConnecting", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setFailover", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isFailover", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isRoaming", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getType", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getSubtype", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getTypeName", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getSubtypeName", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setIsAvailable", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isAvailable", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isConnected", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getDetailedState", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getState", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getReason", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getExtraInfo", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "toString", - args = {} - ) - }) public void testAccessNetworkInfoProperties() { ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( Context.CONNECTIVITY_SERVICE); - NetworkInfo[] ni = cm.getAllNetworkInfo(); - assertTrue(ni.length >= 2); + assertTrue(ni.length >= 1); - assertFalse(ni[TYPE_MOBILE].isFailover()); - assertFalse(ni[TYPE_WIFI].isFailover()); - - // test environment:connect as TYPE_MOBILE, and connect to internet. - assertEquals(TYPE_MOBILE, ni[TYPE_MOBILE].getType()); - assertEquals(TYPE_WIFI, ni[TYPE_WIFI].getType()); - - // don't know the return value - ni[TYPE_MOBILE].getSubtype(); - ni[TYPE_WIFI].getSubtype(); - - assertEquals(MOBILE_TYPE_NAME, ni[TYPE_MOBILE].getTypeName()); - assertEquals(WIFI_TYPE_NAME, ni[TYPE_WIFI].getTypeName()); - - // don't know the return value - ni[TYPE_MOBILE].getSubtypeName(); - ni[TYPE_WIFI].getSubtypeName(); - - if(ni[TYPE_MOBILE].isConnectedOrConnecting()) { - assertTrue(ni[TYPE_MOBILE].isAvailable()); - assertTrue(ni[TYPE_MOBILE].isConnected()); - assertEquals(State.CONNECTED, ni[TYPE_MOBILE].getState()); - assertEquals(DetailedState.CONNECTED, ni[TYPE_MOBILE].getDetailedState()); - ni[TYPE_MOBILE].getReason(); - ni[TYPE_MOBILE].getExtraInfo(); + for (NetworkInfo netInfo: ni) { + switch (netInfo.getType()) { + case TYPE_MOBILE: + assertNetworkInfo(netInfo, MOBILE_TYPE_NAME); + break; + case TYPE_WIFI: + assertNetworkInfo(netInfo, WIFI_TYPE_NAME); + break; + // TODO: Add BLUETOOTH_TETHER testing + default: + break; + } } + } - if(ni[TYPE_WIFI].isConnectedOrConnecting()) { - assertTrue(ni[TYPE_WIFI].isAvailable()); - assertTrue(ni[TYPE_WIFI].isConnected()); - assertEquals(State.CONNECTED, ni[TYPE_WIFI].getState()); - assertEquals(DetailedState.CONNECTED, ni[TYPE_WIFI].getDetailedState()); - ni[TYPE_WIFI].getReason(); - ni[TYPE_WIFI].getExtraInfo(); + private void assertNetworkInfo(NetworkInfo netInfo, String expectedTypeName) { + assertEquals(expectedTypeName, netInfo.getTypeName()); + if(netInfo.isConnectedOrConnecting()) { + assertTrue(netInfo.isAvailable()); + if (State.CONNECTED == netInfo.getState()) { + assertTrue(netInfo.isConnected()); + } + assertTrue(State.CONNECTING == netInfo.getState() + || State.CONNECTED == netInfo.getState()); + assertTrue(DetailedState.SCANNING == netInfo.getDetailedState() + || DetailedState.CONNECTING == netInfo.getDetailedState() + || DetailedState.AUTHENTICATING == netInfo.getDetailedState() + || DetailedState.CONNECTED == netInfo.getDetailedState()); } - - assertFalse(ni[TYPE_MOBILE].isRoaming()); - assertFalse(ni[TYPE_WIFI].isRoaming()); - - assertNotNull(ni[TYPE_MOBILE].toString()); - assertNotNull(ni[TYPE_WIFI].toString()); + assertNotNull(netInfo.toString()); } } From 36b66397630f26068591341982edd8931f01a978 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Tue, 7 Jun 2011 13:53:47 -0700 Subject: [PATCH 0065/1415] Fix for NetworkInfo_DetailedStateTest Update the test to support a new enum value. Once the SignatureTest is fixed to check enums there shouldn't be any need for these enum checking tests. Change-Id: I85d75e86453c37a35f8be9e15d99dd47c690f6ea --- .../android/net/cts/NetworkInfo_DetailedStateTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 196e102dee..7261b167de 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -16,12 +16,13 @@ package android.net.cts; -import android.net.NetworkInfo.DetailedState; -import android.test.AndroidTestCase; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; +import android.net.NetworkInfo.DetailedState; +import android.test.AndroidTestCase; + @TestTargetClass(DetailedState.class) public class NetworkInfo_DetailedStateTest extends AndroidTestCase { @@ -52,7 +53,7 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { ) public void testValues() { DetailedState[] expected = DetailedState.values(); - assertEquals(10, expected.length); + assertEquals(11, expected.length); assertEquals(DetailedState.IDLE, expected[0]); assertEquals(DetailedState.SCANNING, expected[1]); assertEquals(DetailedState.CONNECTING, expected[2]); @@ -63,6 +64,7 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { assertEquals(DetailedState.DISCONNECTING, expected[7]); assertEquals(DetailedState.DISCONNECTED, expected[8]); assertEquals(DetailedState.FAILED, expected[9]); + assertEquals(DetailedState.FAILED, expected[10]); } } From 1ae190ce775f2a8669296acb066e6e06e6607831 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Wed, 22 Jun 2011 15:35:43 -0700 Subject: [PATCH 0066/1415] Fix NetworkInfo_DetailedStateTest Again Change-Id: I07d6a0ee21039859991a9594cd8b4e11ac4eecb6 --- .../net/src/android/net/cts/NetworkInfo_DetailedStateTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 7261b167de..6b9b985122 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -64,7 +64,7 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { assertEquals(DetailedState.DISCONNECTING, expected[7]); assertEquals(DetailedState.DISCONNECTED, expected[8]); assertEquals(DetailedState.FAILED, expected[9]); - assertEquals(DetailedState.FAILED, expected[10]); + assertEquals(DetailedState.BLOCKED, expected[10]); } } From a18b717579a33c3751990d5e98318333b08a057b Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Tue, 21 Jun 2011 14:32:38 -0700 Subject: [PATCH 0067/1415] Test for Apache HttpClient Bug 4554251 This test launches multiple downloads at once to check that the device can open up multiple sockets without OOMing. One test tries to use wifi if available and the other tries to use mobile by disconnecting wifi. The CtsTestServer was modified to handle responses in separate threads to test concurrent downloads. Change-Id: Ifa1a11f409c69c1ae3ce621bf0542e0be56b50e0 --- .../net/http/cts/ApacheHttpClientTest.java | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java diff --git a/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java b/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java new file mode 100644 index 0000000000..e4846fdec2 --- /dev/null +++ b/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2011 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.http.cts; + +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.NetworkInfo.State; +import android.net.Uri; +import android.net.wifi.WifiManager; +import android.test.AndroidTestCase; +import android.util.Log; +import android.webkit.cts.CtsTestServer; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class ApacheHttpClientTest extends AndroidTestCase { + + private static final String TAG = ApacheHttpClientTest.class.getSimpleName(); + + private static final int NUM_DOWNLOADS = 20; + + private static final int SMALL_DOWNLOAD_SIZE = 100 * 1024; + + private CtsTestServer mWebServer; + + private WifiManager mWifiManager; + + private ConnectivityManager mConnectivityManager; + + private boolean mHasTelephony; + + private boolean mHasWifi; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mWebServer = new CtsTestServer(mContext); + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mConnectivityManager = (ConnectivityManager) + mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + + PackageManager packageManager = mContext.getPackageManager(); + mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); + mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + mWebServer.shutdown(); + } + + public void testExecute_withMobile() throws Exception { + if (mHasTelephony) { + disconnectWifiToConnectToMobile(); + } + + downloadMultipleFiles(); + + if (mHasWifi) { + connectToWifi(); + } + } + + public void testExecute_withWifi() throws Exception { + if (mHasWifi) { + if (!mWifiManager.isWifiEnabled()) { + connectToWifi(); + } + downloadMultipleFiles(); + } + } + + private void downloadMultipleFiles() throws ClientProtocolException, IOException { + List responses = new ArrayList(); + for (int i = 0; i < NUM_DOWNLOADS; i++) { + HttpClient httpClient = new DefaultHttpClient(); + HttpGet request = new HttpGet(getSmallDownloadUrl(i).toString()); + HttpResponse response = httpClient.execute(request); + responses.add(response); + } + + for (int i = 0; i < NUM_DOWNLOADS; i++) { + assertDownloadResponse("Download " + i, SMALL_DOWNLOAD_SIZE, responses.get(i)); + } + } + + private Uri getSmallDownloadUrl(int index) { + return Uri.parse(mWebServer.getTestDownloadUrl("cts-small-download-" + index, + SMALL_DOWNLOAD_SIZE)); + } + + private void assertDownloadResponse(String message, int expectedNumBytes, HttpResponse response) + throws IllegalStateException, IOException { + byte[] buffer = new byte[4096]; + assertEquals(200, response.getStatusLine().getStatusCode()); + + InputStream stream = response.getEntity().getContent(); + int numBytes = 0; + while (true) { + int bytesRead = stream.read(buffer); + if (bytesRead < 0) { + break; + } else { + numBytes += bytesRead; + } + } + assertEquals(message, SMALL_DOWNLOAD_SIZE, numBytes); + } + + private void connectToWifi() throws InterruptedException { + if (!mWifiManager.isWifiEnabled()) { + ConnectivityActionReceiver receiver = + new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI, State.CONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + assertTrue(mWifiManager.setWifiEnabled(true)); + assertTrue("Wifi must be configured to connect to an access point for this test.", + receiver.waitForStateChange()); + + mContext.unregisterReceiver(receiver); + } + } + + private void disconnectWifiToConnectToMobile() throws InterruptedException { + if (mHasWifi && mWifiManager.isWifiEnabled()) { + ConnectivityActionReceiver connectMobileReceiver = + new ConnectivityActionReceiver(ConnectivityManager.TYPE_MOBILE, + State.CONNECTED); + ConnectivityActionReceiver disconnectWifiReceiver = + new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI, + State.DISCONNECTED); + IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(connectMobileReceiver, filter); + mContext.registerReceiver(disconnectWifiReceiver, filter); + + assertTrue(mWifiManager.setWifiEnabled(false)); + assertTrue(disconnectWifiReceiver.waitForStateChange()); + assertTrue(connectMobileReceiver.waitForStateChange()); + + mContext.unregisterReceiver(connectMobileReceiver); + mContext.unregisterReceiver(disconnectWifiReceiver); + } + } + + /** Receiver that captures the last connectivity change's network type and state. */ + private class ConnectivityActionReceiver extends BroadcastReceiver { + + private final CountDownLatch mReceiveLatch = new CountDownLatch(1); + + private final int mNetworkType; + + private final State mExpectedState; + + ConnectivityActionReceiver(int networkType, State expectedState) { + mNetworkType = networkType; + mExpectedState = expectedState; + } + + public void onReceive(Context context, Intent intent) { + NetworkInfo networkInfo = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); + int networkType = networkInfo.getType(); + State networkState = networkInfo.getState(); + Log.i(TAG, "Network type: " + networkType + " State: " + networkInfo.getState()); + if (networkType == mNetworkType && networkInfo.getState() == mExpectedState) { + mReceiveLatch.countDown(); + } + } + + public boolean waitForStateChange() throws InterruptedException { + return hasExpectedState() || mReceiveLatch.await(30, TimeUnit.SECONDS); + } + + private boolean hasExpectedState() { + return mExpectedState == mConnectivityManager.getNetworkInfo(mNetworkType).getState(); + } + } +} From 68f66bffff2299aab6103b8fb01854988430c147 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Wed, 17 Aug 2011 14:16:48 -0700 Subject: [PATCH 0068/1415] Fix for ConnectivityManagerTest Bug 5178134 Some network types can throw SecurityExceptions and depend on the build configuration. Don't fail the test if those throw exceptions. Change-Id: I5365f85280a348ef1777d05ce50b2dff17a1312f --- .../android/net/cts/ConnectivityManagerTest.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 3751b3cff0..2db0acbaae 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -35,6 +35,8 @@ import android.net.wifi.WifiManager; import android.test.AndroidTestCase; import android.util.Log; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -170,12 +172,20 @@ public class ConnectivityManagerTest extends AndroidTestCase { args = {int.class, int.class} ) public void testRequestRouteToHost() { + Set exceptionFreeTypes = new HashSet(); + exceptionFreeTypes.add(ConnectivityManager.TYPE_BLUETOOTH); + exceptionFreeTypes.add(ConnectivityManager.TYPE_ETHERNET); + exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE); + exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE_DUN); + exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE_HIPRI); + exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE_MMS); + exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE_SUPL); NetworkInfo[] ni = mCm.getAllNetworkInfo(); for (NetworkInfo n : ni) { - // make sure network is up (except WIFI due to always fail) - if (n.isConnected() && (n.getType() != TYPE_WIFI)) { - assertTrue(mCm.requestRouteToHost(n.getType(), HOST_ADDRESS)); + if (n.isConnected() && exceptionFreeTypes.contains(n.getType())) { + assertTrue("Network type: " + n.getType(), mCm.requestRouteToHost(n.getType(), + HOST_ADDRESS)); } } From 8670b1c23f1c074ce430213efc69f573410eabd3 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Wed, 5 Oct 2011 10:43:01 -0700 Subject: [PATCH 0069/1415] ListeningPortsTest: Make error message more useful. - Add UID of listener to error message. - Convert hex port number to decimal for easier reading by humans. Change-Id: I0b8edcf14ebd0c039b936055a265f4706558f9fe --- tests/cts/net/src/android/net/cts/ListeningPortsTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java index b6e6efbc71..5c1ba7cab8 100644 --- a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java +++ b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java @@ -118,13 +118,18 @@ public class ListeningPortsTest extends TestCase { String localAddress = fields[1]; String state = fields[3]; + String uid = fields[7]; assertTrue(procFilePath + " should have an IP address in the second column", isAddress(localAddress)); + String localIp = localAddress.split(":")[0]; + int localPort = Integer.parseInt(localAddress.split(":")[1], 16); + if (!isException(localAddress) && isPortListening(state, isTcp)) { throw new ListeningPortsAssertionError( - "Found port listening on " + localAddress + " in " + procFilePath); + "Found port listening on addr=" + localIp + ", port=" + + localPort + ", UID=" + uid + " in " + procFilePath); } } } catch (FileNotFoundException notFound) { From 19ad949076faee6697994776ecfbb8c037d8221b Mon Sep 17 00:00:00 2001 From: Steve Block Date: Wed, 5 Oct 2011 19:32:45 +0100 Subject: [PATCH 0070/1415] Add tests for SslError Bug: 5416594 Change-Id: Iebbc9d02088ea986246a8c7e9d4f9b2b84dd8116 --- .../android/net/http/cts/SslErrorTest.java | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100755 tests/cts/net/src/android/net/http/cts/SslErrorTest.java diff --git a/tests/cts/net/src/android/net/http/cts/SslErrorTest.java b/tests/cts/net/src/android/net/http/cts/SslErrorTest.java new file mode 100755 index 0000000000..d186f0e4b3 --- /dev/null +++ b/tests/cts/net/src/android/net/http/cts/SslErrorTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2011 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.http.cts; + +import android.net.http.SslCertificate; +import android.net.http.SslError; + +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +import java.util.Date; + +import junit.framework.TestCase; + +@TestTargetClass(SslError.class) +public class SslErrorTest extends TestCase { + private SslCertificate mCertificate; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mCertificate = new SslCertificate("foo", "bar", new Date(42), new Date(43)); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "hasError", + args = {int.class} + ) + public void testHasError() { + SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); + assertTrue(error.hasError(SslError.SSL_EXPIRED)); + assertFalse(error.hasError(SslError.SSL_UNTRUSTED)); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "addError", + args = {int.class} + ) + public void testAddError() { + SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); + assertFalse(error.hasError(SslError.SSL_UNTRUSTED)); + error.addError(SslError.SSL_UNTRUSTED); + assertTrue(error.hasError(SslError.SSL_UNTRUSTED)); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "addError", + args = {int.class} + ) + public void testAddErrorIgnoresInvalidValues() { + SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); + error.addError(42); + assertFalse(error.hasError(42)); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "SslError", + args = {int.class, SslCertificate.class} + ) + public void testConstructorIgnoresInvalidValues() { + SslError error = new SslError(42, mCertificate); + assertFalse(error.hasError(42)); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPrimaryError", + args = {} + ) + public void testGetPrimaryError() { + SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); + error.addError(SslError.SSL_UNTRUSTED); + assertEquals(error.getPrimaryError(), SslError.SSL_UNTRUSTED); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getPrimaryError", + args = {} + ) + public void testGetPrimaryErrorWithEmptySet() { + SslError error = new SslError(42, mCertificate); + assertEquals(error.getPrimaryError(), -1); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getUrl", + args = {} + ) + public void testGetUrl() { + SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate, "foo"); + assertEquals(error.getUrl(), "foo"); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getUrl", + args = {} + ) + public void testGetUrlWithDeprecatedConstructor() { + SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); + assertEquals(error.getUrl(), ""); + } +} From 0c292bb1176fb40a157b3166db35d5402726f3c6 Mon Sep 17 00:00:00 2001 From: android-htc-contribute Date: Wed, 5 Oct 2011 11:09:36 +0800 Subject: [PATCH 0071/1415] =?UTF-8?q?Data=20call=20establish=20time=20is?= =?UTF-8?q?=20related=20to=20network=20condition=20which=20can=E2=80=99t?= =?UTF-8?q?=20be=20controlled=20by=20the=20device.=20Extend=20the=20time?= =?UTF-8?q?=20limitation=20to=2030=20seconds=20to=20cover=20most=20of=20th?= =?UTF-8?q?e=20cases.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I522f7eb23baa9a652fb3fd633d200cd6307180c8 --- tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 96a935b549..77191cbd67 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -287,7 +287,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } public boolean waitForConnection() throws InterruptedException { - return mReceiveLatch.await(10, TimeUnit.SECONDS); + return mReceiveLatch.await(30, TimeUnit.SECONDS); } } } From 531debc2802064e0e242fc873a711787d6dcd762 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 25 Oct 2011 10:16:06 -0700 Subject: [PATCH 0072/1415] fix IPv6 loopback pattern In /proc/net/udp6 and /proc/net/tcp6, the addresses stored in that file are in network byte order. As a result, the IPv6 loopback address, ::1, is stored as 00000000000000000000000001000000 NOT 00000000000000000000000000000001 Bug: 5473686 Change-Id: I73098d52c981c48d82423c8ce99b6b20d11a5568 --- tests/cts/net/src/android/net/cts/ListeningPortsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java index 5c1ba7cab8..bcec0fe89e 100644 --- a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java +++ b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java @@ -46,7 +46,7 @@ public class ListeningPortsTest extends TestCase { EXCEPTION_PATTERNS.add("[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4 Loopback // IPv6 exceptions - EXCEPTION_PATTERNS.add("[0]{31}1:[0-9A-F]{4}"); // IPv6 Loopback + EXCEPTION_PATTERNS.add("[0]{25}1[0]{6}:[0-9A-F]{4}"); // IPv6 Loopback EXCEPTION_PATTERNS.add("[0]{16}[0]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion } From 3dc050e0eb93003721cfedca704f89908d07a24a Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 25 Oct 2011 10:16:06 -0700 Subject: [PATCH 0073/1415] fix IPv6 loopback pattern In /proc/net/udp6 and /proc/net/tcp6, the addresses stored in that file are in network byte order. As a result, the IPv6 loopback address, ::1, is stored as 00000000000000000000000001000000 NOT 00000000000000000000000000000001 Bug: 5473686 Change-Id: I73098d52c981c48d82423c8ce99b6b20d11a5568 --- tests/cts/net/src/android/net/cts/ListeningPortsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java index 5c1ba7cab8..bcec0fe89e 100644 --- a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java +++ b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java @@ -46,7 +46,7 @@ public class ListeningPortsTest extends TestCase { EXCEPTION_PATTERNS.add("[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4 Loopback // IPv6 exceptions - EXCEPTION_PATTERNS.add("[0]{31}1:[0-9A-F]{4}"); // IPv6 Loopback + EXCEPTION_PATTERNS.add("[0]{25}1[0]{6}:[0-9A-F]{4}"); // IPv6 Loopback EXCEPTION_PATTERNS.add("[0]{16}[0]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion } From 52cc91ff4585faed0d1bc0c6783d5b3a9268da5e Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 25 Oct 2011 10:16:06 -0700 Subject: [PATCH 0074/1415] fix IPv6 loopback pattern In /proc/net/udp6 and /proc/net/tcp6, the addresses stored in that file are in network byte order. As a result, the IPv6 loopback address, ::1, is stored as 00000000000000000000000001000000 NOT 00000000000000000000000000000001 Bug: 5473686 Change-Id: I73098d52c981c48d82423c8ce99b6b20d11a5568 --- tests/cts/net/src/android/net/cts/ListeningPortsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java index 5c1ba7cab8..bcec0fe89e 100644 --- a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java +++ b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java @@ -46,7 +46,7 @@ public class ListeningPortsTest extends TestCase { EXCEPTION_PATTERNS.add("[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4 Loopback // IPv6 exceptions - EXCEPTION_PATTERNS.add("[0]{31}1:[0-9A-F]{4}"); // IPv6 Loopback + EXCEPTION_PATTERNS.add("[0]{25}1[0]{6}:[0-9A-F]{4}"); // IPv6 Loopback EXCEPTION_PATTERNS.add("[0]{16}[0]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion } From fff8fb1b9f869c94dfbc14012caa13dbd7743309 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 1 Nov 2011 16:53:21 -0700 Subject: [PATCH 0075/1415] Move file, change loopback handling, docs. Move the ListeningPortsTest from android.net.cts to android.security.cts, to better indicate that this is a security related test. Start triggering test failures when a process is bound to the loopback interface. In those cases, it's always better to use a UNIX domain socket instead of a locally bound IP socket. UNIX domain sockets can be protected with unix filesystem permissions, or getsockopt(SO_PEERCRED) can be used to indicate who is on the other end of the socket. Drastically fix the documentation to explain why this test is present. Modify the IP addresses and port numbers to be more human readable. Change-Id: Id83aadd1455279a1a2d3fb4fb1915af558355aca --- .../android/net/cts/ListeningPortsTest.java | 172 ------------------ 1 file changed, 172 deletions(-) delete mode 100644 tests/cts/net/src/android/net/cts/ListeningPortsTest.java diff --git a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java b/tests/cts/net/src/android/net/cts/ListeningPortsTest.java deleted file mode 100644 index bcec0fe89e..0000000000 --- a/tests/cts/net/src/android/net/cts/ListeningPortsTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2010 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 java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.List; -import java.util.Scanner; -import java.util.regex.Pattern; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -public class ListeningPortsTest extends TestCase { - - /** Address patterns used to check whether we're checking the right column in /proc/net. */ - private static final List ADDRESS_PATTERNS = new ArrayList(2); - - static { - ADDRESS_PATTERNS.add("[0-9A-F]{8}:[0-9A-F]{4}"); - ADDRESS_PATTERNS.add("[0-9A-F]{32}:[0-9A-F]{4}"); - } - - /** Ports that are allowed to be listening on the emulator. */ - private static final List EXCEPTION_PATTERNS = new ArrayList(6); - - static { - // IPv4 exceptions - EXCEPTION_PATTERNS.add("00000000:15B3"); // 0.0.0.0:5555 - emulator port - EXCEPTION_PATTERNS.add("0F02000A:15B3"); // 10.0.2.15:5555 - net forwarding for emulator - EXCEPTION_PATTERNS.add("[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4 Loopback - - // IPv6 exceptions - EXCEPTION_PATTERNS.add("[0]{25}1[0]{6}:[0-9A-F]{4}"); // IPv6 Loopback - EXCEPTION_PATTERNS.add("[0]{16}[0]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion - EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion - } - - public void testNoListeningTcpPorts() { - assertNoListeningPorts("/proc/net/tcp", true); - } - - public void testNoListeningTcp6Ports() { - assertNoListeningPorts("/proc/net/tcp6", true); - } - - public void testNoListeningUdpPorts() throws Exception { - assertNoListeningUdpPorts("/proc/net/udp"); - } - - public void testNoListeningUdp6Ports() throws Exception { - assertNoListeningUdpPorts("/proc/net/udp6"); - } - - private static final int RETRIES_MAX = 6; - - /** - * UDP tests can be flaky due to DNS lookups. Compensate. - */ - private static void assertNoListeningUdpPorts(String procFilePath) throws Exception { - for (int i = 0; i < RETRIES_MAX; i++) { - try { - assertNoListeningPorts(procFilePath, false); - return; - } catch (ListeningPortsAssertionError e) { - if (i == RETRIES_MAX - 1) { - throw e; - } - Thread.sleep(2 * 1000 * i); - } - } - throw new IllegalStateException("unreachable"); - } - - private static void assertNoListeningPorts(String procFilePath, boolean isTcp) { - - /* - * Sample output of "cat /proc/net/tcp" on emulator: - * - * sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid ... - * 0: 0100007F:13AD 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 ... - * 1: 00000000:15B3 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 ... - * 2: 0F02000A:15B3 0202000A:CE8A 01 00000000:00000000 00:00000000 00000000 0 ... - * - */ - - File procFile = new File(procFilePath); - Scanner scanner = null; - try { - scanner = new Scanner(procFile); - while (scanner.hasNextLine()) { - String line = scanner.nextLine().trim(); - - // Skip column headers - if (line.startsWith("sl")) { - continue; - } - - String[] fields = line.split("\\s+"); - final int expectedNumColumns = 12; - assertTrue(procFilePath + " should have at least " + expectedNumColumns - + " columns of output " + fields, fields.length >= expectedNumColumns); - - String localAddress = fields[1]; - String state = fields[3]; - String uid = fields[7]; - - assertTrue(procFilePath + " should have an IP address in the second column", - isAddress(localAddress)); - - String localIp = localAddress.split(":")[0]; - int localPort = Integer.parseInt(localAddress.split(":")[1], 16); - - if (!isException(localAddress) && isPortListening(state, isTcp)) { - throw new ListeningPortsAssertionError( - "Found port listening on addr=" + localIp + ", port=" - + localPort + ", UID=" + uid + " in " + procFilePath); - } - } - } catch (FileNotFoundException notFound) { - fail("Could not open file " + procFilePath + " to check for listening ports."); - } finally { - if (scanner != null) { - scanner.close(); - } - } - } - - private static boolean isAddress(String localAddress) { - return isPatternMatch(ADDRESS_PATTERNS, localAddress); - } - - private static boolean isException(String localAddress) { - return isPatternMatch(EXCEPTION_PATTERNS, localAddress); - } - - private static boolean isPatternMatch(List patterns, String input) { - for (String pattern : patterns) { - if (Pattern.matches(pattern, input)) { - return true; - } - } - return false; - } - - private static boolean isPortListening(String state, boolean isTcp) { - // 0A = TCP_LISTEN from include/net/tcp_states.h - String listeningState = isTcp ? "0A" : "07"; - return listeningState.equals(state); - } - - private static class ListeningPortsAssertionError extends AssertionFailedError { - private ListeningPortsAssertionError(String msg) { - super(msg); - } - } -} From 59be169eb952ef3322d344ab4ca00ca6544a1132 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Wed, 28 Dec 2011 15:46:57 -0800 Subject: [PATCH 0076/1415] Move Test XML Generation from buildCts.py buildCts.py was the central script that generated all the test package XMLs each time CTS was built. This had a couple problems: 1. All the XML files for ~40 packages needed to be made every time CTS was made. Even if those packages were not touched at all. 2. Couldn't shard the XML generation process across the available cores on a machine. A pool was added to the python script, but it was set to a fixed number. This change moves the test XML generation into a smaller Java program called "cts-java-scanner" and the doclet it relies upon to scan the Java files into "cts-java-scanner-doclet.jar". The output of the scanner like "cts-native-scanner" for native EXEs is piped to the existing cts-xml-generator to produce the test XMLs. New CTS specific rules replace the standard BUILD_PACKAGE and BUILD_HOST_JAVA_LIBRARY. They just add extra rules for the package XML. The BUILD_CTS_PACKAGE rule also adds a rule for copying the "package.apk" to something more like "CtsFooTestCases.apk" to the test case out directory. All the apks, exes, and xmls are now thrown into a "cts-testcases" directory, before they are copied to the final CTS distribution. This change should prevent rebuilding the XMLs unnecessarily and make rebuilding CTS quicker while writing tests. There are still the libcore tests that are always rebuilt, but they can be adapted to fit into this model someday... Change-Id: I52a916aa37fd679057e2709bb0ccec694c9fca01 --- tests/cts/net/Android.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 1fd9ba0c40..1f1e38771d 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -32,5 +32,4 @@ LOCAL_INSTRUMENTATION_FOR := CtsTestStubs # uncomment when dalvik.annotation.Test* are removed or part of SDK #LOCAL_SDK_VERSION := current -include $(BUILD_PACKAGE) - +include $(BUILD_CTS_PACKAGE) From beb5a527e371dceedb16ae1bdc7378889c1897df Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Thu, 12 Jan 2012 14:40:44 -0800 Subject: [PATCH 0077/1415] CTS tests for Intent.normalize...() API's Change-Id: I5b21028dd29f5bd1565c2ca2f65636ca9aa901d0 --- tests/cts/net/src/android/net/cts/UriTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 067ce52372..0d38f6a1d4 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -724,4 +724,12 @@ public class UriTest extends AndroidTestCase { assertTrue(uri.isHierarchical()); assertEquals(uriString, uri.toString()); } + + public void testNormalize() { + assertEquals(Uri.parse(""), Uri.parse("").normalize()); + assertEquals(Uri.parse("http://www.android.com"), + Uri.parse("http://www.android.com").normalize()); + assertEquals(Uri.parse("http://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c"), + Uri.parse("HTTP://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c").normalize()); + } } From 08acbf9245c28369206701537a9916317e1e964b Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Wed, 25 Jan 2012 18:28:41 -0800 Subject: [PATCH 0078/1415] Remove Test Annotations These annotations are not being parsed by any program. Also they are distracting to readers and are painful to maintain. Furthermore, they prevent us from adding the LOCAL_SDK_CURRENT clause to Makefiles which is useful to detect and stop us from using private APIs. Change-Id: Id93b3a80c73df808c342e489f1434261f288204c --- .../net/cts/ConnectivityManagerTest.java | 57 ---- .../src/android/net/cts/CredentialsTest.java | 27 -- .../net/src/android/net/cts/DhcpInfoTest.java | 16 - .../net/cts/LocalServerSocketTest.java | 40 --- .../net/cts/LocalSocketAddressTest.java | 31 -- .../cts/LocalSocketAddress_NamespaceTest.java | 16 - .../src/android/net/cts/LocalSocketTest.java | 171 ---------- .../net/src/android/net/cts/MailToTest.java | 55 --- .../src/android/net/cts/NetworkInfoTest.java | 2 - .../cts/NetworkInfo_DetailedStateTest.java | 16 - .../net/cts/NetworkInfo_StateTest.java | 16 - .../net/src/android/net/cts/ProxyTest.java | 22 -- .../cts/SSLCertificateSocketFactoryTest.java | 71 ---- .../src/android/net/cts/TrafficStatsTest.java | 23 -- .../cts/net/src/android/net/cts/UriTest.java | 319 ------------------ .../src/android/net/cts/Uri_BuilderTest.java | 109 ------ .../net/cts/UrlQuerySanitizerTest.java | 172 ---------- ...er_IllegalCharacterValueSanitizerTest.java | 19 -- ...QuerySanitizer_ParameterValuePairTest.java | 10 - .../net/http/cts/SslCertificateTest.java | 66 ---- .../http/cts/SslCertificate_DNameTest.java | 37 -- .../android/net/http/cts/SslErrorTest.java | 44 --- .../android/net/wifi/cts/ScanResultTest.java | 9 - .../net/wifi/cts/SupplicantStateTest.java | 12 - .../net/wifi/cts/WifiConfigurationTest.java | 17 - .../android/net/wifi/cts/WifiInfoTest.java | 62 ---- .../android/net/wifi/cts/WifiManagerTest.java | 143 -------- .../wifi/cts/WifiManager_WifiLockTest.java | 37 -- 28 files changed, 1619 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index cd80be2797..99d2e43182 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,11 +16,6 @@ package android.net.cts; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; -import dalvik.annotation.ToBeFixed; import android.content.BroadcastReceiver; import android.content.Context; @@ -40,7 +35,6 @@ import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -@TestTargetClass(ConnectivityManager.class) public class ConnectivityManagerTest extends AndroidTestCase { private static final String TAG = ConnectivityManagerTest.class.getSimpleName(); @@ -66,11 +60,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { mPackageManager = getContext().getPackageManager(); } - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getNetworkInfo", - args = {int.class} - ) public void testGetNetworkInfo() { assertTrue(mCm.getAllNetworkInfo().length >= MIN_NUM_NETWORK_TYPES); NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI); @@ -95,18 +84,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertNull(ni); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isNetworkTypeValid", - args = {int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getAllNetworkInfo", - args = {} - ) - }) public void testIsNetworkTypeValid() { NetworkInfo[] ni = mCm.getAllNetworkInfo(); @@ -117,29 +94,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertFalse(ConnectivityManager.isNetworkTypeValid(-1)); } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test getAllNetworkInfo().", - method = "getAllNetworkInfo", - args = {} - ) public void testGetAllNetworkInfo() { NetworkInfo[] ni = mCm.getAllNetworkInfo(); assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "startUsingNetworkFeature", - args = {int.class, java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "stopUsingNetworkFeature", - args = {int.class, java.lang.String.class} - ) - }) public void testStartUsingNetworkFeature() { final String invalidateFeature = "invalidateFeature"; @@ -166,11 +125,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI, mmsFeature)); } - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "requestRouteToHost", - args = {int.class, int.class} - ) public void testRequestRouteToHost() { Set exceptionFreeTypes = new HashSet(); exceptionFreeTypes.add(ConnectivityManager.TYPE_BLUETOOTH); @@ -192,12 +146,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS)); } - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getActiveNetworkInfo", - args = {} - ) - @ToBeFixed(bug="1695243", explanation="No Javadoc") public void testGetActiveNetworkInfo() { NetworkInfo ni = mCm.getActiveNetworkInfo(); @@ -206,11 +154,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } - @TestTargetNew( - level = TestLevel.SUFFICIENT, - method = "getBackgroundDataSetting", - args = {} - ) public void testTest() { mCm.getBackgroundDataSetting(); } diff --git a/tests/cts/net/src/android/net/cts/CredentialsTest.java b/tests/cts/net/src/android/net/cts/CredentialsTest.java index 6cf8c2351e..91c3621eab 100644 --- a/tests/cts/net/src/android/net/cts/CredentialsTest.java +++ b/tests/cts/net/src/android/net/cts/CredentialsTest.java @@ -18,36 +18,9 @@ package android.net.cts; import android.net.Credentials; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargetClass; -@TestTargetClass(android.net.Credentials.class) public class CredentialsTest extends AndroidTestCase { - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "Credentials", - args = {int.class, int.class, int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getGid", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getPid", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getUid", - args = {} - ) - }) public void testCredentials() { // new the Credentials instance // Test with zero inputs diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java index 97bd27a970..085fdd9132 100644 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -18,29 +18,13 @@ package android.net.cts; import android.net.DhcpInfo; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -@TestTargetClass(DhcpInfo.class) public class DhcpInfoTest extends AndroidTestCase { - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test DhcpInfo's constructor.", - method = "DhcpInfo", - args = {} - ) public void testConstructor() { new DhcpInfo(); } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test toString function.", - method = "toString", - args = {} - ) public void testToString() { String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 dns1 0.0.0.0 " + "dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index 21c7d5e299..dc7be1ff4e 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -22,49 +22,9 @@ import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; -import dalvik.annotation.ToBeFixed; -@TestTargetClass(LocalServerSocket.class) public class LocalServerSocketTest extends AndroidTestCase { - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "accept", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "close", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getFileDescriptor", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getLocalSocketAddress", - args = {} - ), - @TestTargetNew( - level = TestLevel.NOT_FEASIBLE, - method = "LocalServerSocket", - args = {java.io.FileDescriptor.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "LocalServerSocket", - args = {java.lang.String.class} - ) - }) - @ToBeFixed(bug = "1520987", explanation = "Cannot find a proper FileDescriptor for " + - "android.net.LocalServerSocket constructor") public void testLocalServerSocket() throws IOException { LocalServerSocket localServerSocket = new LocalServerSocket(LocalSocketTest.mSockAddr); assertNotNull(localServerSocket.getLocalSocketAddress()); diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java index e3141d57e5..6ef003b26f 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java @@ -19,40 +19,9 @@ package android.net.cts; import android.net.LocalSocketAddress; import android.net.LocalSocketAddress.Namespace; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargetClass; -@TestTargetClass(LocalSocketAddress.class) public class LocalSocketAddressTest extends AndroidTestCase { - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test LocalSocketAddress", - method = "LocalSocketAddress", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test LocalSocketAddress", - method = "LocalSocketAddress", - args = {java.lang.String.class, android.net.LocalSocketAddress.Namespace.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test LocalSocketAddress", - method = "getName", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test LocalSocketAddress", - method = "getNamespace", - args = {} - ) - }) public void testNewLocalSocketAddressWithDefaultNamespace() { // default namespace LocalSocketAddress localSocketAddress = new LocalSocketAddress("name"); diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java index fc9de5b14c..97dfa435fa 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java @@ -18,31 +18,15 @@ package android.net.cts; import android.net.LocalSocketAddress.Namespace; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -@TestTargetClass(Namespace.class) public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test valueOf(String name).", - method = "valueOf", - args = {java.lang.String.class} - ) public void testValueOf() { assertEquals(Namespace.ABSTRACT, Namespace.valueOf("ABSTRACT")); assertEquals(Namespace.RESERVED, Namespace.valueOf("RESERVED")); assertEquals(Namespace.FILESYSTEM, Namespace.valueOf("FILESYSTEM")); } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test values().", - method = "values", - args = {} - ) public void testValues() { Namespace[] expected = Namespace.values(); assertEquals(Namespace.ABSTRACT, expected[0]); diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 8e3cd6714b..0a4bc0d4f2 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -25,89 +25,10 @@ import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.test.AndroidTestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargetClass; -@TestTargetClass(LocalSocket.class) public class LocalSocketTest extends AndroidTestCase{ public final static String mSockAddr = "com.android.net.LocalSocketTest"; - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "LocalSocket", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "close", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "connect", - args = {android.net.LocalSocketAddress.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "getAncillaryFileDescriptors", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "getFileDescriptor", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "getInputStream", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "getOutputStream", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "getPeerCredentials", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "isConnected", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "setFileDescriptorsForSend", - args = {java.io.FileDescriptor[].class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "shutdownInput", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test core functions of LocalSocket", - method = "shutdownOutput", - args = {} - ) - }) public void testLocalConnections() throws IOException{ // create client and server socket LocalServerSocket localServerSocket = new LocalServerSocket(mSockAddr); @@ -190,98 +111,6 @@ public class LocalSocketTest extends AndroidTestCase{ } } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "bind", - args = {android.net.LocalSocketAddress.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "connect", - args = {android.net.LocalSocketAddress.class, int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "getLocalSocketAddress", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "getReceiveBufferSize", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "getRemoteSocketAddress", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "getSendBufferSize", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "getSoTimeout", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "isBound", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "isClosed", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "isInputShutdown", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "isOutputShutdown", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "setReceiveBufferSize", - args = {int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "setSendBufferSize", - args = {int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "setSoTimeout", - args = {int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "test secondary functions of LocalSocket", - method = "toString", - args = {} - ) - }) public void testAccessors() throws IOException{ LocalSocket socket = new LocalSocket(); LocalSocketAddress addr = new LocalSocketAddress("secondary"); diff --git a/tests/cts/net/src/android/net/cts/MailToTest.java b/tests/cts/net/src/android/net/cts/MailToTest.java index 01ede1aea0..e454d20628 100644 --- a/tests/cts/net/src/android/net/cts/MailToTest.java +++ b/tests/cts/net/src/android/net/cts/MailToTest.java @@ -19,12 +19,7 @@ package android.net.cts; import android.net.MailTo; import android.test.AndroidTestCase; import android.util.Log; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargetClass; -@TestTargetClass(MailTo.class) public class MailToTest extends AndroidTestCase { private static final String MAILTOURI_1 = "mailto:chris@example.com"; private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue"; @@ -42,56 +37,6 @@ public class MailToTest extends AndroidTestCase { super.setUp(); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test parse mailto URI.", - method = "parse", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test parse mailto URI.", - method = "isMailTo", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test parse mailto URI.", - method = "getTo", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test parse mailto URI.", - method = "getSubject", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test parse mailto URI.", - method = "getBody", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test parse mailto URI.", - method = "getCc", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test parse mailto URI.", - method = "toString", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test parse mailto URI.", - method = "getHeaders", - args = {} - ) - }) public void testParseMailToURI() { assertFalse(MailTo.isMailTo(null)); assertFalse(MailTo.isMailTo("")); diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index 6800c43b0a..e53614b99a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -16,7 +16,6 @@ package android.net.cts; -import dalvik.annotation.TestTargetClass; import android.content.Context; import android.net.ConnectivityManager; @@ -25,7 +24,6 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.test.AndroidTestCase; -@TestTargetClass(NetworkInfo.class) public class NetworkInfoTest extends AndroidTestCase { public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 6b9b985122..3eeb1c5c84 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -16,22 +16,12 @@ package android.net.cts; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; import android.net.NetworkInfo.DetailedState; import android.test.AndroidTestCase; -@TestTargetClass(DetailedState.class) public class NetworkInfo_DetailedStateTest extends AndroidTestCase { - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test valueOf(String name).", - method = "valueOf", - args = {java.lang.String.class} - ) public void testValueOf() { assertEquals(DetailedState.AUTHENTICATING, DetailedState.valueOf("AUTHENTICATING")); assertEquals(DetailedState.CONNECTED, DetailedState.valueOf("CONNECTED")); @@ -45,12 +35,6 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { assertEquals(DetailedState.SUSPENDED, DetailedState.valueOf("SUSPENDED")); } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test values().", - method = "values", - args = {} - ) public void testValues() { DetailedState[] expected = DetailedState.values(); assertEquals(11, expected.length); diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java index 1a51acd091..5303ef1281 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -18,19 +18,9 @@ package android.net.cts; import android.net.NetworkInfo.State; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -@TestTargetClass(State.class) public class NetworkInfo_StateTest extends AndroidTestCase { - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test valueOf(String name).", - method = "valueOf", - args = {java.lang.String.class} - ) public void testValueOf() { assertEquals(State.CONNECTED, State.valueOf("CONNECTED")); assertEquals(State.CONNECTING, State.valueOf("CONNECTING")); @@ -40,12 +30,6 @@ public class NetworkInfo_StateTest extends AndroidTestCase { assertEquals(State.UNKNOWN, State.valueOf("UNKNOWN")); } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test values().", - method = "values", - args = {} - ) public void testValues() { State[] expected = State.values(); assertEquals(6, expected.length); diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java index 0c0586ea84..467d12f9dc 100644 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -16,38 +16,16 @@ package android.net.cts; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; import android.net.Proxy; import android.test.AndroidTestCase; -@TestTargetClass(Proxy.class) public class ProxyTest extends AndroidTestCase { - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "Proxy", - args = {} - ) public void testConstructor() { new Proxy(); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getDefaultPort", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getDefaultHost", - args = {} - ) - }) public void testAccessProperties() { final int minValidPort = 0; final int maxValidPort = 65535; diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index f125550a8b..70ab54d3cd 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -27,13 +27,7 @@ import android.net.SSLCertificateSocketFactory; import android.test.AndroidTestCase; import dalvik.annotation.BrokenTest; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; -import dalvik.annotation.ToBeFixed; -@TestTargetClass(SSLCertificateSocketFactory.class) public class SSLCertificateSocketFactoryTest extends AndroidTestCase { private SSLCertificateSocketFactory mFactory; private int mTimeout; @@ -45,24 +39,6 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { mFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(mTimeout); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getSupportedCipherSuites", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getDefault", - args = {int.class} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getDefaultCipherSuites", - args = {} - ) - }) - @ToBeFixed(bug="1695243", explanation="Android API javadocs are incomplete") public void testAccessProperties() throws Exception { mFactory.getSupportedCipherSuites(); mFactory.getDefaultCipherSuites(); @@ -70,38 +46,6 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { assertNotNull(sf); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createSocket", - args = {java.net.InetAddress.class, int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createSocket", - args = {java.net.Socket.class, java.lang.String.class, int.class, boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createSocket", - args = {java.lang.String.class, int.class} - ), - @TestTargetNew( - level = TestLevel.NOT_FEASIBLE, - method = "createSocket", - args = {java.lang.String.class, int.class, java.net.InetAddress.class, int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createSocket", - args = {java.net.InetAddress.class, int.class, java.net.InetAddress.class, int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "SSLCertificateSocketFactory", - args = {int.class} - ) - }) public void testCreateSocket() throws Exception { new SSLCertificateSocketFactory(100); int port = 443; @@ -153,11 +97,6 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { * * NOTE: Test will fail if external server is not available. */ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createSocket", - args = {String.class, int.class} - ) public void test_createSocket_simple() throws Exception { try { mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT); @@ -174,11 +113,6 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { * * NOTE: Test will fail if external server is not available. */ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createSocket", - args = {Socket.class, String.class, int.class, boolean.class} - ) public void test_createSocket_wrapping() throws Exception { try { Socket underlying = new Socket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT); @@ -197,11 +131,6 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { * * NOTE: Test will fail if external server is not available. */ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createSocket", - args = {String.class, int.class, InetAddress.class, int.class} - ) public void test_createSocket_bind() throws Exception { try { mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT, null, 0); diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 183f891637..a5bbd9886a 100644 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -16,10 +16,6 @@ package android.net.cts; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; import android.net.TrafficStats; import android.os.Process; @@ -31,14 +27,7 @@ import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; -@TestTargetClass(TrafficStats.class) public class TrafficStatsTest extends AndroidTestCase { - @TestTargets({ - @TestTargetNew(level = TestLevel.SUFFICIENT, method = "getMobileTxPackets"), - @TestTargetNew(level = TestLevel.SUFFICIENT, method = "getMobileRxPackets"), - @TestTargetNew(level = TestLevel.SUFFICIENT, method = "getMobileTxBytes"), - @TestTargetNew(level = TestLevel.SUFFICIENT, method = "getMobileRxBytes") - }) public void testGetMobileStats() { // We can't assume a mobile network is even present in this test, so // we simply assert that a valid value is returned. @@ -53,18 +42,6 @@ public class TrafficStatsTest extends AndroidTestCase { TrafficStats.getMobileRxBytes() >= 0); } - @TestTargets({ - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileTxPackets"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileRxPackets"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileTxBytes"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getMobileRxBytes"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalTxPackets"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalRxPackets"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalTxBytes"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getTotalRxBytes"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getUidTxBytes"), - @TestTargetNew(level = TestLevel.PARTIAL_COMPLETE, method = "getUidRxBytes") - }) public void testTrafficStatsForLocalhost() throws IOException { long mobileTxPacketsBefore = TrafficStats.getTotalTxPackets(); long mobileRxPacketsBefore = TrafficStats.getTotalRxPackets(); diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 0d38f6a1d4..3bf8049b0a 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -16,10 +16,6 @@ package android.net.cts; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; import android.content.ContentUris; import android.net.Uri; import android.os.Parcel; @@ -27,14 +23,7 @@ import android.test.AndroidTestCase; import java.io.File; import java.util.Arrays; -@TestTargetClass(Uri.class) public class UriTest extends AndroidTestCase { - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test write to and read frome parcel.", - method = "writeToParcel", - args = {android.os.Parcel.class, android.net.Uri.class} - ) public void testParcelling() { parcelAndUnparcel(Uri.parse("foo:bob%20lee")); parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment")); @@ -60,12 +49,6 @@ public class UriTest extends AndroidTestCase { assertEquals(u, Uri.CREATOR.createFromParcel(p)); } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test buildUpon", - method = "buildUpon", - args = {} - ) public void testBuildUpon() { Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build(); assertEquals("robert", u.getScheme()); @@ -92,80 +75,6 @@ public class UriTest extends AndroidTestCase { assertEquals("foo", b.getScheme()); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getSchemeSpecificPart", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getEncodedSchemeSpecificPart", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getEncodedPath", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getPath", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getEncodedQuery", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getQuery", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getEncodedFragment", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getHost", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getPort", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getUserInfo", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "getEncodedUserInfo", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test string uri.", - method = "parse", - args = {java.lang.String.class} - ) - }) public void testStringUri() { assertEquals("bob lee", Uri.parse("foo:bob%20lee").getSchemeSpecificPart()); @@ -202,12 +111,6 @@ public class UriTest extends AndroidTestCase { assertEquals(-1, uri.getPort()); } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test compareTo", - method = "compareTo", - args = {android.net.Uri.class} - ) public void testCompareTo() { Uri a = Uri.parse("foo:a"); Uri b = Uri.parse("foo:b"); @@ -218,20 +121,6 @@ public class UriTest extends AndroidTestCase { assertEquals(0, b.compareTo(b2)); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test equals and hashCode.", - method = "equals", - args = {java.lang.Object.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test equals and hashCode.", - method = "hashCode", - args = {} - ) - }) public void testEqualsAndHashCode() { Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee"); @@ -260,26 +149,6 @@ public class UriTest extends AndroidTestCase { assertEquals(b.hashCode(), c.hashCode()); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test encode and decode.", - method = "encode", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test encode and decode.", - method = "encode", - args = {java.lang.String.class, java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test encode and decode.", - method = "decode", - args = {java.lang.String.class} - ) - }) public void testEncodeAndDecode() { String encoded = Uri.encode("Bob:/", "/"); assertEquals(-1, encoded.indexOf(':')); @@ -300,12 +169,6 @@ public class UriTest extends AndroidTestCase { assertEquals(s, Uri.decode(Uri.encode(s, null))); } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test fromFile.", - method = "fromFile", - args = {java.io.File.class} - ) public void testFromFile() { File f = new File("/tmp/bob"); Uri uri = Uri.fromFile(f); @@ -316,20 +179,6 @@ public class UriTest extends AndroidTestCase { } catch (NullPointerException e) {} } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test get query parameters.", - method = "getQueryParameter", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test get query parameters.", - method = "getQueryParameters", - args = {java.lang.String.class} - ) - }) public void testQueryParameters() { Uri uri = Uri.parse("content://user"); assertEquals(null, uri.getQueryParameter("a")); @@ -345,26 +194,6 @@ public class UriTest extends AndroidTestCase { assertEquals("d", uri.getQueryParameter("c")); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "getPathSegments", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "getLastPathSegment", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "withAppendedPath", - args = {android.net.Uri.class, java.lang.String.class} - ) - }) public void testPathOperations() { Uri uri = Uri.parse("content://user/a/b"); @@ -402,62 +231,6 @@ public class UriTest extends AndroidTestCase { assertEquals("/a/b/c", withC.getPath()); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "isAbsolute", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "isOpaque", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "isRelative", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "getHost", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "getPort", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "getScheme", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "getSchemeSpecificPart", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "fromParts", - args = {java.lang.String.class, java.lang.String.class, java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test opaque uri.", - method = "toString", - args = {} - ) - }) public void testOpaqueUri() { Uri uri = Uri.parse("mailto:nobody"); testOpaqueUri(uri); @@ -512,98 +285,6 @@ public class UriTest extends AndroidTestCase { assertEquals("mailto:nobody#top", withFragment.toString()); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getAuthority", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getScheme", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getEncodedAuthority", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getPath", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getEncodedPath", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getQuery", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getEncodedQuery", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getFragment", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getEncodedFragment", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "getSchemeSpecificPart", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "isAbsolute", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "isHierarchical", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "isOpaque", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "isRelative", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test hierarchical uris.", - method = "toString", - args = {} - ) - }) public void testHierarchicalUris() { testHierarchical("http", "google.com", "/p1/p2", "query", "fragment"); testHierarchical("file", null, "/p1/p2", null, null); diff --git a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java index 66bdb074b0..4088d822cf 100644 --- a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java +++ b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java @@ -17,119 +17,10 @@ package android.net.cts; import junit.framework.TestCase; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargetClass; import android.net.Uri.Builder; import android.net.Uri; -@TestTargetClass(Uri.Builder.class) public class Uri_BuilderTest extends TestCase { - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "Uri.Builder", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "build", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "scheme", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "authority", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "path", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "query", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "opaquePart", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "fragment", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "appendEncodedPath", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "appendPath", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "appendQueryParameter", - args = {java.lang.String.class, java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "encodedAuthority", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "encodedFragment", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "encodedPath", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "encodedQuery", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "encodedOpaquePart", - args = {java.lang.String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test Builder operations.", - method = "toString", - args = {} - ) - }) public void testBuilderOperations() { Uri uri = Uri.parse("http://google.com/p1?query#fragment"); Builder builder = uri.buildUpon(); diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java index 0dd5db1886..7076ea2990 100644 --- a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -23,12 +23,7 @@ import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; import android.net.UrlQuerySanitizer.ParameterValuePair; import android.net.UrlQuerySanitizer.ValueSanitizer; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; -@TestTargetClass(UrlQuerySanitizer.class) public class UrlQuerySanitizerTest extends AndroidTestCase { private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; @@ -46,173 +41,6 @@ public class UrlQuerySanitizerTest extends AndroidTestCase { private static final String AGE = "age"; private static final String HEIGHT = "height"; - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "UrlQuerySanitizer", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "UrlQuerySanitizer", - args = {String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "parseUrl", - args = {String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "parseQuery", - args = {String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "parseEntry", - args = {String.class, String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getValue", - args = {String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "addSanitizedEntry", - args = {String.class, String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "hasParameter", - args = {String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getParameterSet", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getParameterList", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setUnregisteredParameterValueSanitizer", - args = {ValueSanitizer.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getUnregisteredParameterValueSanitizer", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getAllButNulAndAngleBracketsLegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getAllButNulLegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getAllButWhitespaceLegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getAllIllegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getAmpAndSpaceLegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getAmpLegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getSpaceLegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getUrlAndSpaceLegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getUrlLegal", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "unescape", - args = {String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isHexDigit", - args = {char.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "decodeHexDigit", - args = {char.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setAllowUnregisteredParamaters", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getAllowUnregisteredParamaters", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "registerParameter", - args = {String.class, ValueSanitizer.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "registerParameters", - args = {String[].class, ValueSanitizer.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getEffectiveValueSanitizer", - args = {String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getValueSanitizer", - args = {String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "clear", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setPreferFirstRepeatedParameter", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getPreferFirstRepeatedParameter", - args = {} - ) - }) public void testUrlQuerySanitizer() { MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer(); assertFalse(uqs.getAllowUnregisteredParamaters()); diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java index f85a5347e0..f86af3114e 100644 --- a/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java @@ -19,28 +19,9 @@ package android.net.cts; import android.net.UrlQuerySanitizer; import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; -@TestTargetClass(UrlQuerySanitizer.IllegalCharacterValueSanitizer.class) public class UrlQuerySanitizer_IllegalCharacterValueSanitizerTest extends AndroidTestCase { static final int SPACE_OK = IllegalCharacterValueSanitizer.SPACE_OK; - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test constructor(s) of {@link IllegalCharacterValueSanitizer}", - method = "IllegalCharacterValueSanitizer", - args = {int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Test method: sanitize", - method = "sanitize", - args = {String.class} - ) - }) public void testSanitize() { IllegalCharacterValueSanitizer sanitizer = new IllegalCharacterValueSanitizer(SPACE_OK); assertEquals("Joe User", sanitizer.sanitize("Joe scanResults = mWifiManager.getScanResults(); // this test case should in Wifi environment diff --git a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java index 4e03f5e9ce..075138fc65 100644 --- a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java @@ -18,21 +18,9 @@ package android.net.wifi.cts; import android.net.wifi.SupplicantState; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; -@TestTargetClass(SupplicantState.class) public class SupplicantStateTest extends AndroidTestCase { - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isValidState", - args = {android.net.wifi.SupplicantState.class} - ) - }) public void testIsValidState() { assertTrue(SupplicantState.isValidState(SupplicantState.DISCONNECTED)); assertTrue(SupplicantState.isValidState(SupplicantState.INACTIVE)); diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java index 3018907092..4874feb212 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java @@ -22,12 +22,7 @@ import android.content.Context; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; -@TestTargetClass(WifiConfiguration.class) public class WifiConfigurationTest extends AndroidTestCase { private WifiManager mWifiManager; @Override @@ -37,18 +32,6 @@ public class WifiConfigurationTest extends AndroidTestCase { .getSystemService(Context.WIFI_SERVICE); } - @TestTargets({ - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "WifiConfiguration", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "toString", - args = {} - ) - }) public void testWifiConfiguration() { List wifiConfigurations = mWifiManager.getConfiguredNetworks(); for (int i = 0; i < wifiConfigurations.size(); i++) { diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 44189cd13a..0bf25aa4b2 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -16,10 +16,6 @@ package android.net.wifi.cts; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; import android.content.BroadcastReceiver; import android.content.Context; @@ -31,7 +27,6 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -@TestTargetClass(WifiInfo.class) public class WifiInfoTest extends AndroidTestCase { private static class MySync { int expectedState = STATE_NULL; @@ -103,63 +98,6 @@ public class WifiInfoTest extends AndroidTestCase { } } - @TestTargets({ - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getMacAddress", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getIpAddress", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getDetailedStateOf", - args = {android.net.wifi.SupplicantState.class} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getNetworkId", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getSSID", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getBSSID", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getSupplicantState", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getLinkSpeed", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "toString", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getRssi", - args = {} - ), - @TestTargetNew( - level = TestLevel.PARTIAL, - method = "getHiddenSSID", - args = {} - ) - }) public void testWifiInfoProperties() throws Exception { // this test case should in Wifi environment WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index e2a583b6ef..b3fec542b7 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -16,10 +16,6 @@ package android.net.wifi.cts; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; import android.content.BroadcastReceiver; import android.content.Context; @@ -37,7 +33,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -@TestTargetClass(WifiManager.class) public class WifiManagerTest extends AndroidTestCase { private static class MySync { int expectedState = STATE_NULL; @@ -177,58 +172,6 @@ public class WifiManagerTest extends AndroidTestCase { * 4.pingSupplicant * 5.satrtScan */ - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isWifiEnabled", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setWifiEnabled", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "startScan", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getScanResults", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "pingSupplicant", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "reassociate", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "reconnect", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "disconnect", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createWifiLock", - args = {int.class, String.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "createWifiLock", - args = {String.class} - ) - }) public void testWifiManagerActions() throws Exception { assertTrue(mWifiManager.reconnect()); assertTrue(mWifiManager.reassociate()); @@ -250,33 +193,6 @@ public class WifiManagerTest extends AndroidTestCase { * 3.wifi state * 4.ConnectionInfo */ - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isWifiEnabled", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getWifiState", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setWifiEnabled", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getConnectionInfo", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getDhcpInfo", - args = {} - ) - }) public void testWifiManagerProperties() throws Exception { setWifiEnabled(true); assertTrue(mWifiManager.isWifiEnabled()); @@ -297,53 +213,6 @@ public class WifiManagerTest extends AndroidTestCase { * 6.configured Networks * 7.save configure; */ - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isWifiEnabled", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setWifiEnabled", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "getConfiguredNetworks", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "addNetwork", - args = {android.net.wifi.WifiConfiguration.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "updateNetwork", - args = {android.net.wifi.WifiConfiguration.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "removeNetwork", - args = {int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "enableNetwork", - args = {int.class, boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "disableNetwork", - args = {int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "saveConfiguration", - args = {} - ) - }) public void testWifiManagerNetWork() throws Exception { // store the list of enabled networks, so they can be re-enabled after test completes Set enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); @@ -428,18 +297,6 @@ public class WifiManagerTest extends AndroidTestCase { } } - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "compareSignalLevel", - args = {int.class, int.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "calculateSignalLevel", - args = {int.class, int.class} - ) - }) public void testSignal() { final int numLevels = 9; int expectLevel = 0; diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java index 53150c9650..d48bfb87f2 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java @@ -20,48 +20,11 @@ import android.content.Context; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestTargets; -@TestTargetClass(WifiManager.WifiLock.class) public class WifiManager_WifiLockTest extends AndroidTestCase { private static final String WIFI_TAG = "WifiManager_WifiLockTest"; - @TestTargets({ - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "acquire", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "finalize", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "isHeld", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "release", - args = {} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "setReferenceCounted", - args = {boolean.class} - ), - @TestTargetNew( - level = TestLevel.COMPLETE, - method = "toString", - args = {} - ) - }) public void testWifiLock() { WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); WifiLock wl = wm.createWifiLock(WIFI_TAG); From a36a66a5422bc54af1e8205a9c8c23117515a818 Mon Sep 17 00:00:00 2001 From: Keun young Park Date: Fri, 10 Feb 2012 15:20:37 -0800 Subject: [PATCH 0079/1415] skip WiFi test if not supproted - Support info is coming from PackageManager Bug: 5547397 Change-Id: I35d0ac82fe31a436d38d0436d32c0bb194eba3a6 --- .../android/net/wifi/cts/ScanResultTest.java | 13 +++++++++ .../net/wifi/cts/SupplicantStateTest.java | 4 +++ .../net/wifi/cts/WifiConfigurationTest.java | 4 +++ .../src/android/net/wifi/cts/WifiFeature.java | 28 +++++++++++++++++++ .../android/net/wifi/cts/WifiInfoTest.java | 13 +++++++++ .../android/net/wifi/cts/WifiManagerTest.java | 25 +++++++++++++++++ .../wifi/cts/WifiManager_WifiLockTest.java | 4 +++ 7 files changed, 91 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiFeature.java diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java index 0ab71c70e4..b7202d25ec 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -65,6 +65,10 @@ public class ScanResultTest extends AndroidTestCase { @Override protected void setUp() throws Exception { super.setUp(); + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } mMySync = new MySync(); mIntentFilter = new IntentFilter(); mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); @@ -90,6 +94,11 @@ public class ScanResultTest extends AndroidTestCase { @Override protected void tearDown() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + super.tearDown(); + return; + } mWifiLock.release(); mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) @@ -115,6 +124,10 @@ public class ScanResultTest extends AndroidTestCase { args = {} ) public void testScanResultProperties() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } List scanResults = mWifiManager.getScanResults(); // this test case should in Wifi environment for (int i = 0; i < scanResults.size(); i++) { diff --git a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java index 4e03f5e9ce..88ecfe8a61 100644 --- a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java @@ -34,6 +34,10 @@ public class SupplicantStateTest extends AndroidTestCase { ) }) public void testIsValidState() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } assertTrue(SupplicantState.isValidState(SupplicantState.DISCONNECTED)); assertTrue(SupplicantState.isValidState(SupplicantState.INACTIVE)); assertTrue(SupplicantState.isValidState(SupplicantState.SCANNING)); diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java index 3018907092..f11aa4aa26 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java @@ -50,6 +50,10 @@ public class WifiConfigurationTest extends AndroidTestCase { ) }) public void testWifiConfiguration() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } List wifiConfigurations = mWifiManager.getConfiguredNetworks(); for (int i = 0; i < wifiConfigurations.size(); i++) { WifiConfiguration wifiConfiguration = wifiConfigurations.get(i); diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java new file mode 100644 index 0000000000..d7a83c302f --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 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.wifi.cts; + +import android.content.Context; +import android.content.pm.PackageManager; + +public class WifiFeature { + static boolean isWifiSupported(Context context) { + PackageManager packageManager = context.getPackageManager(); + return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI); + } +} + diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 44189cd13a..2713dfdd3f 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -66,6 +66,10 @@ public class WifiInfoTest extends AndroidTestCase { @Override protected void setUp() throws Exception { super.setUp(); + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } mMySync = new MySync(); mIntentFilter = new IntentFilter(); mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); @@ -84,6 +88,11 @@ public class WifiInfoTest extends AndroidTestCase { @Override protected void tearDown() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + super.tearDown(); + return; + } mWifiLock.release(); mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) @@ -161,6 +170,10 @@ public class WifiInfoTest extends AndroidTestCase { ) }) public void testWifiInfoProperties() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } // this test case should in Wifi environment WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index e2a583b6ef..014f0eed6f 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -90,6 +90,10 @@ public class WifiManagerTest extends AndroidTestCase { @Override protected void setUp() throws Exception { super.setUp(); + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } mMySync = new MySync(); mIntentFilter = new IntentFilter(); mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); @@ -115,6 +119,11 @@ public class WifiManagerTest extends AndroidTestCase { @Override protected void tearDown() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + super.tearDown(); + return; + } mWifiLock.release(); mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) @@ -230,6 +239,10 @@ public class WifiManagerTest extends AndroidTestCase { ) }) public void testWifiManagerActions() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } assertTrue(mWifiManager.reconnect()); assertTrue(mWifiManager.reassociate()); assertTrue(mWifiManager.disconnect()); @@ -278,6 +291,10 @@ public class WifiManagerTest extends AndroidTestCase { ) }) public void testWifiManagerProperties() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } setWifiEnabled(true); assertTrue(mWifiManager.isWifiEnabled()); assertNotNull(mWifiManager.getDhcpInfo()); @@ -345,6 +362,10 @@ public class WifiManagerTest extends AndroidTestCase { ) }) public void testWifiManagerNetWork() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } // store the list of enabled networks, so they can be re-enabled after test completes Set enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); try { @@ -441,6 +462,10 @@ public class WifiManagerTest extends AndroidTestCase { ) }) public void testSignal() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } final int numLevels = 9; int expectLevel = 0; assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels)); diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java index 53150c9650..c1fc4ba712 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java @@ -63,6 +63,10 @@ public class WifiManager_WifiLockTest extends AndroidTestCase { ) }) public void testWifiLock() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); WifiLock wl = wm.createWifiLock(WIFI_TAG); From 4231515a1b116eeddd1269b24459d0f56fe4be07 Mon Sep 17 00:00:00 2001 From: Chia-chi Yeh Date: Tue, 28 Feb 2012 14:05:12 -0800 Subject: [PATCH 0080/1415] Free net.cts from cts.stub. Explicitly include CtsTestServer in Android.mk to eliminate the dependency to cts.stub. This allows net.cts to instrument itself, and it also allows network-specific JNI code to be added in the same package. Change-Id: I624f87e0112619c5b97f2c3589933f666665fa8e --- tests/cts/net/Android.mk | 6 +++--- tests/cts/net/AndroidManifest.xml | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 1fd9ba0c40..bf518907f6 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -23,12 +23,12 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_SRC_FILES := $(call all-java-files-under, src) +# include CtsTestServer as a temporary hack to free net.cts from cts.stub. +LOCAL_SRC_FILES := $(call all-java-files-under, src) \ + ../../src/android/webkit/cts/CtsTestServer.java LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_INSTRUMENTATION_FOR := CtsTestStubs - # uncomment when dalvik.annotation.Test* are removed or part of SDK #LOCAL_SDK_VERSION := current diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index a1f632effb..4fa05654af 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -18,12 +18,20 @@ + + + + + + + + - From 66efc9c3c0db3390d2ad05a7d103ece4d796d3ab Mon Sep 17 00:00:00 2001 From: Chia-chi Yeh Date: Tue, 28 Feb 2012 17:33:10 -0800 Subject: [PATCH 0081/1415] Add CTS test for android.net.VpnService. Bug: 5910784 Change-Id: Icb3d874d4d0917f739bd2638596f28df2a7d206e --- .../src/android/net/cts/VpnServiceTest.java | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/VpnServiceTest.java diff --git a/tests/cts/net/src/android/net/cts/VpnServiceTest.java b/tests/cts/net/src/android/net/cts/VpnServiceTest.java new file mode 100644 index 0000000000..9e35375970 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/VpnServiceTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2012 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 android.content.Intent; +import android.net.VpnService; +import android.os.ParcelFileDescriptor; +import android.test.AndroidTestCase; + +import java.io.File; +import java.net.DatagramSocket; +import java.net.Socket; + +/** + * VpnService API is built with security in mind. However, its security also + * blocks us from writing tests for positive cases. For now we only test for + * negative cases, and we will try to cover the rest in the future. + */ +public class VpnServiceTest extends AndroidTestCase { + + private static final String TAG = VpnServiceTest.class.getSimpleName(); + + private VpnService mVpnService = new VpnService(); + + public void testPrepare() throws Exception { + // Should never return null since we are not prepared. + Intent intent = VpnService.prepare(mContext); + assertNotNull(intent); + + // Should be always resolved by only one activity. + int count = mContext.getPackageManager().queryIntentActivities(intent, 0).size(); + assertEquals(count, 1); + } + + public void testEstablish() throws Exception { + ParcelFileDescriptor descriptor = null; + try { + // Should always return null since we are not prepared. + descriptor = mVpnService.new Builder().addAddress("8.8.8.8", 30).establish(); + assertNull(descriptor); + } finally { + try { + descriptor.close(); + } catch (Exception e) { + // ignore + } + } + } + + public void testProtect_DatagramSocket() throws Exception { + DatagramSocket socket = new DatagramSocket(); + try { + // Should always return false since we are not prepared. + assertFalse(mVpnService.protect(socket)); + } finally { + try { + socket.close(); + } catch (Exception e) { + // ignore + } + } + } + + public void testProtect_Socket() throws Exception { + Socket socket = new Socket(); + try { + // Should always return false since we are not prepared. + assertFalse(mVpnService.protect(socket)); + } finally { + try { + socket.close(); + } catch (Exception e) { + // ignore + } + } + } + + public void testProtect_int() throws Exception { + DatagramSocket socket = new DatagramSocket(); + ParcelFileDescriptor descriptor = ParcelFileDescriptor.fromDatagramSocket(socket); + try { + // Should always return false since we are not prepared. + assertFalse(mVpnService.protect(descriptor.getFd())); + } finally { + try { + descriptor.close(); + } catch (Exception e) { + // ignore + } + try { + socket.close(); + } catch (Exception e) { + // ignore + } + } + } + + public void testTunDevice() throws Exception { + File file = new File("/dev/tun"); + assertTrue(file.exists()); + assertFalse(file.isFile()); + assertFalse(file.isDirectory()); + assertFalse(file.canExecute()); + assertFalse(file.canRead()); + assertFalse(file.canWrite()); + } +} From 248128f2a935c56fbfa03ea9bf8ad67929d6aadd Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Mon, 5 Mar 2012 18:46:33 -0800 Subject: [PATCH 0082/1415] Static Libs for Popular CTS Stub Components com.android.cts.stub is growing very large. Split apart some of the popular components into separate static libraries. This should allow packages to depend on the components they need rather than all of cts.stub. Current code at the moment doesn't have to be changed, because I have CtsTestStubs depending on these new shared libraries. However, change the net package to depend on the ctstestserver static library as a proof of concept rather than including its source directly. Change-Id: I32c54eab3ddfb1d4391d6ffc347fbc9cb2fe97f9 --- tests/cts/net/Android.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index c139d1c5b4..3e48cd21a2 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -24,11 +24,12 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) LOCAL_JAVA_LIBRARIES := android.test.runner # include CtsTestServer as a temporary hack to free net.cts from cts.stub. -LOCAL_SRC_FILES := $(call all-java-files-under, src) \ - ../../src/android/webkit/cts/CtsTestServer.java +LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases +LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver + # uncomment when dalvik.annotation.Test* are removed or part of SDK #LOCAL_SDK_VERSION := current From 6bda9056effc260aa7bc9cf5980358ea321831cc Mon Sep 17 00:00:00 2001 From: Chia-chi Yeh Date: Fri, 30 Mar 2012 13:35:54 -0700 Subject: [PATCH 0083/1415] Add CTS test for android.net.rtp. Bug: 5975113 Change-Id: I20ec3b172a2d6501048418f4c3da06d1b7144fd3 --- tests/cts/net/AndroidManifest.xml | 1 + .../android/net/rtp/cts/AudioCodecTest.java | 73 ++++++++ .../android/net/rtp/cts/AudioGroupTest.java | 170 ++++++++++++++++++ .../android/net/rtp/cts/AudioStreamTest.java | 94 ++++++++++ 4 files changed, 338 insertions(+) create mode 100644 tests/cts/net/src/android/net/rtp/cts/AudioCodecTest.java create mode 100644 tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java create mode 100644 tests/cts/net/src/android/net/rtp/cts/AudioStreamTest.java diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 4fa05654af..b3556f5bec 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -23,6 +23,7 @@ + diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioCodecTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioCodecTest.java new file mode 100644 index 0000000000..412498c309 --- /dev/null +++ b/tests/cts/net/src/android/net/rtp/cts/AudioCodecTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 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.rtp.cts; + +import android.net.rtp.AudioCodec; +import android.test.AndroidTestCase; + +public class AudioCodecTest extends AndroidTestCase { + + private void assertEquals(AudioCodec codec, int type, String rtpmap, String fmtp) { + if (type >= 0) { + assertEquals(codec.type, type); + } else { + assertTrue(codec.type >= 96 && codec.type <= 127); + } + assertEquals(codec.rtpmap.compareToIgnoreCase(rtpmap), 0); + assertEquals(codec.fmtp, fmtp); + } + + public void testConstants() throws Exception { + assertEquals(AudioCodec.PCMU, 0, "PCMU/8000", null); + assertEquals(AudioCodec.PCMA, 8, "PCMA/8000", null); + assertEquals(AudioCodec.GSM, 3, "GSM/8000", null); + assertEquals(AudioCodec.GSM_EFR, -1, "GSM-EFR/8000", null); + assertEquals(AudioCodec.AMR, -1, "AMR/8000", null); + + assertFalse(AudioCodec.AMR.type == AudioCodec.GSM_EFR.type); + } + + public void testGetCodec() throws Exception { + // Bad types. + assertNull(AudioCodec.getCodec(128, "PCMU/8000", null)); + assertNull(AudioCodec.getCodec(-1, "PCMU/8000", null)); + assertNull(AudioCodec.getCodec(96, null, null)); + + // Fixed types. + assertEquals(AudioCodec.getCodec(0, null, null), 0, "PCMU/8000", null); + assertEquals(AudioCodec.getCodec(8, null, null), 8, "PCMA/8000", null); + assertEquals(AudioCodec.getCodec(3, null, null), 3, "GSM/8000", null); + + // Dynamic types. + assertEquals(AudioCodec.getCodec(96, "pcmu/8000", null), 96, "PCMU/8000", null); + assertEquals(AudioCodec.getCodec(97, "pcma/8000", null), 97, "PCMA/8000", null); + assertEquals(AudioCodec.getCodec(98, "gsm/8000", null), 98, "GSM/8000", null); + assertEquals(AudioCodec.getCodec(99, "gsm-efr/8000", null), 99, "GSM-EFR/8000", null); + assertEquals(AudioCodec.getCodec(100, "amr/8000", null), 100, "AMR/8000", null); + } + + public void testGetCodecs() throws Exception { + AudioCodec[] codecs = AudioCodec.getCodecs(); + assertTrue(codecs.length >= 5); + + // The types of the codecs should be different. + boolean[] types = new boolean[128]; + for (AudioCodec codec : codecs) { + assertFalse(types[codec.type]); + types[codec.type] = true; + } + } +} diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java new file mode 100644 index 0000000000..f06d7e9b89 --- /dev/null +++ b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2012 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.rtp.cts; + +import android.content.Context; +import android.media.AudioManager; +import android.net.rtp.AudioCodec; +import android.net.rtp.AudioGroup; +import android.net.rtp.AudioStream; +import android.net.rtp.RtpStream; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; + +public class AudioGroupTest extends AndroidTestCase { + + private static final String TAG = AudioGroupTest.class.getSimpleName(); + + private AudioManager mAudioManager; + + private AudioStream mStreamA; + private DatagramSocket mSocketA; + private AudioStream mStreamB; + private DatagramSocket mSocketB; + private AudioGroup mGroup; + + @Override + public void setUp() throws Exception { + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); + + InetAddress local = InetAddress.getByName("::1"); + + mStreamA = new AudioStream(local); + mStreamA.setMode(RtpStream.MODE_NORMAL); + mStreamA.setCodec(AudioCodec.PCMU); + mSocketA = new DatagramSocket(); + mSocketA.connect(mStreamA.getLocalAddress(), mStreamA.getLocalPort()); + mStreamA.associate(mSocketA.getLocalAddress(), mSocketA.getLocalPort()); + + mStreamB = new AudioStream(local); + mStreamB.setMode(RtpStream.MODE_NORMAL); + mStreamB.setCodec(AudioCodec.PCMU); + mSocketB = new DatagramSocket(); + mSocketB.connect(mStreamB.getLocalAddress(), mStreamB.getLocalPort()); + mStreamB.associate(mSocketB.getLocalAddress(), mSocketB.getLocalPort()); + + mGroup = new AudioGroup(); + } + + @Override + public void tearDown() throws Exception { + mGroup.clear(); + mStreamA.release(); + mSocketA.close(); + mStreamB.release(); + mSocketB.close(); + mAudioManager.setMode(AudioManager.MODE_NORMAL); + } + + private void assertPacket(DatagramSocket socket, int length) throws Exception { + DatagramPacket packet = new DatagramPacket(new byte[length + 1], length + 1); + socket.setSoTimeout(3000); + socket.receive(packet); + assertEquals(packet.getLength(), length); + } + + private void drain(DatagramSocket socket) throws Exception { + DatagramPacket packet = new DatagramPacket(new byte[1], 1); + socket.setSoTimeout(1); + try { + // Drain the socket by retrieving all the packets queued on it. + // A SocketTimeoutException will be thrown when it becomes empty. + while (true) { + socket.receive(packet); + } + } catch (Exception e) { + // ignore. + } + } + + public void testTraffic() throws Exception { + mStreamA.join(mGroup); + assertPacket(mSocketA, 12 + 160); + + mStreamB.join(mGroup); + assertPacket(mSocketB, 12 + 160); + + mStreamA.join(null); + drain(mSocketA); + + drain(mSocketB); + assertPacket(mSocketB, 12 + 160); + + mStreamA.join(mGroup); + assertPacket(mSocketA, 12 + 160); + } + + public void testSetMode() throws Exception { + mGroup.setMode(AudioGroup.MODE_NORMAL); + assertEquals(mGroup.getMode(), AudioGroup.MODE_NORMAL); + + mGroup.setMode(AudioGroup.MODE_MUTED); + assertEquals(mGroup.getMode(), AudioGroup.MODE_MUTED); + + mStreamA.join(mGroup); + mStreamB.join(mGroup); + + mGroup.setMode(AudioGroup.MODE_NORMAL); + assertEquals(mGroup.getMode(), AudioGroup.MODE_NORMAL); + + mGroup.setMode(AudioGroup.MODE_MUTED); + assertEquals(mGroup.getMode(), AudioGroup.MODE_MUTED); + } + + public void testAdd() throws Exception { + mStreamA.join(mGroup); + assertEquals(mGroup.getStreams().length, 1); + + mStreamB.join(mGroup); + assertEquals(mGroup.getStreams().length, 2); + + mStreamA.join(mGroup); + assertEquals(mGroup.getStreams().length, 2); + } + + public void testRemove() throws Exception { + mStreamA.join(mGroup); + assertEquals(mGroup.getStreams().length, 1); + + mStreamA.join(null); + assertEquals(mGroup.getStreams().length, 0); + + mStreamA.join(mGroup); + assertEquals(mGroup.getStreams().length, 1); + } + + public void testClear() throws Exception { + mStreamA.join(mGroup); + mStreamB.join(mGroup); + mGroup.clear(); + + assertEquals(mGroup.getStreams().length, 0); + assertFalse(mStreamA.isBusy()); + assertFalse(mStreamB.isBusy()); + } + + public void testDoubleClear() throws Exception { + mStreamA.join(mGroup); + mStreamB.join(mGroup); + mGroup.clear(); + mGroup.clear(); + } +} diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioStreamTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioStreamTest.java new file mode 100644 index 0000000000..323b02215d --- /dev/null +++ b/tests/cts/net/src/android/net/rtp/cts/AudioStreamTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 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.rtp.cts; + +import android.net.rtp.AudioCodec; +import android.net.rtp.AudioStream; +import android.test.AndroidTestCase; + +import java.net.InetAddress; + +public class AudioStreamTest extends AndroidTestCase { + + private void testRtpStream(InetAddress address) throws Exception { + AudioStream stream = new AudioStream(address); + assertEquals(stream.getLocalAddress(), address); + assertEquals(stream.getLocalPort() % 2, 0); + + assertNull(stream.getRemoteAddress()); + assertEquals(stream.getRemotePort(), -1); + stream.associate(address, 1000); + assertEquals(stream.getRemoteAddress(), address); + assertEquals(stream.getRemotePort(), 1000); + + assertFalse(stream.isBusy()); + stream.release(); + } + + public void testV4Stream() throws Exception { + testRtpStream(InetAddress.getByName("127.0.0.1")); + } + + public void testV6Stream() throws Exception { + testRtpStream(InetAddress.getByName("::1")); + } + + public void testSetDtmfType() throws Exception { + AudioStream stream = new AudioStream(InetAddress.getByName("::1")); + + assertEquals(stream.getDtmfType(), -1); + try { + stream.setDtmfType(0); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // ignore + } + stream.setDtmfType(96); + assertEquals(stream.getDtmfType(), 96); + + stream.setCodec(AudioCodec.getCodec(97, "PCMU/8000", null)); + try { + stream.setDtmfType(97); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // ignore + } + stream.release(); + } + + public void testSetCodec() throws Exception { + AudioStream stream = new AudioStream(InetAddress.getByName("::1")); + + assertNull(stream.getCodec()); + stream.setCodec(AudioCodec.getCodec(97, "PCMU/8000", null)); + assertNotNull(stream.getCodec()); + + stream.setDtmfType(96); + try { + stream.setCodec(AudioCodec.getCodec(96, "PCMU/8000", null)); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // ignore + } + stream.release(); + } + + public void testDoubleRelease() throws Exception { + AudioStream stream = new AudioStream(InetAddress.getByName("::1")); + stream.release(); + stream.release(); + } +} From 7dde0466ab446985a579d3f8254b761339793850 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Wed, 4 Apr 2012 18:22:15 -0700 Subject: [PATCH 0084/1415] Fix NetworkInfo_DetailedStateTest Bug 6292661 Test is missing a new enum value. Change-Id: I0f5983575eb7aeb87b212e44c5476025a4baf609 --- .../net/src/android/net/cts/NetworkInfo_DetailedStateTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index 3eeb1c5c84..b8d0ea4e60 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -37,7 +37,7 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { public void testValues() { DetailedState[] expected = DetailedState.values(); - assertEquals(11, expected.length); + assertEquals(12, expected.length); assertEquals(DetailedState.IDLE, expected[0]); assertEquals(DetailedState.SCANNING, expected[1]); assertEquals(DetailedState.CONNECTING, expected[2]); @@ -49,6 +49,7 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { assertEquals(DetailedState.DISCONNECTED, expected[8]); assertEquals(DetailedState.FAILED, expected[9]); assertEquals(DetailedState.BLOCKED, expected[10]); + assertEquals(DetailedState.VERIFYING_POOR_LINK, expected[11]); } } From fb1b2d0923e40929a476b7eb546a3dd8ebb6b4ea Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Thu, 10 May 2012 14:31:59 -0400 Subject: [PATCH 0085/1415] Track rename of Uri.normalize() to Uri.normalizeScheme(). Change-Id: I0b6c65e033bfb82503f30e5c9e55903278c4a788 --- tests/cts/net/src/android/net/cts/UriTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 3bf8049b0a..ab337d0183 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -406,11 +406,12 @@ public class UriTest extends AndroidTestCase { assertEquals(uriString, uri.toString()); } - public void testNormalize() { - assertEquals(Uri.parse(""), Uri.parse("").normalize()); + public void testNormalizeScheme() { + assertEquals(Uri.parse(""), Uri.parse("").normalizeScheme()); assertEquals(Uri.parse("http://www.android.com"), - Uri.parse("http://www.android.com").normalize()); + Uri.parse("http://www.android.com").normalizeScheme()); assertEquals(Uri.parse("http://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c"), - Uri.parse("HTTP://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c").normalize()); + Uri.parse("HTTP://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c") + .normalizeScheme()); } } From 28ca76b84d2de6eaec2d2c73ab413974ce8c9ab4 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Fri, 8 Jun 2012 16:45:02 -0700 Subject: [PATCH 0086/1415] Flip condition in ApacheHttpClientTest Make sure to wait first and then check the expected state rather than check the expected state first and then waiting. Bug 6293413 Change-Id: Ibcb1127b935708c51fafdc8624cb3a7eefc01bda --- .../cts/net/src/android/net/http/cts/ApacheHttpClientTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java b/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java index e4846fdec2..7d9189ff33 100644 --- a/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java +++ b/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java @@ -200,7 +200,7 @@ public class ApacheHttpClientTest extends AndroidTestCase { } public boolean waitForStateChange() throws InterruptedException { - return hasExpectedState() || mReceiveLatch.await(30, TimeUnit.SECONDS); + return mReceiveLatch.await(30, TimeUnit.SECONDS) || hasExpectedState(); } private boolean hasExpectedState() { From 562af417ed5cd2f8066b2af0d692f6426d00b7d8 Mon Sep 17 00:00:00 2001 From: bs Date: Fri, 22 Jun 2012 21:36:24 +0900 Subject: [PATCH 0087/1415] Fix CTS case testStartUsingNetworkFeature of ConnectivityManagerTest Check if type of network is supported on the devices. The device supporting TYPE_WIFI returns failureCode(-1). But, not supported device returns wifiOnlyStartFailureCode or wifiOnlyStopFailureCode. Change-Id: I070bb19f6740367c476e78b884c2a36d111ff3ee --- .../src/android/net/cts/ConnectivityManagerTest.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index cd80be2797..470458253c 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -161,9 +161,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { invalidateFeature)); } - // Should return failure(-1) because MMS is not supported on WIFI. - assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_WIFI, mmsFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI, mmsFeature)); + ni = mCm.getNetworkInfo(TYPE_WIFI); + if (ni != null) { + // Should return failure(-1) because MMS is not supported on WIFI. + assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_WIFI, + mmsFeature)); + assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI, + mmsFeature)); + } } @TestTargetNew( From 237e076594b059a8631f3cc4863499ec2f967444 Mon Sep 17 00:00:00 2001 From: Brian Muramatsu Date: Tue, 26 Jun 2012 15:05:08 -0700 Subject: [PATCH 0088/1415] Fix WifiInfoTest flakiness Poll a bit longer waiting for getNetworkId and getWifiState to return the proper values. The bug reports seem to indicate that the WiFi is shutting down properly. Add a new static check method to PollingCheck that I think is simpler than the existing way of creating a new PollingCheck, overriding check, and then making sure to call run. This new variation also allows you to specify a message rather than just "unexpected timeout." Bug 6443337 Change-Id: I9f7c942f6e26b957bb717b58b1ab984acc556bf7 --- tests/cts/net/Android.mk | 2 +- .../android/net/wifi/cts/WifiInfoTest.java | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 3e48cd21a2..5c70ad4bb8 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -28,7 +28,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver +LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsutil # uncomment when dalvik.annotation.Test* are removed or part of SDK #LOCAL_SDK_VERSION := current diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index df1323b255..16dc57de2b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -21,12 +21,15 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.cts.util.PollingCheck; import android.net.wifi.SupplicantState; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; +import java.util.concurrent.Callable; + public class WifiInfoTest extends AndroidTestCase { private static class MySync { int expectedState = STATE_NULL; @@ -127,10 +130,21 @@ public class WifiInfoTest extends AndroidTestCase { wifiInfo.getHiddenSSID(); wifiInfo.getMacAddress(); setWifiEnabled(false); - Thread.sleep(DURATION); - wifiInfo = mWifiManager.getConnectionInfo(); - assertEquals(-1, wifiInfo.getNetworkId()); - assertEquals(WifiManager.WIFI_STATE_DISABLED, mWifiManager.getWifiState()); + + PollingCheck.check("getNetworkId not -1", 20000, new Callable() { + @Override + public Boolean call() throws Exception { + WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + return wifiInfo.getNetworkId() == -1; + } + }); + + PollingCheck.check("getWifiState not disabled", 20000, new Callable() { + @Override + public Boolean call() throws Exception { + return mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED; + } + }); } } From f7e73fcc352ddb0b94045a9de0e3c6dce8aadf77 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Tue, 26 Jun 2012 16:54:35 -0700 Subject: [PATCH 0089/1415] Add wifi & p2p Concurrency test Change-Id: I5a35fb097b22b00366b189bad9c44a640a7d5b5a --- .../android/net/wifi/cts/ConcurrencyTest.java | 138 ++++++++++++++++++ .../src/android/net/wifi/cts/WifiFeature.java | 6 +- 2 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java new file mode 100644 index 0000000000..5accd77633 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2012 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.wifi.cts; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.WifiManager; +import android.net.wifi.p2p.WifiP2pManager; +import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_DISABLED; +import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_ENABLED; +import android.test.AndroidTestCase; + +public class ConcurrencyTest extends AndroidTestCase { + private class MySync { + int expectedWifiState; + int expectedP2pState; + } + + private WifiManager mWifiManager; + private MySync mMySync = new MySync(); + + private static final String TAG = "WifiInfoTest"; + private static final int TIMEOUT_MSEC = 6000; + private static final int WAIT_MSEC = 60; + private static final int DURATION = 10000; + private IntentFilter mIntentFilter; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.expectedWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_DISABLED); + mMySync.notify(); + } + } else if(action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.expectedP2pState = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, + WifiP2pManager.WIFI_P2P_STATE_DISABLED); + mMySync.notify(); + } + } + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + if (!WifiFeature.isWifiSupported(getContext()) && + !WifiFeature.isP2pSupported(getContext())) { + // skip the test if WiFi && p2p are not supported + return; + } + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); + + mContext.registerReceiver(mReceiver, mIntentFilter); + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + assertNotNull(mWifiManager); + if (mWifiManager.isWifiEnabled()) { + assertTrue(mWifiManager.setWifiEnabled(false)); + Thread.sleep(DURATION); + } + assertTrue(!mWifiManager.isWifiEnabled()); + mMySync.expectedWifiState = WifiManager.WIFI_STATE_DISABLED; + mMySync.expectedP2pState = WifiP2pManager.WIFI_P2P_STATE_DISABLED; + } + + @Override + protected void tearDown() throws Exception { + if (!WifiFeature.isWifiSupported(getContext()) && + !WifiFeature.isP2pSupported(getContext())) { + // skip the test if WiFi and p2p are not supported + super.tearDown(); + return; + } + mContext.unregisterReceiver(mReceiver); + + if (mWifiManager.isWifiEnabled()) { + assertTrue(mWifiManager.setWifiEnabled(false)); + Thread.sleep(DURATION); + } + super.tearDown(); + } + + private void waitForBroadcasts() { + synchronized (mMySync) { + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && (mMySync.expectedWifiState != WifiManager.WIFI_STATE_ENABLED || + mMySync.expectedP2pState != WifiP2pManager.WIFI_P2P_STATE_ENABLED)) { + try { + mMySync.wait(WAIT_MSEC); + } catch (InterruptedException e) { } + } + } + } + + public void testConcurrency() { + // Cannot support p2p alone + if (!WifiFeature.isWifiSupported(getContext())) { + assertTrue(!WifiFeature.isP2pSupported(getContext())); + return; + } + + if (!WifiFeature.isP2pSupported(getContext())) { + // skip the test if p2p is not supported + return; + } + + // Enable wifi + assertTrue(mWifiManager.setWifiEnabled(true)); + + waitForBroadcasts(); + + assertTrue(mMySync.expectedWifiState == WifiManager.WIFI_STATE_ENABLED); + assertTrue(mMySync.expectedP2pState == WifiP2pManager.WIFI_P2P_STATE_ENABLED); + } + +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java index d7a83c302f..63fa1dd94c 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java @@ -24,5 +24,9 @@ public class WifiFeature { PackageManager packageManager = context.getPackageManager(); return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI); } -} + static boolean isP2pSupported(Context context) { + PackageManager packageManager = context.getPackageManager(); + return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT); + } +} From 30199405c3b15a0dc6778e7465499a7d33f7556c Mon Sep 17 00:00:00 2001 From: Keun young Park Date: Thu, 12 Jul 2012 12:56:04 -0700 Subject: [PATCH 0090/1415] change testRunner to CtsTestRunner - unlock keyguard by default Change-Id: I0452a72cfa54edfa79b485894ffd0493a71122ee --- tests/cts/net/Android.mk | 2 +- tests/cts/net/AndroidManifest.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 5c70ad4bb8..b327392956 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -28,7 +28,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsutil +LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsutil ctstestrunner # uncomment when dalvik.annotation.Test* are removed or part of SDK #LOCAL_SDK_VERSION := current diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index b3556f5bec..ade6728a6e 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -22,6 +22,7 @@ + @@ -31,7 +32,7 @@ - From c0e2e5715be659a19a091b37accef72939cc0dfd Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Mon, 23 Jul 2012 09:28:23 -0700 Subject: [PATCH 0091/1415] Fix NPE in CTS test wifiConfigurations returned by getConfiguredNetworks() can be null. It is only incidental that this test passed fine in the past. Bug: 6822950 Change-Id: I570ab6e7fd6cc5eb150914a5d7ca527ccc2f16cd --- .../android/net/wifi/cts/WifiConfigurationTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java index 92a55b2250..4480a24a9a 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java @@ -38,10 +38,12 @@ public class WifiConfigurationTest extends AndroidTestCase { return; } List wifiConfigurations = mWifiManager.getConfiguredNetworks(); - for (int i = 0; i < wifiConfigurations.size(); i++) { - WifiConfiguration wifiConfiguration = wifiConfigurations.get(i); - assertNotNull(wifiConfiguration); - assertNotNull(wifiConfiguration.toString()); + if (wifiConfigurations != null) { + for (int i = 0; i < wifiConfigurations.size(); i++) { + WifiConfiguration wifiConfiguration = wifiConfigurations.get(i); + assertNotNull(wifiConfiguration); + assertNotNull(wifiConfiguration.toString()); + } } } } From f16bea1f5914495b82e864a0ab92cf412ec6f9d0 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Wed, 25 Jul 2012 12:10:40 -0700 Subject: [PATCH 0092/1415] Ignore case on network info name Bug: 6309231 Change-Id: I41244e25ccbf0d896edebf886c7f67ab1ded0a04 --- tests/cts/net/src/android/net/cts/NetworkInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java index e53614b99a..4a7b4e7e82 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java @@ -53,7 +53,7 @@ public class NetworkInfoTest extends AndroidTestCase { } private void assertNetworkInfo(NetworkInfo netInfo, String expectedTypeName) { - assertEquals(expectedTypeName, netInfo.getTypeName()); + assertEquals(expectedTypeName.compareToIgnoreCase(netInfo.getTypeName()), 0); if(netInfo.isConnectedOrConnecting()) { assertTrue(netInfo.isAvailable()); if (State.CONNECTED == netInfo.getState()) { From e9adc27111e8f78c0281cddfd31708048326473e Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Mon, 13 Aug 2012 12:19:55 -0700 Subject: [PATCH 0093/1415] CTS for timestamp in ScanResult Bug: 2961159 Change-Id: I8f1fd270a71173e2bd43b590914b7315232e4fba --- .../android/net/wifi/cts/ScanResultTest.java | 74 +++++++++++++++++-- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java index 26cfff83fd..c9b82eecc7 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -26,6 +26,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; +import android.util.Log; public class ScanResultTest extends AndroidTestCase { private static class MySync { @@ -39,11 +40,14 @@ public class ScanResultTest extends AndroidTestCase { private static final int STATE_NULL = 0; private static final int STATE_WIFI_CHANGING = 1; private static final int STATE_WIFI_CHANGED = 2; + private static final int STATE_START_SCAN = 3; + private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; private static final String TAG = "WifiInfoTest"; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; - private static final int DURATION = 10000; + private static final int ENABLE_WAIT_MSEC = 10000; + private static final int SCAN_WAIT_MSEC = 10000; private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -54,6 +58,11 @@ public class ScanResultTest extends AndroidTestCase { mMySync.expectedState = STATE_WIFI_CHANGED; mMySync.notify(); } + } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { + synchronized (mMySync) { + mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; + mMySync.notify(); + } } } }; @@ -83,7 +92,7 @@ public class ScanResultTest extends AndroidTestCase { mWifiLock.acquire(); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - Thread.sleep(DURATION); + Thread.sleep(ENABLE_WAIT_MSEC); assertTrue(mWifiManager.isWifiEnabled()); mMySync.expectedState = STATE_NULL; } @@ -99,7 +108,7 @@ public class ScanResultTest extends AndroidTestCase { mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - Thread.sleep(DURATION); + Thread.sleep(ENABLE_WAIT_MSEC); super.tearDown(); } @@ -107,11 +116,15 @@ public class ScanResultTest extends AndroidTestCase { synchronized (mMySync) { mMySync.expectedState = STATE_WIFI_CHANGING; assertTrue(mWifiManager.setWifiEnabled(enable)); - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && mMySync.expectedState == STATE_WIFI_CHANGING) - mMySync.wait(WAIT_MSEC); - } + waitForBroadcast(TIMEOUT_MSEC, STATE_WIFI_CHANGED); + } + } + + private void waitForBroadcast(long timeout, int expectedState) throws Exception { + long waitTime = System.currentTimeMillis() + timeout; + while (System.currentTimeMillis() < waitTime + && mMySync.expectedState != expectedState) + mMySync.wait(WAIT_MSEC); } public void testScanResultProperties() { @@ -127,4 +140,49 @@ public class ScanResultTest extends AndroidTestCase { } } + private void scanAndWait() throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_START_SCAN; + mWifiManager.startScan(); + waitForBroadcast(SCAN_WAIT_MSEC, STATE_SCAN_RESULTS_AVAILABLE); + } + } + + public void testScanResultTimeStamp() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + long timestamp = 0; + String BSSID = null; + + /* Multiple scans to ensure bssid is updated */ + scanAndWait(); + scanAndWait(); + scanAndWait(); + + List scanResults = mWifiManager.getScanResults(); + for (ScanResult result : scanResults) { + BSSID = result.BSSID; + timestamp = result.timestamp; + assertTrue(timestamp != 0); + break; + } + + scanAndWait(); + scanAndWait(); + scanAndWait(); + + scanResults = mWifiManager.getScanResults(); + for (ScanResult result : scanResults) { + if (result.BSSID.equals(BSSID)) { + long timeDiff = (result.timestamp - timestamp) / 1000; + assertTrue (timeDiff > 0); + assertTrue (timeDiff < 6 * SCAN_WAIT_MSEC); + } + } + + } + } From 72010dbfcf461bdcd116d22acbfec362b6583215 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Tue, 14 Aug 2012 12:24:25 -0700 Subject: [PATCH 0094/1415] Revert "CTS for timestamp in ScanResult" This accompanies: https://googleplex-android-review.googlesource.com/217002 This reverts commit e9adc27111e8f78c0281cddfd31708048326473e Change-Id: Ib37b72c59aad34fe9fd4461979c5f51af1218e37 --- .../android/net/wifi/cts/ScanResultTest.java | 74 ++----------------- 1 file changed, 8 insertions(+), 66 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java index c9b82eecc7..26cfff83fd 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -26,7 +26,6 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -import android.util.Log; public class ScanResultTest extends AndroidTestCase { private static class MySync { @@ -40,14 +39,11 @@ public class ScanResultTest extends AndroidTestCase { private static final int STATE_NULL = 0; private static final int STATE_WIFI_CHANGING = 1; private static final int STATE_WIFI_CHANGED = 2; - private static final int STATE_START_SCAN = 3; - private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; private static final String TAG = "WifiInfoTest"; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; - private static final int ENABLE_WAIT_MSEC = 10000; - private static final int SCAN_WAIT_MSEC = 10000; + private static final int DURATION = 10000; private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -58,11 +54,6 @@ public class ScanResultTest extends AndroidTestCase { mMySync.expectedState = STATE_WIFI_CHANGED; mMySync.notify(); } - } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - synchronized (mMySync) { - mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; - mMySync.notify(); - } } } }; @@ -92,7 +83,7 @@ public class ScanResultTest extends AndroidTestCase { mWifiLock.acquire(); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - Thread.sleep(ENABLE_WAIT_MSEC); + Thread.sleep(DURATION); assertTrue(mWifiManager.isWifiEnabled()); mMySync.expectedState = STATE_NULL; } @@ -108,7 +99,7 @@ public class ScanResultTest extends AndroidTestCase { mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - Thread.sleep(ENABLE_WAIT_MSEC); + Thread.sleep(DURATION); super.tearDown(); } @@ -116,15 +107,11 @@ public class ScanResultTest extends AndroidTestCase { synchronized (mMySync) { mMySync.expectedState = STATE_WIFI_CHANGING; assertTrue(mWifiManager.setWifiEnabled(enable)); - waitForBroadcast(TIMEOUT_MSEC, STATE_WIFI_CHANGED); - } - } - - private void waitForBroadcast(long timeout, int expectedState) throws Exception { - long waitTime = System.currentTimeMillis() + timeout; - while (System.currentTimeMillis() < waitTime - && mMySync.expectedState != expectedState) - mMySync.wait(WAIT_MSEC); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mMySync.expectedState == STATE_WIFI_CHANGING) + mMySync.wait(WAIT_MSEC); + } } public void testScanResultProperties() { @@ -140,49 +127,4 @@ public class ScanResultTest extends AndroidTestCase { } } - private void scanAndWait() throws Exception { - synchronized (mMySync) { - mMySync.expectedState = STATE_START_SCAN; - mWifiManager.startScan(); - waitForBroadcast(SCAN_WAIT_MSEC, STATE_SCAN_RESULTS_AVAILABLE); - } - } - - public void testScanResultTimeStamp() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - long timestamp = 0; - String BSSID = null; - - /* Multiple scans to ensure bssid is updated */ - scanAndWait(); - scanAndWait(); - scanAndWait(); - - List scanResults = mWifiManager.getScanResults(); - for (ScanResult result : scanResults) { - BSSID = result.BSSID; - timestamp = result.timestamp; - assertTrue(timestamp != 0); - break; - } - - scanAndWait(); - scanAndWait(); - scanAndWait(); - - scanResults = mWifiManager.getScanResults(); - for (ScanResult result : scanResults) { - if (result.BSSID.equals(BSSID)) { - long timeDiff = (result.timestamp - timestamp) / 1000; - assertTrue (timeDiff > 0); - assertTrue (timeDiff < 6 * SCAN_WAIT_MSEC); - } - } - - } - } From 9420b3fe53c4e4e69488c8851b06932e90af6570 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Tue, 14 Aug 2012 12:24:25 -0700 Subject: [PATCH 0095/1415] Revert "CTS for timestamp in ScanResult" This accompanies: https://googleplex-android-review.googlesource.com/217002 This reverts commit e9adc27111e8f78c0281cddfd31708048326473e Change-Id: Ib37b72c59aad34fe9fd4461979c5f51af1218e37 --- .../android/net/wifi/cts/ScanResultTest.java | 74 ++----------------- 1 file changed, 8 insertions(+), 66 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java index c9b82eecc7..26cfff83fd 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -26,7 +26,6 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -import android.util.Log; public class ScanResultTest extends AndroidTestCase { private static class MySync { @@ -40,14 +39,11 @@ public class ScanResultTest extends AndroidTestCase { private static final int STATE_NULL = 0; private static final int STATE_WIFI_CHANGING = 1; private static final int STATE_WIFI_CHANGED = 2; - private static final int STATE_START_SCAN = 3; - private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; private static final String TAG = "WifiInfoTest"; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; - private static final int ENABLE_WAIT_MSEC = 10000; - private static final int SCAN_WAIT_MSEC = 10000; + private static final int DURATION = 10000; private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -58,11 +54,6 @@ public class ScanResultTest extends AndroidTestCase { mMySync.expectedState = STATE_WIFI_CHANGED; mMySync.notify(); } - } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - synchronized (mMySync) { - mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; - mMySync.notify(); - } } } }; @@ -92,7 +83,7 @@ public class ScanResultTest extends AndroidTestCase { mWifiLock.acquire(); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - Thread.sleep(ENABLE_WAIT_MSEC); + Thread.sleep(DURATION); assertTrue(mWifiManager.isWifiEnabled()); mMySync.expectedState = STATE_NULL; } @@ -108,7 +99,7 @@ public class ScanResultTest extends AndroidTestCase { mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - Thread.sleep(ENABLE_WAIT_MSEC); + Thread.sleep(DURATION); super.tearDown(); } @@ -116,15 +107,11 @@ public class ScanResultTest extends AndroidTestCase { synchronized (mMySync) { mMySync.expectedState = STATE_WIFI_CHANGING; assertTrue(mWifiManager.setWifiEnabled(enable)); - waitForBroadcast(TIMEOUT_MSEC, STATE_WIFI_CHANGED); - } - } - - private void waitForBroadcast(long timeout, int expectedState) throws Exception { - long waitTime = System.currentTimeMillis() + timeout; - while (System.currentTimeMillis() < waitTime - && mMySync.expectedState != expectedState) - mMySync.wait(WAIT_MSEC); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mMySync.expectedState == STATE_WIFI_CHANGING) + mMySync.wait(WAIT_MSEC); + } } public void testScanResultProperties() { @@ -140,49 +127,4 @@ public class ScanResultTest extends AndroidTestCase { } } - private void scanAndWait() throws Exception { - synchronized (mMySync) { - mMySync.expectedState = STATE_START_SCAN; - mWifiManager.startScan(); - waitForBroadcast(SCAN_WAIT_MSEC, STATE_SCAN_RESULTS_AVAILABLE); - } - } - - public void testScanResultTimeStamp() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - long timestamp = 0; - String BSSID = null; - - /* Multiple scans to ensure bssid is updated */ - scanAndWait(); - scanAndWait(); - scanAndWait(); - - List scanResults = mWifiManager.getScanResults(); - for (ScanResult result : scanResults) { - BSSID = result.BSSID; - timestamp = result.timestamp; - assertTrue(timestamp != 0); - break; - } - - scanAndWait(); - scanAndWait(); - scanAndWait(); - - scanResults = mWifiManager.getScanResults(); - for (ScanResult result : scanResults) { - if (result.BSSID.equals(BSSID)) { - long timeDiff = (result.timestamp - timestamp) / 1000; - assertTrue (timeDiff > 0); - assertTrue (timeDiff < 6 * SCAN_WAIT_MSEC); - } - } - - } - } From 72465772e01ba5d05e8f9af138e9f303e5bb2865 Mon Sep 17 00:00:00 2001 From: Yuhao Zheng Date: Tue, 14 Aug 2012 14:24:35 -0700 Subject: [PATCH 0096/1415] CTS test for WiFi watchdog. The new WiFi watchdog requires kernel/driver to export some packet loss counters. This CTS tests whether those counters are correctly exported. Change-Id: Ic764eff64ff2ef354b46f17e46eb74b14f191e4c --- .../android/net/wifi/cts/WifiManagerTest.java | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 5fc23e7b5e..a64477d100 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -21,17 +21,22 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.NetworkInfo; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; import android.net.wifi.WifiConfiguration.Status; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.TxPacketCountListener; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; import android.util.Log; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; public class WifiManagerTest extends AndroidTestCase { private static class MySync { @@ -42,6 +47,7 @@ public class WifiManagerTest extends AndroidTestCase { private WifiLock mWifiLock; private static MySync mMySync; private List mScanResult = null; + private NetworkInfo mNetworkInfo; // Please refer to WifiManager private static final int MIN_RSSI = -100; @@ -78,6 +84,13 @@ public class WifiManagerTest extends AndroidTestCase { mMySync.expectedState = STATE_WIFI_CHANGED; mMySync.notify(); } + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + synchronized (mMySync) { + mNetworkInfo = + (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) + mMySync.notify(); + } } } }; @@ -148,6 +161,18 @@ public class WifiManagerTest extends AndroidTestCase { } } + private void connectWifi() throws Exception { + synchronized (mMySync) { + if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) return; + assertTrue(mWifiManager.reconnect()); + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout + && mNetworkInfo.getState() != NetworkInfo.State.CONNECTED) + mMySync.wait(WAIT_MSEC); + assertTrue(mNetworkInfo.getState() == NetworkInfo.State.CONNECTED); + } + } + private boolean existSSID(String ssid) { for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { if (w.SSID.equals(ssid)) @@ -339,4 +364,65 @@ public class WifiManagerTest extends AndroidTestCase { rssiB = 4; assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0); } + + private int getTxPacketCount() throws Exception { + final AtomicInteger ret = new AtomicInteger(-1); + + mWifiManager.getTxPacketCount(new TxPacketCountListener() { + @Override + public void onSuccess(int count) { + ret.set(count); + } + @Override + public void onFailure(int reason) { + ret.set(0); + } + }); + + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (ret.get() < 0 && System.currentTimeMillis() < timeout) + Thread.sleep(WAIT_MSEC); + assertTrue(ret.get() >= 0); + return ret.get(); + } + + /** + * The new WiFi watchdog requires kernel/driver to export some packet loss + * counters. This CTS tests whether those counters are correctly exported. + * To pass this CTS test, a connected WiFi link is required. + */ + public void testWifiWatchdog() throws Exception { + // Make sure WiFi is enabled + if (!mWifiManager.isWifiEnabled()) { + setWifiEnabled(true); + Thread.sleep(DURATION); + } + assertTrue(mWifiManager.isWifiEnabled()); + + // Wait for a WiFi connection + connectWifi(); + + // Read TX packet counter + int txcount1 = getTxPacketCount(); + + // Do some network operations + HttpURLConnection connection = null; + try { + URL url = new URL("http://www.google.com/"); + connection = (HttpURLConnection) url.openConnection(); + connection.setInstanceFollowRedirects(false); + connection.setConnectTimeout(TIMEOUT_MSEC); + connection.setReadTimeout(TIMEOUT_MSEC); + connection.setUseCaches(false); + connection.getInputStream(); + } catch (Exception e) { + // ignore + } finally { + if (connection != null) connection.disconnect(); + } + + // Read TX packet counter again and make sure it increases + int txcount2 = getTxPacketCount(); + assertTrue(txcount2 > txcount1); + } } From f1537c2ba42ca2a073e3eb9bca8502485bd38655 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Mon, 20 Aug 2012 13:21:49 -0700 Subject: [PATCH 0097/1415] Revert "Revert "CTS for timestamp in ScanResult"" With b/6979211 fixed, we can reinstate timestamps. This reverts commit 72010dbfcf461bdcd116d22acbfec362b6583215 Change-Id: I1066567c728b233ad1d6c6af912c32ef099580e6 --- .../android/net/wifi/cts/ScanResultTest.java | 74 +++++++++++++++++-- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java index 26cfff83fd..c9b82eecc7 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -26,6 +26,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; +import android.util.Log; public class ScanResultTest extends AndroidTestCase { private static class MySync { @@ -39,11 +40,14 @@ public class ScanResultTest extends AndroidTestCase { private static final int STATE_NULL = 0; private static final int STATE_WIFI_CHANGING = 1; private static final int STATE_WIFI_CHANGED = 2; + private static final int STATE_START_SCAN = 3; + private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; private static final String TAG = "WifiInfoTest"; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; - private static final int DURATION = 10000; + private static final int ENABLE_WAIT_MSEC = 10000; + private static final int SCAN_WAIT_MSEC = 10000; private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -54,6 +58,11 @@ public class ScanResultTest extends AndroidTestCase { mMySync.expectedState = STATE_WIFI_CHANGED; mMySync.notify(); } + } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { + synchronized (mMySync) { + mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; + mMySync.notify(); + } } } }; @@ -83,7 +92,7 @@ public class ScanResultTest extends AndroidTestCase { mWifiLock.acquire(); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - Thread.sleep(DURATION); + Thread.sleep(ENABLE_WAIT_MSEC); assertTrue(mWifiManager.isWifiEnabled()); mMySync.expectedState = STATE_NULL; } @@ -99,7 +108,7 @@ public class ScanResultTest extends AndroidTestCase { mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - Thread.sleep(DURATION); + Thread.sleep(ENABLE_WAIT_MSEC); super.tearDown(); } @@ -107,11 +116,15 @@ public class ScanResultTest extends AndroidTestCase { synchronized (mMySync) { mMySync.expectedState = STATE_WIFI_CHANGING; assertTrue(mWifiManager.setWifiEnabled(enable)); - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && mMySync.expectedState == STATE_WIFI_CHANGING) - mMySync.wait(WAIT_MSEC); - } + waitForBroadcast(TIMEOUT_MSEC, STATE_WIFI_CHANGED); + } + } + + private void waitForBroadcast(long timeout, int expectedState) throws Exception { + long waitTime = System.currentTimeMillis() + timeout; + while (System.currentTimeMillis() < waitTime + && mMySync.expectedState != expectedState) + mMySync.wait(WAIT_MSEC); } public void testScanResultProperties() { @@ -127,4 +140,49 @@ public class ScanResultTest extends AndroidTestCase { } } + private void scanAndWait() throws Exception { + synchronized (mMySync) { + mMySync.expectedState = STATE_START_SCAN; + mWifiManager.startScan(); + waitForBroadcast(SCAN_WAIT_MSEC, STATE_SCAN_RESULTS_AVAILABLE); + } + } + + public void testScanResultTimeStamp() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + long timestamp = 0; + String BSSID = null; + + /* Multiple scans to ensure bssid is updated */ + scanAndWait(); + scanAndWait(); + scanAndWait(); + + List scanResults = mWifiManager.getScanResults(); + for (ScanResult result : scanResults) { + BSSID = result.BSSID; + timestamp = result.timestamp; + assertTrue(timestamp != 0); + break; + } + + scanAndWait(); + scanAndWait(); + scanAndWait(); + + scanResults = mWifiManager.getScanResults(); + for (ScanResult result : scanResults) { + if (result.BSSID.equals(BSSID)) { + long timeDiff = (result.timestamp - timestamp) / 1000; + assertTrue (timeDiff > 0); + assertTrue (timeDiff < 6 * SCAN_WAIT_MSEC); + } + } + + } + } From 3de9654925a3c916fbcd814dd64f9872a0d03619 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 16 Sep 2012 17:11:04 -0700 Subject: [PATCH 0098/1415] Fix NetworkInfo CTS test. bug:7074876 Change-Id: I29cf9086fda62dda8078b42a1632f139ec65ee52 --- .../net/src/android/net/cts/NetworkInfo_DetailedStateTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java index b8d0ea4e60..590ce89579 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -37,7 +37,7 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { public void testValues() { DetailedState[] expected = DetailedState.values(); - assertEquals(12, expected.length); + assertEquals(13, expected.length); assertEquals(DetailedState.IDLE, expected[0]); assertEquals(DetailedState.SCANNING, expected[1]); assertEquals(DetailedState.CONNECTING, expected[2]); @@ -50,6 +50,7 @@ public class NetworkInfo_DetailedStateTest extends AndroidTestCase { assertEquals(DetailedState.FAILED, expected[9]); assertEquals(DetailedState.BLOCKED, expected[10]); assertEquals(DetailedState.VERIFYING_POOR_LINK, expected[11]); + assertEquals(DetailedState.CAPTIVE_PORTAL_CHECK, expected[12]); } } From a0a19ea8aa8ed74501a0b0e906796ae0b33b5ea8 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Wed, 17 Oct 2012 15:21:23 -0700 Subject: [PATCH 0099/1415] Make packet count test more robust Ensure the packet count test does not fail due to a single attempt. Our goal is to just ensure the packet count API exists. Bug: 7001746 Change-Id: I8c6604528946166969126cd5b085024f81790a77 --- .../android/net/wifi/cts/WifiManagerTest.java | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index a64477d100..74083015ce 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -399,30 +399,39 @@ public class WifiManagerTest extends AndroidTestCase { } assertTrue(mWifiManager.isWifiEnabled()); - // Wait for a WiFi connection - connectWifi(); + int i = 0; + for (; i < 15; i++) { + // Wait for a WiFi connection + connectWifi(); - // Read TX packet counter - int txcount1 = getTxPacketCount(); + // Read TX packet counter + int txcount1 = getTxPacketCount(); - // Do some network operations - HttpURLConnection connection = null; - try { - URL url = new URL("http://www.google.com/"); - connection = (HttpURLConnection) url.openConnection(); - connection.setInstanceFollowRedirects(false); - connection.setConnectTimeout(TIMEOUT_MSEC); - connection.setReadTimeout(TIMEOUT_MSEC); - connection.setUseCaches(false); - connection.getInputStream(); - } catch (Exception e) { - // ignore - } finally { - if (connection != null) connection.disconnect(); + // Do some network operations + HttpURLConnection connection = null; + try { + URL url = new URL("http://www.google.com/"); + connection = (HttpURLConnection) url.openConnection(); + connection.setInstanceFollowRedirects(false); + connection.setConnectTimeout(TIMEOUT_MSEC); + connection.setReadTimeout(TIMEOUT_MSEC); + connection.setUseCaches(false); + connection.getInputStream(); + } catch (Exception e) { + // ignore + } finally { + if (connection != null) connection.disconnect(); + } + + // Read TX packet counter again and make sure it increases + int txcount2 = getTxPacketCount(); + + if (txcount2 > txcount1) { + break; + } else { + Thread.sleep(DURATION); + } } - - // Read TX packet counter again and make sure it increases - int txcount2 = getTxPacketCount(); - assertTrue(txcount2 > txcount1); + assertTrue(i < 15); } } From 566cad494d504b60710640d931947cff6aade537 Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Fri, 26 Oct 2012 15:38:10 -0700 Subject: [PATCH 0100/1415] Fix race condition causing occasional CTS failures. WifiManagerTest was waiting for SUPPLICANT_STATE_CHANGED_ACTION after enabling or disabling WiFi. Fix the code to check if the WiFi state is already the desired state, and if not, to wait for the WIFI_STATE_CHANGED_ACTION broadcast intent. Bug: 7082455 Change-Id: Id1c2242c32311084f5587ea5403f6b227d1b8b04 --- .../android/net/wifi/cts/WifiManagerTest.java | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 74083015ce..283f63b5d4 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -55,9 +55,10 @@ public class WifiManagerTest extends AndroidTestCase { private static final int STATE_NULL = 0; private static final int STATE_WIFI_CHANGING = 1; - private static final int STATE_WIFI_CHANGED = 2; - private static final int STATE_SCANING = 3; - private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; + private static final int STATE_WIFI_ENABLED = 2; + private static final int STATE_WIFI_DISABLED = 3; + private static final int STATE_SCANNING = 4; + private static final int STATE_SCAN_RESULTS_AVAILABLE = 5; private static final String TAG = "WifiManagerTest"; private static final String SSID1 = "\"WifiManagerTest\""; @@ -76,20 +77,29 @@ public class WifiManagerTest extends AndroidTestCase { mScanResult = mWifiManager.getScanResults(); mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; mScanResult = mWifiManager.getScanResults(); - mMySync.notify(); + mMySync.notifyAll(); } } - } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { + } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN); synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGED; - mMySync.notify(); + if (newState == WifiManager.WIFI_STATE_ENABLED) { + Log.d(TAG, "*** New WiFi state is ENABLED ***"); + mMySync.expectedState = STATE_WIFI_ENABLED; + mMySync.notifyAll(); + } else if (newState == WifiManager.WIFI_STATE_DISABLED) { + Log.d(TAG, "*** New WiFi state is DISABLED ***"); + mMySync.expectedState = STATE_WIFI_DISABLED; + mMySync.notifyAll(); + } } } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { synchronized (mMySync) { mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) - mMySync.notify(); + mMySync.notifyAll(); } } } @@ -122,7 +132,9 @@ public class WifiManagerTest extends AndroidTestCase { setWifiEnabled(true); Thread.sleep(DURATION); assertTrue(mWifiManager.isWifiEnabled()); - mMySync.expectedState = STATE_NULL; + synchronized (mMySync) { + mMySync.expectedState = STATE_NULL; + } } @Override @@ -132,31 +144,34 @@ public class WifiManagerTest extends AndroidTestCase { super.tearDown(); return; } - mWifiLock.release(); - mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); + mWifiLock.release(); + mContext.unregisterReceiver(mReceiver); Thread.sleep(DURATION); super.tearDown(); } private void setWifiEnabled(boolean enable) throws Exception { synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGING; assertTrue(mWifiManager.setWifiEnabled(enable)); - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && mMySync.expectedState == STATE_WIFI_CHANGING) - mMySync.wait(WAIT_MSEC); + if (mWifiManager.isWifiEnabled() != enable) { + mMySync.expectedState = STATE_WIFI_CHANGING; + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + int expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); + while (System.currentTimeMillis() < timeout + && mMySync.expectedState != expectedState) + mMySync.wait(WAIT_MSEC); + } } } private void startScan() throws Exception { synchronized (mMySync) { - mMySync.expectedState = STATE_SCANING; + mMySync.expectedState = STATE_SCANNING; assertTrue(mWifiManager.startScan()); long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANING) + while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANNING) mMySync.wait(WAIT_MSEC); } } From 775417bd58d53683ce3595c8805c280a97a2c8ee Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Mon, 28 Jan 2013 20:00:57 -0800 Subject: [PATCH 0101/1415] Delete frameworks/base/voip use voip-common from frameworks/opt/net/voip Change-Id: Ieaba759a0f69b45c4b8839cbed1fe757cdf190c5 --- tests/cts/net/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index b327392956..f69c4c3e6e 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -21,7 +21,7 @@ LOCAL_MODULE_TAGS := optional # and when built explicitly put it in the data partition LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner voip-common # include CtsTestServer as a temporary hack to free net.cts from cts.stub. LOCAL_SRC_FILES := $(call all-java-files-under, src) From 9ac09493ad1352e8193c7bfa5529f9e55e2b45df Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 5 Feb 2013 11:02:49 -0800 Subject: [PATCH 0102/1415] Add Dns CTS test. Checks java and native calls. Adds some performance tests, but need to look at how that should be used. Change-Id: I158164829da13302d9532275cef3482c4736168e --- tests/cts/net/Android.mk | 4 + tests/cts/net/jni/Android.mk | 30 +++ tests/cts/net/jni/NativeDnsJni.c | 166 ++++++++++++ .../cts/net/src/android/net/cts/DnsTest.java | 237 ++++++++++++++++++ 4 files changed, 437 insertions(+) create mode 100644 tests/cts/net/jni/Android.mk create mode 100644 tests/cts/net/jni/NativeDnsJni.c create mode 100644 tests/cts/net/src/android/net/cts/DnsTest.java diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index f69c4c3e6e..a6543b3a6a 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -23,6 +23,8 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) LOCAL_JAVA_LIBRARIES := android.test.runner voip-common +LOCAL_JNI_SHARED_LIBRARIES := libnativedns_jni + # include CtsTestServer as a temporary hack to free net.cts from cts.stub. LOCAL_SRC_FILES := $(call all-java-files-under, src) @@ -34,3 +36,5 @@ LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsutil ctstestrunner #LOCAL_SDK_VERSION := current include $(BUILD_CTS_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/cts/net/jni/Android.mk b/tests/cts/net/jni/Android.mk new file mode 100644 index 0000000000..75982de3ed --- /dev/null +++ b/tests/cts/net/jni/Android.mk @@ -0,0 +1,30 @@ +# Copyright (C) 2013 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libnativedns_jni + +# Don't include this package in any configuration by default. +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := NativeDnsJni.c + +LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) + +LOCAL_SHARED_LIBRARIES := libnativehelper liblog + +include $(BUILD_SHARED_LIBRARY) diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c new file mode 100644 index 0000000000..de9bb677b5 --- /dev/null +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include +#include +#include +#include + +JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclass class) +{ + const char *node = "www.google.com"; + char *service = NULL; + struct addrinfo *answer; + + int res = getaddrinfo(node, service, NULL, &answer); + ALOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res)); + if (res != 0) return JNI_FALSE; + + // check for v4 & v6 + { + int foundv4 = 0; + int foundv6 = 0; + struct addrinfo *current = answer; + while (current != NULL) { + char buf[256]; + if (current->ai_addr->sa_family == AF_INET) { + inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, + buf, sizeof(buf)); + foundv4 = 1; + ALOGD(" %s", buf); + } else if (current->ai_addr->sa_family == AF_INET6) { + inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, + buf, sizeof(buf)); + foundv6 = 1; + ALOGD(" %s", buf); + } + current = current->ai_next; + } + + freeaddrinfo(answer); + answer = NULL; + if (foundv4 != 1 || foundv6 != 1) { + ALOGD("getaddrinfo(www.google.com) didn't find both v4 and v6"); + return JNI_FALSE; + } + } + + node = "ipv6.google.com"; + res = getaddrinfo(node, service, NULL, &answer); + ALOGD("getaddrinfo(ipv6.google.com) gave res=%d", res); + if (res != 0) return JNI_FALSE; + + { + int foundv4 = 0; + int foundv6 = 0; + struct addrinfo *current = answer; + while (current != NULL) { + char buf[256]; + if (current->ai_addr->sa_family == AF_INET) { + inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, + buf, sizeof(buf)); + ALOGD(" %s", buf); + foundv4 = 1; + } else if (current->ai_addr->sa_family == AF_INET6) { + inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, + buf, sizeof(buf)); + ALOGD(" %s", buf); + foundv6 = 1; + } + current = current->ai_next; + } + + freeaddrinfo(answer); + answer = NULL; + if (foundv4 == 1 || foundv6 != 1) { + ALOGD("getaddrinfo(ipv6.google.com) didn't find only v6"); + return JNI_FALSE; + } + } + + // getnameinfo + struct sockaddr_in sa4; + sa4.sin_family = AF_INET; + sa4.sin_port = 0; + inet_pton(AF_INET, "173.252.110.27", &(sa4.sin_addr)); + + struct sockaddr_in6 sa6; + sa6.sin6_family = AF_INET6; + sa6.sin6_port = 0; + sa6.sin6_flowinfo = 0; + sa6.sin6_scope_id = 0; + inet_pton(AF_INET6, "2001:4860:4001:802::1008", &(sa6.sin6_addr)); + + char buf[NI_MAXHOST]; + int flags = NI_NAMEREQD; + + res = getnameinfo((const struct sockaddr*)&sa4, sizeof(sa4), buf, sizeof(buf), NULL, 0, flags); + if (res != 0) { + ALOGD("getnameinfo(173.252.110.27 (facebook) ) gave error %d (%s)", res, gai_strerror(res)); + return JNI_FALSE; + } + if (strstr(buf, "facebook.com") == NULL) { + ALOGD("getnameinfo(173.252.110.27 (facebook) ) didn't return facebook.com: %s", buf); + return JNI_FALSE; + } + + memset(buf, sizeof(buf), 0); + res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), + NULL, 0, flags); + if (res != 0) { + ALOGD("getnameinfo(2a03:2880:2110:df01:face:b00c::8 (facebook) ) gave error %d (%s)", + res, gai_strerror(res)); + return JNI_FALSE; + } + if (strstr(buf, "1e100.net") == NULL) { + ALOGD("getnameinfo(2a03:2880:2110:df01:face:b00c::8) didn't return facebook.com: %s", buf); + return JNI_FALSE; + } + + // gethostbyname + struct hostent *my_hostent = gethostbyname("www.mit.edu"); + if (my_hostent == NULL) { + ALOGD("gethostbyname(www.mit.edu) gave null response"); + return JNI_FALSE; + } + if ((my_hostent->h_addr_list == NULL) || (*my_hostent->h_addr_list == NULL)) { + ALOGD("gethostbyname(www.mit.edu) gave 0 addresses"); + return JNI_FALSE; + } + { + char **current = my_hostent->h_addr_list; + while (*current != NULL) { + char buf[256]; + inet_ntop(my_hostent->h_addrtype, *current, buf, sizeof(buf)); + ALOGD("gethostbyname(www.mit.edu) gave %s", buf); + current++; + } + } + + // gethostbyaddr + char addr6[16]; + inet_pton(AF_INET6, "2001:4b10:bbc::2", addr6); + my_hostent = gethostbyaddr(addr6, sizeof(addr6), AF_INET6); + if (my_hostent == NULL) { + ALOGD("gethostbyaddr(2001:4b10:bbc::2 (bbc) ) gave null response"); + return JNI_FALSE; + } + ALOGD("gethostbyaddr(2001:4b10:bbc::2 (bbc) ) gave %s for name", + my_hostent->h_name ? my_hostent->h_name : "null"); + if (my_hostent->h_name == NULL) return JNI_FALSE; + return JNI_TRUE; +} diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java new file mode 100644 index 0000000000..cdd95aa077 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2013 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 android.os.SystemClock; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; + +public class DnsTest extends AndroidTestCase { + + static { + System.loadLibrary("nativedns_jni"); + } + + private static final boolean DBG = false; + private static final String TAG = "DnsTest"; + + /** + * @return true on success + */ + private static native boolean testNativeDns(); + + /** + * Verify: + * DNS works - forwards and backwards, giving ipv4 and ipv6 + * Test that DNS work on v4 and v6 networks + * Test Native dns calls (4) + * Todo: + * Cache is flushed when we change networks + * have per-network caches + * No cache when there's no network + * Perf - measure size of first and second tier caches and their effect + * Assert requires network permission + */ + public void testDnsWorks() { + InetAddress addrs[] = {}; + try { + addrs = InetAddress.getAllByName("www.google.com"); + } catch (UnknownHostException e) {} + assertTrue(addrs.length != 0); + boolean foundV4 = false, foundV6 = false; + for (InetAddress addr : addrs) { + if (addr instanceof Inet4Address) foundV4 = true; + else if (addr instanceof Inet6Address) foundV6 = true; + if (DBG) Log.e(TAG, "www.google.com gave " + addr.toString()); + } + assertTrue(foundV4); + assertTrue(foundV6); + try { + addrs = InetAddress.getAllByName("ipv6.google.com"); + } catch (UnknownHostException e) {} + assertTrue(addrs.length != 0); + foundV4 = false; + foundV6 = false; + for (InetAddress addr : addrs) { + if (addr instanceof Inet4Address) foundV4 = true; + else if (addr instanceof Inet6Address) foundV6 = true; + if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString()); + } + assertTrue(foundV4 == false); + assertTrue(foundV6 == true); + assertTrue(testNativeDns()); + } + + private static final String[] URLS = { "www.google.com", "ipv6.google.com", "www.yahoo.com", + "facebook.com", "youtube.com", "blogspot.com", "baidu.com", "wikipedia.org", +// live.com fails rev lookup. + "twitter.com", "qq.com", "msn.com", "yahoo.co.jp", "linkedin.com", + "taobao.com", "google.co.in", "sina.com.cn", "amazon.com", "wordpress.com", + "google.co.uk", "ebay.com", "yandex.ru", "163.com", "google.co.jp", "google.fr", + "microsoft.com", "paypal.com", "google.com.br", "flickr.com", + "mail.ru", "craigslist.org", "fc2.com", "google.it", +// "apple.com", fails rev lookup + "google.es", + "imdb.com", "google.ru", "soho.com", "bbc.co.uk", "vkontakte.ru", "ask.com", + "tumblr.com", "weibo.com", "go.com", "xvideos.com", "livejasmin.com", "cnn.com", + "youku.com", "blogspot.com", "soso.com", "google.ca", "aol.com", "tudou.com", + "xhamster.com", "megaupload.com", "ifeng.com", "zedo.com", "mediafire.com", "ameblo.jp", + "pornhub.com", "google.co.id", "godaddy.com", "adobe.com", "rakuten.co.jp", "about.com", + "espn.go.com", "4shared.com", "alibaba.com","ebay.de", "yieldmanager.com", + "wordpress.org", "livejournal.com", "google.com.tr", "google.com.mx", "renren.com", + "livedoor.com", "google.com.au", "youporn.com", "uol.com.br", "cnet.com", "conduit.com", + "google.pl", "myspace.com", "nytimes.com", "ebay.co.uk", "chinaz.com", "hao123.com", + "thepiratebay.org", "doubleclick.com", "alipay.com", "netflix.com", "cnzz.com", + "huffingtonpost.com", "twitpic.com", "weather.com", "babylon.com", "amazon.de", + "dailymotion.com", "orkut.com", "orkut.com.br", "google.com.sa", "odnoklassniki.ru", + "amazon.co.jp", "google.nl", "goo.ne.jp", "stumbleupon.com", "tube8.com", "tmall.com", + "imgur.com", "globo.com", "secureserver.net", "fileserve.com", "tianya.cn", "badoo.com", + "ehow.com", "photobucket.com", "imageshack.us", "xnxx.com", "deviantart.com", + "filestube.com", "addthis.com", "douban.com", "vimeo.com", "sogou.com", + "stackoverflow.com", "reddit.com", "dailymail.co.uk", "redtube.com", "megavideo.com", + "taringa.net", "pengyou.com", "amazon.co.uk", "fbcdn.net", "aweber.com", "spiegel.de", + "rapidshare.com", "mixi.jp", "360buy.com", "google.cn", "digg.com", "answers.com", + "bit.ly", "indiatimes.com", "skype.com", "yfrog.com", "optmd.com", "google.com.eg", + "google.com.pk", "58.com", "hotfile.com", "google.co.th", + "bankofamerica.com", "sourceforge.net", "maktoob.com", "warriorforum.com", "rediff.com", + "google.co.za", "56.com", "torrentz.eu", "clicksor.com", "avg.com", + "download.com", "ku6.com", "statcounter.com", "foxnews.com", "google.com.ar", + "nicovideo.jp", "reference.com", "liveinternet.ru", "ucoz.ru", "xinhuanet.com", + "xtendmedia.com", "naver.com", "youjizz.com", "domaintools.com", "sparkstudios.com", + "rambler.ru", "scribd.com", "kaixin001.com", "mashable.com", "adultfirendfinder.com", + "files.wordpress.com", "guardian.co.uk", "bild.de", "yelp.com", "wikimedia.org", + "chase.com", "onet.pl", "ameba.jp", "pconline.com.cn", "free.fr", "etsy.com", + "typepad.com", "youdao.com", "megaclick.com", "digitalpoint.com", "blogfa.com", + "salesforce.com", "adf.ly", "ganji.com", "wikia.com", "archive.org", "terra.com.br", + "w3schools.com", "ezinearticles.com", "wjs.com", "google.com.my", "clickbank.com", + "squidoo.com", "hulu.com", "repubblica.it", "google.be", "allegro.pl", "comcast.net", + "narod.ru", "zol.com.cn", "orange.fr", "soufun.com", "hatena.ne.jp", "google.gr", + "in.com", "techcrunch.com", "orkut.co.in", "xunlei.com", + "reuters.com", "google.com.vn", "hostgator.com", "kaskus.us", "espncricinfo.com", + "hootsuite.com", "qiyi.com", "gmx.net", "xing.com", "php.net", "soku.com", "web.de", + "libero.it", "groupon.com", "51.la", "slideshare.net", "booking.com", "seesaa.net", + "126.com", "telegraph.co.uk", "wretch.cc", "twimg.com", "rutracker.org", "angege.com", + "nba.com", "dell.com", "leboncoin.fr", "people.com", "google.com.tw", "walmart.com", + "daum.net", "2ch.net", "constantcontact.com", "nifty.com", "mywebsearch.com", + "tripadvisor.com", "google.se", "paipai.com", "google.com.ua", "ning.com", "hp.com", + "google.at", "joomla.org", "icio.us", "hudong.com", "csdn.net", "getfirebug.com", + "ups.com", "cj.com", "google.ch", "camzap.com", "wordreference.com", "tagged.com", + "wp.pl", "mozilla.com", "google.ru", "usps.com", "china.com", "themeforest.net", + "search-results.com", "tribalfusion.com", "thefreedictionary.com", "isohunt.com", + "linkwithin.com", "cam4.com", "plentyoffish.com", "wellsfargo.com", "metacafe.com", + "depositfiles.com", "freelancer.com", "opendns.com", "homeway.com", "engadget.com", + "10086.cn", "360.cn", "marca.com", "dropbox.com", "ign.com", "match.com", "google.pt", + "facemoods.com", "hardsextube.com", "google.com.ph", "lockerz.com", "istockphoto.com", + "partypoker.com", "netlog.com", "outbrain.com", "elpais.com", "fiverr.com", + "biglobe.ne.jp", "corriere.it", "love21cn.com", "yesky.com", "spankwire.com", + "ig.com.br", "imagevenue.com", "hubpages.com", "google.co.ve"}; + +// TODO - this works, but is slow and cts doesn't do anything with the result. +// Maybe require a min performance, a min cache size (detectable) and/or move +// to perf testing + private static final int LOOKUP_COUNT_GOAL = URLS.length; + public void skiptestDnsPerf() { + ArrayList results = new ArrayList(); + int failures = 0; + try { + for (int numberOfUrls = URLS.length; numberOfUrls > 0; numberOfUrls--) { + failures = 0; + int iterationLimit = LOOKUP_COUNT_GOAL / numberOfUrls; + long startTime = SystemClock.elapsedRealtimeNanos(); + for (int iteration = 0; iteration < iterationLimit; iteration++) { + for (int urlIndex = 0; urlIndex < numberOfUrls; urlIndex++) { + try { + InetAddress addr = InetAddress.getByName(URLS[urlIndex]); + } catch (UnknownHostException e) { + Log.e(TAG, "failed first lookup of " + URLS[urlIndex]); + failures++; + try { + InetAddress addr = InetAddress.getByName(URLS[urlIndex]); + } catch (UnknownHostException ee) { + failures++; + Log.e(TAG, "failed SECOND lookup of " + URLS[urlIndex]); + } + } + } + } + long endTime = SystemClock.elapsedRealtimeNanos(); + float nsPer = ((float)(endTime-startTime) / iterationLimit) / numberOfUrls/ 1000; + String thisResult = new String("getByName for " + numberOfUrls + " took " + + (endTime - startTime)/1000 + "(" + nsPer + ") with " + + failures + " failures\n"); + Log.d(TAG, thisResult); + results.add(thisResult); + } + // build up a list of addresses + ArrayList addressList = new ArrayList(); + for (String url : URLS) { + try { + InetAddress addr = InetAddress.getByName(url); + addressList.add(addr.getAddress()); + } catch (UnknownHostException e) { + Log.e(TAG, "Exception making reverseDNS list: " + e.toString()); + } + } + for (int numberOfAddrs = addressList.size(); numberOfAddrs > 0; numberOfAddrs--) { + int iterationLimit = LOOKUP_COUNT_GOAL / numberOfAddrs; + failures = 0; + long startTime = SystemClock.elapsedRealtimeNanos(); + for (int iteration = 0; iteration < iterationLimit; iteration++) { + for (int addrIndex = 0; addrIndex < numberOfAddrs; addrIndex++) { + try { + InetAddress addr = InetAddress.getByAddress(addressList.get(addrIndex)); + String hostname = addr.getHostName(); + } catch (UnknownHostException e) { + failures++; + Log.e(TAG, "Failure doing reverse DNS lookup: " + e.toString()); + try { + InetAddress addr = + InetAddress.getByAddress(addressList.get(addrIndex)); + String hostname = addr.getHostName(); + + } catch (UnknownHostException ee) { + failures++; + Log.e(TAG, "Failure doing SECOND reverse DNS lookup: " + + ee.toString()); + } + } + } + } + long endTime = SystemClock.elapsedRealtimeNanos(); + float nsPer = ((endTime-startTime) / iterationLimit) / numberOfAddrs / 1000; + String thisResult = new String("getHostName for " + numberOfAddrs + " took " + + (endTime - startTime)/1000 + "(" + nsPer + ") with " + + failures + " failures\n"); + Log.d(TAG, thisResult); + results.add(thisResult); + } + for (String result : results) Log.d(TAG, result); + + InetAddress exit = InetAddress.getByName("exitrightnow.com"); + Log.e(TAG, " exit address= "+exit.toString()); + + } catch (Exception e) { + Log.e(TAG, "bad URL in testDnsPerf: " + e.toString()); + } + } +} From fe3b3f62a45320e8492457b16953fb1c81298ab9 Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Fri, 1 Mar 2013 16:41:16 -0800 Subject: [PATCH 0103/1415] Fixup TrafficStats test wrt mobile vs total vs loopback - Use getMobileBlabla() instead of getTotalBlabla() - Have getTotalBlabla() reflect the fact that it includes loopback. - Adjust checks to take headers, acks, and packet counts into account. Change-Id: I9e1dfbbbdb9a6f932a14a2e3baee7a34469b9008 --- .../src/android/net/cts/TrafficStatsTest.java | 132 ++++++++++++------ 1 file changed, 87 insertions(+), 45 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index a5bbd9886a..89933bfc5c 100644 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -42,19 +42,29 @@ public class TrafficStatsTest extends AndroidTestCase { TrafficStats.getMobileRxBytes() >= 0); } + long tcpPacketToIpBytes(long packetCount, long bytes) { + // ip header + tcp header + data. + // Tcp header is mostly 32. Syn has different tcp options -> 40. Don't care. + return packetCount * (20 + 32 + bytes); + } + public void testTrafficStatsForLocalhost() throws IOException { - long mobileTxPacketsBefore = TrafficStats.getTotalTxPackets(); - long mobileRxPacketsBefore = TrafficStats.getTotalRxPackets(); - long mobileTxBytesBefore = TrafficStats.getTotalTxBytes(); - long mobileRxBytesBefore = TrafficStats.getTotalRxBytes(); + long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets(); + long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets(); + long mobileTxBytesBefore = TrafficStats.getMobileTxBytes(); + long mobileRxBytesBefore = TrafficStats.getMobileRxBytes(); long totalTxPacketsBefore = TrafficStats.getTotalTxPackets(); long totalRxPacketsBefore = TrafficStats.getTotalRxPackets(); long totalTxBytesBefore = TrafficStats.getTotalTxBytes(); long totalRxBytesBefore = TrafficStats.getTotalRxBytes(); long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid()); long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); + long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid()); + long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid()); // Transfer 1MB of data across an explicitly localhost socket. + final int byteCount = 1024; + final int packetCount = 1024; final ServerSocket server = new ServerSocket(0); new Thread("TrafficStatsTest.testTrafficStatsForLocalhost") { @@ -62,9 +72,15 @@ public class TrafficStatsTest extends AndroidTestCase { public void run() { try { Socket socket = new Socket("localhost", server.getLocalPort()); + // Make sure that each write()+flush() turns into a packet: + // disable Nagle. + socket.setTcpNoDelay(true); OutputStream out = socket.getOutputStream(); - byte[] buf = new byte[1024]; - for (int i = 0; i < 1024; i++) out.write(buf); + byte[] buf = new byte[byteCount]; + for (int i = 0; i < packetCount; i++) { + out.write(buf); + out.flush(); + } out.close(); socket.close(); } catch (IOException e) { @@ -75,9 +91,9 @@ public class TrafficStatsTest extends AndroidTestCase { try { Socket socket = server.accept(); InputStream in = socket.getInputStream(); - byte[] buf = new byte[1024]; + byte[] buf = new byte[byteCount]; int read = 0; - while (read < 1048576) { + while (read < byteCount * packetCount) { int n = in.read(buf); assertTrue("Unexpected EOF", n > 0); read += n; @@ -92,50 +108,76 @@ public class TrafficStatsTest extends AndroidTestCase { } catch (InterruptedException e) { } - long mobileTxPacketsAfter = TrafficStats.getTotalTxPackets(); - long mobileRxPacketsAfter = TrafficStats.getTotalRxPackets(); - long mobileTxBytesAfter = TrafficStats.getTotalTxBytes(); - long mobileRxBytesAfter = TrafficStats.getTotalRxBytes(); + long mobileTxPacketsAfter = TrafficStats.getMobileTxPackets(); + long mobileRxPacketsAfter = TrafficStats.getMobileRxPackets(); + long mobileTxBytesAfter = TrafficStats.getMobileTxBytes(); + long mobileRxBytesAfter = TrafficStats.getMobileRxBytes(); long totalTxPacketsAfter = TrafficStats.getTotalTxPackets(); long totalRxPacketsAfter = TrafficStats.getTotalRxPackets(); long totalTxBytesAfter = TrafficStats.getTotalTxBytes(); long totalRxBytesAfter = TrafficStats.getTotalRxBytes(); long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid()); long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid()); - - // Localhost traffic should *not* count against mobile or total stats. - // There might be some other traffic, but nowhere near 1MB. - - assertTrue("mtxp: " + mobileTxPacketsBefore + " -> " + mobileTxPacketsAfter, - mobileTxPacketsAfter >= mobileTxPacketsBefore && - mobileTxPacketsAfter <= mobileTxPacketsBefore + 500); - assertTrue("mrxp: " + mobileRxPacketsBefore + " -> " + mobileRxPacketsAfter, - mobileRxPacketsAfter >= mobileRxPacketsBefore && - mobileRxPacketsAfter <= mobileRxPacketsBefore + 500); - assertTrue("mtxb: " + mobileTxBytesBefore + " -> " + mobileTxBytesAfter, - mobileTxBytesAfter >= mobileTxBytesBefore && - mobileTxBytesAfter <= mobileTxBytesBefore + 200000); - assertTrue("mrxb: " + mobileRxBytesBefore + " -> " + mobileRxBytesAfter, - mobileRxBytesAfter >= mobileRxBytesBefore && - mobileRxBytesAfter <= mobileRxBytesBefore + 200000); - - assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, - totalTxPacketsAfter >= totalTxPacketsBefore && - totalTxPacketsAfter <= totalTxPacketsBefore + 500); - assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, - totalRxPacketsAfter >= totalRxPacketsBefore && - totalRxPacketsAfter <= totalRxPacketsBefore + 500); - assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, - totalTxBytesAfter >= totalTxBytesBefore && - totalTxBytesAfter <= totalTxBytesBefore + 200000); - assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, - totalRxBytesAfter >= totalRxBytesBefore && - totalRxBytesAfter <= totalRxBytesBefore + 200000); + long uidTxPacketsAfter = TrafficStats.getUidTxPackets(Process.myUid()); + long uidRxPacketsAfter = TrafficStats.getUidRxPackets(Process.myUid()); + long uidTxDeltaBytes = uidTxBytesAfter - uidTxBytesBefore; + long uidTxDeltaPackets = uidTxPacketsAfter - uidTxPacketsBefore; + long uidRxDeltaBytes = uidRxBytesAfter - uidRxBytesBefore; + long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore; // Localhost traffic *does* count against per-UID stats. - assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter, - uidTxBytesAfter >= uidTxBytesBefore + 1048576); - assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter, - uidRxBytesAfter >= uidRxBytesBefore + 1048576); + /* + * Calculations: + * - bytes + * bytes is approx: packets * data + packets * acks; + * but sometimes there are less acks than packets, so we set a lower + * limit of 1 ack. + * - setup/teardown + * + 7 approx.: syn, syn-ack, ack, fin-ack, ack, fin-ack, ack; + * but sometimes the last find-acks just vanish, so we set a lower limit of +5. + */ + assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets, + uidTxDeltaPackets >= packetCount + 5 && + uidTxDeltaPackets <= packetCount + packetCount + 7); + assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets, + uidRxDeltaPackets >= packetCount + 5 && + uidRxDeltaPackets <= packetCount + packetCount + 7); + assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes, + uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(5, 0) && + uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + 7, 0)); + assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes, + uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(5, 0) && + uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + 7, 0)); + + // Localhost traffic *does* count against total stats. + // Fudge by 132 packets of 1500 bytes not related to the test. + assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, + totalTxPacketsAfter >= totalTxPacketsBefore + uidTxDeltaPackets && + totalTxPacketsAfter <= totalTxPacketsBefore + uidTxDeltaPackets + 132); + assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, + totalRxPacketsAfter >= totalRxPacketsBefore + uidRxDeltaPackets && + totalRxPacketsAfter <= totalRxPacketsBefore + uidRxDeltaPackets + 132); + assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, + totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes && + totalTxBytesAfter <= totalTxBytesBefore + uidTxDeltaBytes + 132 * 1500); + assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, + totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes && + totalRxBytesAfter <= totalRxBytesBefore + uidRxDeltaBytes + 132 * 1500); + + // Localhost traffic should *not* count against mobile stats, + // There might be some other traffic, but nowhere near 1MB. + assertTrue("mtxp: " + mobileTxPacketsBefore + " -> " + mobileTxPacketsAfter, + mobileTxPacketsAfter >= mobileTxPacketsBefore && + mobileTxPacketsAfter <= mobileTxPacketsBefore + 500); + assertTrue("mrxp: " + mobileRxPacketsBefore + " -> " + mobileRxPacketsAfter, + mobileRxPacketsAfter >= mobileRxPacketsBefore && + mobileRxPacketsAfter <= mobileRxPacketsBefore + 500); + assertTrue("mtxb: " + mobileTxBytesBefore + " -> " + mobileTxBytesAfter, + mobileTxBytesAfter >= mobileTxBytesBefore && + mobileTxBytesAfter <= mobileTxBytesBefore + 200000); + assertTrue("mrxb: " + mobileRxBytesBefore + " -> " + mobileRxBytesAfter, + mobileRxBytesAfter >= mobileRxBytesBefore && + mobileRxBytesAfter <= mobileRxBytesBefore + 200000); + } } From 98eea9f03a0fc047c7ae6821f5220c4a4556fee3 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Fri, 22 Mar 2013 13:56:03 -0700 Subject: [PATCH 0104/1415] Add cts to test quotes on ssid in WifiInfo Bug: 7892415 Change-Id: I0e7b97762aa755f9d10655572be0ad550e370716 --- tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 16dc57de2b..8719b6b029 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -122,7 +122,13 @@ public class WifiInfoTest extends AndroidTestCase { assertNotNull(wifiInfo.toString()); SupplicantState.isValidState(wifiInfo.getSupplicantState()); WifiInfo.getDetailedStateOf(SupplicantState.DISCONNECTED); - wifiInfo.getSSID(); + String ssid = wifiInfo.getSSID(); + if (ssid.startsWith("0x") == false) { + // Non-hex string should be quoted + assertTrue(ssid.charAt(0) == '"'); + assertTrue(ssid.charAt(ssid.length() - 1) == '"'); + } + wifiInfo.getBSSID(); wifiInfo.getIpAddress(); wifiInfo.getLinkSpeed(); From 66bc4595dc8f98817fbc1529f2a8c7df7fb46580 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 26 Mar 2013 14:00:34 -0700 Subject: [PATCH 0105/1415] TrafficStats are always supported, tag tests. Bug: 8417220 Change-Id: I2a06d2e752606cec4bfe35266d9e37271c275d95 --- .../src/android/net/cts/TrafficStatsTest.java | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 89933bfc5c..180d259bbc 100644 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -16,7 +16,6 @@ package android.net.cts; - import android.net.TrafficStats; import android.os.Process; import android.test.AndroidTestCase; @@ -26,20 +25,48 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class TrafficStatsTest extends AndroidTestCase { - public void testGetMobileStats() { + public void testValidMobileStats() { // We can't assume a mobile network is even present in this test, so // we simply assert that a valid value is returned. - assertTrue(TrafficStats.getMobileTxPackets() == TrafficStats.UNSUPPORTED || - TrafficStats.getMobileTxPackets() >= 0); - assertTrue(TrafficStats.getMobileRxPackets() == TrafficStats.UNSUPPORTED || - TrafficStats.getMobileRxPackets() >= 0); - assertTrue(TrafficStats.getMobileTxBytes() == TrafficStats.UNSUPPORTED || - TrafficStats.getMobileTxBytes() >= 0); - assertTrue(TrafficStats.getMobileRxBytes() == TrafficStats.UNSUPPORTED || - TrafficStats.getMobileRxBytes() >= 0); + assertTrue(TrafficStats.getMobileTxPackets() >= 0); + assertTrue(TrafficStats.getMobileRxPackets() >= 0); + assertTrue(TrafficStats.getMobileTxBytes() >= 0); + assertTrue(TrafficStats.getMobileRxBytes() >= 0); + } + + public void testValidTotalStats() { + assertTrue(TrafficStats.getTotalTxPackets() >= 0); + assertTrue(TrafficStats.getTotalRxPackets() >= 0); + assertTrue(TrafficStats.getTotalTxBytes() >= 0); + assertTrue(TrafficStats.getTotalRxBytes() >= 0); + } + + public void testThreadStatsTag() throws Exception { + TrafficStats.setThreadStatsTag(0xf00d); + assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xf00d); + + final CountDownLatch latch = new CountDownLatch(1); + + new Thread("TrafficStatsTest.testThreadStatsTag") { + @Override + public void run() { + assertTrue("Tag leaked", TrafficStats.getThreadStatsTag() != 0xf00d); + TrafficStats.setThreadStatsTag(0xcafe); + assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xcafe); + latch.countDown(); + } + }.start(); + + latch.await(5, TimeUnit.SECONDS); + assertTrue("Tag lost", TrafficStats.getThreadStatsTag() == 0xf00d); + + TrafficStats.clearThreadStatsTag(); + assertTrue("Tag not cleared", TrafficStats.getThreadStatsTag() != 0xf00d); } long tcpPacketToIpBytes(long packetCount, long bytes) { From 5e1b502ce8b8639e20458e058ef00b311ccdd38e Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 11 Mar 2013 14:32:33 -0700 Subject: [PATCH 0106/1415] Add CTS tests for ConnectivityService bug:4074341 Change-Id: Ic02d08e51c051789ed7fa1c949d42fa22bdc8a08 --- .../net/cts/ConnectivityManagerTest.java | 184 +++++++++++++----- 1 file changed, 138 insertions(+), 46 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 4fa69a88f3..c24415901c 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; +import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; @@ -30,7 +31,10 @@ import android.net.wifi.WifiManager; import android.test.AndroidTestCase; import android.util.Log; +import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -51,6 +55,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { private ConnectivityManager mCm; private WifiManager mWifiManager; private PackageManager mPackageManager; + private final HashMap mNetworks = + new HashMap(); + private final ListmProtectedNetworks = new ArrayList(); @Override protected void setUp() throws Exception { @@ -58,45 +65,115 @@ public class ConnectivityManagerTest extends AndroidTestCase { mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); mPackageManager = getContext().getPackageManager(); - } - public void testGetNetworkInfo() { - assertTrue(mCm.getAllNetworkInfo().length >= MIN_NUM_NETWORK_TYPES); - NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI); - if (ni != null) { - State state = ni.getState(); - assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() - && state.ordinal() >= State.CONNECTING.ordinal()); - DetailedState ds = ni.getDetailedState(); - assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() - && ds.ordinal() >= DetailedState.IDLE.ordinal()); + String[] naStrings = getContext().getResources().getStringArray( + com.android.internal.R.array.networkAttributes); + for (String naString : naStrings) { + try { + NetworkConfig n = new NetworkConfig(naString); + mNetworks.put(n.type, n); + } catch (Exception e) {} } - ni = mCm.getNetworkInfo(TYPE_MOBILE); - if (ni != null) { - State state = ni.getState(); - assertTrue(State.UNKNOWN.ordinal() >= state.ordinal() - && state.ordinal() >= State.CONNECTING.ordinal()); - DetailedState ds = ni.getDetailedState(); - assertTrue(DetailedState.FAILED.ordinal() >= ds.ordinal() - && ds.ordinal() >= DetailedState.IDLE.ordinal()); + + int[] protectedNetworks = getContext().getResources().getIntArray( + com.android.internal.R.array.config_protectedNetworks); + for (int p : protectedNetworks) { + mProtectedNetworks.add(p); } - ni = mCm.getNetworkInfo(-1); - assertNull(ni); } public void testIsNetworkTypeValid() { + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_MMS)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_SUPL)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_DUN)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_HIPRI)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIMAX)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_BLUETOOTH)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_DUMMY)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_ETHERNET)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_FOTA)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P)); + assertFalse(mCm.isNetworkTypeValid(-1)); + assertTrue(mCm.isNetworkTypeValid(0)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE)); + assertFalse(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE+1)); NetworkInfo[] ni = mCm.getAllNetworkInfo(); - for (NetworkInfo n : ni) { + for (NetworkInfo n: ni) { assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType())); } - assertFalse(ConnectivityManager.isNetworkTypeValid(-1)); + + } + + public void testSetNetworkPreference() { + // verify swtiching between two default networks - need to connectable networks though + // could use test and whatever the current active network is + NetworkInfo active = mCm.getActiveNetworkInfo(); + int originalPref = mCm.getNetworkPreference(); + int currentPref = originalPref; + for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { + mCm.setNetworkPreference(type); + NetworkConfig c = mNetworks.get(type); + boolean expectWorked = (c != null && c.isDefault()); + try { + Thread.currentThread().sleep(100); + } catch (InterruptedException e) {} + int foundType = mCm.getNetworkPreference(); + if (expectWorked) { + assertTrue("We should have been able to switch prefered type " + type, + foundType == type); + currentPref = foundType; + } else { + assertTrue("We should not have been able to switch type " + type, + foundType == currentPref); + } + } + mCm.setNetworkPreference(originalPref); + } + + public void testGetActiveNetworkInfo() { + NetworkInfo ni = mCm.getActiveNetworkInfo(); + + assertTrue("You must have an active network connection to complete CTS", ni != null); + assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); + assertTrue(ni.getState() == State.CONNECTED); + } + + public void testGetNetworkInfo() { + for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { + if (isSupported(type)) { + NetworkInfo ni = mCm.getNetworkInfo(type); + assertTrue("Info shouldn't be null for " + type, ni != null); + State state = ni.getState(); + assertTrue("Bad state for " + type, State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue("Bad detailed state for " + type, + DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + } else { + assertNull("Info should be null for " + type, mCm.getNetworkInfo(type)); + } + } } public void testGetAllNetworkInfo() { NetworkInfo[] ni = mCm.getAllNetworkInfo(); assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); + for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { + int desiredFoundCount = (isSupported(type) ? 1 : 0); + int foundCount = 0; + for (NetworkInfo i : ni) { + if (i.getType() == type) foundCount++; + } + assertTrue("Unexpected foundCount of " + foundCount + " for type " + type, + foundCount == desiredFoundCount); + } } public void testStartUsingNetworkFeature() { @@ -130,35 +207,46 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } - public void testRequestRouteToHost() { - Set exceptionFreeTypes = new HashSet(); - exceptionFreeTypes.add(ConnectivityManager.TYPE_BLUETOOTH); - exceptionFreeTypes.add(ConnectivityManager.TYPE_ETHERNET); - exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE); - exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE_DUN); - exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE_HIPRI); - exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE_MMS); - exceptionFreeTypes.add(ConnectivityManager.TYPE_MOBILE_SUPL); + private boolean isSupported(int networkType) { + return mNetworks.containsKey(networkType); + } - NetworkInfo[] ni = mCm.getAllNetworkInfo(); - for (NetworkInfo n : ni) { - if (n.isConnected() && exceptionFreeTypes.contains(n.getType())) { - assertTrue("Network type: " + n.getType(), mCm.requestRouteToHost(n.getType(), - HOST_ADDRESS)); + // true if only the system can turn it on + private boolean isNetworkProtected(int networkType) { + return mProtectedNetworks.contains(networkType); + } + + public void testIsNetworkSupported() { + for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { + boolean supported = mCm.isNetworkSupported(type); + if (isSupported(type)) { + assertTrue(supported); + } else { + assertFalse(supported); } } + } + + public void testRequestRouteToHost() { + for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { + NetworkInfo ni = mCm.getNetworkInfo(type); + boolean expectToWork = isSupported(type) && !isNetworkProtected(type) && + ni != null && ni.isConnected(); + + try { + assertTrue("Network type " + type, + mCm.requestRouteToHost(type, HOST_ADDRESS) == expectToWork); + } catch (Exception e) { + Log.d(TAG, "got exception in requestRouteToHost for type " + type); + assertFalse("Exception received for type " + type, expectToWork); + } + + //TODO verify route table + } assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS)); } - public void testGetActiveNetworkInfo() { - NetworkInfo ni = mCm.getActiveNetworkInfo(); - - if (ni != null) { - assertTrue(ni.getType() >= 0); - } - } - public void testTest() { mCm.getBackgroundDataSetting(); } @@ -197,12 +285,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue("Couldn't requestRouteToHost using HIPRI.", mCm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, HOST_ADDRESS)); - + // TODO check dns selection + // TODO check routes } catch (InterruptedException e) { fail("Broadcast receiver waiting for ConnectivityManager interrupted."); } finally { mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, FEATURE_ENABLE_HIPRI); + // TODO wait for HIPRI to go + // TODO check dns selection + // TODO check routes if (!isWifiConnected) { mWifiManager.setWifiEnabled(false); } From 9d24abdc7db2b70fae03a44e013ae02f06ba3daf Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Fri, 19 Apr 2013 10:47:42 -0700 Subject: [PATCH 0107/1415] EAP API CTS tests Bug: 8646305 Change-Id: Id5595ee0d1bfedae827df8c99516cd4e27d0a97a --- .../wifi/cts/WifiEnterpriseConfigTest.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java new file mode 100644 index 0000000000..58298d5f10 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2013 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.wifi.cts; + +import android.content.Context; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiEnterpriseConfig; +import android.net.wifi.WifiEnterpriseConfig.Eap; +import android.net.wifi.WifiEnterpriseConfig.Phase2; +import android.net.wifi.WifiManager; +import android.test.AndroidTestCase; + +public class WifiEnterpriseConfigTest extends AndroidTestCase { + private WifiManager mWifiManager; + + private static final String SSID = "\"TestSSID\""; + private static final String IDENTITY = "identity"; + private static final String PASSWORD = "password"; + private static final String SUBJECT_MATCH = "subjectmatch"; + private static final String ANON_IDENTITY = "anonidentity"; + private static final int ENABLE_DELAY = 10000; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mWifiManager = (WifiManager) mContext + .getSystemService(Context.WIFI_SERVICE); + assertNotNull(mWifiManager); + mWifiManager.setWifiEnabled(true); + Thread.sleep(ENABLE_DELAY); + assertTrue(mWifiManager.isWifiEnabled()); + } + + public void testSettersAndGetters() { + WifiEnterpriseConfig config = new WifiEnterpriseConfig(); + assertTrue(config.getEapMethod() == Eap.NONE); + config.setEapMethod(Eap.PEAP); + assertTrue(config.getEapMethod() == Eap.PEAP); + config.setEapMethod(Eap.PWD); + assertTrue(config.getEapMethod() == Eap.PWD); + config.setEapMethod(Eap.TLS); + assertTrue(config.getEapMethod() == Eap.TLS); + config.setEapMethod(Eap.TTLS); + assertTrue(config.getEapMethod() == Eap.TTLS); + assertTrue(config.getPhase2Method() == Phase2.NONE); + config.setPhase2Method(Phase2.PAP); + assertTrue(config.getPhase2Method() == Phase2.PAP); + config.setPhase2Method(Phase2.MSCHAP); + assertTrue(config.getPhase2Method() == Phase2.MSCHAP); + config.setPhase2Method(Phase2.MSCHAPV2); + assertTrue(config.getPhase2Method() == Phase2.MSCHAPV2); + config.setPhase2Method(Phase2.GTC); + assertTrue(config.getPhase2Method() == Phase2.GTC); + config.setIdentity(IDENTITY); + assertTrue(config.getIdentity().equals(IDENTITY)); + config.setAnonymousIdentity(ANON_IDENTITY); + assertTrue(config.getAnonymousIdentity().equals(ANON_IDENTITY)); + config.setPassword(PASSWORD); + assertTrue(config.getPassword().equals(PASSWORD)); + config.setCaCertificate(null); + config.setClientKeyEntry(null, null); + config.setSubjectMatch(SUBJECT_MATCH); + assertTrue(config.getSubjectMatch().equals(SUBJECT_MATCH)); + } + + public void testAddEapNetwork() { + WifiConfiguration config = new WifiConfiguration(); + WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); + enterpriseConfig.setEapMethod(Eap.PWD); + enterpriseConfig.setIdentity(IDENTITY); + enterpriseConfig.setPassword(PASSWORD); + config.SSID = SSID; + config.enterpriseConfig = enterpriseConfig; + + int netId = mWifiManager.addNetwork(config); + assertTrue(doesSsidExist(SSID)); + mWifiManager.removeNetwork(netId); + assertFalse(doesSsidExist(SSID)); + } + + private boolean doesSsidExist(String ssid) { + for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { + if (w.SSID.equals(ssid)) + return true; + } + return false; + } +} From a47523d872cd4a07cf660692fabd38bd8abd505f Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Thu, 25 Apr 2013 12:55:58 -0700 Subject: [PATCH 0108/1415] Fix file permissions Java source files are not generally executable. Change-Id: I4fe45a3eb7bc136ba29dd6632bf9865f2f940bf3 --- tests/cts/net/src/android/net/http/cts/SslErrorTest.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 tests/cts/net/src/android/net/http/cts/SslErrorTest.java diff --git a/tests/cts/net/src/android/net/http/cts/SslErrorTest.java b/tests/cts/net/src/android/net/http/cts/SslErrorTest.java old mode 100755 new mode 100644 From fc0f6f4721bb6fbe3a938b58abd2e2e0cb2b8018 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 25 Apr 2013 17:08:18 -0700 Subject: [PATCH 0109/1415] Add debug logging. Also fix timing issue with setNetworkPreference bug:8658717 Change-Id: Ifc6de4758a3d800a52f4e53cb4c6d2a4c6109390 --- .../net/cts/ConnectivityManagerTest.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index c24415901c..d4bff12a18 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -113,25 +113,30 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testSetNetworkPreference() { // verify swtiching between two default networks - need to connectable networks though // could use test and whatever the current active network is - NetworkInfo active = mCm.getActiveNetworkInfo(); int originalPref = mCm.getNetworkPreference(); int currentPref = originalPref; for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { mCm.setNetworkPreference(type); NetworkConfig c = mNetworks.get(type); boolean expectWorked = (c != null && c.isDefault()); - try { - Thread.currentThread().sleep(100); - } catch (InterruptedException e) {} - int foundType = mCm.getNetworkPreference(); + int totalSleep = 0; + int foundType = ConnectivityManager.TYPE_NONE; + while (totalSleep < 1000) { + try { + Thread.currentThread().sleep(100); + } catch (InterruptedException e) {} + totalSleep += 100; + foundType = mCm.getNetworkPreference(); + if (currentPref != foundType) break; + } if (expectWorked) { assertTrue("We should have been able to switch prefered type " + type, foundType == type); - currentPref = foundType; } else { assertTrue("We should not have been able to switch type " + type, - foundType == currentPref); + foundType != type); } + currentPref = foundType; } mCm.setNetworkPreference(originalPref); } @@ -171,6 +176,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { for (NetworkInfo i : ni) { if (i.getType() == type) foundCount++; } + if (foundCount != desiredFoundCount) { + Log.e(TAG, "failure in testGetAllNetworkInfo. Dump of returned NetworkInfos:"); + for (NetworkInfo networkInfo : ni) Log.e(TAG, " " + networkInfo); + } assertTrue("Unexpected foundCount of " + foundCount + " for type " + type, foundCount == desiredFoundCount); } From e2b2f9f3900aabae17251d6eb41dccb1d7e03c08 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 25 Apr 2013 17:08:18 -0700 Subject: [PATCH 0110/1415] Add debug logging. Also fix timing issue with setNetworkPreference bug:8658717 Change-Id: Ifc6de4758a3d800a52f4e53cb4c6d2a4c6109390 --- .../net/cts/ConnectivityManagerTest.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index c24415901c..d4bff12a18 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -113,25 +113,30 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testSetNetworkPreference() { // verify swtiching between two default networks - need to connectable networks though // could use test and whatever the current active network is - NetworkInfo active = mCm.getActiveNetworkInfo(); int originalPref = mCm.getNetworkPreference(); int currentPref = originalPref; for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { mCm.setNetworkPreference(type); NetworkConfig c = mNetworks.get(type); boolean expectWorked = (c != null && c.isDefault()); - try { - Thread.currentThread().sleep(100); - } catch (InterruptedException e) {} - int foundType = mCm.getNetworkPreference(); + int totalSleep = 0; + int foundType = ConnectivityManager.TYPE_NONE; + while (totalSleep < 1000) { + try { + Thread.currentThread().sleep(100); + } catch (InterruptedException e) {} + totalSleep += 100; + foundType = mCm.getNetworkPreference(); + if (currentPref != foundType) break; + } if (expectWorked) { assertTrue("We should have been able to switch prefered type " + type, foundType == type); - currentPref = foundType; } else { assertTrue("We should not have been able to switch type " + type, - foundType == currentPref); + foundType != type); } + currentPref = foundType; } mCm.setNetworkPreference(originalPref); } @@ -171,6 +176,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { for (NetworkInfo i : ni) { if (i.getType() == type) foundCount++; } + if (foundCount != desiredFoundCount) { + Log.e(TAG, "failure in testGetAllNetworkInfo. Dump of returned NetworkInfos:"); + for (NetworkInfo networkInfo : ni) Log.e(TAG, " " + networkInfo); + } assertTrue("Unexpected foundCount of " + foundCount + " for type " + type, foundCount == desiredFoundCount); } From 69f9447ac9d12cda32307ea987fab8080cff93e5 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 20 May 2013 10:32:34 -0700 Subject: [PATCH 0111/1415] DO NOT MERGE - remove dns test from MR2 bug:8658901 Change-Id: I979f38545d7bde91e3711d09ba4278e02183a05b --- .../cts/net/src/android/net/cts/DnsTest.java | 237 ------------------ 1 file changed, 237 deletions(-) delete mode 100644 tests/cts/net/src/android/net/cts/DnsTest.java diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java deleted file mode 100644 index cdd95aa077..0000000000 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2013 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 android.os.SystemClock; -import android.test.AndroidTestCase; -import android.util.Log; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; - -public class DnsTest extends AndroidTestCase { - - static { - System.loadLibrary("nativedns_jni"); - } - - private static final boolean DBG = false; - private static final String TAG = "DnsTest"; - - /** - * @return true on success - */ - private static native boolean testNativeDns(); - - /** - * Verify: - * DNS works - forwards and backwards, giving ipv4 and ipv6 - * Test that DNS work on v4 and v6 networks - * Test Native dns calls (4) - * Todo: - * Cache is flushed when we change networks - * have per-network caches - * No cache when there's no network - * Perf - measure size of first and second tier caches and their effect - * Assert requires network permission - */ - public void testDnsWorks() { - InetAddress addrs[] = {}; - try { - addrs = InetAddress.getAllByName("www.google.com"); - } catch (UnknownHostException e) {} - assertTrue(addrs.length != 0); - boolean foundV4 = false, foundV6 = false; - for (InetAddress addr : addrs) { - if (addr instanceof Inet4Address) foundV4 = true; - else if (addr instanceof Inet6Address) foundV6 = true; - if (DBG) Log.e(TAG, "www.google.com gave " + addr.toString()); - } - assertTrue(foundV4); - assertTrue(foundV6); - try { - addrs = InetAddress.getAllByName("ipv6.google.com"); - } catch (UnknownHostException e) {} - assertTrue(addrs.length != 0); - foundV4 = false; - foundV6 = false; - for (InetAddress addr : addrs) { - if (addr instanceof Inet4Address) foundV4 = true; - else if (addr instanceof Inet6Address) foundV6 = true; - if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString()); - } - assertTrue(foundV4 == false); - assertTrue(foundV6 == true); - assertTrue(testNativeDns()); - } - - private static final String[] URLS = { "www.google.com", "ipv6.google.com", "www.yahoo.com", - "facebook.com", "youtube.com", "blogspot.com", "baidu.com", "wikipedia.org", -// live.com fails rev lookup. - "twitter.com", "qq.com", "msn.com", "yahoo.co.jp", "linkedin.com", - "taobao.com", "google.co.in", "sina.com.cn", "amazon.com", "wordpress.com", - "google.co.uk", "ebay.com", "yandex.ru", "163.com", "google.co.jp", "google.fr", - "microsoft.com", "paypal.com", "google.com.br", "flickr.com", - "mail.ru", "craigslist.org", "fc2.com", "google.it", -// "apple.com", fails rev lookup - "google.es", - "imdb.com", "google.ru", "soho.com", "bbc.co.uk", "vkontakte.ru", "ask.com", - "tumblr.com", "weibo.com", "go.com", "xvideos.com", "livejasmin.com", "cnn.com", - "youku.com", "blogspot.com", "soso.com", "google.ca", "aol.com", "tudou.com", - "xhamster.com", "megaupload.com", "ifeng.com", "zedo.com", "mediafire.com", "ameblo.jp", - "pornhub.com", "google.co.id", "godaddy.com", "adobe.com", "rakuten.co.jp", "about.com", - "espn.go.com", "4shared.com", "alibaba.com","ebay.de", "yieldmanager.com", - "wordpress.org", "livejournal.com", "google.com.tr", "google.com.mx", "renren.com", - "livedoor.com", "google.com.au", "youporn.com", "uol.com.br", "cnet.com", "conduit.com", - "google.pl", "myspace.com", "nytimes.com", "ebay.co.uk", "chinaz.com", "hao123.com", - "thepiratebay.org", "doubleclick.com", "alipay.com", "netflix.com", "cnzz.com", - "huffingtonpost.com", "twitpic.com", "weather.com", "babylon.com", "amazon.de", - "dailymotion.com", "orkut.com", "orkut.com.br", "google.com.sa", "odnoklassniki.ru", - "amazon.co.jp", "google.nl", "goo.ne.jp", "stumbleupon.com", "tube8.com", "tmall.com", - "imgur.com", "globo.com", "secureserver.net", "fileserve.com", "tianya.cn", "badoo.com", - "ehow.com", "photobucket.com", "imageshack.us", "xnxx.com", "deviantart.com", - "filestube.com", "addthis.com", "douban.com", "vimeo.com", "sogou.com", - "stackoverflow.com", "reddit.com", "dailymail.co.uk", "redtube.com", "megavideo.com", - "taringa.net", "pengyou.com", "amazon.co.uk", "fbcdn.net", "aweber.com", "spiegel.de", - "rapidshare.com", "mixi.jp", "360buy.com", "google.cn", "digg.com", "answers.com", - "bit.ly", "indiatimes.com", "skype.com", "yfrog.com", "optmd.com", "google.com.eg", - "google.com.pk", "58.com", "hotfile.com", "google.co.th", - "bankofamerica.com", "sourceforge.net", "maktoob.com", "warriorforum.com", "rediff.com", - "google.co.za", "56.com", "torrentz.eu", "clicksor.com", "avg.com", - "download.com", "ku6.com", "statcounter.com", "foxnews.com", "google.com.ar", - "nicovideo.jp", "reference.com", "liveinternet.ru", "ucoz.ru", "xinhuanet.com", - "xtendmedia.com", "naver.com", "youjizz.com", "domaintools.com", "sparkstudios.com", - "rambler.ru", "scribd.com", "kaixin001.com", "mashable.com", "adultfirendfinder.com", - "files.wordpress.com", "guardian.co.uk", "bild.de", "yelp.com", "wikimedia.org", - "chase.com", "onet.pl", "ameba.jp", "pconline.com.cn", "free.fr", "etsy.com", - "typepad.com", "youdao.com", "megaclick.com", "digitalpoint.com", "blogfa.com", - "salesforce.com", "adf.ly", "ganji.com", "wikia.com", "archive.org", "terra.com.br", - "w3schools.com", "ezinearticles.com", "wjs.com", "google.com.my", "clickbank.com", - "squidoo.com", "hulu.com", "repubblica.it", "google.be", "allegro.pl", "comcast.net", - "narod.ru", "zol.com.cn", "orange.fr", "soufun.com", "hatena.ne.jp", "google.gr", - "in.com", "techcrunch.com", "orkut.co.in", "xunlei.com", - "reuters.com", "google.com.vn", "hostgator.com", "kaskus.us", "espncricinfo.com", - "hootsuite.com", "qiyi.com", "gmx.net", "xing.com", "php.net", "soku.com", "web.de", - "libero.it", "groupon.com", "51.la", "slideshare.net", "booking.com", "seesaa.net", - "126.com", "telegraph.co.uk", "wretch.cc", "twimg.com", "rutracker.org", "angege.com", - "nba.com", "dell.com", "leboncoin.fr", "people.com", "google.com.tw", "walmart.com", - "daum.net", "2ch.net", "constantcontact.com", "nifty.com", "mywebsearch.com", - "tripadvisor.com", "google.se", "paipai.com", "google.com.ua", "ning.com", "hp.com", - "google.at", "joomla.org", "icio.us", "hudong.com", "csdn.net", "getfirebug.com", - "ups.com", "cj.com", "google.ch", "camzap.com", "wordreference.com", "tagged.com", - "wp.pl", "mozilla.com", "google.ru", "usps.com", "china.com", "themeforest.net", - "search-results.com", "tribalfusion.com", "thefreedictionary.com", "isohunt.com", - "linkwithin.com", "cam4.com", "plentyoffish.com", "wellsfargo.com", "metacafe.com", - "depositfiles.com", "freelancer.com", "opendns.com", "homeway.com", "engadget.com", - "10086.cn", "360.cn", "marca.com", "dropbox.com", "ign.com", "match.com", "google.pt", - "facemoods.com", "hardsextube.com", "google.com.ph", "lockerz.com", "istockphoto.com", - "partypoker.com", "netlog.com", "outbrain.com", "elpais.com", "fiverr.com", - "biglobe.ne.jp", "corriere.it", "love21cn.com", "yesky.com", "spankwire.com", - "ig.com.br", "imagevenue.com", "hubpages.com", "google.co.ve"}; - -// TODO - this works, but is slow and cts doesn't do anything with the result. -// Maybe require a min performance, a min cache size (detectable) and/or move -// to perf testing - private static final int LOOKUP_COUNT_GOAL = URLS.length; - public void skiptestDnsPerf() { - ArrayList results = new ArrayList(); - int failures = 0; - try { - for (int numberOfUrls = URLS.length; numberOfUrls > 0; numberOfUrls--) { - failures = 0; - int iterationLimit = LOOKUP_COUNT_GOAL / numberOfUrls; - long startTime = SystemClock.elapsedRealtimeNanos(); - for (int iteration = 0; iteration < iterationLimit; iteration++) { - for (int urlIndex = 0; urlIndex < numberOfUrls; urlIndex++) { - try { - InetAddress addr = InetAddress.getByName(URLS[urlIndex]); - } catch (UnknownHostException e) { - Log.e(TAG, "failed first lookup of " + URLS[urlIndex]); - failures++; - try { - InetAddress addr = InetAddress.getByName(URLS[urlIndex]); - } catch (UnknownHostException ee) { - failures++; - Log.e(TAG, "failed SECOND lookup of " + URLS[urlIndex]); - } - } - } - } - long endTime = SystemClock.elapsedRealtimeNanos(); - float nsPer = ((float)(endTime-startTime) / iterationLimit) / numberOfUrls/ 1000; - String thisResult = new String("getByName for " + numberOfUrls + " took " + - (endTime - startTime)/1000 + "(" + nsPer + ") with " + - failures + " failures\n"); - Log.d(TAG, thisResult); - results.add(thisResult); - } - // build up a list of addresses - ArrayList addressList = new ArrayList(); - for (String url : URLS) { - try { - InetAddress addr = InetAddress.getByName(url); - addressList.add(addr.getAddress()); - } catch (UnknownHostException e) { - Log.e(TAG, "Exception making reverseDNS list: " + e.toString()); - } - } - for (int numberOfAddrs = addressList.size(); numberOfAddrs > 0; numberOfAddrs--) { - int iterationLimit = LOOKUP_COUNT_GOAL / numberOfAddrs; - failures = 0; - long startTime = SystemClock.elapsedRealtimeNanos(); - for (int iteration = 0; iteration < iterationLimit; iteration++) { - for (int addrIndex = 0; addrIndex < numberOfAddrs; addrIndex++) { - try { - InetAddress addr = InetAddress.getByAddress(addressList.get(addrIndex)); - String hostname = addr.getHostName(); - } catch (UnknownHostException e) { - failures++; - Log.e(TAG, "Failure doing reverse DNS lookup: " + e.toString()); - try { - InetAddress addr = - InetAddress.getByAddress(addressList.get(addrIndex)); - String hostname = addr.getHostName(); - - } catch (UnknownHostException ee) { - failures++; - Log.e(TAG, "Failure doing SECOND reverse DNS lookup: " + - ee.toString()); - } - } - } - } - long endTime = SystemClock.elapsedRealtimeNanos(); - float nsPer = ((endTime-startTime) / iterationLimit) / numberOfAddrs / 1000; - String thisResult = new String("getHostName for " + numberOfAddrs + " took " + - (endTime - startTime)/1000 + "(" + nsPer + ") with " + - failures + " failures\n"); - Log.d(TAG, thisResult); - results.add(thisResult); - } - for (String result : results) Log.d(TAG, result); - - InetAddress exit = InetAddress.getByName("exitrightnow.com"); - Log.e(TAG, " exit address= "+exit.toString()); - - } catch (Exception e) { - Log.e(TAG, "bad URL in testDnsPerf: " + e.toString()); - } - } -} From ff53e104b1dc85f380551a5d5698b0a165cd2233 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 20 May 2013 10:32:34 -0700 Subject: [PATCH 0112/1415] DO NOT MERGE - remove dns test from MR2 bug:8658901 Change-Id: I979f38545d7bde91e3711d09ba4278e02183a05b --- .../cts/net/src/android/net/cts/DnsTest.java | 237 ------------------ 1 file changed, 237 deletions(-) delete mode 100644 tests/cts/net/src/android/net/cts/DnsTest.java diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java deleted file mode 100644 index cdd95aa077..0000000000 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2013 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 android.os.SystemClock; -import android.test.AndroidTestCase; -import android.util.Log; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; - -public class DnsTest extends AndroidTestCase { - - static { - System.loadLibrary("nativedns_jni"); - } - - private static final boolean DBG = false; - private static final String TAG = "DnsTest"; - - /** - * @return true on success - */ - private static native boolean testNativeDns(); - - /** - * Verify: - * DNS works - forwards and backwards, giving ipv4 and ipv6 - * Test that DNS work on v4 and v6 networks - * Test Native dns calls (4) - * Todo: - * Cache is flushed when we change networks - * have per-network caches - * No cache when there's no network - * Perf - measure size of first and second tier caches and their effect - * Assert requires network permission - */ - public void testDnsWorks() { - InetAddress addrs[] = {}; - try { - addrs = InetAddress.getAllByName("www.google.com"); - } catch (UnknownHostException e) {} - assertTrue(addrs.length != 0); - boolean foundV4 = false, foundV6 = false; - for (InetAddress addr : addrs) { - if (addr instanceof Inet4Address) foundV4 = true; - else if (addr instanceof Inet6Address) foundV6 = true; - if (DBG) Log.e(TAG, "www.google.com gave " + addr.toString()); - } - assertTrue(foundV4); - assertTrue(foundV6); - try { - addrs = InetAddress.getAllByName("ipv6.google.com"); - } catch (UnknownHostException e) {} - assertTrue(addrs.length != 0); - foundV4 = false; - foundV6 = false; - for (InetAddress addr : addrs) { - if (addr instanceof Inet4Address) foundV4 = true; - else if (addr instanceof Inet6Address) foundV6 = true; - if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString()); - } - assertTrue(foundV4 == false); - assertTrue(foundV6 == true); - assertTrue(testNativeDns()); - } - - private static final String[] URLS = { "www.google.com", "ipv6.google.com", "www.yahoo.com", - "facebook.com", "youtube.com", "blogspot.com", "baidu.com", "wikipedia.org", -// live.com fails rev lookup. - "twitter.com", "qq.com", "msn.com", "yahoo.co.jp", "linkedin.com", - "taobao.com", "google.co.in", "sina.com.cn", "amazon.com", "wordpress.com", - "google.co.uk", "ebay.com", "yandex.ru", "163.com", "google.co.jp", "google.fr", - "microsoft.com", "paypal.com", "google.com.br", "flickr.com", - "mail.ru", "craigslist.org", "fc2.com", "google.it", -// "apple.com", fails rev lookup - "google.es", - "imdb.com", "google.ru", "soho.com", "bbc.co.uk", "vkontakte.ru", "ask.com", - "tumblr.com", "weibo.com", "go.com", "xvideos.com", "livejasmin.com", "cnn.com", - "youku.com", "blogspot.com", "soso.com", "google.ca", "aol.com", "tudou.com", - "xhamster.com", "megaupload.com", "ifeng.com", "zedo.com", "mediafire.com", "ameblo.jp", - "pornhub.com", "google.co.id", "godaddy.com", "adobe.com", "rakuten.co.jp", "about.com", - "espn.go.com", "4shared.com", "alibaba.com","ebay.de", "yieldmanager.com", - "wordpress.org", "livejournal.com", "google.com.tr", "google.com.mx", "renren.com", - "livedoor.com", "google.com.au", "youporn.com", "uol.com.br", "cnet.com", "conduit.com", - "google.pl", "myspace.com", "nytimes.com", "ebay.co.uk", "chinaz.com", "hao123.com", - "thepiratebay.org", "doubleclick.com", "alipay.com", "netflix.com", "cnzz.com", - "huffingtonpost.com", "twitpic.com", "weather.com", "babylon.com", "amazon.de", - "dailymotion.com", "orkut.com", "orkut.com.br", "google.com.sa", "odnoklassniki.ru", - "amazon.co.jp", "google.nl", "goo.ne.jp", "stumbleupon.com", "tube8.com", "tmall.com", - "imgur.com", "globo.com", "secureserver.net", "fileserve.com", "tianya.cn", "badoo.com", - "ehow.com", "photobucket.com", "imageshack.us", "xnxx.com", "deviantart.com", - "filestube.com", "addthis.com", "douban.com", "vimeo.com", "sogou.com", - "stackoverflow.com", "reddit.com", "dailymail.co.uk", "redtube.com", "megavideo.com", - "taringa.net", "pengyou.com", "amazon.co.uk", "fbcdn.net", "aweber.com", "spiegel.de", - "rapidshare.com", "mixi.jp", "360buy.com", "google.cn", "digg.com", "answers.com", - "bit.ly", "indiatimes.com", "skype.com", "yfrog.com", "optmd.com", "google.com.eg", - "google.com.pk", "58.com", "hotfile.com", "google.co.th", - "bankofamerica.com", "sourceforge.net", "maktoob.com", "warriorforum.com", "rediff.com", - "google.co.za", "56.com", "torrentz.eu", "clicksor.com", "avg.com", - "download.com", "ku6.com", "statcounter.com", "foxnews.com", "google.com.ar", - "nicovideo.jp", "reference.com", "liveinternet.ru", "ucoz.ru", "xinhuanet.com", - "xtendmedia.com", "naver.com", "youjizz.com", "domaintools.com", "sparkstudios.com", - "rambler.ru", "scribd.com", "kaixin001.com", "mashable.com", "adultfirendfinder.com", - "files.wordpress.com", "guardian.co.uk", "bild.de", "yelp.com", "wikimedia.org", - "chase.com", "onet.pl", "ameba.jp", "pconline.com.cn", "free.fr", "etsy.com", - "typepad.com", "youdao.com", "megaclick.com", "digitalpoint.com", "blogfa.com", - "salesforce.com", "adf.ly", "ganji.com", "wikia.com", "archive.org", "terra.com.br", - "w3schools.com", "ezinearticles.com", "wjs.com", "google.com.my", "clickbank.com", - "squidoo.com", "hulu.com", "repubblica.it", "google.be", "allegro.pl", "comcast.net", - "narod.ru", "zol.com.cn", "orange.fr", "soufun.com", "hatena.ne.jp", "google.gr", - "in.com", "techcrunch.com", "orkut.co.in", "xunlei.com", - "reuters.com", "google.com.vn", "hostgator.com", "kaskus.us", "espncricinfo.com", - "hootsuite.com", "qiyi.com", "gmx.net", "xing.com", "php.net", "soku.com", "web.de", - "libero.it", "groupon.com", "51.la", "slideshare.net", "booking.com", "seesaa.net", - "126.com", "telegraph.co.uk", "wretch.cc", "twimg.com", "rutracker.org", "angege.com", - "nba.com", "dell.com", "leboncoin.fr", "people.com", "google.com.tw", "walmart.com", - "daum.net", "2ch.net", "constantcontact.com", "nifty.com", "mywebsearch.com", - "tripadvisor.com", "google.se", "paipai.com", "google.com.ua", "ning.com", "hp.com", - "google.at", "joomla.org", "icio.us", "hudong.com", "csdn.net", "getfirebug.com", - "ups.com", "cj.com", "google.ch", "camzap.com", "wordreference.com", "tagged.com", - "wp.pl", "mozilla.com", "google.ru", "usps.com", "china.com", "themeforest.net", - "search-results.com", "tribalfusion.com", "thefreedictionary.com", "isohunt.com", - "linkwithin.com", "cam4.com", "plentyoffish.com", "wellsfargo.com", "metacafe.com", - "depositfiles.com", "freelancer.com", "opendns.com", "homeway.com", "engadget.com", - "10086.cn", "360.cn", "marca.com", "dropbox.com", "ign.com", "match.com", "google.pt", - "facemoods.com", "hardsextube.com", "google.com.ph", "lockerz.com", "istockphoto.com", - "partypoker.com", "netlog.com", "outbrain.com", "elpais.com", "fiverr.com", - "biglobe.ne.jp", "corriere.it", "love21cn.com", "yesky.com", "spankwire.com", - "ig.com.br", "imagevenue.com", "hubpages.com", "google.co.ve"}; - -// TODO - this works, but is slow and cts doesn't do anything with the result. -// Maybe require a min performance, a min cache size (detectable) and/or move -// to perf testing - private static final int LOOKUP_COUNT_GOAL = URLS.length; - public void skiptestDnsPerf() { - ArrayList results = new ArrayList(); - int failures = 0; - try { - for (int numberOfUrls = URLS.length; numberOfUrls > 0; numberOfUrls--) { - failures = 0; - int iterationLimit = LOOKUP_COUNT_GOAL / numberOfUrls; - long startTime = SystemClock.elapsedRealtimeNanos(); - for (int iteration = 0; iteration < iterationLimit; iteration++) { - for (int urlIndex = 0; urlIndex < numberOfUrls; urlIndex++) { - try { - InetAddress addr = InetAddress.getByName(URLS[urlIndex]); - } catch (UnknownHostException e) { - Log.e(TAG, "failed first lookup of " + URLS[urlIndex]); - failures++; - try { - InetAddress addr = InetAddress.getByName(URLS[urlIndex]); - } catch (UnknownHostException ee) { - failures++; - Log.e(TAG, "failed SECOND lookup of " + URLS[urlIndex]); - } - } - } - } - long endTime = SystemClock.elapsedRealtimeNanos(); - float nsPer = ((float)(endTime-startTime) / iterationLimit) / numberOfUrls/ 1000; - String thisResult = new String("getByName for " + numberOfUrls + " took " + - (endTime - startTime)/1000 + "(" + nsPer + ") with " + - failures + " failures\n"); - Log.d(TAG, thisResult); - results.add(thisResult); - } - // build up a list of addresses - ArrayList addressList = new ArrayList(); - for (String url : URLS) { - try { - InetAddress addr = InetAddress.getByName(url); - addressList.add(addr.getAddress()); - } catch (UnknownHostException e) { - Log.e(TAG, "Exception making reverseDNS list: " + e.toString()); - } - } - for (int numberOfAddrs = addressList.size(); numberOfAddrs > 0; numberOfAddrs--) { - int iterationLimit = LOOKUP_COUNT_GOAL / numberOfAddrs; - failures = 0; - long startTime = SystemClock.elapsedRealtimeNanos(); - for (int iteration = 0; iteration < iterationLimit; iteration++) { - for (int addrIndex = 0; addrIndex < numberOfAddrs; addrIndex++) { - try { - InetAddress addr = InetAddress.getByAddress(addressList.get(addrIndex)); - String hostname = addr.getHostName(); - } catch (UnknownHostException e) { - failures++; - Log.e(TAG, "Failure doing reverse DNS lookup: " + e.toString()); - try { - InetAddress addr = - InetAddress.getByAddress(addressList.get(addrIndex)); - String hostname = addr.getHostName(); - - } catch (UnknownHostException ee) { - failures++; - Log.e(TAG, "Failure doing SECOND reverse DNS lookup: " + - ee.toString()); - } - } - } - } - long endTime = SystemClock.elapsedRealtimeNanos(); - float nsPer = ((endTime-startTime) / iterationLimit) / numberOfAddrs / 1000; - String thisResult = new String("getHostName for " + numberOfAddrs + " took " + - (endTime - startTime)/1000 + "(" + nsPer + ") with " + - failures + " failures\n"); - Log.d(TAG, thisResult); - results.add(thisResult); - } - for (String result : results) Log.d(TAG, result); - - InetAddress exit = InetAddress.getByName("exitrightnow.com"); - Log.e(TAG, " exit address= "+exit.toString()); - - } catch (Exception e) { - Log.e(TAG, "bad URL in testDnsPerf: " + e.toString()); - } - } -} From c8ddd2d7809b9ee490444193bb0b919c1b6bdc4c Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 27 Jun 2013 11:28:11 -0700 Subject: [PATCH 0113/1415] Fix CTS test for scan-always-available env Even if you disable wifi the supplicant will still be pingable if we're set in always scanning mode. Make the test aware. bug:9545987 Change-Id: I7f1bd0166b877a706de51f8ef169355c98ae25a3 --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 283f63b5d4..2580dbee9f 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -233,7 +233,7 @@ public class WifiManagerTest extends AndroidTestCase { startScan(); setWifiEnabled(false); Thread.sleep(DURATION); - assertFalse(mWifiManager.pingSupplicant()); + assertTrue(mWifiManager.pingSupplicant() == mWifiManager.isScanAlwaysAvailable()); final String TAG = "Test"; assertNotNull(mWifiManager.createWifiLock(TAG)); assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); From 4fd65d09bc6c77bd6157d3c92bd889f5cac49bd2 Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Tue, 23 Jul 2013 16:04:58 -0700 Subject: [PATCH 0114/1415] Add a CTS test for NSD manager API A simple test that registers, discovers and then resolves a service. Bug: 9574276 Change-Id: I685df3c02112cf79b11b2c97efd560dda7232fda --- .../android/net/wifi/cts/NsdManagerTest.java | 424 ++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java new file mode 100644 index 0000000000..482a4e39a6 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2012 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.wifi.cts; + +import android.content.Context; +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.Random; +import java.util.List; +import java.util.ArrayList; + +public class NsdManagerTest extends AndroidTestCase { + + private static final String TAG = "NsdManagerTest"; + private static final String SERVICE_TYPE = "_nmt._tcp"; + private static final int TIMEOUT = 2000; + + private static final boolean DBG = false; + + NsdManager mNsdManager; + + NsdManager.RegistrationListener mRegistrationListener; + NsdManager.DiscoveryListener mDiscoveryListener; + NsdManager.ResolveListener mResolveListener; + + public NsdManagerTest() { + mRegistrationListener = new NsdManager.RegistrationListener() { + @Override + public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + setEvent("onRegistrationFailed", errorCode); + } + + @Override + public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + setEvent("onUnregistrationFailed", errorCode); + } + + @Override + public void onServiceRegistered(NsdServiceInfo serviceInfo) { + setEvent("onServiceRegistered", serviceInfo); + } + + @Override + public void onServiceUnregistered(NsdServiceInfo serviceInfo) { + setEvent("onServiceUnregistered", serviceInfo); + } + }; + mDiscoveryListener = new NsdManager.DiscoveryListener() { + @Override + public void onStartDiscoveryFailed(String serviceType, int errorCode) { + setEvent("onStartDiscoveryFailed", errorCode); + } + + @Override + public void onStopDiscoveryFailed(String serviceType, int errorCode) { + setEvent("onStopDiscoveryFailed", errorCode); + } + + @Override + public void onDiscoveryStarted(String serviceType) { + NsdServiceInfo info = new NsdServiceInfo(); + info.setServiceType(serviceType); + setEvent("onDiscoveryStarted", info); + } + + @Override + public void onDiscoveryStopped(String serviceType) { + NsdServiceInfo info = new NsdServiceInfo(); + info.setServiceType(serviceType); + setEvent("onDiscoveryStopped", info); + } + + @Override + public void onServiceFound(NsdServiceInfo serviceInfo) { + setEvent("onServiceFound", serviceInfo); + } + + @Override + public void onServiceLost(NsdServiceInfo serviceInfo) { + setEvent("onServiceLost", serviceInfo); + } + }; + mResolveListener = new NsdManager.ResolveListener() { + @Override + public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { + setEvent("onResolveFailed", errorCode); + } + + @Override + public void onServiceResolved(NsdServiceInfo serviceInfo) { + setEvent("onServiceResolved", serviceInfo); + } + }; + } + + private final class EventData { + EventData(String callbackName, NsdServiceInfo info) { + mCallbackName = callbackName; + mSucceeded = true; + mErrorCode = 0; + mInfo = info; + } + EventData(String callbackName, int errorCode) { + mCallbackName = callbackName; + mSucceeded = false; + mErrorCode = errorCode; + mInfo = null; + } + private final String mCallbackName; + private final boolean mSucceeded; + private final int mErrorCode; + private final NsdServiceInfo mInfo; + } + + private final List mEventCache = new ArrayList(); + + private void setEvent(String callbackName, int errorCode) { + if (DBG) Log.d(TAG, callbackName + " failed with " + String.valueOf(errorCode)); + EventData eventData = new EventData(callbackName, errorCode); + synchronized (mEventCache) { + mEventCache.add(eventData); + mEventCache.notify(); + } + } + + private void setEvent(String callbackName, NsdServiceInfo info) { + if (DBG) Log.d(TAG, "Received event " + callbackName + " for " + info.getServiceName()); + EventData eventData = new EventData(callbackName, info); + synchronized (mEventCache) { + mEventCache.add(eventData); + mEventCache.notify(); + } + } + + void clearEventCache() { + synchronized(mEventCache) { + mEventCache.clear(); + } + } + + int eventCacheSize() { + synchronized(mEventCache) { + return mEventCache.size(); + } + } + + private int mWaitId = 0; + private EventData waitForCallback(String callbackName) { + + synchronized(mEventCache) { + + mWaitId ++; + if (DBG) Log.d(TAG, "Waiting for " + callbackName + ", id=" + String.valueOf(mWaitId)); + + try { + long startTime = android.os.SystemClock.uptimeMillis(); + long elapsedTime = 0; + int index = 0; + while (elapsedTime < TIMEOUT ) { + // first check if we've received that event + for (; index < mEventCache.size(); index++) { + EventData e = mEventCache.get(index); + if (e.mCallbackName.equals(callbackName)) { + if (DBG) Log.d(TAG, "exiting wait id=" + String.valueOf(mWaitId)); + return e; + } + } + + // Not yet received, just wait + mEventCache.wait(TIMEOUT - elapsedTime); + elapsedTime = android.os.SystemClock.uptimeMillis() - startTime; + } + // we exited the loop because of TIMEOUT; fail the call + if (DBG) Log.d(TAG, "timed out waiting id=" + String.valueOf(mWaitId)); + return null; + } catch (InterruptedException e) { + return null; // wait timed out! + } + } + } + + private String mServiceName; + + @Override + public void setUp() { + if (DBG) Log.d(TAG, "Setup test ..."); + mNsdManager = (NsdManager) getContext().getSystemService(Context.NSD_SERVICE); + + Random rand = new Random(); + mServiceName = new String("NsdTest"); + for (int i = 0; i < 4; i++) { + mServiceName = mServiceName + String.valueOf(rand.nextInt(10)); + } + } + + @Override + public void tearDown() { + if (DBG) Log.d(TAG, "Tear down test ..."); + } + + public void runTest() throws Exception { + NsdServiceInfo si = new NsdServiceInfo(); + si.setServiceType(SERVICE_TYPE); + si.setServiceName(mServiceName); + + EventData lastEvent = null; + + if (DBG) Log.d(TAG, "Starting test ..."); + + ServerSocket socket; + int localPort; + + try { + socket = new ServerSocket(0); + localPort = socket.getLocalPort(); + si.setPort(localPort); + } catch (IOException e) { + if (DBG) Log.d(TAG, "Could not open a local socket"); + assertTrue(false); + return; + } + + if (DBG) Log.d(TAG, "Port = " + String.valueOf(localPort)); + + clearEventCache(); + + mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); + lastEvent = waitForCallback("onServiceRegistered"); // id = 1 + assertTrue(lastEvent != null); + assertTrue(lastEvent.mSucceeded); + assertTrue(eventCacheSize() == 1); + + // We may not always get the name that we tried to register; + // This events tells us the name that was registered. + String registeredName = lastEvent.mInfo.getServiceName(); + si.setServiceName(registeredName); + + clearEventCache(); + + mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, + mDiscoveryListener); + + // Expect discovery started + lastEvent = waitForCallback("onDiscoveryStarted"); // id = 2 + + assertTrue(lastEvent != null); + assertTrue(lastEvent.mSucceeded); + + // Remove this event, so accounting becomes easier later + mEventCache.remove(lastEvent); + + // Expect a service record to be discovered (and filter the ones + // that are unrelated to this test) + boolean found = false; + for (int i = 0; i < 32; i++) { + + lastEvent = waitForCallback("onServiceFound"); // id = 3 + if (lastEvent == null) { + // no more onServiceFound events are being reported! + break; + } + + assertTrue(lastEvent.mSucceeded); + + if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + + lastEvent.mInfo.getServiceName()); + + if (lastEvent.mInfo.getServiceName().equals(registeredName)) { + // Save it, as it will get overwritten with new serviceFound events + si = lastEvent.mInfo; + found = true; + } + + // Remove this event from the event cache, so it won't be found by subsequent + // calls to waitForCallback + mEventCache.remove(lastEvent); + } + + assertTrue(found); + + // We've removed all serviceFound events, and we've removed the discoveryStarted + // event as well, so now the event cache should be empty! + assertTrue(eventCacheSize() == 0); + + // Resolve the service + clearEventCache(); + mNsdManager.resolveService(si, mResolveListener); + lastEvent = waitForCallback("onServiceResolved"); // id = 4 + + assertTrue(lastEvent != null); + assertTrue(lastEvent.mSucceeded); + + if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": Port = " + + String.valueOf(lastEvent.mInfo.getPort())); + + assertTrue(lastEvent.mInfo.getPort() == localPort); + assertTrue(eventCacheSize() == 1); + + clearEventCache(); + + // Unregister the service + mNsdManager.unregisterService(mRegistrationListener); + lastEvent = waitForCallback("onServiceUnregistered"); // id = 5 + + assertTrue(lastEvent != null); + assertTrue(lastEvent.mSucceeded); + + // Expect a callback for service lost + lastEvent = waitForCallback("onServiceLost"); // id = 6 + + assertTrue(lastEvent != null); + assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); + + assertTrue(eventCacheSize() == 2); + + // Register service again to see if we discover it + clearEventCache(); + + si = new NsdServiceInfo(); + si.setServiceType(SERVICE_TYPE); + si.setServiceName(mServiceName); + si.setPort(localPort); + mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); + + lastEvent = waitForCallback("onServiceRegistered"); // id = 7 + + assertTrue(lastEvent != null); + assertTrue(lastEvent.mSucceeded); + + registeredName = lastEvent.mInfo.getServiceName(); + + // Expect a record to be discovered + lastEvent = waitForCallback("onServiceFound"); // id = 8 + + assertTrue(lastEvent != null); + assertTrue(lastEvent.mSucceeded); + + if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + + lastEvent.mInfo.getServiceName()); + + assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); + + assertTrue(eventCacheSize() == 2); + clearEventCache(); + + mNsdManager.stopServiceDiscovery(mDiscoveryListener); + lastEvent = waitForCallback("onDiscoveryStopped"); // id = 9 + assertTrue(lastEvent != null); + assertTrue(lastEvent.mSucceeded); + assertTrue(eventCacheSize() == 1); + + clearEventCache(); + mNsdManager.unregisterService(mRegistrationListener); + + lastEvent = waitForCallback("onServiceUnregistered"); // id = 10 + assertTrue(lastEvent != null); + assertTrue(lastEvent.mSucceeded); + assertTrue(eventCacheSize() == 1); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a73db07a5373747a804e0cabe4c077278d97f3aa Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 17 Aug 2013 16:47:29 -0700 Subject: [PATCH 0115/1415] Add test for TYPE_MOBILE_IA. Bug: 10373518 Change-Id: Ifb976760ea91a858bfc5387fb93e465665cf078f --- tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index d4bff12a18..6f67ed99ea 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -97,6 +97,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS)); assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS)); assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IA)); assertFalse(mCm.isNetworkTypeValid(-1)); assertTrue(mCm.isNetworkTypeValid(0)); assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE)); From 58a91ac733b29226e2e5447060db6d15e71b7d07 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 12 Aug 2013 16:55:27 +0900 Subject: [PATCH 0116/1415] Add a CTS test for IPv6 ping socket support. IPv6 ping socket support is needed for apps to successfully run ping6, but the kernel support was only merged recently. This test ensures that the required kernel support is available. Bug: 9701153 Change-Id: Ieac32ca9dbcaf3890fa3e57c1326fa83787ac6d1 --- .../src/android/net/ipv6/cts/PingTest.java | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 tests/cts/net/src/android/net/ipv6/cts/PingTest.java diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java new file mode 100644 index 0000000000..41eb03d34d --- /dev/null +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2013 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.ipv6.cts; + +import android.test.AndroidTestCase; +import android.util.Log; + +import libcore.io.ErrnoException; +import libcore.io.Libcore; +import libcore.io.StructTimeval; +import static libcore.io.OsConstants.*; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Random; + +public class PingTest extends AndroidTestCase { + /** Maximum size of the packets we're using to test. */ + private static final int MAX_SIZE = 4096; + + /** Number of packets to test. */ + private static final int NUM_PACKETS = 10; + + /** The beginning of an ICMPv6 echo request: type, code, and uninitialized checksum. */ + private static final byte[] PING_HEADER = new byte[] { + (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }; + + /** + * Returns a byte array containing an ICMPv6 echo request with the specified payload length. + */ + private byte[] pingPacket(int payloadLength) { + byte[] packet = new byte[payloadLength + 8]; + new Random().nextBytes(packet); + System.arraycopy(PING_HEADER, 0, packet, 0, PING_HEADER.length); + return packet; + } + + /** + * Checks that the first length bytes of two byte arrays are equal. + */ + private void assertArrayBytesEqual(byte[] expected, byte[] actual, int length) { + for (int i = 0; i < length; i++) { + assertEquals("Arrays differ at index " + i + ":", expected[i], actual[i]); + } + } + + /** + * Creates an IPv6 ping socket and sets a receive timeout of 100ms. + */ + private FileDescriptor createPingSocket() throws ErrnoException { + FileDescriptor s = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); + Libcore.os.setsockoptTimeval(s, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(100)); + return s; + } + + /** + * Sends a ping packet to a random port on the specified address on the specified socket. + */ + private void sendPing(FileDescriptor s, + InetAddress address, byte[] packet) throws ErrnoException, IOException { + // Pick a random port. Choose a range that gives a reasonable chance of picking a low port. + int port = (int) (Math.random() * 2048); + + // Send the packet. + int ret = Libcore.os.sendto(s, ByteBuffer.wrap(packet), 0, address, port); + assertEquals(packet.length, ret); + } + + /** + * Checks that a socket has received a response appropriate to the specified packet. + */ + private void checkResponse(FileDescriptor s, + InetAddress dest, byte[] sent) throws ErrnoException, IOException { + // Receive the response. + InetSocketAddress from = new InetSocketAddress(); + ByteBuffer responseBuffer = ByteBuffer.allocate(MAX_SIZE); + int bytesRead = Libcore.os.recvfrom(s, responseBuffer, 0, from); + + // Check the source address and scope ID. + assertTrue(from.getAddress() instanceof Inet6Address); + Inet6Address fromAddress = (Inet6Address) from.getAddress(); + assertEquals(0, fromAddress.getScopeId()); + assertNull(fromAddress.getScopedInterface()); + assertEquals(dest.getHostAddress(), fromAddress.getHostAddress()); + + // Check the packet length. + assertEquals(sent.length, bytesRead); + + // Check the response is an echo reply. + byte[] response = new byte[bytesRead]; + responseBuffer.get(response, 0, bytesRead); + assertEquals((byte) 0x81, response[0]); + + // Find out what ICMP ID was used in the packet that was sent. + int id = ((InetSocketAddress) Libcore.os.getsockname(s)).getPort(); + sent[4] = (byte) (id / 256); + sent[5] = (byte) (id % 256); + + // Ensure the response is the same as the packet, except for the type (which is 0x81) + // and the ID and checksum, which are set by the kernel. + response[0] = (byte) 0x80; // Type. + response[2] = response[3] = (byte) 0x00; // Checksum. + assertArrayBytesEqual(response, sent, bytesRead); + } + + /** + * Sends NUM_PACKETS random ping packets to ::1 and checks the replies. + */ + public void testLoopbackPing() throws ErrnoException, IOException { + // Generate a random ping packet and send it to localhost. + InetAddress ipv6Loopback = InetAddress.getByName(null); + assertEquals("localhost/::1", ipv6Loopback.toString()); + + for (int i = 0; i < NUM_PACKETS; i++) { + byte[] packet = pingPacket((int) (Math.random() * MAX_SIZE)); + FileDescriptor s = createPingSocket(); + sendPing(s, ipv6Loopback, packet); + checkResponse(s, ipv6Loopback, packet); + // Check closing the socket doesn't raise an exception. + Libcore.os.close(s); + } + } +} From 5d5ff5a81da9c43e84a29588b3b4ed7ba39d3e97 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Tue, 20 Aug 2013 21:59:33 -0700 Subject: [PATCH 0117/1415] Change SSLCertificateSocketFactoryTest to use googlemail.com Bug: 10351880 Change-Id: I759fe361b0c543535d100ca26ca5047ff4dbc026 --- .../android/net/cts/SSLCertificateSocketFactoryTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 70ab54d3cd..ceb74d1f31 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -86,9 +86,9 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { } // a host and port that are expected to be available but have - // a cert with a different CN, in this case CN=mtalk.google.com - private static String TEST_CREATE_SOCKET_HOST = "mobile-gtalk.l.google.com"; - private static int TEST_CREATE_SOCKET_PORT = 5228; + // a cert with a different CN, in this case CN=mail.google.com + private static String TEST_CREATE_SOCKET_HOST = "googlemail.com"; + private static int TEST_CREATE_SOCKET_PORT = 443; /** * b/2807618 Make sure that hostname verifcation in cases were it From 27c7fe542070a4c5fec4b1e16261adc4661eb9f9 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Tue, 20 Aug 2013 21:59:33 -0700 Subject: [PATCH 0118/1415] Change SSLCertificateSocketFactoryTest to use googlemail.com Bug: 10351880 (cherry picked from commit d6e12427d0b69032fc82d0635a7b10bdbd39c78c) Change-Id: I0d2708c507da5cd84f61bdd50ac3b76b3ac15a0d --- .../android/net/cts/SSLCertificateSocketFactoryTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 70ab54d3cd..ceb74d1f31 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -86,9 +86,9 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { } // a host and port that are expected to be available but have - // a cert with a different CN, in this case CN=mtalk.google.com - private static String TEST_CREATE_SOCKET_HOST = "mobile-gtalk.l.google.com"; - private static int TEST_CREATE_SOCKET_PORT = 5228; + // a cert with a different CN, in this case CN=mail.google.com + private static String TEST_CREATE_SOCKET_HOST = "googlemail.com"; + private static int TEST_CREATE_SOCKET_PORT = 443; /** * b/2807618 Make sure that hostname verifcation in cases were it From 4bc10e0fbe66b1e1a7987795d16bc1b6a5cef977 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Tue, 20 Aug 2013 21:59:33 -0700 Subject: [PATCH 0119/1415] Change SSLCertificateSocketFactoryTest to use googlemail.com Bug: 10351880 (cherry picked from commit 5d5ff5a81da9c43e84a29588b3b4ed7ba39d3e97) Change-Id: Ied4db819e0a62352776f7b19365e30a079a51b9f --- .../android/net/cts/SSLCertificateSocketFactoryTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 70ab54d3cd..ceb74d1f31 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -86,9 +86,9 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { } // a host and port that are expected to be available but have - // a cert with a different CN, in this case CN=mtalk.google.com - private static String TEST_CREATE_SOCKET_HOST = "mobile-gtalk.l.google.com"; - private static int TEST_CREATE_SOCKET_PORT = 5228; + // a cert with a different CN, in this case CN=mail.google.com + private static String TEST_CREATE_SOCKET_HOST = "googlemail.com"; + private static int TEST_CREATE_SOCKET_PORT = 443; /** * b/2807618 Make sure that hostname verifcation in cases were it From af3296605b2072078d9881bfd27d913adcef006f Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Thu, 12 Sep 2013 15:04:37 -0700 Subject: [PATCH 0120/1415] TrafficStats: fix uncertainty in flushing network traffic Flushing TCP traffic isn't reliable enough to force a packet on the socket, even with Nagle disabled. The kernel's socket sendto() is being invoked with 1024 bytes each time, but something deeper in the stack is merging packets. So now we wait 5ms between each of the 1024 packets after flushing. This allows running the test overnight in a loop without failure instead of only ~5 times. The error messages are now more detailed. Bug: 10668088 Change-Id: Ic47bec81c6dba2fad8b96eb4a41f183115c371de --- .../src/android/net/cts/TrafficStatsTest.java | 103 +++++++++++++----- 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 180d259bbc..9483bdccf1 100644 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -19,7 +19,11 @@ package android.net.cts; import android.net.TrafficStats; import android.os.Process; import android.test.AndroidTestCase; +import android.util.Log; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -29,6 +33,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public class TrafficStatsTest extends AndroidTestCase { + private static final String LOG_TAG = "TrafficStatsTest"; + public void testValidMobileStats() { // We can't assume a mobile network is even present in this test, so // we simply assert that a valid value is returned. @@ -75,19 +81,39 @@ public class TrafficStatsTest extends AndroidTestCase { return packetCount * (20 + 32 + bytes); } + private void accessOwnTrafficStats() throws IOException { + final int ownAppUid = getContext().getApplicationInfo().uid; + Log.d(LOG_TAG, "accesOwnTrafficStatsWithTags(): about to read qtaguid stats for own uid " + ownAppUid); + + boolean foundOwnDetailedStats = false; + try { + BufferedReader qtaguidReader = new BufferedReader(new FileReader("/proc/net/xt_qtaguid/stats")); + String line; + while ((line = qtaguidReader.readLine()) != null) { + String tokens[] = line.split(" "); + if (tokens.length > 3 && tokens[3].equals(String.valueOf(ownAppUid))) { + Log.d(LOG_TAG, "accessOwnTrafficStatsWithTags(): got own stats: " + line); + } + } + qtaguidReader.close(); + } catch (FileNotFoundException e) { + fail("Was not able to access qtaguid/stats: " + e); + } + } + public void testTrafficStatsForLocalhost() throws IOException { - long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets(); - long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets(); - long mobileTxBytesBefore = TrafficStats.getMobileTxBytes(); - long mobileRxBytesBefore = TrafficStats.getMobileRxBytes(); - long totalTxPacketsBefore = TrafficStats.getTotalTxPackets(); - long totalRxPacketsBefore = TrafficStats.getTotalRxPackets(); - long totalTxBytesBefore = TrafficStats.getTotalTxBytes(); - long totalRxBytesBefore = TrafficStats.getTotalRxBytes(); - long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid()); - long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); - long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid()); - long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid()); + final long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets(); + final long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets(); + final long mobileTxBytesBefore = TrafficStats.getMobileTxBytes(); + final long mobileRxBytesBefore = TrafficStats.getMobileRxBytes(); + final long totalTxPacketsBefore = TrafficStats.getTotalTxPackets(); + final long totalRxPacketsBefore = TrafficStats.getTotalRxPackets(); + final long totalTxBytesBefore = TrafficStats.getTotalTxBytes(); + final long totalRxBytesBefore = TrafficStats.getTotalRxBytes(); + final long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid()); + final long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); + final long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid()); + final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid()); // Transfer 1MB of data across an explicitly localhost socket. final int byteCount = 1024; @@ -104,22 +130,36 @@ public class TrafficStatsTest extends AndroidTestCase { socket.setTcpNoDelay(true); OutputStream out = socket.getOutputStream(); byte[] buf = new byte[byteCount]; + TrafficStats.setThreadStatsTag(0x42); + TrafficStats.tagSocket(socket); + accessOwnTrafficStats(); for (int i = 0; i < packetCount; i++) { out.write(buf); out.flush(); + try { + // Bug: 10668088, Even with Nagle disabled, and flushing the 1024 bytes + // the kernel still regroups data into a larger packet. + Thread.sleep(5); + } catch (InterruptedException e) { + } } out.close(); socket.close(); + accessOwnTrafficStats(); } catch (IOException e) { + Log.i(LOG_TAG, "Badness during writes to socket: " + e); } } }.start(); + int read = 0; try { Socket socket = server.accept(); + socket.setTcpNoDelay(true); + TrafficStats.setThreadStatsTag(0x43); + TrafficStats.tagSocket(socket); InputStream in = socket.getInputStream(); byte[] buf = new byte[byteCount]; - int read = 0; while (read < byteCount * packetCount) { int n = in.read(buf); assertTrue("Unexpected EOF", n > 0); @@ -128,6 +168,7 @@ public class TrafficStatsTest extends AndroidTestCase { } finally { server.close(); } + assertTrue("Not all data read back", read >= byteCount * packetCount); // It's too fast to call getUidTxBytes function. try { @@ -163,18 +204,30 @@ public class TrafficStatsTest extends AndroidTestCase { * + 7 approx.: syn, syn-ack, ack, fin-ack, ack, fin-ack, ack; * but sometimes the last find-acks just vanish, so we set a lower limit of +5. */ - assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets, - uidTxDeltaPackets >= packetCount + 5 && - uidTxDeltaPackets <= packetCount + packetCount + 7); - assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets, - uidRxDeltaPackets >= packetCount + 5 && - uidRxDeltaPackets <= packetCount + packetCount + 7); - assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes, - uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(5, 0) && - uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + 7, 0)); - assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes, - uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(5, 0) && - uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + 7, 0)); + final int maxExpectedExtraPackets = 7; + final int minExpectedExtraPackets = 5; + + + assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + + " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + + uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets, + uidTxDeltaPackets >= packetCount + minExpectedExtraPackets && + uidTxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets); + assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets + + " Wanted: " + uidRxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + + uidRxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets, + uidRxDeltaPackets >= packetCount + minExpectedExtraPackets && + uidRxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets); + assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes + + " Wanted: " + uidTxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + + uidTxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), + uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && + uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0)); + assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes + + " Wanted: " + uidRxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + + uidRxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), + uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && + uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0)); // Localhost traffic *does* count against total stats. // Fudge by 132 packets of 1500 bytes not related to the test. From e52091e2cca0a5c1195581d0405c5cace3a82901 Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Mon, 23 Sep 2013 16:21:04 -0700 Subject: [PATCH 0121/1415] Fix broken DNS Test Couple of lines were just wrong (typo?) - and I have reduced our dependence on multiple static IPs (used to test reverse mapping). It can still get broken when external servers change their IP addresses though. Bug: 8658901 Change-Id: I745c958df2f61130798552f0f5f736c73fb5de30 --- tests/cts/net/jni/NativeDnsJni.c | 50 +++++++++++-------- .../cts/net/src/android/net/cts/DnsTest.java | 11 +++- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index de9bb677b5..b975594b26 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -20,6 +20,11 @@ #include #include +const char *GoogleDNSIpV4Address="8.8.8.8"; +const char *GoogleDNSIpV4Address2="8.8.4.4"; +const char *GoogleDNSIpV6Address="2001:4860:4860::8888"; +const char *GoogleDNSIpV6Address2="2001:4860:4860::8844"; + JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclass class) { const char *node = "www.google.com"; @@ -53,8 +58,8 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas freeaddrinfo(answer); answer = NULL; - if (foundv4 != 1 || foundv6 != 1) { - ALOGD("getaddrinfo(www.google.com) didn't find both v4 and v6"); + if (foundv4 != 1 && foundv6 != 1) { + ALOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address"); return JNI_FALSE; } } @@ -96,49 +101,50 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas struct sockaddr_in sa4; sa4.sin_family = AF_INET; sa4.sin_port = 0; - inet_pton(AF_INET, "173.252.110.27", &(sa4.sin_addr)); + inet_pton(AF_INET, GoogleDNSIpV4Address, &(sa4.sin_addr)); struct sockaddr_in6 sa6; sa6.sin6_family = AF_INET6; sa6.sin6_port = 0; sa6.sin6_flowinfo = 0; sa6.sin6_scope_id = 0; - inet_pton(AF_INET6, "2001:4860:4001:802::1008", &(sa6.sin6_addr)); + inet_pton(AF_INET6, GoogleDNSIpV6Address2, &(sa6.sin6_addr)); char buf[NI_MAXHOST]; int flags = NI_NAMEREQD; res = getnameinfo((const struct sockaddr*)&sa4, sizeof(sa4), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { - ALOGD("getnameinfo(173.252.110.27 (facebook) ) gave error %d (%s)", res, gai_strerror(res)); + ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res, + gai_strerror(res)); return JNI_FALSE; } - if (strstr(buf, "facebook.com") == NULL) { - ALOGD("getnameinfo(173.252.110.27 (facebook) ) didn't return facebook.com: %s", buf); + if (strstr(buf, "google.com") == NULL) { + ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com: %s", + GoogleDNSIpV4Address, buf); return JNI_FALSE; } memset(buf, sizeof(buf), 0); - res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), - NULL, 0, flags); + res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { - ALOGD("getnameinfo(2a03:2880:2110:df01:face:b00c::8 (facebook) ) gave error %d (%s)", - res, gai_strerror(res)); + ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, + res, gai_strerror(res)); return JNI_FALSE; } - if (strstr(buf, "1e100.net") == NULL) { - ALOGD("getnameinfo(2a03:2880:2110:df01:face:b00c::8) didn't return facebook.com: %s", buf); + if (strstr(buf, "google.com") == NULL) { + ALOGD("getnameinfo(%s) didn't return google.com: %s", GoogleDNSIpV6Address2, buf); return JNI_FALSE; } // gethostbyname - struct hostent *my_hostent = gethostbyname("www.mit.edu"); + struct hostent *my_hostent = gethostbyname("www.youtube.com"); if (my_hostent == NULL) { - ALOGD("gethostbyname(www.mit.edu) gave null response"); + ALOGD("gethostbyname(www.youtube.com) gave null response"); return JNI_FALSE; } if ((my_hostent->h_addr_list == NULL) || (*my_hostent->h_addr_list == NULL)) { - ALOGD("gethostbyname(www.mit.edu) gave 0 addresses"); + ALOGD("gethostbyname(www.youtube.com) gave 0 addresses"); return JNI_FALSE; } { @@ -146,21 +152,23 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas while (*current != NULL) { char buf[256]; inet_ntop(my_hostent->h_addrtype, *current, buf, sizeof(buf)); - ALOGD("gethostbyname(www.mit.edu) gave %s", buf); + ALOGD("gethostbyname(www.youtube.com) gave %s", buf); current++; } } // gethostbyaddr char addr6[16]; - inet_pton(AF_INET6, "2001:4b10:bbc::2", addr6); + inet_pton(AF_INET6, GoogleDNSIpV6Address, addr6); my_hostent = gethostbyaddr(addr6, sizeof(addr6), AF_INET6); if (my_hostent == NULL) { - ALOGD("gethostbyaddr(2001:4b10:bbc::2 (bbc) ) gave null response"); + ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address); return JNI_FALSE; } - ALOGD("gethostbyaddr(2001:4b10:bbc::2 (bbc) ) gave %s for name", - my_hostent->h_name ? my_hostent->h_name : "null"); + + ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address, + my_hostent->h_name ? my_hostent->h_name : "null"); + if (my_hostent->h_name == NULL) return JNI_FALSE; return JNI_TRUE; } diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index cdd95aa077..879a962233 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -64,8 +64,13 @@ public class DnsTest extends AndroidTestCase { else if (addr instanceof Inet6Address) foundV6 = true; if (DBG) Log.e(TAG, "www.google.com gave " + addr.toString()); } - assertTrue(foundV4); - assertTrue(foundV6); + + // assertTrue(foundV4); + // assertTrue(foundV6); + + // We should have at least one of the addresses to connect! + assertTrue(foundV4 || foundV6); + try { addrs = InetAddress.getAllByName("ipv6.google.com"); } catch (UnknownHostException e) {} @@ -77,8 +82,10 @@ public class DnsTest extends AndroidTestCase { else if (addr instanceof Inet6Address) foundV6 = true; if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString()); } + assertTrue(foundV4 == false); assertTrue(foundV6 == true); + assertTrue(testNativeDns()); } From 851672c1ed70e93049280e862e68d8c0874ada96 Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Thu, 10 Oct 2013 14:56:43 -0700 Subject: [PATCH 0122/1415] Ignore duplicate events from mDNS stack in CTS It is too late to fix the duplicate events, and they may have existed in JB-MR2 as well. So fixing CTS to ignore them for now. Bug: 11049532 Change-Id: I0785a32dbac04eacb6994b428b12ce1ec27945d2 --- .../android/net/wifi/cts/NsdManagerTest.java | 133 +++++++++++------- 1 file changed, 84 insertions(+), 49 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java index 482a4e39a6..d1e4c447c3 100644 --- a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java @@ -43,6 +43,12 @@ public class NsdManagerTest extends AndroidTestCase { NsdManager.ResolveListener mResolveListener; public NsdManagerTest() { + initRegistrationListener(); + initDiscoveryListener(); + initResolveListener(); + } + + private void initRegistrationListener() { mRegistrationListener = new NsdManager.RegistrationListener() { @Override public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { @@ -64,6 +70,9 @@ public class NsdManagerTest extends AndroidTestCase { setEvent("onServiceUnregistered", serviceInfo); } }; + } + + private void initDiscoveryListener() { mDiscoveryListener = new NsdManager.DiscoveryListener() { @Override public void onStartDiscoveryFailed(String serviceType, int errorCode) { @@ -99,6 +108,9 @@ public class NsdManagerTest extends AndroidTestCase { setEvent("onServiceLost", serviceInfo); } }; + } + + private void initResolveListener() { mResolveListener = new NsdManager.ResolveListener() { @Override public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { @@ -112,6 +124,8 @@ public class NsdManagerTest extends AndroidTestCase { }; } + + private final class EventData { EventData(String callbackName, NsdServiceInfo info) { mCallbackName = callbackName; @@ -198,6 +212,29 @@ public class NsdManagerTest extends AndroidTestCase { } } + private EventData waitForNewEvents() throws InterruptedException { + if (DBG) Log.d(TAG, "Waiting for a bit, id=" + String.valueOf(mWaitId)); + + long startTime = android.os.SystemClock.uptimeMillis(); + long elapsedTime = 0; + synchronized (mEventCache) { + int index = mEventCache.size(); + while (elapsedTime < TIMEOUT ) { + // first check if we've received that event + for (; index < mEventCache.size(); index++) { + EventData e = mEventCache.get(index); + return e; + } + + // Not yet received, just wait + mEventCache.wait(TIMEOUT - elapsedTime); + elapsedTime = android.os.SystemClock.uptimeMillis() - startTime; + } + } + + return null; + } + private String mServiceName; @Override @@ -266,7 +303,9 @@ public class NsdManagerTest extends AndroidTestCase { assertTrue(lastEvent.mSucceeded); // Remove this event, so accounting becomes easier later - mEventCache.remove(lastEvent); + synchronized (mEventCache) { + mEventCache.remove(lastEvent); + } // Expect a service record to be discovered (and filter the ones // that are unrelated to this test) @@ -292,7 +331,9 @@ public class NsdManagerTest extends AndroidTestCase { // Remove this event from the event cache, so it won't be found by subsequent // calls to waitForCallback - mEventCache.remove(lastEvent); + synchronized (mEventCache) { + mEventCache.remove(lastEvent); + } } assertTrue(found); @@ -315,6 +356,7 @@ public class NsdManagerTest extends AndroidTestCase { assertTrue(lastEvent.mInfo.getPort() == localPort); assertTrue(eventCacheSize() == 1); + assertTrue(checkForAdditionalEvents()); clearEventCache(); // Unregister the service @@ -333,12 +375,17 @@ public class NsdManagerTest extends AndroidTestCase { assertTrue(eventCacheSize() == 2); // Register service again to see if we discover it + checkForAdditionalEvents(); clearEventCache(); si = new NsdServiceInfo(); si.setServiceType(SERVICE_TYPE); si.setServiceName(mServiceName); si.setPort(localPort); + + // Create a new registration listener and register same service again + initRegistrationListener(); + mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); lastEvent = waitForCallback("onServiceRegistered"); // id = 7 @@ -358,67 +405,55 @@ public class NsdManagerTest extends AndroidTestCase { lastEvent.mInfo.getServiceName()); assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); + assertTrue(checkCacheSize(2)); - assertTrue(eventCacheSize() == 2); + checkForAdditionalEvents(); clearEventCache(); mNsdManager.stopServiceDiscovery(mDiscoveryListener); lastEvent = waitForCallback("onDiscoveryStopped"); // id = 9 assertTrue(lastEvent != null); assertTrue(lastEvent.mSucceeded); - assertTrue(eventCacheSize() == 1); + assertTrue(checkCacheSize(1)); + checkForAdditionalEvents(); clearEventCache(); + mNsdManager.unregisterService(mRegistrationListener); lastEvent = waitForCallback("onServiceUnregistered"); // id = 10 assertTrue(lastEvent != null); assertTrue(lastEvent.mSucceeded); - assertTrue(eventCacheSize() == 1); + assertTrue(checkCacheSize(1)); + } + + boolean checkCacheSize(int size) { + synchronized (mEventCache) { + int cacheSize = mEventCache.size(); + if (cacheSize != size) { + Log.d(TAG, "id = " + mWaitId + ": event cache size = " + cacheSize); + for (int i = 0; i < cacheSize; i++) { + EventData e = mEventCache.get(i); + String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : ""; + Log.d(TAG, "eventName is " + e.mCallbackName + sname); + } + } + return (cacheSize == size); + } + } + + boolean checkForAdditionalEvents() { + try { + EventData e = waitForNewEvents(); + if (e != null) { + String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : ""; + Log.d(TAG, "ignoring unexpected event " + e.mCallbackName + sname); + } + return (e == null); + } + catch (InterruptedException ex) { + return false; + } } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From b29370db3447b4115523c03cb5019df601984f23 Mon Sep 17 00:00:00 2001 From: Johan Redestig Date: Wed, 30 Oct 2013 14:14:58 +0100 Subject: [PATCH 0123/1415] Lookup private resources in run-time This fixes the following cases for us: android.net.cts.ConnectivityManagerTest#testGetAllNetworkInfo android.net.cts.ConnectivityManagerTest#testGetNetworkInfo android.net.cts.ConnectivityManagerTest#testIsNetworkSupported android.net.cts.ConnectivityManagerTest#testRequestRouteToHost android.net.cts.ConnectivityManagerTest#testSetNetworkPreference We need to use the prebuilt binary but that has dependency to private resource identities that differs in our environment. With this change the resources are looked up in run-time to avoid the build time dependency. Change-Id: I6579338b591ca7a0da3f03f796136269c7789780 --- .../src/android/net/cts/ConnectivityManagerTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index d4bff12a18..b93e115ba0 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -66,8 +66,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); mPackageManager = getContext().getPackageManager(); - String[] naStrings = getContext().getResources().getStringArray( - com.android.internal.R.array.networkAttributes); + // Get com.android.internal.R.array.networkAttributes + int resId = getContext().getResources().getIdentifier("networkAttributes", "array", "android"); + String[] naStrings = getContext().getResources().getStringArray(resId); + for (String naString : naStrings) { try { NetworkConfig n = new NetworkConfig(naString); @@ -75,8 +77,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (Exception e) {} } - int[] protectedNetworks = getContext().getResources().getIntArray( - com.android.internal.R.array.config_protectedNetworks); + // Get com.android.internal.R.array.config_protectedNetworks + resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android"); + int[] protectedNetworks = getContext().getResources().getIntArray(resId); for (int p : protectedNetworks) { mProtectedNetworks.add(p); } From 7fd24cb8dfb0a150a75dc02fa23a1e3a2ff156eb Mon Sep 17 00:00:00 2001 From: Stuart Scott Date: Thu, 7 Nov 2013 10:30:32 -0800 Subject: [PATCH 0124/1415] Refactoring CTS to remove PTS references. PTS is now a part of CTS bug: 11561456 Change-Id: I577296fe7735790e285aa4747dc7832bc8ae5b6d --- tests/cts/net/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index a6543b3a6a..7219fc483f 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -30,7 +30,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsutil ctstestrunner +LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsdeviceutil ctstestrunner # uncomment when dalvik.annotation.Test* are removed or part of SDK #LOCAL_SDK_VERSION := current From 638d1eeee7ade6ac512a5acd39b870b2fabdeeee Mon Sep 17 00:00:00 2001 From: William Luh Date: Tue, 12 Nov 2013 10:05:11 -0800 Subject: [PATCH 0125/1415] CTS test for X509TrustManagerExtensions.isUserAddedCertificate. Bug: 11257762 Change-Id: I4d8bec7b75613b3286063e28b0fe0cba4e5c716b --- tests/cts/net/Android.mk | 2 +- .../cts/X509TrustManagerExtensionsTest.java | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/cts/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index a6543b3a6a..83523cc0b7 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -21,7 +21,7 @@ LOCAL_MODULE_TAGS := optional # and when built explicitly put it in the data partition LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) -LOCAL_JAVA_LIBRARIES := android.test.runner voip-common +LOCAL_JAVA_LIBRARIES := android.test.runner voip-common conscrypt LOCAL_JNI_SHARED_LIBRARIES := libnativedns_jni diff --git a/tests/cts/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java b/tests/cts/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java new file mode 100644 index 0000000000..9c0d7744c7 --- /dev/null +++ b/tests/cts/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012 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.http.cts; + +import android.net.http.X509TrustManagerExtensions; +import android.util.Base64; + +import java.io.File; +import java.io.ByteArrayInputStream; + +import java.security.KeyStore; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import junit.framework.TestCase; + +import com.android.org.conscrypt.TrustedCertificateStore; +import com.android.org.conscrypt.TrustManagerImpl; + +public class X509TrustManagerExtensionsTest extends TestCase { + + public void testIsUserAddedCert() throws Exception { + final String testCert = + "MIICfjCCAeegAwIBAgIJAMefIzKHY5H4MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV" + + "BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEPMA0G" + + "A1UECgwGR2V3Z3VsMRMwEQYDVQQDDApnZXdndWwuY29tMB4XDTEzMTEwNTAwNDE0" + + "MFoXDTEzMTIwNTAwNDE0MFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYw" + + "FAYDVQQHDA1Nb3VudGFpbiBWaWV3MQ8wDQYDVQQKDAZHZXdndWwxEzARBgNVBAMM" + + "Cmdld2d1bC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKpc/I0Ss4sm" + + "yV2iX5xRMM7+XXAhiWrceGair4MpvDrGIa1kFj2phtx4IqTfDnNU7AhRJYkDYmJQ" + + "fUJ8i6F+I08uNiGVO4DtPJbZcBXg9ME9EMaJCslm995ueeNWSw1Ky8zM0tt4p+94" + + "BcXJ7PC3N2WgkvtE8xwNbaeUfhGPzJKXAgMBAAGjUDBOMB0GA1UdDgQWBBQQ/iW7" + + "JCkSI2sbn4nTBiZ9PSiO8zAfBgNVHSMEGDAWgBQQ/iW7JCkSI2sbn4nTBiZ9PSiO" + + "8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBABQBrUOWTCSIl3vkRR3w" + + "3bPzh3BpqDmxH9xe4rZr+MVKKjpGjY1z2m2EEtyNz3tbgVQym5+si00DUHFL0IP1" + + "SuRULmPyEpTBVbV+PA5Kc967ZcDgYt4JtdMcCeKbIFaU6r8oEYEL2PTlNZmgbunM" + + "pXktkhVvNxZeSa8yM9bPhXkN"; + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate)cf.generateCertificate( + new ByteArrayInputStream(Base64.decode(testCert, Base64.DEFAULT))); + + // Test without adding cert to keystore. + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + X509TrustManagerExtensions tmeNegative = + new X509TrustManagerExtensions(new TrustManagerImpl(keyStore)); + assertEquals(false, tmeNegative.isUserAddedCertificate(cert)); + + // Test with cert added to keystore. + final File DIR_TEMP = new File(System.getProperty("java.io.tmpdir")); + final File DIR_TEST = new File(DIR_TEMP, "test"); + final File system = new File(DIR_TEST, "system-test"); + final File added = new File(DIR_TEST, "added-test"); + final File deleted = new File(DIR_TEST, "deleted-test"); + + TrustedCertificateStore tcs = new TrustedCertificateStore(system, added, deleted); + added.mkdirs(); + tcs.installCertificate(cert); + X509TrustManagerExtensions tmePositive = + new X509TrustManagerExtensions(new TrustManagerImpl(keyStore, null, tcs)); + assertEquals(true, tmePositive.isUserAddedCertificate(cert)); + } +} From 652d30b4b586d90f6f6451a1bd470c00b41101ea Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Thu, 16 Jan 2014 14:52:46 -0800 Subject: [PATCH 0126/1415] Test default config of SSLCertificateSocketFactory. Bug: 11220570 Change-Id: I37440f3e8eda18215b9af703c027e4c8ca0334bf --- tests/cts/net/Android.mk | 3 ++- .../android/net/cts/SSLCertificateSocketFactoryTest.java | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 7219fc483f..82abd6265f 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -30,7 +30,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsdeviceutil ctstestrunner +LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsdeviceutil ctstestrunner \ + core-tests-support # uncomment when dalvik.annotation.Test* are removed or part of SDK #LOCAL_SDK_VERSION := current diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index ceb74d1f31..cb8aeaf711 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -28,6 +28,8 @@ import android.test.AndroidTestCase; import dalvik.annotation.BrokenTest; +import libcore.javax.net.ssl.SSLDefaultConfigurationAsserts; + public class SSLCertificateSocketFactoryTest extends AndroidTestCase { private SSLCertificateSocketFactory mFactory; private int mTimeout; @@ -39,6 +41,10 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { mFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(mTimeout); } + public void testDefaultConfiguration() throws Exception { + SSLDefaultConfigurationAsserts.assertSSLSocketFactory(mFactory); + } + public void testAccessProperties() throws Exception { mFactory.getSupportedCipherSuites(); mFactory.getDefaultCipherSuites(); From 0244dd7e3e59ccc335923313a2f19a05ac8191f5 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 30 Jan 2014 11:55:49 -0800 Subject: [PATCH 0127/1415] Document kernel code necessary to pass PingTest. Change-Id: If6fec0c5193cd897b4c3534843bcd589b40c2948 --- .../net/src/android/net/ipv6/cts/PingTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java index 41eb03d34d..2c8aaef4bc 100644 --- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -34,6 +34,21 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; +/** + * Checks that the device has kernel support for the IPv6 ping socket. This allows ping6 to work + * without root privileges. The necessary kernel code is in Linux 3.11 or above, or the + * common/android-3.x kernel trees. If you are not running one of these kernels, the + * functionality can be obtained by cherry-picking the following patches from David Miller's + * net-next tree: + *
    + *
  • 6d0bfe2 net: ipv6: Add IPv6 support to the ping socket. + *
  • c26d6b4 ping: always initialize ->sin6_scope_id and ->sin6_flowinfo + *
  • fbfe80c net: ipv6: fix wrong ping_v6_sendmsg return value + *
  • a1bdc45 net: ipv6: add missing lock in ping_v6_sendmsg + *
  • cf970c0 ping: prevent NULL pointer dereference on write to msg_name + *
+ * or the equivalent backports to the common/android-3.x trees. + */ public class PingTest extends AndroidTestCase { /** Maximum size of the packets we're using to test. */ private static final int MAX_SIZE = 4096; From 0ffaf6dba79cd9f2e48d576ced2e8fcb31c85ab9 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 3 Feb 2014 12:40:20 -0800 Subject: [PATCH 0128/1415] Test both recvfrom() and read() in PingTest. Change-Id: I2f49534f22bd718ce08c3408e38eeb97e09e5d6c --- .../src/android/net/ipv6/cts/PingTest.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java index 2c8aaef4bc..acf474fce4 100644 --- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -105,19 +105,25 @@ public class PingTest extends AndroidTestCase { /** * Checks that a socket has received a response appropriate to the specified packet. */ - private void checkResponse(FileDescriptor s, - InetAddress dest, byte[] sent) throws ErrnoException, IOException { - // Receive the response. - InetSocketAddress from = new InetSocketAddress(); + private void checkResponse(FileDescriptor s, InetAddress dest, + byte[] sent, boolean useRecvfrom) throws ErrnoException, IOException { ByteBuffer responseBuffer = ByteBuffer.allocate(MAX_SIZE); - int bytesRead = Libcore.os.recvfrom(s, responseBuffer, 0, from); + int bytesRead; - // Check the source address and scope ID. - assertTrue(from.getAddress() instanceof Inet6Address); - Inet6Address fromAddress = (Inet6Address) from.getAddress(); - assertEquals(0, fromAddress.getScopeId()); - assertNull(fromAddress.getScopedInterface()); - assertEquals(dest.getHostAddress(), fromAddress.getHostAddress()); + // Receive the response. + if (useRecvfrom) { + InetSocketAddress from = new InetSocketAddress(); + bytesRead = Libcore.os.recvfrom(s, responseBuffer, 0, from); + + // Check the source address and scope ID. + assertTrue(from.getAddress() instanceof Inet6Address); + Inet6Address fromAddress = (Inet6Address) from.getAddress(); + assertEquals(0, fromAddress.getScopeId()); + assertNull(fromAddress.getScopedInterface()); + assertEquals(dest.getHostAddress(), fromAddress.getHostAddress()); + } else { + bytesRead = Libcore.os.read(s, responseBuffer); + } // Check the packet length. assertEquals(sent.length, bytesRead); @@ -150,8 +156,11 @@ public class PingTest extends AndroidTestCase { for (int i = 0; i < NUM_PACKETS; i++) { byte[] packet = pingPacket((int) (Math.random() * MAX_SIZE)); FileDescriptor s = createPingSocket(); + // Use both recvfrom and read(). sendPing(s, ipv6Loopback, packet); - checkResponse(s, ipv6Loopback, packet); + checkResponse(s, ipv6Loopback, packet, true); + sendPing(s, ipv6Loopback, packet); + checkResponse(s, ipv6Loopback, packet, false); // Check closing the socket doesn't raise an exception. Libcore.os.close(s); } From 2678d5bcf77cd494967c1e4183168f7ea88c72bb Mon Sep 17 00:00:00 2001 From: Daniel Kim Date: Fri, 16 Aug 2013 12:00:28 -0700 Subject: [PATCH 0129/1415] cherry pick from aosp. https://android-review.googlesource.com/63805 Fix for Wifi watchdog test when Wifi is not supported Added a check to see if Wifi is supported like other tests in the class Signed-off-by: Daniel Kim --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 283f63b5d4..213dc1785f 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -407,6 +407,10 @@ public class WifiManagerTest extends AndroidTestCase { * To pass this CTS test, a connected WiFi link is required. */ public void testWifiWatchdog() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } // Make sure WiFi is enabled if (!mWifiManager.isWifiEnabled()) { setWifiEnabled(true); From cf8d741f3d677c32aeb600fb855287dcea08926e Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Thu, 9 Jan 2014 14:32:20 -0800 Subject: [PATCH 0130/1415] Move to android.support.test as CTS instrumentation runner. Also do the following related cleanup - Remove references to deprecated BrokenTest and KnownFailure - Switch CTS tests to build against SDK and not private android.test.runner where possible Bug: 12924356 Change-Id: If6151b836456eec4838f8d7d6e11c9834c007fca --- tests/cts/net/Android.mk | 4 ++-- tests/cts/net/AndroidManifest.xml | 7 +++++-- .../android/net/cts/SSLCertificateSocketFactoryTest.java | 2 -- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 1653335046..da19a4da78 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -21,7 +21,7 @@ LOCAL_MODULE_TAGS := optional # and when built explicitly put it in the data partition LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) -LOCAL_JAVA_LIBRARIES := android.test.runner voip-common conscrypt +LOCAL_JAVA_LIBRARIES := voip-common conscrypt LOCAL_JNI_SHARED_LIBRARIES := libnativedns_jni @@ -33,7 +33,7 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsdeviceutil ctstestrunner \ core-tests-support -# uncomment when dalvik.annotation.Test* are removed or part of SDK +# uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current include $(BUILD_CTS_PACKAGE) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index ade6728a6e..652262d491 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -32,9 +32,12 @@ - + android:label="CTS tests of android.net"> + + diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index cb8aeaf711..6175923e46 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -26,8 +26,6 @@ import javax.net.ssl.SSLPeerUnverifiedException; import android.net.SSLCertificateSocketFactory; import android.test.AndroidTestCase; -import dalvik.annotation.BrokenTest; - import libcore.javax.net.ssl.SSLDefaultConfigurationAsserts; public class SSLCertificateSocketFactoryTest extends AndroidTestCase { From 0d4434d998a9fc7c314523503b0a09a8422acc71 Mon Sep 17 00:00:00 2001 From: Junjie Hu Date: Thu, 13 Mar 2014 16:25:12 +0800 Subject: [PATCH 0131/1415] Fix CTS android.net package testTrafficStatsForLocalhost seldom fail issue For testTrafficStatsForLocalhost's UID testing, it will also calcuate the wlan0 interface. There are some TCP re-tranmission in SSLCertificateSocketFactoryTest and it is the same UID as this test case. Need to consider those extra pacetks. For example, Before testTrafficStatsForLocalhost test casae: 01-08 15:49:11.316 7826 7839 D TrafficStats: parseUidStats, buffer: 14 wlan0 0x0 10067 0 31857 67 4582 55 31857 67 0 0 0 0 4582 55 0 0 0 0 01-08 15:49:11.335 7826 7839 D TrafficStats: parseUidStats, buffer: 24 lo 0x0 10067 0 40 1 60 1 40 1 0 0 0 0 60 1 0 0 0 0 After testTrafficStatsForLocalhost test casae: 01-08 15:49:19.210 7826 7839 D TrafficStats: parseUidStats, buffer: 14 wlan0 0x0 10067 0 31857 67 4738 58 31857 67 0 0 0 0 4738 58 0 0 0 0 01-08 15:49:19.212 7826 7839 D TrafficStats: parseUidStats, buffer: 24 lo 0x0 10067 0 1155336 2053 1155408 2054 1155336 2053 0 0 0 0 1155408 2054 0 0 0 0 => There are three extra IP packets after testing due to TCP FIN retreamsisions in previous test case Suggest to add some extra IP packets for consider the extra traffic in wlan0 interface. Signed-off-by: Junjie Hu Change-Id: I981f98fc8647469fb105361516b6a59c53530c70 --- .../src/android/net/cts/TrafficStatsTest.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) mode change 100644 => 100755 tests/cts/net/src/android/net/cts/TrafficStatsTest.java diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java old mode 100644 new mode 100755 index 9483bdccf1..5b93beead5 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -207,27 +207,37 @@ public class TrafficStatsTest extends AndroidTestCase { final int maxExpectedExtraPackets = 7; final int minExpectedExtraPackets = 5; + // Some other tests don't cleanup connections correctly. + // They have the same UID, so we discount their lingering traffic + // which happens only on non-localhost, such as TCP FIN retranmission packets + long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore) - uidTxDeltaPackets; + long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) - uidRxDeltaPackets; + if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { + Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); + // Make sure that not too many non-localhost packets are accounted for + assertTrue("too many non-localhost packets on the sam UID", deltaTxOtherPackets + deltaTxOtherPackets < 20); + } assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + - uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets, + uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets + "+" + deltaTxOtherPackets, uidTxDeltaPackets >= packetCount + minExpectedExtraPackets && - uidTxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets); + uidTxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets + " Wanted: " + uidRxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + uidRxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets, uidRxDeltaPackets >= packetCount + minExpectedExtraPackets && - uidRxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets); + uidRxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes + " Wanted: " + uidTxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + uidTxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && - uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0)); + uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaTxOtherPackets, 0)); assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes + " Wanted: " + uidRxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + uidRxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && - uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0)); + uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaRxOtherPackets, 0)); // Localhost traffic *does* count against total stats. // Fudge by 132 packets of 1500 bytes not related to the test. From 81f625634e59c74a68abb67188d7cad3b848eb97 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 24 Apr 2014 16:58:17 -0700 Subject: [PATCH 0132/1415] Libcore.os has moved to android.system.Os. Change-Id: Icfd1cffbed754c147f83fc42ce905beb7904340c --- .../src/android/net/ipv6/cts/PingTest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java index acf474fce4..49fc59c716 100644 --- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -19,10 +19,10 @@ package android.net.ipv6.cts; import android.test.AndroidTestCase; import android.util.Log; -import libcore.io.ErrnoException; -import libcore.io.Libcore; -import libcore.io.StructTimeval; -import static libcore.io.OsConstants.*; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructTimeval; +import static android.system.OsConstants.*; import java.io.FileDescriptor; import java.io.IOException; @@ -84,8 +84,8 @@ public class PingTest extends AndroidTestCase { * Creates an IPv6 ping socket and sets a receive timeout of 100ms. */ private FileDescriptor createPingSocket() throws ErrnoException { - FileDescriptor s = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); - Libcore.os.setsockoptTimeval(s, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(100)); + FileDescriptor s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); + Os.setsockoptTimeval(s, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(100)); return s; } @@ -98,7 +98,7 @@ public class PingTest extends AndroidTestCase { int port = (int) (Math.random() * 2048); // Send the packet. - int ret = Libcore.os.sendto(s, ByteBuffer.wrap(packet), 0, address, port); + int ret = Os.sendto(s, ByteBuffer.wrap(packet), 0, address, port); assertEquals(packet.length, ret); } @@ -113,7 +113,7 @@ public class PingTest extends AndroidTestCase { // Receive the response. if (useRecvfrom) { InetSocketAddress from = new InetSocketAddress(); - bytesRead = Libcore.os.recvfrom(s, responseBuffer, 0, from); + bytesRead = Os.recvfrom(s, responseBuffer, 0, from); // Check the source address and scope ID. assertTrue(from.getAddress() instanceof Inet6Address); @@ -122,7 +122,7 @@ public class PingTest extends AndroidTestCase { assertNull(fromAddress.getScopedInterface()); assertEquals(dest.getHostAddress(), fromAddress.getHostAddress()); } else { - bytesRead = Libcore.os.read(s, responseBuffer); + bytesRead = Os.read(s, responseBuffer); } // Check the packet length. @@ -134,7 +134,7 @@ public class PingTest extends AndroidTestCase { assertEquals((byte) 0x81, response[0]); // Find out what ICMP ID was used in the packet that was sent. - int id = ((InetSocketAddress) Libcore.os.getsockname(s)).getPort(); + int id = ((InetSocketAddress) Os.getsockname(s)).getPort(); sent[4] = (byte) (id / 256); sent[5] = (byte) (id % 256); @@ -162,7 +162,7 @@ public class PingTest extends AndroidTestCase { sendPing(s, ipv6Loopback, packet); checkResponse(s, ipv6Loopback, packet, false); // Check closing the socket doesn't raise an exception. - Libcore.os.close(s); + Os.close(s); } } } From 5f308a9b10d6b9d36f12ef46e1b88fc0b5c71999 Mon Sep 17 00:00:00 2001 From: Vinod Krishnan Date: Thu, 5 Jun 2014 15:03:18 -0700 Subject: [PATCH 0133/1415] Small change to CTS Change-Id: I7b31bd6b05dd1379dcf7d4627eee1856fda87164 --- tests/cts/net/src/android/net/cts/VpnServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/VpnServiceTest.java b/tests/cts/net/src/android/net/cts/VpnServiceTest.java index 9e35375970..8bdd7b0895 100644 --- a/tests/cts/net/src/android/net/cts/VpnServiceTest.java +++ b/tests/cts/net/src/android/net/cts/VpnServiceTest.java @@ -42,7 +42,7 @@ public class VpnServiceTest extends AndroidTestCase { // Should be always resolved by only one activity. int count = mContext.getPackageManager().queryIntentActivities(intent, 0).size(); - assertEquals(count, 1); + assertEquals(1, count); } public void testEstablish() throws Exception { From fd24c913c286c24c535f8ff4283275be84a0b9bb Mon Sep 17 00:00:00 2001 From: Jason Parks Date: Wed, 11 Jun 2014 12:37:49 -0500 Subject: [PATCH 0134/1415] =?UTF-8?q?Don=E2=80=99t=20run=20the=20WifiConfi?= =?UTF-8?q?g=20tests=20if=20there=20is=20no=20Wifi.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 15090701 Change-Id: I19d3fd5fe8165d94dd5d4d952bd5674b5df19684 --- .../net/wifi/cts/WifiEnterpriseConfigTest.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java index 58298d5f10..6e395aaa14 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java @@ -17,6 +17,7 @@ package android.net.wifi.cts; import android.content.Context; +import android.content.pm.PackageManager; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiEnterpriseConfig.Eap; @@ -34,6 +35,11 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { private static final String ANON_IDENTITY = "anonidentity"; private static final int ENABLE_DELAY = 10000; + private boolean hasWifi() { + return getContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WIFI); + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -42,10 +48,16 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { assertNotNull(mWifiManager); mWifiManager.setWifiEnabled(true); Thread.sleep(ENABLE_DELAY); - assertTrue(mWifiManager.isWifiEnabled()); + if (hasWifi()) { + assertTrue(mWifiManager.isWifiEnabled()); + } } public void testSettersAndGetters() { + if (!hasWifi()) { + return; + } + WifiEnterpriseConfig config = new WifiEnterpriseConfig(); assertTrue(config.getEapMethod() == Eap.NONE); config.setEapMethod(Eap.PEAP); @@ -78,6 +90,10 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { } public void testAddEapNetwork() { + if (!hasWifi()) { + return; + } + WifiConfiguration config = new WifiConfiguration(); WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); enterpriseConfig.setEapMethod(Eap.PWD); From d8b41009bdd19c976ec45c33eaf8025005475986 Mon Sep 17 00:00:00 2001 From: Benson Huang Date: Wed, 25 Jun 2014 15:02:11 +0800 Subject: [PATCH 0135/1415] Fix CTS testStartUsingNetworkFeature_enableHipri fail The return value of mWifiManager.isWifiEnabled() && mWifiManager.getConnectionInfo().getSSID() != null can not correctly identify if WiFi is connected or not. The fix is to modify the code logic used to judge if WiFi is connected. Bug 15578218 and 15578219 Change-Id: I8ae40980c9cd1ea91dafe0ca7c893c84b35709bf Signed-off-by: Benson Huang --- .../src/android/net/cts/ConnectivityManagerTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index adb2b3a35e..5656119d0f 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -272,9 +272,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { return; } - boolean isWifiConnected = mWifiManager.isWifiEnabled() - && mWifiManager.getConnectionInfo().getSSID() != null; + boolean isWifiEnabled = mWifiManager.isWifiEnabled(); + boolean isWifiConnected = false; + NetworkInfo nwInfo = mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (nwInfo != null) { + isWifiConnected = nwInfo.isConnected(); + } try { // Make sure WiFi is connected to an access point. if (!isWifiConnected) { @@ -308,7 +312,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { // TODO wait for HIPRI to go // TODO check dns selection // TODO check routes - if (!isWifiConnected) { + if (!isWifiEnabled) { mWifiManager.setWifiEnabled(false); } } From c893f50f6f995cf2bb866eea22beede36881e20e Mon Sep 17 00:00:00 2001 From: Benson Huang Date: Wed, 25 Jun 2014 15:02:11 +0800 Subject: [PATCH 0136/1415] Fix CTS testStartUsingNetworkFeature_enableHipri fail The return value of mWifiManager.isWifiEnabled() && mWifiManager.getConnectionInfo().getSSID() != null can not correctly identify if WiFi is connected or not. The fix is to modify the code logic used to judge if WiFi is connected. Bug 15578218 and 15578219 Change-Id: I8ae40980c9cd1ea91dafe0ca7c893c84b35709bf Signed-off-by: Benson Huang --- .../src/android/net/cts/ConnectivityManagerTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 6f67ed99ea..e769be19ae 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -269,9 +269,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { return; } - boolean isWifiConnected = mWifiManager.isWifiEnabled() - && mWifiManager.getConnectionInfo().getSSID() != null; + boolean isWifiEnabled = mWifiManager.isWifiEnabled(); + boolean isWifiConnected = false; + NetworkInfo nwInfo = mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (nwInfo != null) { + isWifiConnected = nwInfo.isConnected(); + } try { // Make sure WiFi is connected to an access point. if (!isWifiConnected) { @@ -305,7 +309,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { // TODO wait for HIPRI to go // TODO check dns selection // TODO check routes - if (!isWifiConnected) { + if (!isWifiEnabled) { mWifiManager.setWifiEnabled(false); } } From e6694c32fe5cff9d8fd7a47eaf30534ba67d2306 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 16 Jul 2014 18:47:53 +0900 Subject: [PATCH 0137/1415] Add a CTS test for multinetwork features. For now, just checks that the kernel sysctls are present and have the right permissions and expected values. Bug: 15605143 Change-Id: I5feb6cb5f25b97e88cd0d9e8071213d13d4cc6e8 --- .../src/android/net/cts/MultinetworkTest.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/MultinetworkTest.java diff --git a/tests/cts/net/src/android/net/cts/MultinetworkTest.java b/tests/cts/net/src/android/net/cts/MultinetworkTest.java new file mode 100644 index 0000000000..256c03010a --- /dev/null +++ b/tests/cts/net/src/android/net/cts/MultinetworkTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 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 android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.system.StructStat; +import android.test.AndroidTestCase; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * Tests for multinetwork functionality. + */ +public class MultinetworkTest extends AndroidTestCase { + + // Global sysctls. Must be present and set to 1. + private static final String[] GLOBAL_SYSCTLS = { + "/proc/sys/net/ipv4/fwmark_reflect", + "/proc/sys/net/ipv6/fwmark_reflect", + "/proc/sys/net/ipv4/tcp_fwmark_accept", + }; + + // Per-interface IPv6 autoconf sysctls. + private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf"; + private static final String AUTOCONF_SYSCTL = "accept_ra_rt_table"; + + // Expected mode, UID, and GID of sysctl files. + private static final int SYSCTL_MODE = 0100644; + private static final int SYSCTL_UID = 0; + private static final int SYSCTL_GID = 0; + + private void checkSysctlPermissions(String fileName) throws ErrnoException { + StructStat stat = Os.stat(fileName); + assertEquals("mode of " + fileName + ":", SYSCTL_MODE, stat.st_mode); + assertEquals("UID of " + fileName + ":", SYSCTL_UID, stat.st_uid); + assertEquals("GID of " + fileName + ":", SYSCTL_GID, stat.st_gid); + } + + private void assertLess(String what, int a, int b) { + assertTrue(what + " expected < " + b + " but was: " + a, a < b); + } + + private String readFile(String fileName) throws ErrnoException, IOException { + byte[] buf = new byte[1024]; + FileDescriptor fd = Os.open(fileName, 0, OsConstants.O_RDONLY); + int bytesRead = Os.read(fd, buf, 0, buf.length); + assertLess("length of " + fileName + ":", bytesRead, buf.length); + return new String(buf); + } + + /** + * Checks that the sysctls for multinetwork kernel features are present and + * enabled. The necessary kernel commits are: + * + * Mainline Linux: + * e110861 net: add a sysctl to reflect the fwmark on replies + * 1b3c61d net: Use fwmark reflection in PMTU discovery. + * 84f39b0 net: support marking accepting TCP sockets + * + * Common Android tree (e.g., 3.10): + * a03f539 net: ipv6: autoconf routes into per-device tables + */ + public void testProcFiles() throws ErrnoException, IOException, NumberFormatException { + for (String sysctl : GLOBAL_SYSCTLS) { + checkSysctlPermissions(sysctl); + int value = Integer.parseInt(readFile(sysctl).trim()); + assertEquals("value of " + sysctl + ":", 1, value); + } + + File[] interfaceDirs = new File(IPV6_SYSCTL_DIR).listFiles(); + for (File interfaceDir : interfaceDirs) { + if (interfaceDir.getName().equals("all") || interfaceDir.getName().equals("lo")) { + continue; + } + String sysctl = new File(interfaceDir, AUTOCONF_SYSCTL).getAbsolutePath(); + checkSysctlPermissions(sysctl); + int value = Integer.parseInt(readFile(sysctl).trim()); + assertLess("value of " + sysctl + ":", value, 0); + } + } +} From 39f61377a5b30302f9f85b6cb8ac1df5585b3ebc Mon Sep 17 00:00:00 2001 From: Constantin Musca Date: Fri, 23 May 2014 14:20:29 +0300 Subject: [PATCH 0138/1415] LocalSocketTest.testAccessors: fix the *SendBufferSize* test If one sets a *SendBufferSize* value which is less than (2048 + SKB_DATA_ALIGN(sizeof(struct sk_buff))) then the value retrieved will be (2 * (2048 + SKB_DATA_ALIGN(sizeof(struct sk_buff)))). Otherwise, the value will be doubled. Modify the test to use a larger value. Bug: 16442451 Change-Id: I2d89393b1ad441783c8a082b072a806b8901830c Signed-off-by: Constantin Musca --- tests/cts/net/src/android/net/cts/LocalSocketTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 0a4bc0d4f2..865ec21da3 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -126,8 +126,8 @@ public class LocalSocketTest extends AndroidTestCase{ socket.setReceiveBufferSize(1999); assertEquals(1999 << 1, socket.getReceiveBufferSize()); - socket.setSendBufferSize(1998); - assertEquals(1998 << 1, socket.getSendBufferSize()); + socket.setSendBufferSize(3998); + assertEquals(3998 << 1, socket.getSendBufferSize()); // Timeout is not support at present, so set is ignored socket.setSoTimeout(1996); From 67e673f04eab563809c241a8d465bcd132741581 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Thu, 25 Sep 2014 10:07:21 -0400 Subject: [PATCH 0139/1415] Update CTS ConnectivityManager tests to work with L release. Removed most of getNetworkPreference() and setNetworkPreference() tests as these functions are now fully deprecated and do nothing. Just test that they are still callable. Adjust startUsingNetworkFeature() and stopUsingNetworkFeature() failure codes to match new behavior. Tested on devices with Wifi and Cellular radios, and Wifi-only. bug:17417896 bug:17354855 Change-Id: Iea8b25e399f4e5b6ec3d2101ebf520f89697c4da --- .../net/cts/ConnectivityManagerTest.java | 46 +++++-------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 5656119d0f..d79ecdddb4 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,7 +16,6 @@ package android.net.cts; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -31,6 +30,8 @@ import android.net.wifi.WifiManager; import android.test.AndroidTestCase; import android.util.Log; +import com.android.internal.telephony.PhoneConstants; + import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -115,34 +116,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { } public void testSetNetworkPreference() { - // verify swtiching between two default networks - need to connectable networks though - // could use test and whatever the current active network is - int originalPref = mCm.getNetworkPreference(); - int currentPref = originalPref; - for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { - mCm.setNetworkPreference(type); - NetworkConfig c = mNetworks.get(type); - boolean expectWorked = (c != null && c.isDefault()); - int totalSleep = 0; - int foundType = ConnectivityManager.TYPE_NONE; - while (totalSleep < 1000) { - try { - Thread.currentThread().sleep(100); - } catch (InterruptedException e) {} - totalSleep += 100; - foundType = mCm.getNetworkPreference(); - if (currentPref != foundType) break; - } - if (expectWorked) { - assertTrue("We should have been able to switch prefered type " + type, - foundType == type); - } else { - assertTrue("We should not have been able to switch type " + type, - foundType != type); - } - currentPref = foundType; - } - mCm.setNetworkPreference(originalPref); + // getNetworkPreference() and setNetworkPreference() are both deprecated so they do + // not preform any action. Verify they are at least still callable. + mCm.setNetworkPreference(mCm.getNetworkPreference()); } public void testGetActiveNetworkInfo() { @@ -194,13 +170,13 @@ public class ConnectivityManagerTest extends AndroidTestCase { final String invalidateFeature = "invalidateFeature"; final String mmsFeature = "enableMMS"; final int failureCode = -1; - final int wifiOnlyStartFailureCode = 3; - final int wifiOnlyStopFailureCode = 1; + final int wifiOnlyStartFailureCode = PhoneConstants.APN_REQUEST_FAILED; + final int wifiOnlyStopFailureCode = -1; NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE); if (ni != null) { - assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, - invalidateFeature)); + assertEquals(PhoneConstants.APN_REQUEST_FAILED, + mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); } else { @@ -212,8 +188,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { ni = mCm.getNetworkInfo(TYPE_WIFI); if (ni != null) { - // Should return failure(-1) because MMS is not supported on WIFI. - assertEquals(failureCode, mCm.startUsingNetworkFeature(TYPE_WIFI, + // Should return failure because MMS is not supported on WIFI. + assertEquals(PhoneConstants.APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI, mmsFeature)); assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI, mmsFeature)); From 94995b1dc8d4f66bc13a45961a79c17f646acf55 Mon Sep 17 00:00:00 2001 From: Unsuk Jung Date: Thu, 9 Oct 2014 00:59:51 -0700 Subject: [PATCH 0140/1415] Build CTS tests as multilib apks CTS-tradefed uses the same apk for both 32 and 64 bit tests. Bug: 17924614 Change-Id: Idbf2d93c54efbb1c281ad9e93f0f39430614df61 --- tests/cts/net/Android.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index da19a4da78..46d4d819ac 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -21,6 +21,9 @@ LOCAL_MODULE_TAGS := optional # and when built explicitly put it in the data partition LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) +# Include both the 32 and 64 bit versions +LOCAL_MULTILIB := both + LOCAL_JAVA_LIBRARIES := voip-common conscrypt LOCAL_JNI_SHARED_LIBRARIES := libnativedns_jni From 383973418884541fd80308d9e124960dcc4719da Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 14 Oct 2014 18:40:09 -0700 Subject: [PATCH 0141/1415] Add cts test for wifi scan timestamp. Bug:18014366 Change-Id: Ie25c53eb12077f4f03f45c7e6828a8ace25c0fdb --- .../android/net/wifi/cts/WifiManagerTest.java | 52 +++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 7faea64648..d8df064311 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -28,6 +28,7 @@ import android.net.wifi.WifiConfiguration.Status; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.TxPacketCountListener; import android.net.wifi.WifiManager.WifiLock; +import android.os.SystemClock; import android.test.AndroidTestCase; import android.util.Log; @@ -36,6 +37,7 @@ import java.net.URL; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class WifiManagerTest extends AndroidTestCase { @@ -46,7 +48,7 @@ public class WifiManagerTest extends AndroidTestCase { private WifiManager mWifiManager; private WifiLock mWifiLock; private static MySync mMySync; - private List mScanResult = null; + private List mScanResults = null; private NetworkInfo mNetworkInfo; // Please refer to WifiManager @@ -66,6 +68,10 @@ public class WifiManagerTest extends AndroidTestCase { private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; private static final int DURATION = 10000; + private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000; + private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; + private static final int WIFI_SCAN_TEST_ITERATIONS = 5; + private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -74,9 +80,9 @@ public class WifiManagerTest extends AndroidTestCase { if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { synchronized (mMySync) { if (mWifiManager.getScanResults() != null) { - mScanResult = mWifiManager.getScanResults(); + mScanResults = mWifiManager.getScanResults(); mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; - mScanResult = mWifiManager.getScanResults(); + mScanResults = mWifiManager.getScanResults(); mMySync.notifyAll(); } } @@ -260,6 +266,46 @@ public class WifiManagerTest extends AndroidTestCase { assertFalse(mWifiManager.isWifiEnabled()); } + /** + * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with + * {@link SystemClock#elapsedRealtime()} on device.

+ * To run this test in cts-tradefed: + * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp + */ + public void testWifiScanTimestamp() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + Log.d(TAG, "Skipping test as WiFi is not supported"); + return; + } + if (!mWifiManager.isWifiEnabled()) { + setWifiEnabled(true); + } + // Scan multiple times to make sure scan timestamps increase with device timestamp. + for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) { + startScan(); + // Make sure at least one AP is found. + assertFalse("empty scan results!", mScanResults.isEmpty()); + long nowMillis = SystemClock.elapsedRealtime(); + // Keep track of how many APs are fresh in one scan. + int numFreshAps = 0; + for (ScanResult result : mScanResults) { + long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp); + if (Math.abs(nowMillis - scanTimeMillis) < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) { + numFreshAps++; + } + } + // At least half of the APs in the scan should be fresh. + int numTotalAps = mScanResults.size(); + String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: " + + numFreshAps; + assertTrue(msg, numFreshAps * 2 >= mScanResults.size()); + if (i < WIFI_SCAN_TEST_ITERATIONS - 1) { + // Wait before running next iteration. + Thread.sleep(WIFI_SCAN_TEST_INTERVAL_MILLIS); + } + } + } + /** * test point of wifiManager NetWork: * 1.add NetWork From 0b3e6eb196c105833b8fbdabaa4f73fcab8b5f8c Mon Sep 17 00:00:00 2001 From: Vinit Deshpande Date: Tue, 21 Oct 2014 11:54:37 -0700 Subject: [PATCH 0142/1415] Relax NsdManagerTest's duplicate event check We have seen quite a few of these; and it doesn't seem to be pointing to any device implementation problem. Hence relaxing the test. Bug: 18005417 Change-Id: Iee983527ddff4f5336ccb48c04ce851102f13349 --- tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java index d1e4c447c3..d43472805b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java @@ -356,7 +356,7 @@ public class NsdManagerTest extends AndroidTestCase { assertTrue(lastEvent.mInfo.getPort() == localPort); assertTrue(eventCacheSize() == 1); - assertTrue(checkForAdditionalEvents()); + checkForAdditionalEvents(); clearEventCache(); // Unregister the service From 164529620828506486a1f1055696698242299547 Mon Sep 17 00:00:00 2001 From: Vinit Deshpande Date: Thu, 23 Oct 2014 17:02:19 -0700 Subject: [PATCH 0143/1415] Remove enableNetwork(netId, disableOthers) check from CTS We don't really disable any networks anymore; so there's not much to be verified. Bug: 17937171 Change-Id: I57e16953bdc0a698f3bc5fba555b39bc450c13ab --- .../net/src/android/net/wifi/cts/WifiManagerTest.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index d8df064311..152789cafb 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -213,8 +213,9 @@ public class WifiManagerTest extends AndroidTestCase { private void assertDisableOthers(WifiConfiguration wifiConfiguration, boolean disableOthers) { for (WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { if ((!w.SSID.equals(wifiConfiguration.SSID)) && w.status != Status.CURRENT) { - if (disableOthers) + if (disableOthers) { assertEquals(Status.DISABLED, w.status); + } } } } @@ -321,6 +322,7 @@ public class WifiManagerTest extends AndroidTestCase { // skip the test if WiFi is not supported return; } + // store the list of enabled networks, so they can be re-enabled after test completes Set enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); try { @@ -353,11 +355,6 @@ public class WifiManagerTest extends AndroidTestCase { wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); assertDisableOthers(wifiConfiguration, disableOthers); assertEquals(Status.ENABLED, wifiConfiguration.status); - disableOthers = true; - - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertDisableOthers(wifiConfiguration, disableOthers); assertTrue(mWifiManager.disableNetwork(netId)); wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); From 5bba35cb162393646ba4e89e65988e8e949d04a5 Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Tue, 18 Nov 2014 20:15:25 -0800 Subject: [PATCH 0144/1415] Fix build breakage due to SSLDefaultConfigurationAsserts rename. libcore's SSLDefaultConfigurationAsserts was renamed and refactored into SSLConfigurationAsserts in 782740701db73dd2dc4fef9df8cde270b0e631a4. This CL adjusts the affected CTS test for android.net.SSLCertificateSocketFactory accordingly. Change-Id: I663042e7c08ad616b2dedc226acda54c95fd6968 --- .../src/android/net/cts/SSLCertificateSocketFactoryTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 6175923e46..60ac226440 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -26,7 +26,7 @@ import javax.net.ssl.SSLPeerUnverifiedException; import android.net.SSLCertificateSocketFactory; import android.test.AndroidTestCase; -import libcore.javax.net.ssl.SSLDefaultConfigurationAsserts; +import libcore.javax.net.ssl.SSLConfigurationAsserts; public class SSLCertificateSocketFactoryTest extends AndroidTestCase { private SSLCertificateSocketFactory mFactory; @@ -40,7 +40,7 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { } public void testDefaultConfiguration() throws Exception { - SSLDefaultConfigurationAsserts.assertSSLSocketFactory(mFactory); + SSLConfigurationAsserts.assertSSLSocketFactoryDefaultConfiguration(mFactory); } public void testAccessProperties() throws Exception { From 5d5cd1f27d85f5b90573b31f80e860cc2c4ba4a8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 16 Nov 2014 20:09:24 -0800 Subject: [PATCH 0145/1415] Add a CTS test for the VPN API. Bug: 15605143 Change-Id: I8e5f8b281b6ee16acf8daf1b4a1113847e1ccabd --- tests/cts/hostside/Android.mk | 31 ++ tests/cts/hostside/app/Android.mk | 32 ++ tests/cts/hostside/app/AndroidManifest.xml | 38 +++ .../android/cts/net/hostside/MyActivity.java | 53 ++++ .../cts/net/hostside/MyVpnService.java | 155 ++++++++++ .../cts/net/hostside/UdpReflector.java | 113 +++++++ .../com/android/cts/net/hostside/VpnTest.java | 281 ++++++++++++++++++ .../android/cts/net/HostsideNetworkTests.java | 105 +++++++ 8 files changed, 808 insertions(+) create mode 100644 tests/cts/hostside/Android.mk create mode 100644 tests/cts/hostside/app/Android.mk create mode 100644 tests/cts/hostside/app/AndroidManifest.xml create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/UdpReflector.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java diff --git a/tests/cts/hostside/Android.mk b/tests/cts/hostside/Android.mk new file mode 100644 index 0000000000..6637d6186f --- /dev/null +++ b/tests/cts/hostside/Android.mk @@ -0,0 +1,31 @@ +# Copyright (C) 2014 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_MODULE := CtsHostsideNetworkTests + +LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt + +LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork + +include $(BUILD_CTS_HOST_JAVA_LIBRARY) + +# Build the test APKs using their own makefiles +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk new file mode 100644 index 0000000000..29b620d2c3 --- /dev/null +++ b/tests/cts/hostside/app/Android.mk @@ -0,0 +1,32 @@ +# +# Copyright (C) 2014 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_SDK_VERSION := current +LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := CtsHostsideNetworkTestsApp + +LOCAL_PROGUARD_ENABLED := disabled +LOCAL_DEX_PREOPT := false + +include $(BUILD_PACKAGE) diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml new file mode 100644 index 0000000000..cdde7dcb34 --- /dev/null +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java new file mode 100644 index 0000000000..375c8523c8 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import android.app.Activity; +import android.content.Intent; +import android.net.VpnService; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.view.WindowManager; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class MyActivity extends Activity { + private final LinkedBlockingQueue mResult = new LinkedBlockingQueue<>(1); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (mResult.offer(resultCode) == false) { + throw new RuntimeException("Queue is full! This should never happen"); + } + } + + public Integer getResult(int timeoutMs) throws InterruptedException { + return mResult.poll(timeoutMs, TimeUnit.MILLISECONDS); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java new file mode 100644 index 0000000000..1a12aaa14f --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import android.content.Intent; +import android.net.VpnService; +import android.os.ParcelFileDescriptor; +import android.content.pm.PackageManager.NameNotFoundException; +import android.text.TextUtils; +import android.util.Log; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; + +public class MyVpnService extends VpnService { + + private static String TAG = "MyVpnService"; + private static int MTU = 1799; + + private ParcelFileDescriptor mFd = null; + private UdpReflector mUdpReflector = null; + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + String packageName = getPackageName(); + String cmd = intent.getStringExtra(packageName + ".cmd"); + if ("disconnect".equals(cmd)) { + stop(); + } else if ("connect".equals(cmd)) { + start(packageName, intent); + } + + return START_NOT_STICKY; + } + + private void start(String packageName, Intent intent) { + Builder builder = new Builder(); + + String addresses = intent.getStringExtra(packageName + ".addresses"); + if (addresses != null) { + String[] addressArray = addresses.split(","); + for (int i = 0; i < addressArray.length; i++) { + String[] prefixAndMask = addressArray[i].split("/"); + try { + InetAddress address = InetAddress.getByName(prefixAndMask[0]); + int prefixLength = Integer.parseInt(prefixAndMask[1]); + builder.addAddress(address, prefixLength); + } catch (UnknownHostException|NumberFormatException| + ArrayIndexOutOfBoundsException e) { + continue; + } + } + } + + String routes = intent.getStringExtra(packageName + ".routes"); + if (routes != null) { + String[] routeArray = routes.split(","); + for (int i = 0; i < routeArray.length; i++) { + String[] prefixAndMask = routeArray[i].split("/"); + try { + InetAddress address = InetAddress.getByName(prefixAndMask[0]); + int prefixLength = Integer.parseInt(prefixAndMask[1]); + builder.addRoute(address, prefixLength); + } catch (UnknownHostException|NumberFormatException| + ArrayIndexOutOfBoundsException e) { + continue; + } + } + } + + String allowed = intent.getStringExtra(packageName + ".allowedapplications"); + if (allowed != null) { + String[] packageArray = allowed.split(","); + for (int i = 0; i < packageArray.length; i++) { + String allowedPackage = packageArray[i]; + if (!TextUtils.isEmpty(allowedPackage)) { + try { + builder.addAllowedApplication(allowedPackage); + } catch(NameNotFoundException e) { + continue; + } + } + } + } + + String disallowed = intent.getStringExtra(packageName + ".disallowedapplications"); + if (disallowed != null) { + String[] packageArray = disallowed.split(","); + for (int i = 0; i < packageArray.length; i++) { + String disallowedPackage = packageArray[i]; + if (!TextUtils.isEmpty(disallowedPackage)) { + try { + builder.addDisallowedApplication(disallowedPackage); + } catch(NameNotFoundException e) { + continue; + } + } + } + } + + builder.setMtu(MTU); + builder.setBlocking(true); + builder.setSession("MyVpnService"); + + Log.i(TAG, "Establishing VPN," + + " addresses=" + addresses + + " routes=" + routes + + " allowedApplications=" + allowed + + " disallowedApplications=" + disallowed); + + mFd = builder.establish(); + Log.i(TAG, "Established, fd=" + (mFd == null ? "null" : mFd.getFd())); + + mUdpReflector = new UdpReflector(mFd.getFileDescriptor(), MTU); + mUdpReflector.start(); + } + + private void stop() { + if (mUdpReflector != null) { + mUdpReflector.interrupt(); + mUdpReflector = null; + } + try { + if (mFd != null) { + Log.i(TAG, "Closing filedescriptor"); + mFd.close(); + } + } catch(IOException e) { + } finally { + mFd = null; + } + } + + @Override + public void onDestroy() { + stop(); + super.onDestroy(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/UdpReflector.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/UdpReflector.java new file mode 100644 index 0000000000..a730fed08a --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/UdpReflector.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import android.system.Os; +import android.system.ErrnoException; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; + +public class UdpReflector extends Thread { + + private static int IPV4_HEADER_LENGTH = 20; + private static int IPV6_HEADER_LENGTH = 40; + private static int UDP_HEADER_LENGTH = 8; + + private static int IPV4_PROTO_OFFSET = 9; + private static int IPV6_PROTO_OFFSET = 6; + private static int IPPROTO_UDP = 17; + + private static int IPV4_ADDR_OFFSET = 12; + private static int IPV6_ADDR_OFFSET = 8; + private static int IPV4_ADDR_LENGTH = 4; + private static int IPV6_ADDR_LENGTH = 16; + + private static String TAG = "UdpReflector"; + + private FileDescriptor mFd; + private byte[] mBuf; + + public UdpReflector(FileDescriptor fd, int mtu) { + super("UdpReflector"); + mFd = fd; + mBuf = new byte[mtu]; + } + + private static void swapBytes(byte[] buf, int pos1, int pos2, int len) { + for (int i = 0; i < len; i++) { + byte b = buf[pos1 + i]; + buf[pos1 + i] = buf[pos2 + i]; + buf[pos2 + i] = b; + } + } + + /** Reads one packet from our mFd, and possibly writes the packet back. */ + private void processPacket() { + int len; + try { + len = Os.read(mFd, mBuf, 0, mBuf.length); + } catch (ErrnoException|IOException e) { + Log.e(TAG, "Error reading packet: " + e.getMessage()); + return; + } + + int version = mBuf[0] >> 4; + int addressOffset, protoOffset, headerLength, addressLength; + if (version == 4) { + headerLength = IPV4_HEADER_LENGTH; + protoOffset = IPV4_PROTO_OFFSET; + addressOffset = IPV4_ADDR_OFFSET; + addressLength = IPV4_ADDR_LENGTH; + } else if (version == 6) { + headerLength = IPV6_HEADER_LENGTH; + protoOffset = IPV6_PROTO_OFFSET; + addressOffset = IPV6_ADDR_OFFSET; + addressLength = IPV6_ADDR_LENGTH; + } else { + return; + } + + if (len < headerLength + UDP_HEADER_LENGTH || mBuf[protoOffset] != IPPROTO_UDP) { + return; + } + + // Swap src and dst IP addresses. + swapBytes(mBuf, addressOffset, addressOffset + addressLength, addressLength); + + // Swap dst and src ports. + int portOffset = headerLength; + swapBytes(mBuf, portOffset, portOffset + 2, 2); + + // Send the packet back. We don't need to recalculate the checksum because we didn't change + // the packet bytes, we only moved them around. + try { + len = Os.write(mFd, mBuf, 0, len); + } catch (ErrnoException|IOException e) { + Log.e(TAG, "Error writing packet: " + e.getMessage()); + } + } + + public void run() { + Log.i(TAG, "UdpReflector starting fd=" + mFd + " valid=" + mFd.valid()); + while (!interrupted() && mFd.valid()) { + processPacket(); + } + Log.i(TAG, "UdpReflector exiting fd=" + mFd + " valid=" + mFd.valid()); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java new file mode 100644 index 0000000000..cdd370ee67 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.VpnService; +import android.os.ParcelFileDescriptor; +import android.os.SystemClock; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiObjectNotFoundException; +import android.support.test.uiautomator.UiScrollable; +import android.support.test.uiautomator.UiSelector; +import android.test.MoreAsserts; +import android.test.InstrumentationTestCase; +import android.text.TextUtils; +import android.util.Log; + +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.Inet6Address; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Tests for {@link DocumentsProvider} and interaction with platform intents + * like {@link Intent#ACTION_OPEN_DOCUMENT}. + */ +public class VpnTest extends InstrumentationTestCase { + + public static String TAG = "VpnTest"; + public static int TIMEOUT_MS = 3 * 1000; + + private UiDevice mDevice; + private MyActivity mActivity; + private String mPackageName; + private ConnectivityManager mCM; + Network mNetwork; + NetworkCallback mCallback; + final Object mLock = new Object(); + + private boolean supportedHardware() { + final PackageManager pm = getInstrumentation().getContext().getPackageManager(); + return !pm.hasSystemFeature("android.hardware.type.television") && + !pm.hasSystemFeature("android.hardware.type.watch"); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + mNetwork = null; + mCallback = null; + + mDevice = UiDevice.getInstance(getInstrumentation()); + mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(), + MyActivity.class, null); + mPackageName = mActivity.getPackageName(); + mCM = (ConnectivityManager) mActivity.getSystemService(mActivity.CONNECTIVITY_SERVICE); + mDevice.waitForIdle(); + } + + @Override + public void tearDown() throws Exception { + if (mCallback != null) { + mCM.unregisterNetworkCallback(mCallback); + } + Log.i(TAG, "Stopping VPN"); + stopVpn(); + mActivity.finish(); + super.tearDown(); + } + + private void prepareVpn() throws Exception { + final int REQUEST_ID = 42; + + // Attempt to prepare. + Log.i(TAG, "Preparing VPN"); + Intent intent = VpnService.prepare(mActivity); + + if (intent != null) { + // Start the confirmation dialog and click OK. + mActivity.startActivityForResult(intent, REQUEST_ID); + mDevice.waitForIdle(); + + String packageName = intent.getComponent().getPackageName(); + String resourceIdRegex = "android:id/button1$|button_start_vpn"; + final UiObject okButton = new UiObject(new UiSelector() + .className("android.widget.Button") + .packageName(packageName) + .resourceIdMatches(resourceIdRegex)); + if (okButton.waitForExists(TIMEOUT_MS) == false) { + mActivity.finishActivity(REQUEST_ID); + fail("VpnService.prepare returned an Intent for '" + intent.getComponent() + "' " + + "to display the VPN confirmation dialog, but this test could not find the " + + "button to allow the VPN application to connect. Please ensure that the " + + "component displays a button with a resource ID matching the regexp: '" + + resourceIdRegex + "'."); + } + + // Click the button and wait for RESULT_OK. + okButton.click(); + try { + int result = mActivity.getResult(TIMEOUT_MS); + if (result != MyActivity.RESULT_OK) { + fail("The VPN confirmation dialog did not return RESULT_OK when clicking on " + + "the button matching the regular expression '" + resourceIdRegex + + "' of " + intent.getComponent() + "'. Please ensure that clicking on " + + "that button allows the VPN application to connect. " + + "Return value: " + result); + } + } catch (InterruptedException e) { + fail("VPN confirmation dialog did not return after " + TIMEOUT_MS + "ms"); + } + + // Now we should be prepared. + intent = VpnService.prepare(mActivity); + if (intent != null) { + fail("VpnService.prepare returned non-null even after the VPN dialog " + + intent.getComponent() + "returned RESULT_OK."); + } + } + } + + private void startVpn( + String[] addresses, String[] routes, + String allowedApplications, String disallowedApplications) throws Exception { + + prepareVpn(); + + // Register a callback so we will be notified when our VPN comes up. + final NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + mCallback = new NetworkCallback() { + public void onAvailable(Network network) { + synchronized (mLock) { + Log.i(TAG, "Got available callback for network=" + network); + mNetwork = network; + mLock.notify(); + } + } + }; + mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown. + + // Start the service and wait up for TIMEOUT_MS ms for the VPN to come up. + Intent intent = new Intent(mActivity, MyVpnService.class) + .putExtra(mPackageName + ".cmd", "connect") + .putExtra(mPackageName + ".addresses", TextUtils.join(",", addresses)) + .putExtra(mPackageName + ".routes", TextUtils.join(",", routes)) + .putExtra(mPackageName + ".allowedapplications", allowedApplications) + .putExtra(mPackageName + ".disallowedapplications", disallowedApplications); + mActivity.startService(intent); + synchronized (mLock) { + if (mNetwork == null) { + mLock.wait(TIMEOUT_MS); + } + } + + if (mNetwork == null) { + fail("VPN did not become available after " + TIMEOUT_MS + "ms"); + } + + // Unfortunately, when the available callback fires, the VPN UID ranges are not yet + // configured. Give the system some time to do so. http://b/18436087 . + try { Thread.sleep(300); } catch(InterruptedException e) {} + } + + private void stopVpn() { + // Simply calling mActivity.stopService() won't stop the service, because the system binds + // to the service for the purpose of sending it a revoke command if another VPN comes up, + // and stopping a bound service has no effect. Instead, "start" the service again with an + // Intent that tells it to disconnect. + Intent intent = new Intent(mActivity, MyVpnService.class) + .putExtra(mPackageName + ".cmd", "disconnect"); + mActivity.startService(intent); + } + + private static void checkUdpEcho( + String to, String expectedFrom, boolean expectReply) throws IOException { + DatagramSocket s; + InetAddress address = InetAddress.getByName(to); + if (address instanceof Inet6Address) { // http://b/18094870 + s = new DatagramSocket(0, InetAddress.getByName("::")); + } else { + s = new DatagramSocket(); + } + s.setSoTimeout(100); // ms. + + String msg = "Hello, world!"; + DatagramPacket p = new DatagramPacket(msg.getBytes(), msg.length()); + s.connect(address, 7); + + if (expectedFrom != null) { + assertEquals("Unexpected source address: ", + expectedFrom, s.getLocalAddress().getHostAddress()); + } + + try { + if (expectReply) { + s.send(p); + s.receive(p); + MoreAsserts.assertEquals(msg.getBytes(), p.getData()); + } else { + try { + s.send(p); + s.receive(p); + fail("Received unexpected reply"); + } catch(IOException expected) {} + } + } finally { + s.close(); + } + } + + private static void expectUdpEcho(String to, String expectedFrom) throws IOException { + checkUdpEcho(to, expectedFrom, true); + } + + private static void expectNoUdpEcho(String to) throws IOException { + checkUdpEcho(to, null, false); + } + + public void testDefault() throws Exception { + if (!supportedHardware()) return; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"192.0.2.0/24", "2001:db8::/32"}, + "", ""); + + expectUdpEcho("192.0.2.251", "192.0.2.2"); + expectUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); + } + + public void testAppAllowed() throws Exception { + if (!supportedHardware()) return; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, + mPackageName, ""); + + expectUdpEcho("192.0.2.251", "192.0.2.2"); + expectUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); + } + + public void testAppDisallowed() throws Exception { + if (!supportedHardware()) return; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"192.0.2.0/24", "2001:db8::/32"}, + "", mPackageName); + + expectNoUdpEcho("192.0.2.251"); + expectNoUdpEcho("2001:db8:dead:beef::f00"); + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java new file mode 100644 index 0000000000..a7698f36ac --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net; + +import com.android.cts.tradefed.build.CtsBuildHelper; +import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; +import com.android.ddmlib.testrunner.TestIdentifier; +import com.android.ddmlib.testrunner.TestResult; +import com.android.ddmlib.testrunner.TestResult.TestStatus; +import com.android.ddmlib.testrunner.TestRunResult; +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.testtype.DeviceTestCase; +import com.android.tradefed.testtype.IAbi; +import com.android.tradefed.testtype.IAbiReceiver; +import com.android.tradefed.testtype.IBuildReceiver; +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.result.CollectingTestListener; + +import java.util.Map; + +public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver { + private static final String TEST_PKG = "com.android.cts.net.hostside"; + private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk"; + + private IAbi mAbi; + private CtsBuildHelper mCtsBuild; + + @Override + public void setAbi(IAbi abi) { + mAbi = abi; + } + + @Override + public void setBuild(IBuildInfo buildInfo) { + mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + assertNotNull(mAbi); + assertNotNull(mCtsBuild); + + getDevice().uninstallPackage(TEST_PKG); + + assertNull(getDevice().installPackage(mCtsBuild.getTestApp(TEST_APK), false)); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + getDevice().uninstallPackage(TEST_PKG); + } + + public void testVpn() throws Exception { + runDeviceTests(TEST_PKG, ".VpnTest"); + } + + public void runDeviceTests(String packageName, String testClassName) + throws DeviceNotAvailableException { + RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, + "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + + final CollectingTestListener listener = new CollectingTestListener(); + getDevice().runInstrumentationTests(testRunner, listener); + + final TestRunResult result = listener.getCurrentRunResults(); + if (result.isRunFailure()) { + throw new AssertionError("Failed to successfully run device tests for " + + result.getName() + ": " + result.getRunFailureMessage()); + } + + if (result.hasFailedTests()) { + // build a meaningful error message + StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n"); + for (Map.Entry resultEntry : + result.getTestResults().entrySet()) { + if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) { + errorBuilder.append(resultEntry.getKey().toString()); + errorBuilder.append(":\n"); + errorBuilder.append(resultEntry.getValue().getStackTrace()); + } + } + throw new AssertionError(errorBuilder.toString()); + } + } +} From 96f656c39edf5983ce0bb8f6d5f9c0f1ac761507 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Tue, 9 Dec 2014 13:28:37 +0000 Subject: [PATCH 0146/1415] Track changes to Posix.* API. We need to flip() the byte buffer before attempting to read the data written to it. bug: 18641009 Change-Id: I4c69f67bb74d84583c6f71488bdc3c9a683a4f18 --- tests/cts/net/src/android/net/ipv6/cts/PingTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java index 49fc59c716..e9bfb43b5e 100644 --- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -130,6 +130,7 @@ public class PingTest extends AndroidTestCase { // Check the response is an echo reply. byte[] response = new byte[bytesRead]; + responseBuffer.flip(); responseBuffer.get(response, 0, bytesRead); assertEquals((byte) 0x81, response[0]); From 18fc2cd3c4ea315d0909cdfb1449431da1dc4429 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Wed, 10 Dec 2014 20:22:47 +0900 Subject: [PATCH 0147/1415] Consider VPN always to be a supported type. Change-Id I02eb5f22737720095f646f8db5c87fd66da129d6 adds VPN as a supported network type to all device configurations directly in software, independent of any external per-device configuration. Reflect this expectation in the test. Bug: 18439110 Bug: 18668362 Change-Id: I7fca77e564219c96e8a78372d4885c7b7f012a48 --- .../net/src/android/net/cts/ConnectivityManagerTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index d79ecdddb4..15d368f515 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -197,7 +197,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { } private boolean isSupported(int networkType) { - return mNetworks.containsKey(networkType); + // Change-Id I02eb5f22737720095f646f8db5c87fd66da129d6 added VPN support + // to all devices directly in software, independent of any external + // configuration. + return mNetworks.containsKey(networkType) || + (networkType == ConnectivityManager.TYPE_VPN); } // true if only the system can turn it on From 913b99435035eca3be12eb31180dca54b2c79957 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Tue, 9 Dec 2014 15:48:50 -0800 Subject: [PATCH 0148/1415] Skip testDnsWorks if the active network for watch is proxy. Bug: 18625962 Change-Id: I56dacf8d93c1557b44eaf80fbc80eb6a596a9436 --- .../cts/net/src/android/net/cts/DnsTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index 879a962233..0377d048e7 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -16,6 +16,10 @@ package android.net.cts; +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.os.SystemClock; import android.test.AndroidTestCase; import android.util.Log; @@ -34,6 +38,7 @@ public class DnsTest extends AndroidTestCase { private static final boolean DBG = false; private static final String TAG = "DnsTest"; + private static final String PROXY_NETWORK_TYPE = "PROXY"; /** * @return true on success @@ -71,6 +76,14 @@ public class DnsTest extends AndroidTestCase { // We should have at least one of the addresses to connect! assertTrue(foundV4 || foundV6); + // Skip the rest of the test if the active network for watch is PROXY. + // TODO: Check NetworkInfo type in addition to type name once ag/601257 is merged. + if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH) + && activeNetworkInfoIsProxy()) { + Log.i(TAG, "Skipping test because the active network type name is PROXY."); + return; + } + try { addrs = InetAddress.getAllByName("ipv6.google.com"); } catch (UnknownHostException e) {} @@ -241,4 +254,15 @@ public class DnsTest extends AndroidTestCase { Log.e(TAG, "bad URL in testDnsPerf: " + e.toString()); } } + + private boolean activeNetworkInfoIsProxy() { + ConnectivityManager cm = (ConnectivityManager) + getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo info = cm.getActiveNetworkInfo(); + if (PROXY_NETWORK_TYPE.equals(info.getTypeName())) { + return true; + } + + return false; + } } From 0e87f2b861c61e0f53038cdd8d22fa7bca992354 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Tue, 9 Dec 2014 13:28:37 +0000 Subject: [PATCH 0149/1415] Track changes to Posix.* API. We need to flip() the byte buffer before attempting to read the data written to it. bug: 18641009 (cherry picked from commit 96f656c39edf5983ce0bb8f6d5f9c0f1ac761507) Change-Id: Ib796fafa1e4cf81351245fff6763ce17924acde9 --- tests/cts/net/src/android/net/ipv6/cts/PingTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java index 49fc59c716..e9bfb43b5e 100644 --- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -130,6 +130,7 @@ public class PingTest extends AndroidTestCase { // Check the response is an echo reply. byte[] response = new byte[bytesRead]; + responseBuffer.flip(); responseBuffer.get(response, 0, bytesRead); assertEquals((byte) 0x81, response[0]); From 83375d2bd22063f379b579be439883606ae296b8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 29 Nov 2014 18:53:49 +0900 Subject: [PATCH 0150/1415] Test TCP and ICMPv6 on VPNs in addition to UDP. Bug: 15605143 Change-Id: Ifd7a646990619057e714a789902df2c157a768c0 --- .../cts/net/hostside/MyVpnService.java | 12 +- .../cts/net/hostside/PacketReflector.java | 234 ++++++++++++++++++ .../cts/net/hostside/UdpReflector.java | 113 --------- .../com/android/cts/net/hostside/VpnTest.java | 230 +++++++++++++++-- 4 files changed, 445 insertions(+), 144 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java delete mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/UdpReflector.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java index 1a12aaa14f..a3f400c388 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java @@ -34,7 +34,7 @@ public class MyVpnService extends VpnService { private static int MTU = 1799; private ParcelFileDescriptor mFd = null; - private UdpReflector mUdpReflector = null; + private PacketReflector mPacketReflector = null; @Override public int onStartCommand(Intent intent, int flags, int startId) { @@ -127,14 +127,14 @@ public class MyVpnService extends VpnService { mFd = builder.establish(); Log.i(TAG, "Established, fd=" + (mFd == null ? "null" : mFd.getFd())); - mUdpReflector = new UdpReflector(mFd.getFileDescriptor(), MTU); - mUdpReflector.start(); + mPacketReflector = new PacketReflector(mFd.getFileDescriptor(), MTU); + mPacketReflector.start(); } private void stop() { - if (mUdpReflector != null) { - mUdpReflector.interrupt(); - mUdpReflector = null; + if (mPacketReflector != null) { + mPacketReflector.interrupt(); + mPacketReflector = null; } try { if (mFd != null) { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java new file mode 100644 index 0000000000..dd0f792b21 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; + +public class PacketReflector extends Thread { + + private static int IPV4_HEADER_LENGTH = 20; + private static int IPV6_HEADER_LENGTH = 40; + + private static int IPV4_ADDR_OFFSET = 12; + private static int IPV6_ADDR_OFFSET = 8; + private static int IPV4_ADDR_LENGTH = 4; + private static int IPV6_ADDR_LENGTH = 16; + + private static int IPV4_PROTO_OFFSET = 9; + private static int IPV6_PROTO_OFFSET = 6; + + private static final byte IPPROTO_ICMP = 1; + private static final byte IPPROTO_TCP = 6; + private static final byte IPPROTO_UDP = 17; + private static final byte IPPROTO_ICMPV6 = 58; + + private static int ICMP_HEADER_LENGTH = 8; + private static int TCP_HEADER_LENGTH = 20; + private static int UDP_HEADER_LENGTH = 8; + + private static final byte ICMP_ECHO = 8; + private static final byte ICMP_ECHOREPLY = 0; + private static final byte ICMPV6_ECHO_REQUEST = (byte) 128; + private static final byte ICMPV6_ECHO_REPLY = (byte) 129; + + private static String TAG = "PacketReflector"; + + private FileDescriptor mFd; + private byte[] mBuf; + + public PacketReflector(FileDescriptor fd, int mtu) { + super("PacketReflector"); + mFd = fd; + mBuf = new byte[mtu]; + } + + private static void swapBytes(byte[] buf, int pos1, int pos2, int len) { + for (int i = 0; i < len; i++) { + byte b = buf[pos1 + i]; + buf[pos1 + i] = buf[pos2 + i]; + buf[pos2 + i] = b; + } + } + + private static void swapAddresses(byte[] buf, int version) { + int addrPos, addrLen; + switch(version) { + case 4: + addrPos = IPV4_ADDR_OFFSET; + addrLen = IPV4_ADDR_LENGTH; + break; + case 6: + addrPos = IPV6_ADDR_OFFSET; + addrLen = IPV6_ADDR_LENGTH; + break; + default: + throw new IllegalArgumentException(); + } + swapBytes(buf, addrPos, addrPos + addrLen, addrLen); + } + + // Reflect TCP packets: swap the source and destination addresses, but don't change the ports. + // This is used by the test to "connect to itself" through the VPN. + private void processTcpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + TCP_HEADER_LENGTH) { + return; + } + + // Swap src and dst IP addresses. + swapAddresses(buf, version); + + // Send the packet back. + writePacket(buf, len); + } + + // Echo UDP packets: swap source and destination addresses, and source and destination ports. + // This is used by the test to check that the bytes it sends are echoed back. + private void processUdpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + UDP_HEADER_LENGTH) { + return; + } + + // Swap src and dst IP addresses. + swapAddresses(buf, version); + + // Swap dst and src ports. + int portOffset = hdrLen; + swapBytes(buf, portOffset, portOffset + 2, 2); + + // Send the packet back. + writePacket(buf, len); + } + + private void processIcmpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + ICMP_HEADER_LENGTH) { + return; + } + + byte type = buf[hdrLen]; + if (!(version == 4 && type == ICMP_ECHO) && + !(version == 6 && type == ICMPV6_ECHO_REQUEST)) { + return; + } + + // Save the ping packet we received. + byte[] request = buf.clone(); + + // Swap src and dst IP addresses, and send the packet back. + // This effectively pings the device to see if it replies. + swapAddresses(buf, version); + writePacket(buf, len); + + // The device should have replied, and buf should now contain a ping response. + int received = readPacket(buf); + if (received != len) { + Log.i(TAG, "Reflecting ping did not result in ping response: " + + "read=" + received + " expected=" + len); + return; + } + + // Compare the response we got with the original packet. + // The only thing that should have changed are addresses, type and checksum. + // Overwrite them with the received bytes and see if the packet is otherwise identical. + request[hdrLen] = buf[hdrLen]; // Type. + request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1. + request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2. + for (int i = 0; i < len; i++) { + if (buf[i] != request[i]) { + Log.i(TAG, "Received non-matching packet when expecting ping response."); + return; + } + } + + // Now swap the addresses again and reflect the packet. This sends a ping reply. + swapAddresses(buf, version); + writePacket(buf, len); + } + + private void writePacket(byte[] buf, int len) { + try { + Os.write(mFd, buf, 0, len); + } catch (ErrnoException|IOException e) { + Log.e(TAG, "Error writing packet: " + e.getMessage()); + } + } + + private int readPacket(byte[] buf) { + int len; + try { + len = Os.read(mFd, buf, 0, buf.length); + } catch (ErrnoException|IOException e) { + Log.e(TAG, "Error reading packet: " + e.getMessage()); + len = -1; + } + return len; + } + + // Reads one packet from our mFd, and possibly writes the packet back. + private void processPacket() { + int len = readPacket(mBuf); + if (len < 1) { + return; + } + + int version = mBuf[0] >> 4; + int addrPos, protoPos, hdrLen, addrLen; + if (version == 4) { + hdrLen = IPV4_HEADER_LENGTH; + protoPos = IPV4_PROTO_OFFSET; + addrPos = IPV4_ADDR_OFFSET; + addrLen = IPV4_ADDR_LENGTH; + } else if (version == 6) { + hdrLen = IPV6_HEADER_LENGTH; + protoPos = IPV6_PROTO_OFFSET; + addrPos = IPV6_ADDR_OFFSET; + addrLen = IPV6_ADDR_LENGTH; + } else { + return; + } + + if (len < hdrLen) { + return; + } + + byte proto = mBuf[protoPos]; + switch (proto) { + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + processIcmpPacket(mBuf, version, len, hdrLen); + break; + case IPPROTO_TCP: + processTcpPacket(mBuf, version, len, hdrLen); + break; + case IPPROTO_UDP: + processUdpPacket(mBuf, version, len, hdrLen); + break; + } + } + + public void run() { + Log.i(TAG, "PacketReflector starting fd=" + mFd + " valid=" + mFd.valid()); + while (!interrupted() && mFd.valid()) { + processPacket(); + } + Log.i(TAG, "PacketReflector exiting fd=" + mFd + " valid=" + mFd.valid()); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/UdpReflector.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/UdpReflector.java deleted file mode 100644 index a730fed08a..0000000000 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/UdpReflector.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2014 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 com.android.cts.net.hostside; - -import android.system.Os; -import android.system.ErrnoException; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; - -public class UdpReflector extends Thread { - - private static int IPV4_HEADER_LENGTH = 20; - private static int IPV6_HEADER_LENGTH = 40; - private static int UDP_HEADER_LENGTH = 8; - - private static int IPV4_PROTO_OFFSET = 9; - private static int IPV6_PROTO_OFFSET = 6; - private static int IPPROTO_UDP = 17; - - private static int IPV4_ADDR_OFFSET = 12; - private static int IPV6_ADDR_OFFSET = 8; - private static int IPV4_ADDR_LENGTH = 4; - private static int IPV6_ADDR_LENGTH = 16; - - private static String TAG = "UdpReflector"; - - private FileDescriptor mFd; - private byte[] mBuf; - - public UdpReflector(FileDescriptor fd, int mtu) { - super("UdpReflector"); - mFd = fd; - mBuf = new byte[mtu]; - } - - private static void swapBytes(byte[] buf, int pos1, int pos2, int len) { - for (int i = 0; i < len; i++) { - byte b = buf[pos1 + i]; - buf[pos1 + i] = buf[pos2 + i]; - buf[pos2 + i] = b; - } - } - - /** Reads one packet from our mFd, and possibly writes the packet back. */ - private void processPacket() { - int len; - try { - len = Os.read(mFd, mBuf, 0, mBuf.length); - } catch (ErrnoException|IOException e) { - Log.e(TAG, "Error reading packet: " + e.getMessage()); - return; - } - - int version = mBuf[0] >> 4; - int addressOffset, protoOffset, headerLength, addressLength; - if (version == 4) { - headerLength = IPV4_HEADER_LENGTH; - protoOffset = IPV4_PROTO_OFFSET; - addressOffset = IPV4_ADDR_OFFSET; - addressLength = IPV4_ADDR_LENGTH; - } else if (version == 6) { - headerLength = IPV6_HEADER_LENGTH; - protoOffset = IPV6_PROTO_OFFSET; - addressOffset = IPV6_ADDR_OFFSET; - addressLength = IPV6_ADDR_LENGTH; - } else { - return; - } - - if (len < headerLength + UDP_HEADER_LENGTH || mBuf[protoOffset] != IPPROTO_UDP) { - return; - } - - // Swap src and dst IP addresses. - swapBytes(mBuf, addressOffset, addressOffset + addressLength, addressLength); - - // Swap dst and src ports. - int portOffset = headerLength; - swapBytes(mBuf, portOffset, portOffset + 2, 2); - - // Send the packet back. We don't need to recalculate the checksum because we didn't change - // the packet bytes, we only moved them around. - try { - len = Os.write(mFd, mBuf, 0, len); - } catch (ErrnoException|IOException e) { - Log.e(TAG, "Error writing packet: " + e.getMessage()); - } - } - - public void run() { - Log.i(TAG, "UdpReflector starting fd=" + mFd + " valid=" + mFd.valid()); - while (!interrupted() && mFd.valid()) { - processPacket(); - } - Log.i(TAG, "UdpReflector exiting fd=" + mFd + " valid=" + mFd.valid()); - } -} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index cdd370ee67..8bb2a2c4c5 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -16,6 +16,8 @@ package com.android.cts.net.hostside; +import static android.system.OsConstants.*; + import android.content.Intent; import android.content.pm.PackageManager; import android.net.ConnectivityManager; @@ -25,34 +27,58 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.VpnService; -import android.os.ParcelFileDescriptor; -import android.os.SystemClock; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; import android.support.test.uiautomator.UiScrollable; import android.support.test.uiautomator.UiSelector; -import android.test.MoreAsserts; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructPollfd; import android.test.InstrumentationTestCase; +import android.test.MoreAsserts; import android.text.TextUtils; import android.util.Log; +import java.io.Closeable; +import java.io.FileDescriptor; import java.io.IOException; -import java.net.SocketTimeoutException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; -import java.net.InetAddress; import java.net.Inet6Address; -import java.util.concurrent.atomic.AtomicReference; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Random; /** - * Tests for {@link DocumentsProvider} and interaction with platform intents - * like {@link Intent#ACTION_OPEN_DOCUMENT}. + * Tests for the VpnService API. + * + * These tests establish a VPN via the VpnService API, and have the service reflect the packets back + * to the device without causing any network traffic. This allows testing the local VPN data path + * without a network connection or a VPN server. + * + * Note: in Lollipop, VPN functionality relies on kernel support for UID-based routing. If these + * tests fail, it may be due to the lack of kernel support. The necessary patches can be + * cherry-picked from the Android common kernel trees: + * + * android-3.10: + * https://android-review.googlesource.com/#/c/99220/ + * https://android-review.googlesource.com/#/c/100545/ + * + * android-3.4: + * https://android-review.googlesource.com/#/c/99225/ + * https://android-review.googlesource.com/#/c/100557/ + * */ public class VpnTest extends InstrumentationTestCase { public static String TAG = "VpnTest"; public static int TIMEOUT_MS = 3 * 1000; + public static int SOCKET_TIMEOUT_MS = 100; private UiDevice mDevice; private MyActivity mActivity; @@ -201,8 +227,156 @@ public class VpnTest extends InstrumentationTestCase { mActivity.startService(intent); } - private static void checkUdpEcho( - String to, String expectedFrom, boolean expectReply) throws IOException { + private static void closeQuietly(Closeable c) { + if (c != null) { + try { + c.close(); + } catch (IOException e) { + } + } + } + + private static void checkPing(String to) throws IOException, ErrnoException { + InetAddress address = InetAddress.getByName(to); + FileDescriptor s; + final int LENGTH = 64; + byte[] packet = new byte[LENGTH]; + byte[] header; + + // Construct a ping packet. + Random random = new Random(); + random.nextBytes(packet); + if (address instanceof Inet6Address) { + s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); + header = new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; + } else { + // Note that this doesn't actually work due to http://b/18558481 . + s = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); + header = new byte[] { (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; + } + System.arraycopy(header, 0, packet, 0, header.length); + + // Send the packet. + int port = random.nextInt(65534) + 1; + Os.connect(s, address, port); + Os.write(s, packet, 0, packet.length); + + // Expect a reply. + StructPollfd pollfd = new StructPollfd(); + pollfd.events = (short) POLLIN; // "error: possible loss of precision" + pollfd.fd = s; + int ret = Os.poll(new StructPollfd[] { pollfd }, SOCKET_TIMEOUT_MS); + assertEquals("Expected reply after sending ping", 1, ret); + + byte[] reply = new byte[LENGTH]; + int read = Os.read(s, reply, 0, LENGTH); + assertEquals(LENGTH, read); + + // Find out what the kernel set the ICMP ID to. + InetSocketAddress local = (InetSocketAddress) Os.getsockname(s); + port = local.getPort(); + packet[4] = (byte) ((port >> 8) & 0xff); + packet[5] = (byte) (port & 0xff); + + // Check the contents. + if (packet[0] == (byte) 0x80) { + packet[0] = (byte) 0x81; + } else { + packet[0] = 0; + } + // Zero out the checksum in the reply so it matches the uninitialized checksum in packet. + reply[2] = reply[3] = 0; + MoreAsserts.assertEquals(packet, reply); + } + + // Writes data to out and checks that it appears identically on in. + private static void writeAndCheckData( + OutputStream out, InputStream in, byte[] data) throws IOException { + out.write(data, 0, data.length); + out.flush(); + + byte[] read = new byte[data.length]; + int bytesRead = 0, totalRead = 0; + do { + bytesRead = in.read(read, totalRead, read.length - totalRead); + totalRead += bytesRead; + } while (bytesRead >= 0 && totalRead < data.length); + assertEquals(totalRead, data.length); + MoreAsserts.assertEquals(data, read); + } + + private static void checkTcpReflection(String to, String expectedFrom) throws IOException { + // Exercise TCP over the VPN by "connecting to ourselves". We open a server socket and a + // client socket, and connect the client socket to a remote host, with the port of the + // server socket. The PacketReflector reflects the packets, changing the source addresses + // but not the ports, so our client socket is connected to our server socket, though both + // sockets think their peers are on the "remote" IP address. + + // Open a listening socket. + ServerSocket listen = new ServerSocket(0, 10, InetAddress.getByName("::")); + + // Connect the client socket to it. + InetAddress toAddr = InetAddress.getByName(to); + Socket client = new Socket(); + try { + client.connect(new InetSocketAddress(toAddr, listen.getLocalPort()), SOCKET_TIMEOUT_MS); + if (expectedFrom == null) { + closeQuietly(listen); + closeQuietly(client); + fail("Expected connection to fail, but it succeeded."); + } + } catch (IOException e) { + if (expectedFrom != null) { + closeQuietly(listen); + fail("Expected connection to succeed, but it failed."); + } else { + // We expected the connection to fail, and it did, so there's nothing more to test. + return; + } + } + + // The connection succeeded, and we expected it to succeed. Send some data; if things are + // working, the data will be sent to the VPN, reflected by the PacketReflector, and arrive + // at our server socket. For good measure, send some data in the other direction. + Socket server = null; + try { + // Accept the connection on the server side. + listen.setSoTimeout(SOCKET_TIMEOUT_MS); + server = listen.accept(); + + // Check that the source and peer addresses are as expected. + assertEquals(expectedFrom, client.getLocalAddress().getHostAddress()); + assertEquals(expectedFrom, server.getLocalAddress().getHostAddress()); + assertEquals( + new InetSocketAddress(toAddr, client.getLocalPort()), + server.getRemoteSocketAddress()); + assertEquals( + new InetSocketAddress(toAddr, server.getLocalPort()), + client.getRemoteSocketAddress()); + + // Now write some data. + final int LENGTH = 32768; + byte[] data = new byte[LENGTH]; + new Random().nextBytes(data); + + // Make sure our writes don't block or time out, because we're single-threaded and can't + // read and write at the same time. + server.setReceiveBufferSize(LENGTH * 2); + client.setSendBufferSize(LENGTH * 2); + client.setSoTimeout(SOCKET_TIMEOUT_MS); + server.setSoTimeout(SOCKET_TIMEOUT_MS); + + // Send some data from client to server, then from server to client. + writeAndCheckData(client.getOutputStream(), server.getInputStream(), data); + writeAndCheckData(server.getOutputStream(), client.getInputStream(), data); + } finally { + closeQuietly(listen); + closeQuietly(client); + closeQuietly(server); + } + } + + private static void checkUdpEcho(String to, String expectedFrom) throws IOException { DatagramSocket s; InetAddress address = InetAddress.getByName(to); if (address instanceof Inet6Address) { // http://b/18094870 @@ -210,10 +384,12 @@ public class VpnTest extends InstrumentationTestCase { } else { s = new DatagramSocket(); } - s.setSoTimeout(100); // ms. + s.setSoTimeout(SOCKET_TIMEOUT_MS); - String msg = "Hello, world!"; - DatagramPacket p = new DatagramPacket(msg.getBytes(), msg.length()); + Random random = new Random(); + byte[] data = new byte[random.nextInt(1650)]; + random.nextBytes(data); + DatagramPacket p = new DatagramPacket(data, data.length); s.connect(address, 7); if (expectedFrom != null) { @@ -222,10 +398,10 @@ public class VpnTest extends InstrumentationTestCase { } try { - if (expectReply) { + if (expectedFrom != null) { s.send(p); s.receive(p); - MoreAsserts.assertEquals(msg.getBytes(), p.getData()); + MoreAsserts.assertEquals(data, p.getData()); } else { try { s.send(p); @@ -238,12 +414,19 @@ public class VpnTest extends InstrumentationTestCase { } } - private static void expectUdpEcho(String to, String expectedFrom) throws IOException { - checkUdpEcho(to, expectedFrom, true); + private void checkTrafficOnVpn() throws IOException, ErrnoException { + checkUdpEcho("192.0.2.251", "192.0.2.2"); + checkUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); + checkPing("2001:db8:dead:beef::f00"); + checkTcpReflection("192.0.2.252", "192.0.2.2"); + checkTcpReflection("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); } - private static void expectNoUdpEcho(String to) throws IOException { - checkUdpEcho(to, null, false); + private void checkNoTrafficOnVpn() throws IOException, ErrnoException { + checkUdpEcho("192.0.2.251", null); + checkUdpEcho("2001:db8:dead:beef::f00", null); + checkTcpReflection("192.0.2.252", null); + checkTcpReflection("2001:db8:dead:beef::f00", null); } public void testDefault() throws Exception { @@ -253,8 +436,7 @@ public class VpnTest extends InstrumentationTestCase { new String[] {"192.0.2.0/24", "2001:db8::/32"}, "", ""); - expectUdpEcho("192.0.2.251", "192.0.2.2"); - expectUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); + checkTrafficOnVpn(); } public void testAppAllowed() throws Exception { @@ -264,8 +446,7 @@ public class VpnTest extends InstrumentationTestCase { new String[] {"0.0.0.0/0", "::/0"}, mPackageName, ""); - expectUdpEcho("192.0.2.251", "192.0.2.2"); - expectUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); + checkTrafficOnVpn(); } public void testAppDisallowed() throws Exception { @@ -275,7 +456,6 @@ public class VpnTest extends InstrumentationTestCase { new String[] {"192.0.2.0/24", "2001:db8::/32"}, "", mPackageName); - expectNoUdpEcho("192.0.2.251"); - expectNoUdpEcho("2001:db8:dead:beef::f00"); + checkNoTrafficOnVpn(); } } From 51130c9726d50609d84d212dd0a54917ef2a9386 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Thu, 15 Jan 2015 15:54:04 +0000 Subject: [PATCH 0151/1415] Add HttpResponseCacheTest as a CTS test Moving HttpResponseCacheTest.java from frameworks/base/core/tests/coretests/src/android/net/http to cts/tests/tests/net/src/android/net/http/cts And making it work in the CTS runner by setting temp directory permissions and making sure the cache is initialized. Change-Id: I032014789f27a66c1a7a0aee0fa0494f6041238e --- tests/cts/net/Android.mk | 6 +- .../net/http/cts/HttpResponseCacheTest.java | 158 ++++++++++++++++++ 2 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 46d4d819ac..f6e5c90951 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -26,15 +26,15 @@ LOCAL_MULTILIB := both LOCAL_JAVA_LIBRARIES := voip-common conscrypt -LOCAL_JNI_SHARED_LIBRARIES := libnativedns_jni +LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni # include CtsTestServer as a temporary hack to free net.cts from cts.stub. LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsdeviceutil ctstestrunner \ - core-tests-support +LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support ctsdeviceutil \ + ctstestrunner ctstestserver mockwebserver # uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current diff --git a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java new file mode 100644 index 0000000000..545541d68b --- /dev/null +++ b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2011 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.http.cts; + +import com.google.mockwebserver.MockResponse; +import com.google.mockwebserver.MockWebServer; + +import junit.framework.TestCase; + +import android.cts.util.FileUtils; +import android.net.http.HttpResponseCache; + +import java.io.File; +import java.io.InputStream; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.ResponseCache; +import java.net.URI; +import java.net.URLConnection; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public final class HttpResponseCacheTest extends TestCase { + + private File cacheDir; + private MockWebServer server = new MockWebServer(); + + @Override public void setUp() throws Exception { + super.setUp(); + String tmp = System.getProperty("java.io.tmpdir"); + cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); + cacheDir.mkdirs(); + // Make the cache directory read / writable. + FileUtils.setPermissions(cacheDir.getPath(), 0777); + } + + @Override protected void tearDown() throws Exception { + ResponseCache.setDefault(null); + server.shutdown(); + super.tearDown(); + } + + public void testInstall() throws Exception { + HttpResponseCache installed = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + assertNotNull(installed); + assertSame(installed, ResponseCache.getDefault()); + assertSame(installed, HttpResponseCache.getDefault()); + } + + public void testSecondEquivalentInstallDoesNothing() throws Exception { + HttpResponseCache first = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + HttpResponseCache another = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + assertSame(first, another); + } + + public void testInstallClosesPreviouslyInstalled() throws Exception { + HttpResponseCache first = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + initializeCache(first); + + HttpResponseCache another = HttpResponseCache.install(cacheDir, 8 * 1024 * 1024); + initializeCache(first); + + assertNotSame(first, another); + try { + first.flush(); + fail(); + } catch (IllegalStateException expected) { + } + } + + public void testGetInstalledWithWrongTypeInstalled() { + ResponseCache.setDefault(new ResponseCache() { + @Override public CacheResponse get(URI uri, String requestMethod, + Map> requestHeaders) { + return null; + } + @Override public CacheRequest put(URI uri, URLConnection connection) { + return null; + } + }); + assertNull(HttpResponseCache.getInstalled()); + } + + public void testCloseCloses() throws Exception { + HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + initializeCache(cache); + + cache.close(); + try { + cache.flush(); + fail(); + } catch (IllegalStateException expected) { + } + } + + public void testCloseUninstalls() throws Exception { + HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + cache.close(); + assertNull(ResponseCache.getDefault()); + } + + public void testDeleteUninstalls() throws Exception { + HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + cache.delete(); + assertNull(ResponseCache.getDefault()); + } + + /** + * Make sure that statistics tracking are wired all the way through the + * wrapper class. http://code.google.com/p/android/issues/detail?id=25418 + */ + public void testStatisticsTracking() throws Exception { + HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + + server.enqueue(new MockResponse() + .addHeader("Cache-Control: max-age=60") + .setBody("A")); + server.play(); + + URLConnection c1 = server.getUrl("/").openConnection(); + InputStream inputStream1 = c1.getInputStream(); + assertEquals('A', inputStream1.read()); + inputStream1.close(); + + assertEquals(1, cache.getRequestCount()); + assertEquals(1, cache.getNetworkCount()); + assertEquals(0, cache.getHitCount()); + + URLConnection c2 = server.getUrl("/").openConnection(); + assertEquals('A', c2.getInputStream().read()); + + URLConnection c3 = server.getUrl("/").openConnection(); + assertEquals('A', c3.getInputStream().read()); + assertEquals(3, cache.getRequestCount()); + assertEquals(1, cache.getNetworkCount()); + assertEquals(2, cache.getHitCount()); + } + + private void initializeCache(HttpResponseCache cache) { + // Ensure the cache is initialized, otherwise various methods are no-ops. + cache.size(); + } +} From 970cbe09b59d9d8f2cd3207b432f2eb07741d454 Mon Sep 17 00:00:00 2001 From: Filip Matusiak Date: Thu, 15 Jan 2015 17:48:07 +0100 Subject: [PATCH 0152/1415] Accept more than one SD in NsdManagerTest In current implementation it's been assumed that there will be only one interface registered for service discovery in mdnsresponder. In reality there's possibility that some real but currently unused interfaces will have link-local address assigned prior to registration, which will cause mdnsresponder to register these interfaces for service discovery. This will result in SERVICE_LOST and SERVICE_FOUND events to be received more than one time. Current test implementation is not 100% prone for this situation - depending upon time gap between both events it can PASS or FAIL. Fix by removing an assert on number of received events. Change-Id: I147dc4d600f41f6d63d2b9e4bcb10efe90d5b3ec --- tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java index d1e4c447c3..95e0495746 100644 --- a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java @@ -372,8 +372,6 @@ public class NsdManagerTest extends AndroidTestCase { assertTrue(lastEvent != null); assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); - assertTrue(eventCacheSize() == 2); - // Register service again to see if we discover it checkForAdditionalEvents(); clearEventCache(); @@ -405,7 +403,6 @@ public class NsdManagerTest extends AndroidTestCase { lastEvent.mInfo.getServiceName()); assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); - assertTrue(checkCacheSize(2)); checkForAdditionalEvents(); clearEventCache(); From 013161a64ab996e0b7cc18251e6af19de8cedbbf Mon Sep 17 00:00:00 2001 From: Takayuki Hoshi Date: Tue, 20 Jan 2015 14:40:11 +0900 Subject: [PATCH 0153/1415] Normalize ipv6.cts.PingTest#testLoopbackPing's packet size Bug: 19063377 Change-Id: I8c7b2253cfa5c81afbc6c4de05f2965f4184b683 --- tests/cts/net/src/android/net/ipv6/cts/PingTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java index 49fc59c716..582b81ae6a 100644 --- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -53,6 +53,9 @@ public class PingTest extends AndroidTestCase { /** Maximum size of the packets we're using to test. */ private static final int MAX_SIZE = 4096; + /** Size of the ICMPv6 header. */ + private static final int ICMP_HEADER_SIZE = 8; + /** Number of packets to test. */ private static final int NUM_PACKETS = 10; @@ -65,7 +68,7 @@ public class PingTest extends AndroidTestCase { * Returns a byte array containing an ICMPv6 echo request with the specified payload length. */ private byte[] pingPacket(int payloadLength) { - byte[] packet = new byte[payloadLength + 8]; + byte[] packet = new byte[payloadLength + ICMP_HEADER_SIZE]; new Random().nextBytes(packet); System.arraycopy(PING_HEADER, 0, packet, 0, PING_HEADER.length); return packet; @@ -154,7 +157,7 @@ public class PingTest extends AndroidTestCase { assertEquals("localhost/::1", ipv6Loopback.toString()); for (int i = 0; i < NUM_PACKETS; i++) { - byte[] packet = pingPacket((int) (Math.random() * MAX_SIZE)); + byte[] packet = pingPacket((int) (Math.random() * (MAX_SIZE - ICMP_HEADER_SIZE))); FileDescriptor s = createPingSocket(); // Use both recvfrom and read(). sendPing(s, ipv6Loopback, packet); From 17e2c23ad30c5ec6f911bf53939f2a6e66776bf8 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 29 Jan 2015 23:02:17 -0800 Subject: [PATCH 0154/1415] Add missing include. Change-Id: I2a52d050a39e2c6dd38af868ea444278d9b6d54d --- tests/cts/net/jni/NativeDnsJni.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index b975594b26..4eb3c7aebc 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -18,6 +18,7 @@ #include #include #include +#include #include const char *GoogleDNSIpV4Address="8.8.8.8"; From 505728b35af4617c647fec742b8eaeadd4009894 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Fri, 12 Dec 2014 10:55:51 +0000 Subject: [PATCH 0155/1415] Add explicit dependencies on org.apache.http.legacy Test modules that depend on the CTS testserver must declare explicit dependencies on org.apache.http.legacy. Also fix some bizarre build rules; ctstestserver builds directly against the framework but compiled into apps that target SDK 16. bug: 18027885 Change-Id: I905942d8ed71812499df94e3e5970c0b08716528 --- tests/cts/net/Android.mk | 2 +- tests/cts/net/AndroidManifest.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index f6e5c90951..a35e145e5f 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -24,7 +24,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) # Include both the 32 and 64 bit versions LOCAL_MULTILIB := both -LOCAL_JAVA_LIBRARIES := voip-common conscrypt +LOCAL_JAVA_LIBRARIES := voip-common conscrypt org.apache.http.legacy LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 652262d491..bca2d2c1ba 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -30,6 +30,7 @@ + Date: Wed, 4 Feb 2015 10:37:07 -0800 Subject: [PATCH 0156/1415] Split the build of the CTS infrastructure from the tests. This allows developers to build the test packages individually without needing to build the entire CTS release. Add new build target for support packages bug: 18945639 Change-Id: I60b79797b2d254b96aa98f88cfd5b19d195ea982 --- tests/cts/hostside/app/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index 29b620d2c3..055287a733 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -29,4 +29,4 @@ LOCAL_PACKAGE_NAME := CtsHostsideNetworkTestsApp LOCAL_PROGUARD_ENABLED := disabled LOCAL_DEX_PREOPT := false -include $(BUILD_PACKAGE) +include $(BUILD_CTS_SUPPORT_PACKAGE) From cbdec383f28a9b11795b0fceab58c72cfac769ff Mon Sep 17 00:00:00 2001 From: Qiwen Zhao Date: Mon, 30 Mar 2015 10:51:01 -0700 Subject: [PATCH 0157/1415] DO NOT MERGE ANYWHERE. Revert "DO NOT MERGE ANYWHERE." This reverts commit b7c798f9b84c7c100aa37e6aa77e7f31460c7bd7, reversing changes made to 4e8ecc32db5d3a17ccec099681425c34b630d23b. --- tests/cts/net/Android.mk | 6 +- tests/cts/net/jni/NativeDnsJni.c | 1 - .../src/android/net/cts/LocalSocketTest.java | 4 +- .../cts/SSLCertificateSocketFactoryTest.java | 4 +- .../net/http/cts/HttpResponseCacheTest.java | 158 ------------------ .../android/net/wifi/cts/NsdManagerTest.java | 3 + 6 files changed, 10 insertions(+), 166 deletions(-) delete mode 100644 tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index f6e5c90951..46d4d819ac 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -26,15 +26,15 @@ LOCAL_MULTILIB := both LOCAL_JAVA_LIBRARIES := voip-common conscrypt -LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni +LOCAL_JNI_SHARED_LIBRARIES := libnativedns_jni # include CtsTestServer as a temporary hack to free net.cts from cts.stub. LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support ctsdeviceutil \ - ctstestrunner ctstestserver mockwebserver +LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsdeviceutil ctstestrunner \ + core-tests-support # uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 4eb3c7aebc..b975594b26 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -18,7 +18,6 @@ #include #include #include -#include #include const char *GoogleDNSIpV4Address="8.8.8.8"; diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 865ec21da3..0a4bc0d4f2 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -126,8 +126,8 @@ public class LocalSocketTest extends AndroidTestCase{ socket.setReceiveBufferSize(1999); assertEquals(1999 << 1, socket.getReceiveBufferSize()); - socket.setSendBufferSize(3998); - assertEquals(3998 << 1, socket.getSendBufferSize()); + socket.setSendBufferSize(1998); + assertEquals(1998 << 1, socket.getSendBufferSize()); // Timeout is not support at present, so set is ignored socket.setSoTimeout(1996); diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 60ac226440..6175923e46 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -26,7 +26,7 @@ import javax.net.ssl.SSLPeerUnverifiedException; import android.net.SSLCertificateSocketFactory; import android.test.AndroidTestCase; -import libcore.javax.net.ssl.SSLConfigurationAsserts; +import libcore.javax.net.ssl.SSLDefaultConfigurationAsserts; public class SSLCertificateSocketFactoryTest extends AndroidTestCase { private SSLCertificateSocketFactory mFactory; @@ -40,7 +40,7 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { } public void testDefaultConfiguration() throws Exception { - SSLConfigurationAsserts.assertSSLSocketFactoryDefaultConfiguration(mFactory); + SSLDefaultConfigurationAsserts.assertSSLSocketFactory(mFactory); } public void testAccessProperties() throws Exception { diff --git a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java deleted file mode 100644 index 545541d68b..0000000000 --- a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2011 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.http.cts; - -import com.google.mockwebserver.MockResponse; -import com.google.mockwebserver.MockWebServer; - -import junit.framework.TestCase; - -import android.cts.util.FileUtils; -import android.net.http.HttpResponseCache; - -import java.io.File; -import java.io.InputStream; -import java.net.CacheRequest; -import java.net.CacheResponse; -import java.net.ResponseCache; -import java.net.URI; -import java.net.URLConnection; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -public final class HttpResponseCacheTest extends TestCase { - - private File cacheDir; - private MockWebServer server = new MockWebServer(); - - @Override public void setUp() throws Exception { - super.setUp(); - String tmp = System.getProperty("java.io.tmpdir"); - cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); - cacheDir.mkdirs(); - // Make the cache directory read / writable. - FileUtils.setPermissions(cacheDir.getPath(), 0777); - } - - @Override protected void tearDown() throws Exception { - ResponseCache.setDefault(null); - server.shutdown(); - super.tearDown(); - } - - public void testInstall() throws Exception { - HttpResponseCache installed = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); - assertNotNull(installed); - assertSame(installed, ResponseCache.getDefault()); - assertSame(installed, HttpResponseCache.getDefault()); - } - - public void testSecondEquivalentInstallDoesNothing() throws Exception { - HttpResponseCache first = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); - HttpResponseCache another = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); - assertSame(first, another); - } - - public void testInstallClosesPreviouslyInstalled() throws Exception { - HttpResponseCache first = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); - initializeCache(first); - - HttpResponseCache another = HttpResponseCache.install(cacheDir, 8 * 1024 * 1024); - initializeCache(first); - - assertNotSame(first, another); - try { - first.flush(); - fail(); - } catch (IllegalStateException expected) { - } - } - - public void testGetInstalledWithWrongTypeInstalled() { - ResponseCache.setDefault(new ResponseCache() { - @Override public CacheResponse get(URI uri, String requestMethod, - Map> requestHeaders) { - return null; - } - @Override public CacheRequest put(URI uri, URLConnection connection) { - return null; - } - }); - assertNull(HttpResponseCache.getInstalled()); - } - - public void testCloseCloses() throws Exception { - HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); - initializeCache(cache); - - cache.close(); - try { - cache.flush(); - fail(); - } catch (IllegalStateException expected) { - } - } - - public void testCloseUninstalls() throws Exception { - HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); - cache.close(); - assertNull(ResponseCache.getDefault()); - } - - public void testDeleteUninstalls() throws Exception { - HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); - cache.delete(); - assertNull(ResponseCache.getDefault()); - } - - /** - * Make sure that statistics tracking are wired all the way through the - * wrapper class. http://code.google.com/p/android/issues/detail?id=25418 - */ - public void testStatisticsTracking() throws Exception { - HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); - - server.enqueue(new MockResponse() - .addHeader("Cache-Control: max-age=60") - .setBody("A")); - server.play(); - - URLConnection c1 = server.getUrl("/").openConnection(); - InputStream inputStream1 = c1.getInputStream(); - assertEquals('A', inputStream1.read()); - inputStream1.close(); - - assertEquals(1, cache.getRequestCount()); - assertEquals(1, cache.getNetworkCount()); - assertEquals(0, cache.getHitCount()); - - URLConnection c2 = server.getUrl("/").openConnection(); - assertEquals('A', c2.getInputStream().read()); - - URLConnection c3 = server.getUrl("/").openConnection(); - assertEquals('A', c3.getInputStream().read()); - assertEquals(3, cache.getRequestCount()); - assertEquals(1, cache.getNetworkCount()); - assertEquals(2, cache.getHitCount()); - } - - private void initializeCache(HttpResponseCache cache) { - // Ensure the cache is initialized, otherwise various methods are no-ops. - cache.size(); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java index e132cce25f..d43472805b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java @@ -372,6 +372,8 @@ public class NsdManagerTest extends AndroidTestCase { assertTrue(lastEvent != null); assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); + assertTrue(eventCacheSize() == 2); + // Register service again to see if we discover it checkForAdditionalEvents(); clearEventCache(); @@ -403,6 +405,7 @@ public class NsdManagerTest extends AndroidTestCase { lastEvent.mInfo.getServiceName()); assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); + assertTrue(checkCacheSize(2)); checkForAdditionalEvents(); clearEventCache(); From b1f33d49d0cb0601ff633a5237b3ac4e23355e67 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 18 May 2015 11:56:32 +0900 Subject: [PATCH 0158/1415] Unbreak PingTest. The test is failing because it expects ::1" to resolve to "localhost", but it now resolves to "ip6-localhost". Bug: 18791191 Bug: 19953381 Change-Id: I62279b6219c32e817253c686bf408f0a2fc1fa6b --- tests/cts/net/src/android/net/ipv6/cts/PingTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java index eddb416972..c23ad30f05 100644 --- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -155,7 +155,7 @@ public class PingTest extends AndroidTestCase { public void testLoopbackPing() throws ErrnoException, IOException { // Generate a random ping packet and send it to localhost. InetAddress ipv6Loopback = InetAddress.getByName(null); - assertEquals("localhost/::1", ipv6Loopback.toString()); + assertEquals("::1", ipv6Loopback.getHostAddress()); for (int i = 0; i < NUM_PACKETS; i++) { byte[] packet = pingPacket((int) (Math.random() * (MAX_SIZE - ICMP_HEADER_SIZE))); From 9288414c301d559df739a635453b2ef9db740d22 Mon Sep 17 00:00:00 2001 From: Constantin Musca Date: Fri, 23 May 2014 14:20:29 +0300 Subject: [PATCH 0159/1415] LocalSocketTest.testAccessors: fix the *SendBufferSize* test If one sets a *SendBufferSize* value which is less than (2048 + SKB_DATA_ALIGN(sizeof(struct sk_buff))) then the value retrieved will be (2 * (2048 + SKB_DATA_ALIGN(sizeof(struct sk_buff)))). Otherwise, the value will be doubled. Modify the test to consider both cases. Change-Id: I2d89393b1ad441783c8a082b072a806b8901830c Signed-off-by: Constantin Musca --- .../cts/net/src/android/net/cts/LocalSocketTest.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 0a4bc0d4f2..70d69c8aa3 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -112,6 +112,7 @@ public class LocalSocketTest extends AndroidTestCase{ } public void testAccessors() throws IOException{ + final int INITIAL_SEND_BUFFER_SIZE = 1998; LocalSocket socket = new LocalSocket(); LocalSocketAddress addr = new LocalSocketAddress("secondary"); @@ -126,8 +127,14 @@ public class LocalSocketTest extends AndroidTestCase{ socket.setReceiveBufferSize(1999); assertEquals(1999 << 1, socket.getReceiveBufferSize()); - socket.setSendBufferSize(1998); - assertEquals(1998 << 1, socket.getSendBufferSize()); + socket.setSendBufferSize(INITIAL_SEND_BUFFER_SIZE); + int sendBufferSize = socket.getSendBufferSize(); + if ((INITIAL_SEND_BUFFER_SIZE << 1) < sendBufferSize) { + socket.setSendBufferSize(sendBufferSize / 2); + assertEquals(sendBufferSize, socket.getSendBufferSize()); + } else { + assertEquals(INITIAL_SEND_BUFFER_SIZE << 1, sendBufferSize); + } // Timeout is not support at present, so set is ignored socket.setSoTimeout(1996); From 5aae92d233392c8a710f2a3a39baead3c7b909b8 Mon Sep 17 00:00:00 2001 From: Filip Matusiak Date: Thu, 15 Jan 2015 17:48:07 +0100 Subject: [PATCH 0160/1415] Accept more than one SD in NsdManagerTest In current implementation it's been assumed that there will be only one interface registered for service discovery in mdnsresponder. In reality there's possibility that some real but currently unused interfaces will have link-local address assigned prior to registration, which will cause mdnsresponder to register these interfaces for service discovery. This will result in SERVICE_LOST and SERVICE_FOUND events to be received more than one time. Current test implementation is not 100% prone for this situation - depending upon time gap between both events it can PASS or FAIL. Fix by removing an assert on number of received events. Change-Id: I147dc4d600f41f6d63d2b9e4bcb10efe90d5b3ec (cherry picked from commit 970cbe09b59d9d8f2cd3207b432f2eb07741d454) --- tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java index d43472805b..e132cce25f 100644 --- a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java @@ -372,8 +372,6 @@ public class NsdManagerTest extends AndroidTestCase { assertTrue(lastEvent != null); assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); - assertTrue(eventCacheSize() == 2); - // Register service again to see if we discover it checkForAdditionalEvents(); clearEventCache(); @@ -405,7 +403,6 @@ public class NsdManagerTest extends AndroidTestCase { lastEvent.mInfo.getServiceName()); assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); - assertTrue(checkCacheSize(2)); checkForAdditionalEvents(); clearEventCache(); From fe5e165d399946ac7da71767abffa1b7e7456698 Mon Sep 17 00:00:00 2001 From: Junjie Hu Date: Thu, 23 Apr 2015 19:33:01 +0800 Subject: [PATCH 0161/1415] Fix testVpn timing issue for com.android.cts.net.HostsideNetworkTests class It is a issue caused by bad test case. Please ensure the previous vpn connection is disconnected before running next vpn test case, this will affect the test result.And the CTS test case also tries to connect socket before the vpn rule is set in netd. It is the same issue as http://b/18436087 . The delay 300ms is too short, and recommend extend to 1000 or 3000 ms. Since L MR1 is known as supporting some low memory device, we suggest fixing the new CTS test case for some low-end devices. Change-Id: I6051c95c663e867fc66c580ce8bd8d25fce0b8fc Signed-off-by: Junjie Hu --- .../com/android/cts/net/hostside/VpnTest.java | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) mode change 100644 => 100755 tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java old mode 100644 new mode 100755 index 8bb2a2c4c5..5045cc26b4 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -87,6 +87,7 @@ public class VpnTest extends InstrumentationTestCase { Network mNetwork; NetworkCallback mCallback; final Object mLock = new Object(); + final Object mLockShutdown = new Object(); private boolean supportedHardware() { final PackageManager pm = getInstrumentation().getContext().getPackageManager(); @@ -204,7 +205,9 @@ public class VpnTest extends InstrumentationTestCase { mActivity.startService(intent); synchronized (mLock) { if (mNetwork == null) { + Log.i(TAG, "bf mLock"); mLock.wait(TIMEOUT_MS); + Log.i(TAG, "af mLock"); } } @@ -214,10 +217,27 @@ public class VpnTest extends InstrumentationTestCase { // Unfortunately, when the available callback fires, the VPN UID ranges are not yet // configured. Give the system some time to do so. http://b/18436087 . - try { Thread.sleep(300); } catch(InterruptedException e) {} + try { Thread.sleep(3000); } catch(InterruptedException e) {} } private void stopVpn() { + // Register a callback so we will be notified when our VPN comes up. + final NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + mCallback = new NetworkCallback() { + public void onLost(Network network) { + synchronized (mLockShutdown) { + Log.i(TAG, "Got lost callback for network=" + network + ",mNetwork = " + mNetwork); + if( mNetwork == network){ + mLockShutdown.notify(); + } + } + } + }; + mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown. // Simply calling mActivity.stopService() won't stop the service, because the system binds // to the service for the purpose of sending it a revoke command if another VPN comes up, // and stopping a bound service has no effect. Instead, "start" the service again with an @@ -225,6 +245,13 @@ public class VpnTest extends InstrumentationTestCase { Intent intent = new Intent(mActivity, MyVpnService.class) .putExtra(mPackageName + ".cmd", "disconnect"); mActivity.startService(intent); + synchronized (mLockShutdown) { + try { + Log.i(TAG, "bf mLockShutdown"); + mLockShutdown.wait(TIMEOUT_MS); + Log.i(TAG, "af mLockShutdown"); + } catch(InterruptedException e) {} + } } private static void closeQuietly(Closeable c) { @@ -433,7 +460,7 @@ public class VpnTest extends InstrumentationTestCase { if (!supportedHardware()) return; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, - new String[] {"192.0.2.0/24", "2001:db8::/32"}, + new String[] {"0.0.0.0/0", "::/0"}, "", ""); checkTrafficOnVpn(); @@ -443,7 +470,7 @@ public class VpnTest extends InstrumentationTestCase { if (!supportedHardware()) return; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, - new String[] {"0.0.0.0/0", "::/0"}, + new String[] {"192.0.2.0/24", "2001:db8::/32"}, mPackageName, ""); checkTrafficOnVpn(); From b38eedcb8f7f3e88563639f693ea35b4c90b7f86 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Thu, 18 Jun 2015 13:57:17 +0100 Subject: [PATCH 0162/1415] Remove cell / wifi manipulation from ApacheHttpClientTest The testcase was manipulating the Wifi / Cell networks, presumably in an effort to make data pass over each type of network. The test was sending / receiving data using the loopback interface so it doesn't make much sense. testExecute_withMobile would fail if the device did not have a SIM / mobile data connection *and* if the wifi network was up when the test ran; it would fail waiting for the mobile data network to enter the CONNECTED state. If the wifi connection was down at the start it would assume the mobile data connection was up already and proceed with the test (which passed, because it didn't actually use the network). This change chops out parts of this test to leave just HttpClient-related code. Bug: 21874093 Change-Id: I8248b840f58f939661eff2345f70a9e786e593f3 --- .../net/http/cts/ApacheHttpClientTest.java | 121 +----------------- 1 file changed, 2 insertions(+), 119 deletions(-) diff --git a/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java b/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java index 7d9189ff33..2e5306df89 100644 --- a/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java +++ b/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java @@ -21,56 +21,27 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.NetworkInfo.State; import android.net.Uri; -import android.net.wifi.WifiManager; import android.test.AndroidTestCase; -import android.util.Log; import android.webkit.cts.CtsTestServer; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; public class ApacheHttpClientTest extends AndroidTestCase { - private static final String TAG = ApacheHttpClientTest.class.getSimpleName(); - private static final int NUM_DOWNLOADS = 20; private static final int SMALL_DOWNLOAD_SIZE = 100 * 1024; private CtsTestServer mWebServer; - private WifiManager mWifiManager; - - private ConnectivityManager mConnectivityManager; - - private boolean mHasTelephony; - - private boolean mHasWifi; - @Override protected void setUp() throws Exception { super.setUp(); mWebServer = new CtsTestServer(mContext); - mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - mConnectivityManager = (ConnectivityManager) - mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - - PackageManager packageManager = mContext.getPackageManager(); - mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); - mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI); } @Override @@ -79,25 +50,8 @@ public class ApacheHttpClientTest extends AndroidTestCase { mWebServer.shutdown(); } - public void testExecute_withMobile() throws Exception { - if (mHasTelephony) { - disconnectWifiToConnectToMobile(); - } - + public void testExecute() throws Exception { downloadMultipleFiles(); - - if (mHasWifi) { - connectToWifi(); - } - } - - public void testExecute_withWifi() throws Exception { - if (mHasWifi) { - if (!mWifiManager.isWifiEnabled()) { - connectToWifi(); - } - downloadMultipleFiles(); - } } private void downloadMultipleFiles() throws ClientProtocolException, IOException { @@ -134,77 +88,6 @@ public class ApacheHttpClientTest extends AndroidTestCase { numBytes += bytesRead; } } - assertEquals(message, SMALL_DOWNLOAD_SIZE, numBytes); - } - - private void connectToWifi() throws InterruptedException { - if (!mWifiManager.isWifiEnabled()) { - ConnectivityActionReceiver receiver = - new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI, State.CONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - assertTrue(mWifiManager.setWifiEnabled(true)); - assertTrue("Wifi must be configured to connect to an access point for this test.", - receiver.waitForStateChange()); - - mContext.unregisterReceiver(receiver); - } - } - - private void disconnectWifiToConnectToMobile() throws InterruptedException { - if (mHasWifi && mWifiManager.isWifiEnabled()) { - ConnectivityActionReceiver connectMobileReceiver = - new ConnectivityActionReceiver(ConnectivityManager.TYPE_MOBILE, - State.CONNECTED); - ConnectivityActionReceiver disconnectWifiReceiver = - new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI, - State.DISCONNECTED); - IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(connectMobileReceiver, filter); - mContext.registerReceiver(disconnectWifiReceiver, filter); - - assertTrue(mWifiManager.setWifiEnabled(false)); - assertTrue(disconnectWifiReceiver.waitForStateChange()); - assertTrue(connectMobileReceiver.waitForStateChange()); - - mContext.unregisterReceiver(connectMobileReceiver); - mContext.unregisterReceiver(disconnectWifiReceiver); - } - } - - /** Receiver that captures the last connectivity change's network type and state. */ - private class ConnectivityActionReceiver extends BroadcastReceiver { - - private final CountDownLatch mReceiveLatch = new CountDownLatch(1); - - private final int mNetworkType; - - private final State mExpectedState; - - ConnectivityActionReceiver(int networkType, State expectedState) { - mNetworkType = networkType; - mExpectedState = expectedState; - } - - public void onReceive(Context context, Intent intent) { - NetworkInfo networkInfo = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); - int networkType = networkInfo.getType(); - State networkState = networkInfo.getState(); - Log.i(TAG, "Network type: " + networkType + " State: " + networkInfo.getState()); - if (networkType == mNetworkType && networkInfo.getState() == mExpectedState) { - mReceiveLatch.countDown(); - } - } - - public boolean waitForStateChange() throws InterruptedException { - return mReceiveLatch.await(30, TimeUnit.SECONDS) || hasExpectedState(); - } - - private boolean hasExpectedState() { - return mExpectedState == mConnectivityManager.getNetworkInfo(mNetworkType).getState(); - } + assertEquals(message, expectedNumBytes, numBytes); } } From 1c542daddb748c0f8f913b599a394f3494e774e0 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Thu, 14 May 2015 17:20:39 +0900 Subject: [PATCH 0163/1415] multinetwork native API CTS test Bug: 19537384 Bug: 21833352 Change-Id: I03df80beca241fe3c952aae65de0cd081751de07 --- tests/cts/net/Android.mk | 3 +- tests/cts/net/jni/Android.mk | 9 + tests/cts/net/jni/NativeMultinetworkJni.c | 216 ++++++++++++++++++ .../android/net/cts/MultinetworkApiTest.java | 155 +++++++++++++ ...kTest.java => MultinetworkSysctlTest.java} | 4 +- 5 files changed, 384 insertions(+), 3 deletions(-) create mode 100644 tests/cts/net/jni/NativeMultinetworkJni.c create mode 100644 tests/cts/net/src/android/net/cts/MultinetworkApiTest.java rename tests/cts/net/src/android/net/cts/{MultinetworkTest.java => MultinetworkSysctlTest.java} (97%) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index a35e145e5f..652487126d 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -26,7 +26,8 @@ LOCAL_MULTILIB := both LOCAL_JAVA_LIBRARIES := voip-common conscrypt org.apache.http.legacy -LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni +LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni \ + libnativemultinetwork_jni # include CtsTestServer as a temporary hack to free net.cts from cts.stub. LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/tests/cts/net/jni/Android.mk b/tests/cts/net/jni/Android.mk index 75982de3ed..ca82b30b13 100644 --- a/tests/cts/net/jni/Android.mk +++ b/tests/cts/net/jni/Android.mk @@ -28,3 +28,12 @@ LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := libnativehelper liblog include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := libnativemultinetwork_jni +# Don't include this package in any configuration by default. +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := NativeMultinetworkJni.c +LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) +LOCAL_SHARED_LIBRARIES := libandroid libnativehelper liblog +include $(BUILD_SHARED_LIBRARY) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c new file mode 100644 index 0000000000..9a5ab9c422 --- /dev/null +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2010 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. + */ + + +#define LOG_TAG "MultinetworkApiTest" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNUSED(X) ((void) X) + +static const char kHostname[] = "connectivitycheck.android.com"; + + +JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runGetaddrinfoCheck( + JNIEnv* env, jclass class, jlong nethandle) { + UNUSED(env); + UNUSED(class); + net_handle_t handle = (net_handle_t) nethandle; + struct addrinfo *res = NULL; + + errno = 0; + int rval = android_getaddrinfofornetwork(handle, kHostname, NULL, NULL, &res); + const int saved_errno = errno; + freeaddrinfo(res); + + ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", + handle, kHostname, rval, saved_errno); + return rval == 0 ? 0 : -saved_errno; +} + +JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetprocnetwork( + JNIEnv* env, jclass class, jlong nethandle) { + UNUSED(env); + UNUSED(class); + net_handle_t handle = (net_handle_t) nethandle; + + errno = 0; + int rval = android_setprocnetwork(handle); + const int saved_errno = errno; + ALOGD("android_setprocnetwork(%llu) returned rval=%d errno=%d", + handle, rval, saved_errno); + return rval == 0 ? 0 : -saved_errno; +} + +JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetsocknetwork( + JNIEnv* env, jclass class, jlong nethandle) { + UNUSED(env); + UNUSED(class); + net_handle_t handle = (net_handle_t) nethandle; + + errno = 0; + int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + ALOGD("socket() failed, errno=%d", errno); + return -errno; + } + + errno = 0; + int rval = android_setsocknetwork(handle, fd); + const int saved_errno = errno; + ALOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", + handle, fd, rval, saved_errno); + close(fd); + return rval == 0 ? 0 : -saved_errno; +} + +static const int kSockaddrStrLen = INET6_ADDRSTRLEN + strlen("[]:65535"); + +void sockaddr_ntop(const struct sockaddr *sa, socklen_t salen, char *dst, const size_t size) { + char addrstr[INET6_ADDRSTRLEN]; + char portstr[sizeof("65535")]; + char buf[sizeof(addrstr) + sizeof(portstr) + sizeof("[]:")]; + int ret = getnameinfo(sa, salen, + addrstr, sizeof(addrstr), + portstr, sizeof(portstr), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret == 0) { + snprintf(buf, sizeof(buf), + (sa->sa_family == AF_INET6) ? "[%s]:%s" : "%s:%s", + addrstr, portstr); + } else { + sprintf(buf, "???"); + } + + strlcpy(dst, buf, (strlen(buf) < size - 1) ? strlen(buf) : size - 1); +} + +JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( + JNIEnv* env, jclass class, jlong nethandle) { + UNUSED(env); + UNUSED(class); + const struct addrinfo kHints = { + .ai_flags = AI_ADDRCONFIG, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + .ai_protocol = IPPROTO_UDP, + }; + struct addrinfo *res = NULL; + net_handle_t handle = (net_handle_t) nethandle; + + // Quoth Ian Swett: + // "QUIC always uses 80 and 443, but only 443 is used for secure(HTTPS) traffic." + int rval = android_getaddrinfofornetwork(handle, kHostname, "80", &kHints, &res); + if (rval != 0) { + ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", + handle, kHostname, rval, errno); + freeaddrinfo(res); + return -errno; + } + + // Rely upon getaddrinfo sorting the best destination to the front. + int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (fd < 0) { + ALOGD("socket(%d, %d, %d) failed, errno=%d", + res->ai_family, res->ai_socktype, res->ai_protocol, errno); + freeaddrinfo(res); + return -errno; + } + + rval = android_setsocknetwork(handle, fd); + ALOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", + handle, fd, rval, errno); + if (rval != 0) { + close(fd); + freeaddrinfo(res); + return -errno; + } + + char addrstr[kSockaddrStrLen]; + sockaddr_ntop(res->ai_addr, res->ai_addrlen, addrstr, sizeof(addrstr)); + ALOGD("Attempting connect() to %s...", addrstr); + + rval = connect(fd, res->ai_addr, res->ai_addrlen); + if (rval != 0) { + close(fd); + freeaddrinfo(res); + return -errno; + } + freeaddrinfo(res); + + struct sockaddr_storage src_addr; + socklen_t src_addrlen = sizeof(src_addr); + if (getsockname(fd, (struct sockaddr *)&src_addr, &src_addrlen) != 0) { + close(fd); + return -errno; + } + sockaddr_ntop((const struct sockaddr *)&src_addr, sizeof(src_addr), addrstr, sizeof(addrstr)); + ALOGD("... from %s", addrstr); + + // Don't let reads or writes block indefinitely. + const struct timeval timeo = { 5, 0 }; // 5 seconds + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); + + uint8_t quic_packet[] = { + 0x0c, // public flags: 64bit conn ID, 8bit sequence number + 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID + 0x01, // sequence number + 0x00, // private flags + 0x07, // type: regular frame type "PING" + }; + + arc4random_buf(quic_packet + 1, 8); // random connection ID + + ssize_t sent = send(fd, quic_packet, sizeof(quic_packet), 0); + if (sent < (ssize_t)sizeof(quic_packet)) { + ALOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errno); + close(fd); + return -errno; + } + + uint8_t response[1500]; + ssize_t rcvd = recv(fd, response, sizeof(response), 0); + if (rcvd < sent) { + ALOGD("recv() returned rcvd=%zd, errno=%d", rcvd, errno); + close(fd); + return -errno; + } + + int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); + if (conn_id_cmp != 0) { + ALOGD("sent and received connection IDs do not match"); + close(fd); + return -EPROTO; + } + + // TODO: log, and compare to the IP address encoded in the + // response, since this should be a public reset packet. + + close(fd); + return 0; +} diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java new file mode 100644 index 0000000000..51ee50ed2a --- /dev/null +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -0,0 +1,155 @@ +/* + * 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.net.cts; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkUtils; +import android.system.ErrnoException; +import android.system.OsConstants; +import android.test.AndroidTestCase; + +import java.util.ArrayList; + + +public class MultinetworkApiTest extends AndroidTestCase { + + static { + System.loadLibrary("nativemultinetwork_jni"); + } + + private static final String TAG = "MultinetworkNativeApiTest"; + + /** + * @return 0 on success + */ + private static native int runGetaddrinfoCheck(long networkHandle); + private static native int runSetprocnetwork(long networkHandle); + private static native int runSetsocknetwork(long networkHandle); + private static native int runDatagramCheck(long networkHandle); + + private ConnectivityManager mCM; + + protected void setUp() throws Exception { + super.setUp(); + mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + } + + private Network[] getTestableNetworks() { + final ArrayList testableNetworks = new ArrayList(); + for (Network network : mCM.getAllNetworks()) { + final NetworkCapabilities nc = mCM.getNetworkCapabilities(network); + if (nc != null + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + testableNetworks.add(network); + } + } + + assertTrue( + "This test requires that at least one network be connected. " + + "Please ensure that the device is connected to a network.", + testableNetworks.size() >= 1); + return testableNetworks.toArray(new Network[0]); + } + + public void testGetaddrinfo() throws ErrnoException { + for (Network network : getTestableNetworks()) { + int errno = runGetaddrinfoCheck(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "getaddrinfo on " + mCM.getNetworkInfo(network), -errno); + } + } + } + + public void testSetprocnetwork() throws ErrnoException { + // Hopefully no prior test in this process space has set a default network. + assertNull(mCM.getProcessDefaultNetwork()); + assertEquals(0, NetworkUtils.getBoundNetworkForProcess()); + + for (Network network : getTestableNetworks()) { + mCM.setProcessDefaultNetwork(null); + assertNull(mCM.getProcessDefaultNetwork()); + + int errno = runSetprocnetwork(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "setprocnetwork on " + mCM.getNetworkInfo(network), -errno); + } + Network processDefault = mCM.getProcessDefaultNetwork(); + assertNotNull(processDefault); + assertEquals(network, processDefault); + // TODO: open DatagramSockets, connect them to 192.0.2.1 and 2001:db8::, + // and ensure that the source address is in fact on this network as + // determined by mCM.getLinkProperties(network). + + mCM.setProcessDefaultNetwork(null); + } + + for (Network network : getTestableNetworks()) { + NetworkUtils.bindProcessToNetwork(0); + assertNull(mCM.getBoundNetworkForProcess()); + + int errno = runSetprocnetwork(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "setprocnetwork on " + mCM.getNetworkInfo(network), -errno); + } + assertEquals(network, new Network(mCM.getBoundNetworkForProcess())); + // TODO: open DatagramSockets, connect them to 192.0.2.1 and 2001:db8::, + // and ensure that the source address is in fact on this network as + // determined by mCM.getLinkProperties(network). + + NetworkUtils.bindProcessToNetwork(0); + } + } + + public void testSetsocknetwork() throws ErrnoException { + for (Network network : getTestableNetworks()) { + int errno = runSetsocknetwork(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "setsocknetwork on " + mCM.getNetworkInfo(network), -errno); + } + } + } + + public void testNativeDatagramTransmission() throws ErrnoException { + for (Network network : getTestableNetworks()) { + int errno = runDatagramCheck(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "DatagramCheck on " + mCM.getNetworkInfo(network), -errno); + } + } + } + + public void testNoSuchNetwork() { + final Network eNoNet = new Network(54321); + assertNull(mCM.getNetworkInfo(eNoNet)); + + final long eNoNetHandle = eNoNet.getNetworkHandle(); + assertEquals(-OsConstants.ENONET, runSetsocknetwork(eNoNetHandle)); + assertEquals(-OsConstants.ENONET, runSetprocnetwork(eNoNetHandle)); + // TODO: correct test permissions so this call is not silently re-mapped + // to query on the default network. + // assertEquals(-OsConstants.ENONET, runGetaddrinfoCheck(eNoNetHandle)); + } +} diff --git a/tests/cts/net/src/android/net/cts/MultinetworkTest.java b/tests/cts/net/src/android/net/cts/MultinetworkSysctlTest.java similarity index 97% rename from tests/cts/net/src/android/net/cts/MultinetworkTest.java rename to tests/cts/net/src/android/net/cts/MultinetworkSysctlTest.java index 256c03010a..c091a1340c 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkSysctlTest.java @@ -27,9 +27,9 @@ import java.io.FileDescriptor; import java.io.IOException; /** - * Tests for multinetwork functionality. + * Tests for multinetwork sysctl functionality. */ -public class MultinetworkTest extends AndroidTestCase { +public class MultinetworkSysctlTest extends AndroidTestCase { // Global sysctls. Must be present and set to 1. private static final String[] GLOBAL_SYSCTLS = { From dda68d2e2dbf5c689dcaca8f811127f3e8ec84f0 Mon Sep 17 00:00:00 2001 From: Ang Li Date: Mon, 22 Jun 2015 12:46:27 -0700 Subject: [PATCH 0164/1415] Add CTS tests for passpoint APIs in enterprise config. b/22001019 Change-Id: I35f6fa624f4b8fcd722296e12bc5aefc76ea96c6 --- .../net/wifi/cts/WifiEnterpriseConfigTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java index 6e395aaa14..6c416ca9f3 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java @@ -32,6 +32,10 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { private static final String IDENTITY = "identity"; private static final String PASSWORD = "password"; private static final String SUBJECT_MATCH = "subjectmatch"; + private static final String ALT_SUBJECT_MATCH = "altsubjectmatch"; + private static final String DOM_SUBJECT_MATCH = "domsubjectmatch"; + private static final String PLMN = "plmn"; + private static final String REALM = "realm"; private static final String ANON_IDENTITY = "anonidentity"; private static final int ENABLE_DELAY = 10000; @@ -87,6 +91,15 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { config.setClientKeyEntry(null, null); config.setSubjectMatch(SUBJECT_MATCH); assertTrue(config.getSubjectMatch().equals(SUBJECT_MATCH)); + // Hotspot 2.0 related attributes + config.setPlmn(PLMN); + assertTrue(config.getPlmn().equals(PLMN)); + config.setPlmn(REALM); + assertTrue(config.getRealm().equals(REALM)); + config.setAltSubjectMatch(ALT_SUBJECT_MATCH); + assertTrue(config.getAltSubjectMatch().equals(ALT_SUBJECT_MATCH)); + config.setDomainSuffixMatch(DOM_SUBJECT_MATCH); + assertTrue(config.getDomainSuffixMatch().equals(DOM_SUBJECT_MATCH)); } public void testAddEapNetwork() { From 5e671fabe635f30a9937f42f37bb812216c04597 Mon Sep 17 00:00:00 2001 From: Johan Redestig Date: Wed, 30 Oct 2013 14:14:58 +0100 Subject: [PATCH 0165/1415] Lookup private resources in run-time This fixes the following cases for us: android.net.cts.ConnectivityManagerTest#testGetAllNetworkInfo android.net.cts.ConnectivityManagerTest#testGetNetworkInfo android.net.cts.ConnectivityManagerTest#testIsNetworkSupported android.net.cts.ConnectivityManagerTest#testRequestRouteToHost android.net.cts.ConnectivityManagerTest#testSetNetworkPreference We need to use the prebuilt binary but that has dependency to private resource identities that differs in our environment. With this change the resources are looked up in run-time to avoid the build time dependency. Change-Id: I6579338b591ca7a0da3f03f796136269c7789780 (cherry picked from commit b29370db3447b4115523c03cb5019df601984f23) --- .../src/android/net/cts/ConnectivityManagerTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index e769be19ae..5656119d0f 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -66,8 +66,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); mPackageManager = getContext().getPackageManager(); - String[] naStrings = getContext().getResources().getStringArray( - com.android.internal.R.array.networkAttributes); + // Get com.android.internal.R.array.networkAttributes + int resId = getContext().getResources().getIdentifier("networkAttributes", "array", "android"); + String[] naStrings = getContext().getResources().getStringArray(resId); + for (String naString : naStrings) { try { NetworkConfig n = new NetworkConfig(naString); @@ -75,8 +77,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (Exception e) {} } - int[] protectedNetworks = getContext().getResources().getIntArray( - com.android.internal.R.array.config_protectedNetworks); + // Get com.android.internal.R.array.config_protectedNetworks + resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android"); + int[] protectedNetworks = getContext().getResources().getIntArray(resId); for (int p : protectedNetworks) { mProtectedNetworks.add(p); } From c16f65807b0251fdb0149d0bb1eacba370b585b1 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Fri, 3 Jul 2015 11:55:29 +0100 Subject: [PATCH 0166/1415] Modify test now that LocalSocket.getSoTimeout() does something Bug: 3106438 Change-Id: Iac7153607d5da44f21d66da80e2db27b17002d8d --- tests/cts/net/src/android/net/cts/LocalSocketTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 865ec21da3..24410d5248 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -129,9 +129,9 @@ public class LocalSocketTest extends AndroidTestCase{ socket.setSendBufferSize(3998); assertEquals(3998 << 1, socket.getSendBufferSize()); - // Timeout is not support at present, so set is ignored - socket.setSoTimeout(1996); assertEquals(0, socket.getSoTimeout()); + socket.setSoTimeout(1996); + assertTrue(socket.getSoTimeout() > 0); try { socket.getRemoteSocketAddress(); From 8fbc09bde8c5723d57a3b188e7fc69916cc62cca Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Fri, 3 Jul 2015 15:04:48 +0100 Subject: [PATCH 0167/1415] More tests for LocalSocket Tests for OutputStream.flush() and InputStream.available(). Bug: 3106438 Change-Id: I024e8fb95cc52678eb4b8df5584d21c9cf4b505a --- .../src/android/net/cts/LocalSocketTest.java | 127 +++++++++++++++++- 1 file changed, 123 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 24410d5248..22a2c7a2d9 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -16,16 +16,19 @@ package android.net.cts; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import android.net.Credentials; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.test.AndroidTestCase; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + public class LocalSocketTest extends AndroidTestCase{ public final static String mSockAddr = "com.android.net.LocalSocketTest"; @@ -168,4 +171,120 @@ public class LocalSocketTest extends AndroidTestCase{ // expected } } + + public void testAvailable() throws Exception { + LocalServerSocket localServerSocket = new LocalServerSocket(mSockAddr); + LocalSocket clientSocket = new LocalSocket(); + + // establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(mSockAddr); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + LocalSocket serverSocket = localServerSocket.accept(); + + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + assertEquals(0, serverInputStream.available()); + + byte[] buffer = new byte[50]; + clientOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); + + InputStream clientInputStream = clientSocket.getInputStream(); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + assertEquals(0, clientInputStream.available()); + serverOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); + + clientSocket.close(); + serverSocket.close(); + } + + public void testFlush() throws Exception { + LocalServerSocket localServerSocket = new LocalServerSocket(mSockAddr); + LocalSocket clientSocket = new LocalSocket(); + + // establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(mSockAddr); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + LocalSocket serverSocket = localServerSocket.accept(); + + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + testFlushWorks(clientOutputStream, serverInputStream); + + OutputStream serverOutputStream = serverSocket.getOutputStream(); + InputStream clientInputStream = clientSocket.getInputStream(); + testFlushWorks(serverOutputStream, clientInputStream); + + clientSocket.close(); + serverSocket.close(); + } + + private void testFlushWorks(OutputStream outputStream, InputStream inputStream) + throws Exception { + final int bytesToTransfer = 50; + StreamReader inputStreamReader = new StreamReader(inputStream, bytesToTransfer); + + byte[] buffer = new byte[bytesToTransfer]; + outputStream.write(buffer); + assertEquals(bytesToTransfer, inputStream.available()); + + // Start consuming the data. + inputStreamReader.start(); + + // This doesn't actually flush any buffers, it just polls until the reader has read all the + // bytes. + outputStream.flush(); + + inputStreamReader.waitForCompletion(5000); + inputStreamReader.assertBytesRead(bytesToTransfer); + assertEquals(0, inputStream.available()); + } + + private static class StreamReader extends Thread { + private final InputStream is; + private final int expectedByteCount; + private final CountDownLatch completeLatch = new CountDownLatch(1); + + private volatile Exception exception; + private int bytesRead; + + private StreamReader(InputStream is, int expectedByteCount) { + this.is = is; + this.expectedByteCount = expectedByteCount; + } + + @Override + public void run() { + try { + byte[] buffer = new byte[10]; + int readCount; + while ((readCount = is.read(buffer)) >= 0) { + bytesRead += readCount; + if (bytesRead >= expectedByteCount) { + break; + } + } + } catch (IOException e) { + exception = e; + } finally { + completeLatch.countDown(); + } + } + + public void waitForCompletion(long waitMillis) throws Exception { + if (!completeLatch.await(waitMillis, TimeUnit.MILLISECONDS)) { + fail("Timeout waiting for completion"); + } + if (exception != null) { + throw new Exception("Read failed", exception); + } + } + + public void assertBytesRead(int expected) { + assertEquals(expected, bytesRead); + } + } } From cb57c86657f230c34480ceb72cdbce43fe62302f Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Fri, 3 Jul 2015 17:38:43 +0100 Subject: [PATCH 0168/1415] Fix missing socket closure in LocalSocketTest Noticed as a result of 8fbc09bde8c5723d57a3b188e7fc69916cc62cca. One of the AF_UNIX sockets being created in three tests was not being closed (until GC/finalization). Because the name is now used in multiple tests some of the tests would fail in the CTS test runner ("Address already in use") if no GC had occurred. Bug: 3106438 Change-Id: I7debe5ed26d9d09e71a3d8a1b5b7d85b13e6e069 --- tests/cts/net/src/android/net/cts/LocalSocketTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 22a2c7a2d9..9da8fbe272 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -116,7 +116,7 @@ public class LocalSocketTest extends AndroidTestCase{ public void testAccessors() throws IOException{ LocalSocket socket = new LocalSocket(); - LocalSocketAddress addr = new LocalSocketAddress("secondary"); + LocalSocketAddress addr = new LocalSocketAddress(mSockAddr); assertFalse(socket.isBound()); socket.bind(addr); @@ -170,6 +170,8 @@ public class LocalSocketTest extends AndroidTestCase{ } catch (UnsupportedOperationException e) { // expected } + + socket.close(); } public void testAvailable() throws Exception { @@ -198,6 +200,7 @@ public class LocalSocketTest extends AndroidTestCase{ clientSocket.close(); serverSocket.close(); + localServerSocket.close(); } public void testFlush() throws Exception { @@ -220,6 +223,7 @@ public class LocalSocketTest extends AndroidTestCase{ clientSocket.close(); serverSocket.close(); + localServerSocket.close(); } private void testFlushWorks(OutputStream outputStream, InputStream inputStream) From 2ee5bd54a5c8901a9d8bd3508dc7ed82898b7d2c Mon Sep 17 00:00:00 2001 From: Ang Li Date: Wed, 8 Jul 2015 13:39:48 -0700 Subject: [PATCH 0169/1415] Fix a naming error in WifiEnterpriseConfigTest.java b/22349111 Change-Id: Ic9c847dfb1d58f274e91e22042c07995c72daa12 --- .../net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java index 6c416ca9f3..2cc59511dd 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java @@ -94,7 +94,7 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { // Hotspot 2.0 related attributes config.setPlmn(PLMN); assertTrue(config.getPlmn().equals(PLMN)); - config.setPlmn(REALM); + config.setRealm(REALM); assertTrue(config.getRealm().equals(REALM)); config.setAltSubjectMatch(ALT_SUBJECT_MATCH); assertTrue(config.getAltSubjectMatch().equals(ALT_SUBJECT_MATCH)); From 20b7b91edf3f6ae736e8362e2c58eab324f39b8f Mon Sep 17 00:00:00 2001 From: Junjie Hu Date: Fri, 10 Jul 2015 19:28:31 -0700 Subject: [PATCH 0170/1415] Fix CTS android.net package testTrafficStatsForLocalhost seldom fail issue (cherry-picked from master: 0d4434d998a9fc7c314523503b0a09a8422acc71 conflict + added Log) For testTrafficStatsForLocalhost's UID testing, it will also calcuate the wlan0 interface. There are some TCP re-tranmission in SSLCertificateSocketFactoryTest and it is the same UID as this test case. Need to consider those extra pacetks. For example, Before testTrafficStatsForLocalhost test casae: 01-08 15:49:11.316 7826 7839 D TrafficStats: parseUidStats, buffer: 14 wlan0 0x0 10067 0 31857 67 4582 55 31857 67 0 0 0 0 4582 55 0 0 0 0 01-08 15:49:11.335 7826 7839 D TrafficStats: parseUidStats, buffer: 24 lo 0x0 10067 0 40 1 60 1 40 1 0 0 0 0 60 1 0 0 0 0 After testTrafficStatsForLocalhost test casae: 01-08 15:49:19.210 7826 7839 D TrafficStats: parseUidStats, buffer: 14 wlan0 0x0 10067 0 31857 67 4738 58 31857 67 0 0 0 0 4738 58 0 0 0 0 01-08 15:49:19.212 7826 7839 D TrafficStats: parseUidStats, buffer: 24 lo 0x0 10067 0 1155336 2053 1155408 2054 1155336 2053 0 0 0 0 1155408 2054 0 0 0 0 => There are three extra IP packets after testing due to TCP FIN retreamsisions in previous test case Suggest to add some extra IP packets for consider the extra traffic in wlan0 interface. Signed-off-by: Junjie Hu Change-Id: I981f98fc8647469fb105361516b6a59c53530c70 --- .../src/android/net/cts/TrafficStatsTest.java | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 180d259bbc..0d02df7c17 100644 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -19,6 +19,7 @@ package android.net.cts; import android.net.TrafficStats; import android.os.Process; import android.test.AndroidTestCase; +import android.util.Log; import java.io.IOException; import java.io.InputStream; @@ -29,6 +30,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public class TrafficStatsTest extends AndroidTestCase { + private static final String LOG_TAG = "TrafficStatsTest"; public void testValidMobileStats() { // We can't assume a mobile network is even present in this test, so // we simply assert that a valid value is returned. @@ -163,18 +165,40 @@ public class TrafficStatsTest extends AndroidTestCase { * + 7 approx.: syn, syn-ack, ack, fin-ack, ack, fin-ack, ack; * but sometimes the last find-acks just vanish, so we set a lower limit of +5. */ - assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets, - uidTxDeltaPackets >= packetCount + 5 && - uidTxDeltaPackets <= packetCount + packetCount + 7); - assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets, - uidRxDeltaPackets >= packetCount + 5 && - uidRxDeltaPackets <= packetCount + packetCount + 7); - assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes, - uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(5, 0) && - uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + 7, 0)); - assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes, - uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(5, 0) && - uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + 7, 0)); + final int maxExpectedExtraPackets = 7; + final int minExpectedExtraPackets = 5; + + // Some other tests don't cleanup connections correctly. + // They have the same UID, so we discount their lingering traffic + // which happens only on non-localhost, such as TCP FIN retranmission packets + long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore) - uidTxDeltaPackets; + long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) - uidRxDeltaPackets; + if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { + Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); + // Make sure that not too many non-localhost packets are accounted for + assertTrue("too many non-localhost packets on the sam UID", deltaTxOtherPackets + deltaTxOtherPackets < 20); + } + + assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + + " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + + uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets + "+" + deltaTxOtherPackets, + uidTxDeltaPackets >= packetCount + minExpectedExtraPackets && + uidTxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); + assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets + + " Wanted: " + uidRxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + + uidRxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets, + uidRxDeltaPackets >= packetCount + minExpectedExtraPackets && + uidRxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); + assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes + + " Wanted: " + uidTxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + + uidTxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), + uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && + uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaTxOtherPackets, 0)); + assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes + + " Wanted: " + uidRxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + + uidRxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), + uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && + uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaRxOtherPackets, 0)); // Localhost traffic *does* count against total stats. // Fudge by 132 packets of 1500 bytes not related to the test. From 810a62236ca892be3001bc24c325f41fe754efff Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Tue, 14 Jul 2015 18:59:40 -0700 Subject: [PATCH 0171/1415] Fix CTS build Revert "Merge "resolve merge conflicts of a97c792 to kitkat-cts-dev" into kitkat-cts-dev" This reverts commit 9feaaaf44682c72dc5c771c93ef01ec793b6a7e3, reversing changes made to 65fbe1fcd153c5647f8d1e1a7443b3f04b7b25fd. --- .../net/src/android/net/cts/TrafficStatsTest.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 74cd7718ea..5b93beead5 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit; public class TrafficStatsTest extends AndroidTestCase { private static final String LOG_TAG = "TrafficStatsTest"; + public void testValidMobileStats() { // We can't assume a mobile network is even present in this test, so // we simply assert that a valid value is returned. @@ -217,17 +218,6 @@ public class TrafficStatsTest extends AndroidTestCase { assertTrue("too many non-localhost packets on the sam UID", deltaTxOtherPackets + deltaTxOtherPackets < 20); } - // Some other tests don't cleanup connections correctly. - // They have the same UID, so we discount their lingering traffic - // which happens only on non-localhost, such as TCP FIN retranmission packets - long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore) - uidTxDeltaPackets; - long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) - uidRxDeltaPackets; - if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { - Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); - // Make sure that not too many non-localhost packets are accounted for - assertTrue("too many non-localhost packets on the sam UID", deltaTxOtherPackets + deltaTxOtherPackets < 20); - } - assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets + "+" + deltaTxOtherPackets, From 0852bee4a9b363de1c361b1a12564dc59ded1771 Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Tue, 14 Jul 2015 18:59:40 -0700 Subject: [PATCH 0172/1415] Fix CTS build Revert "Merge "resolve merge conflicts of a97c792 to kitkat-cts-dev" into kitkat-cts-dev" This reverts commit 9feaaaf44682c72dc5c771c93ef01ec793b6a7e3, reversing changes made to 65fbe1fcd153c5647f8d1e1a7443b3f04b7b25fd. --- .../net/src/android/net/cts/TrafficStatsTest.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 74cd7718ea..5b93beead5 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit; public class TrafficStatsTest extends AndroidTestCase { private static final String LOG_TAG = "TrafficStatsTest"; + public void testValidMobileStats() { // We can't assume a mobile network is even present in this test, so // we simply assert that a valid value is returned. @@ -217,17 +218,6 @@ public class TrafficStatsTest extends AndroidTestCase { assertTrue("too many non-localhost packets on the sam UID", deltaTxOtherPackets + deltaTxOtherPackets < 20); } - // Some other tests don't cleanup connections correctly. - // They have the same UID, so we discount their lingering traffic - // which happens only on non-localhost, such as TCP FIN retranmission packets - long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore) - uidTxDeltaPackets; - long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) - uidRxDeltaPackets; - if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { - Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); - // Make sure that not too many non-localhost packets are accounted for - assertTrue("too many non-localhost packets on the sam UID", deltaTxOtherPackets + deltaTxOtherPackets < 20); - } - assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets + "+" + deltaTxOtherPackets, From 708349cba6559e81564481844b3e69ae3de4ec02 Mon Sep 17 00:00:00 2001 From: Jim Guggemos Date: Tue, 14 Jul 2015 15:15:04 -0600 Subject: [PATCH 0173/1415] New CTS test for ConnectivityManager.getActiveNetwork. Bug: 21833352 Change-Id: I970a114e3c94c9885186bd55c608bbc4bcb9a7fa --- .../src/android/net/cts/ConnectivityManagerTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 15d368f515..7c70293846 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; +import android.net.Network; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -129,6 +130,17 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue(ni.getState() == State.CONNECTED); } + public void testGetActiveNetwork() { + Network network = mCm.getActiveNetwork(); + assertTrue("You must have an active network connection to complete CTS", network != null); + + NetworkInfo ni = mCm.getNetworkInfo(network); + assertTrue("Network returned from getActiveNetwork was invalid", ni != null); + // Similar to testGetActiveNetworkInfo above. + assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); + assertTrue(ni.getState() == State.CONNECTED); + } + public void testGetNetworkInfo() { for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { if (isSupported(type)) { From 7443acfd8f25c05270a7a5482e4a9cd2c0073308 Mon Sep 17 00:00:00 2001 From: Jim Guggemos Date: Tue, 14 Jul 2015 12:03:12 -0600 Subject: [PATCH 0174/1415] New CTS test for ConnectivityManager.(un)registerNetworkCallback. Tested on device with wifi enabled and disabled before executing the test. Bug: 21833352 Change-Id: I42222bd229a370f780f08fa056d331ff1431b87a --- .../net/cts/ConnectivityManagerTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 7c70293846..34baac9819 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -23,10 +23,12 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; +import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.test.AndroidTestCase; import android.util.Log; @@ -310,6 +312,51 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + /** + * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to + * see if we get a callback for the TRANSPORT_WIFI transport type being available. + * + *

In order to test that a NetworkCallback occurs, we need some change in the network + * state (either a transport or capability is now available). The most straightforward is + * WiFi. We could add a version that uses the telephony data connection but it's not clear + * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?). + */ + public void testRegisterNetworkCallback() { + if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { + Log.i(TAG, "testRegisterNetworkCallback cannot execute unless devices supports WiFi"); + return; + } + + // We will register for a WIFI network being available or lost. + NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + + boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); + + try { + // Make sure WiFi is connected to an access point to start with. + if (!previousWifiEnabledState) { + connectToWifi(); + } + + // Now we should expect to get a network callback about availability of the wifi + // network even if it was already connected as a state-based action when the callback + // is registered. + assertTrue("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI", + callback.waitForAvailable()); + } catch (InterruptedException e) { + fail("Broadcast receiver or NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + + // Return WiFI to its original enabled/disabled state. + mWifiManager.setWifiEnabled(previousWifiEnabledState); + } + } + private void connectToWifi() throws InterruptedException { ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI); @@ -350,4 +397,21 @@ public class ConnectivityManagerTest extends AndroidTestCase { return mReceiveLatch.await(30, TimeUnit.SECONDS); } } + + /** + * Callback used in testRegisterNetworkCallback that allows caller to block on + * {@code onAvailable}. + */ + private class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CountDownLatch mAvailableLatch = new CountDownLatch(1); + + public boolean waitForAvailable() throws InterruptedException { + return mAvailableLatch.await(30, TimeUnit.SECONDS); + } + + @Override + public void onAvailable(Network network) { + mAvailableLatch.countDown(); + } + } } From adbcf224267a1df7362dad13b0862b50f57b3c68 Mon Sep 17 00:00:00 2001 From: Liangcai Li Date: Fri, 10 Jan 2014 16:01:46 +0800 Subject: [PATCH 0175/1415] Support WiFi only device at runtime. As what is done in ConnectivityService to fix bug: 8562845. Otherwise some related tests like 'testGetAllNetworkInfo' would fail with runtime detection on WiFi only device. Change-Id: I94922729c11826b3711abf42f594dcdd994324b6 Signed-off-by: Liangcai Li --- .../net/src/android/net/cts/ConnectivityManagerTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 5656119d0f..ab4bc7ec55 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -30,6 +30,7 @@ import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; import android.test.AndroidTestCase; import android.util.Log; +import android.os.SystemProperties; import java.util.ArrayList; import java.util.HashMap; @@ -69,10 +70,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Get com.android.internal.R.array.networkAttributes int resId = getContext().getResources().getIdentifier("networkAttributes", "array", "android"); String[] naStrings = getContext().getResources().getStringArray(resId); - + //TODO: What is the "correct" way to determine if this is a wifi only device? + boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false); for (String naString : naStrings) { try { NetworkConfig n = new NetworkConfig(naString); + if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) { + continue; + } mNetworks.put(n.type, n); } catch (Exception e) {} } From e2815d360a9e4cd05c01c666183445f6b6294779 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Fri, 24 Jul 2015 02:23:15 +0900 Subject: [PATCH 0176/1415] QUIC port 80 support is going away Change-Id: I29a81e67d121b2e7e832e9e0d5e798d70b4c594a --- tests/cts/net/jni/NativeMultinetworkJni.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index 9a5ab9c422..4da0c1c4a3 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -122,9 +122,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( struct addrinfo *res = NULL; net_handle_t handle = (net_handle_t) nethandle; - // Quoth Ian Swett: - // "QUIC always uses 80 and 443, but only 443 is used for secure(HTTPS) traffic." - int rval = android_getaddrinfofornetwork(handle, kHostname, "80", &kHints, &res); + int rval = android_getaddrinfofornetwork(handle, kHostname, "443", &kHints, &res); if (rval != 0) { ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", handle, kHostname, rval, errno); From 9030d1aceb09288418731435aa7fade736b21383 Mon Sep 17 00:00:00 2001 From: Jim Guggemos Date: Tue, 21 Jul 2015 20:08:24 -0600 Subject: [PATCH 0177/1415] New tests for (un)registerNetworkCallback with PendingIntent. Fixed up flakiness if WiFi was disabled before executing the test. Bug: 21833352 Change-Id: Ief7e12c4a7151722ec926ac38ced9f8903cdb607 --- .../net/cts/ConnectivityManagerTest.java | 172 +++++++++++++++--- 1 file changed, 149 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 34baac9819..1895dccb7a 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,6 +16,7 @@ package android.net.cts; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -53,6 +54,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 + // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. + private static final String NETWORK_CALLBACK_ACTION = + "ConnectivityManagerTest.NetworkCallbackAction"; + // device could have only one interface: data, wifi. private static final int MIN_NUM_NETWORK_TYPES = 1; @@ -127,17 +132,18 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testGetActiveNetworkInfo() { NetworkInfo ni = mCm.getActiveNetworkInfo(); - assertTrue("You must have an active network connection to complete CTS", ni != null); + assertNotNull("You must have an active network connection to complete CTS", ni); assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); assertTrue(ni.getState() == State.CONNECTED); } public void testGetActiveNetwork() { Network network = mCm.getActiveNetwork(); - assertTrue("You must have an active network connection to complete CTS", network != null); + assertNotNull("You must have an active network connection to complete CTS", network); NetworkInfo ni = mCm.getNetworkInfo(network); - assertTrue("Network returned from getActiveNetwork was invalid", ni != null); + assertNotNull("Network returned from getActiveNetwork was invalid", ni); + // Similar to testGetActiveNetworkInfo above. assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); assertTrue(ni.getState() == State.CONNECTED); @@ -280,8 +286,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { } // Register a receiver that will capture the connectivity change for hipri. - ConnectivityActionReceiver receiver = - new ConnectivityActionReceiver(ConnectivityManager.TYPE_MOBILE_HIPRI); + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + ConnectivityManager.TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED); IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(receiver, filter); @@ -292,7 +298,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue("Couldn't start using the HIPRI feature.", result != -1); // Check that the ConnectivityManager reported that it connected using hipri... - assertTrue("Couldn't connect using hipri...", receiver.waitForConnection()); + assertTrue("Couldn't connect using hipri...", receiver.waitForState()); assertTrue("Couldn't requestRouteToHost using HIPRI.", mCm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, HOST_ADDRESS)); @@ -307,7 +313,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { // TODO check dns selection // TODO check routes if (!isWifiEnabled) { - mWifiManager.setWifiEnabled(false); + disconnectFromWifi(); } } } @@ -323,7 +329,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { */ public void testRegisterNetworkCallback() { if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { - Log.i(TAG, "testRegisterNetworkCallback cannot execute unless devices supports WiFi"); + Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); return; } @@ -353,47 +359,167 @@ public class ConnectivityManagerTest extends AndroidTestCase { mCm.unregisterNetworkCallback(callback); // Return WiFI to its original enabled/disabled state. - mWifiManager.setWifiEnabled(previousWifiEnabledState); + if (!previousWifiEnabledState) { + disconnectFromWifi(); + } } } - private void connectToWifi() throws InterruptedException { - ConnectivityActionReceiver receiver = - new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI); + /** + * Tests both registerNetworkCallback and unregisterNetworkCallback similarly to + * {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead + * of a {@code NetworkCallback}. + */ + public void testRegisterNetworkCallback_withPendingIntent() { + if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { + Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); + return; + } + + // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined + // action, NETWORK_CALLBACK_ACTION. + IntentFilter filter = new IntentFilter(); + filter.addAction(NETWORK_CALLBACK_ACTION); + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + mContext.registerReceiver(receiver, filter); + + // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION. + Intent intent = new Intent(NETWORK_CALLBACK_ACTION); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + + // We will register for a WIFI network being available or lost. + NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + mCm.registerNetworkCallback(request, pendingIntent); + + boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); + + try { + // Make sure WiFi is connected to an access point to start with. + if (!previousWifiEnabledState) { + connectToWifi(); + } + + // Now we expect to get the Intent delivered notifying of the availability of the wifi + // network even if it was already connected as a state-based action when the callback + // is registered. + assertTrue("Did not receive expected Intent " + intent + " for TRANSPORT_WIFI", + receiver.waitForState()); + } catch (InterruptedException e) { + fail("Broadcast receiver or NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(pendingIntent); + pendingIntent.cancel(); + mContext.unregisterReceiver(receiver); + + // Return WiFI to its original enabled/disabled state. + if (!previousWifiEnabledState) { + disconnectFromWifi(); + } + } + } + + /** Enable WiFi and wait for it to become connected to a network. */ + private void connectToWifi() { + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(receiver, filter); - assertTrue(mWifiManager.setWifiEnabled(true)); - assertTrue("Wifi must be configured to connect to an access point for this test.", - receiver.waitForConnection()); + boolean connected = false; + try { + assertTrue(mWifiManager.setWifiEnabled(true)); + connected = receiver.waitForState(); + } catch (InterruptedException ex) { + fail("connectToWifi was interrupted"); + } finally { + mContext.unregisterReceiver(receiver); + } - mContext.unregisterReceiver(receiver); + assertTrue("Wifi must be configured to connect to an access point for this test.", + connected); } - /** Receiver that captures the last connectivity change's network type and state. */ + /** Disable WiFi and wait for it to become disconnected from the network. */ + private void disconnectFromWifi() { + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + boolean disconnected = false; + try { + assertTrue(mWifiManager.setWifiEnabled(false)); + disconnected = receiver.waitForState(); + } catch (InterruptedException ex) { + fail("disconnectFromWifi was interrupted"); + } finally { + mContext.unregisterReceiver(receiver); + } + + assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); + } + + /** + * Receiver that captures the last connectivity change's network type and state. Recognizes + * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. + */ private class ConnectivityActionReceiver extends BroadcastReceiver { private final CountDownLatch mReceiveLatch = new CountDownLatch(1); private final int mNetworkType; + private final NetworkInfo.State mNetState; - ConnectivityActionReceiver(int networkType) { + ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) { mNetworkType = networkType; + mNetState = netState; } public void onReceive(Context context, Intent intent) { - NetworkInfo networkInfo = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); + String action = intent.getAction(); + NetworkInfo networkInfo = null; + + // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable + // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is + // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { + networkInfo = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo); + } else if (NETWORK_CALLBACK_ACTION.equals(action)) { + Network network = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); + networkInfo = mCm.getNetworkInfo(network); + if (networkInfo == null) { + // When disconnecting, it seems like we get an intent sent with an invalid + // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), + // it is invalid. Ignore these. + Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " + + "invalid network"); + return; + } + } else { + fail("ConnectivityActionReceiver received unxpected intent action: " + action); + } + + assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); int networkType = networkInfo.getType(); State networkState = networkInfo.getState(); Log.i(TAG, "Network type: " + networkType + " state: " + networkState); - if (networkType == mNetworkType && networkInfo.getState() == State.CONNECTED) { + if (networkType == mNetworkType && networkInfo.getState() == mNetState) { mReceiveLatch.countDown(); } } - public boolean waitForConnection() throws InterruptedException { + public boolean waitForState() throws InterruptedException { return mReceiveLatch.await(30, TimeUnit.SECONDS); } } @@ -402,7 +528,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * Callback used in testRegisterNetworkCallback that allows caller to block on * {@code onAvailable}. */ - private class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { private final CountDownLatch mAvailableLatch = new CountDownLatch(1); public boolean waitForAvailable() throws InterruptedException { From e57e9bcb96cb61cfa9306431089300fd28f44675 Mon Sep 17 00:00:00 2001 From: Fyodor Kupolov Date: Wed, 29 Jul 2015 11:24:34 -0700 Subject: [PATCH 0178/1415] Fix for ScanResultTest and WifiManagerTest Added ACCESS_COARSE_LOCATION permission - it is now required to receive Wi-Fi scan results(b/21852542). Bug: 22790182 Change-Id: Idb72c200b08f7e4e95571504ab42c9e706f5c921 --- tests/cts/net/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index bca2d2c1ba..001e2946b1 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -20,6 +20,7 @@ + From cfc277c7f13f8b9fce9adf538596f4b1ce210f51 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 6 Aug 2015 16:09:55 +0900 Subject: [PATCH 0179/1415] Update CTS for unsupported legacy ConnectivityManager APIs http://ag/736511 made the deprecated ConnectivityManager routing APIs {start,stop}UsingNetworkFeature and requestRouteToHost throw exceptions for apps whose target SDK version is 23 or above. Move the tests for these APIs to a new APK that targets SDK version 22 and update the current test APK to ensure that they throw an exception. Bug: 22977863 Bug: 23003441 Bug: 23003635 Change-Id: Icf58e928fdc0018d977ce8aa315866659d32debb --- .../net/cts/ConnectivityManagerTest.java | 128 ++++-------------- 1 file changed, 25 insertions(+), 103 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index e4d77b1c77..88dbd7c686 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -67,7 +67,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { private PackageManager mPackageManager; private final HashMap mNetworks = new HashMap(); - private final ListmProtectedNetworks = new ArrayList(); @Override protected void setUp() throws Exception { @@ -90,13 +89,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { mNetworks.put(n.type, n); } catch (Exception e) {} } - - // Get com.android.internal.R.array.config_protectedNetworks - resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android"); - int[] protectedNetworks = getContext().getResources().getIntArray(resId); - for (int p : protectedNetworks) { - mProtectedNetworks.add(p); - } } public void testIsNetworkTypeValid() { @@ -190,6 +182,27 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) { + try { + mCm.startUsingNetworkFeature(networkType, feature); + fail("startUsingNetworkFeature is no longer supported in the current API version"); + } catch (UnsupportedOperationException expected) {} + } + + private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) { + try { + mCm.startUsingNetworkFeature(networkType, feature); + fail("stopUsingNetworkFeature is no longer supported in the current API version"); + } catch (UnsupportedOperationException expected) {} + } + + private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) { + try { + mCm.requestRouteToHost(networkType, hostAddress); + fail("requestRouteToHost is no longer supported in the current API version"); + } catch (UnsupportedOperationException expected) {} + } + public void testStartUsingNetworkFeature() { final String invalidateFeature = "invalidateFeature"; @@ -198,27 +211,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { final int wifiOnlyStartFailureCode = PhoneConstants.APN_REQUEST_FAILED; final int wifiOnlyStopFailureCode = -1; - NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE); - if (ni != null) { - assertEquals(PhoneConstants.APN_REQUEST_FAILED, - mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, - invalidateFeature)); - } else { - assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE, - invalidateFeature)); - assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, - invalidateFeature)); - } - - ni = mCm.getNetworkInfo(TYPE_WIFI); - if (ni != null) { - // Should return failure because MMS is not supported on WIFI. - assertEquals(PhoneConstants.APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI, - mmsFeature)); - assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI, - mmsFeature)); - } + assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature); + assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature); + assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature); } private boolean isSupported(int networkType) { @@ -229,11 +224,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { (networkType == ConnectivityManager.TYPE_VPN); } - // true if only the system can turn it on - private boolean isNetworkProtected(int networkType) { - return mProtectedNetworks.contains(networkType); - } - public void testIsNetworkSupported() { for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { boolean supported = mCm.isNetworkSupported(type); @@ -247,82 +237,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testRequestRouteToHost() { for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { - NetworkInfo ni = mCm.getNetworkInfo(type); - boolean expectToWork = isSupported(type) && !isNetworkProtected(type) && - ni != null && ni.isConnected(); - - try { - assertTrue("Network type " + type, - mCm.requestRouteToHost(type, HOST_ADDRESS) == expectToWork); - } catch (Exception e) { - Log.d(TAG, "got exception in requestRouteToHost for type " + type); - assertFalse("Exception received for type " + type, expectToWork); - } - - //TODO verify route table + assertRequestRouteToHostUnsupported(type, HOST_ADDRESS); } - - assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS)); } public void testTest() { mCm.getBackgroundDataSetting(); } - /** Test that hipri can be brought up when Wifi is enabled. */ - public void testStartUsingNetworkFeature_enableHipri() throws Exception { - if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) - || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { - // This test requires a mobile data connection and WiFi. - return; - } - - boolean isWifiEnabled = mWifiManager.isWifiEnabled(); - boolean isWifiConnected = false; - - NetworkInfo nwInfo = mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI); - if (nwInfo != null) { - isWifiConnected = nwInfo.isConnected(); - } - try { - // Make sure WiFi is connected to an access point. - if (!isWifiConnected) { - connectToWifi(); - } - - // Register a receiver that will capture the connectivity change for hipri. - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - // Try to start using the hipri feature... - int result = mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - FEATURE_ENABLE_HIPRI); - assertTrue("Couldn't start using the HIPRI feature.", result != -1); - - // Check that the ConnectivityManager reported that it connected using hipri... - assertTrue("Couldn't connect using hipri...", receiver.waitForState()); - - assertTrue("Couldn't requestRouteToHost using HIPRI.", - mCm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, HOST_ADDRESS)); - // TODO check dns selection - // TODO check routes - } catch (InterruptedException e) { - fail("Broadcast receiver waiting for ConnectivityManager interrupted."); - } finally { - mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - FEATURE_ENABLE_HIPRI); - // TODO wait for HIPRI to go - // TODO check dns selection - // TODO check routes - if (!isWifiEnabled) { - disconnectFromWifi(); - } - } - } - /** * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to * see if we get a callback for the TRANSPORT_WIFI transport type being available. From f19c63e5b169e15f7f6a4bb8cf82d45e81f9a6e1 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Fri, 7 Aug 2015 12:45:14 +0900 Subject: [PATCH 0180/1415] Add trivial retransmission of QUIC packets Also: - correct use of strlcpy() - add some more logging Bug: 21833352 Bug: 22181260 Change-Id: Id153e17b8d4d32a35d38846599aa51147739e163 --- tests/cts/net/jni/NativeMultinetworkJni.c | 53 ++++++++++++++++------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index 4da0c1c4a3..ad56b510c3 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -93,7 +93,8 @@ static const int kSockaddrStrLen = INET6_ADDRSTRLEN + strlen("[]:65535"); void sockaddr_ntop(const struct sockaddr *sa, socklen_t salen, char *dst, const size_t size) { char addrstr[INET6_ADDRSTRLEN]; char portstr[sizeof("65535")]; - char buf[sizeof(addrstr) + sizeof(portstr) + sizeof("[]:")]; + char buf[kSockaddrStrLen+1]; + int ret = getnameinfo(sa, salen, addrstr, sizeof(addrstr), portstr, sizeof(portstr), @@ -106,7 +107,7 @@ void sockaddr_ntop(const struct sockaddr *sa, socklen_t salen, char *dst, const sprintf(buf, "???"); } - strlcpy(dst, buf, (strlen(buf) < size - 1) ? strlen(buf) : size - 1); + strlcpy(dst, buf, size); } JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( @@ -122,7 +123,8 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( struct addrinfo *res = NULL; net_handle_t handle = (net_handle_t) nethandle; - int rval = android_getaddrinfofornetwork(handle, kHostname, "443", &kHints, &res); + static const char kPort[] = "443"; + int rval = android_getaddrinfofornetwork(handle, kHostname, kPort, &kHints, &res); if (rval != 0) { ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", handle, kHostname, rval, errno); @@ -148,9 +150,9 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -errno; } - char addrstr[kSockaddrStrLen]; + char addrstr[kSockaddrStrLen+1]; sockaddr_ntop(res->ai_addr, res->ai_addrlen, addrstr, sizeof(addrstr)); - ALOGD("Attempting connect() to %s...", addrstr); + ALOGD("Attempting connect() to %s ...", addrstr); rval = connect(fd, res->ai_addr, res->ai_addrlen); if (rval != 0) { @@ -170,10 +172,12 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( ALOGD("... from %s", addrstr); // Don't let reads or writes block indefinitely. - const struct timeval timeo = { 5, 0 }; // 5 seconds + const struct timeval timeo = { 2, 0 }; // 2 seconds setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); + // For reference see: + // https://tools.ietf.org/html/draft-tsvwg-quic-protocol-01#section-6.1 uint8_t quic_packet[] = { 0x0c, // public flags: 64bit conn ID, 8bit sequence number 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID @@ -184,19 +188,36 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( arc4random_buf(quic_packet + 1, 8); // random connection ID - ssize_t sent = send(fd, quic_packet, sizeof(quic_packet), 0); - if (sent < (ssize_t)sizeof(quic_packet)) { - ALOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errno); - close(fd); - return -errno; - } - uint8_t response[1500]; - ssize_t rcvd = recv(fd, response, sizeof(response), 0); + ssize_t sent, rcvd; + static const int MAX_RETRIES = 5; + int i, errnum = 0; + + for (i = 0; i < MAX_RETRIES; i++) { + sent = send(fd, quic_packet, sizeof(quic_packet), 0); + if (sent < (ssize_t)sizeof(quic_packet)) { + errnum = errno; + ALOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum); + close(fd); + return -errnum; + } + + rcvd = recv(fd, response, sizeof(response), 0); + if (rcvd > 0) { + break; + } else { + errnum = errno; + ALOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d", + i + 1, MAX_RETRIES, rcvd, errnum); + } + } if (rcvd < sent) { - ALOGD("recv() returned rcvd=%zd, errno=%d", rcvd, errno); + ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); + if (rcvd <= 0) { + ALOGD("Does this network block UDP port %s?", kPort); + } close(fd); - return -errno; + return -EPROTO; } int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); From de95223f871d9aec9be68dee3afc89d0c36be952 Mon Sep 17 00:00:00 2001 From: Nash Lincoln Date: Thu, 17 Sep 2015 13:46:25 -0700 Subject: [PATCH 0181/1415] migrate net tests to cts_v2 bug:21762834 Change-Id: Ic86dee963720c1412a42ec231c81c97d7f322420 --- tests/cts/net/Android.mk | 3 +++ tests/cts/net/AndroidManifest.xml | 4 ++-- tests/cts/net/AndroidTest.xml | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/AndroidTest.xml diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 652487126d..716141d5b2 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -40,6 +40,9 @@ LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support ctsdeviceutil \ # uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current +# Tag this module as a cts_v2 test artifact +LOCAL_COMPATIBILITY_SUITE := cts_v2 + include $(BUILD_CTS_PACKAGE) include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 001e2946b1..2bc82164de 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -16,7 +16,7 @@ --> + package="android.net.cts"> @@ -35,7 +35,7 @@ diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml new file mode 100644 index 0000000000..ee0d636939 --- /dev/null +++ b/tests/cts/net/AndroidTest.xml @@ -0,0 +1,22 @@ + + + + From 45984684aa2688924e10ea95c3951ece6c9b3f0b Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 22 Sep 2015 08:07:46 -0400 Subject: [PATCH 0182/1415] CTS: verify ConnectivityManager.requestNetwork throws for restricted networks Bug:21900139 Change-Id: Ib026bc4e66437f015729bdf7c923145ffa41fbde --- .../net/cts/ConnectivityManagerTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index d79ecdddb4..eeae257a26 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,16 +16,21 @@ package android.net.cts; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; +import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.test.AndroidTestCase; import android.util.Log; @@ -334,4 +339,23 @@ public class ConnectivityManagerTest extends AndroidTestCase { return mReceiveLatch.await(30, TimeUnit.SECONDS); } } + + /** Verify restricted networks cannot be requested. */ + public void testRestrictedNetworks() { + // Verify we can request unrestricted networks: + NetworkRequest request = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_INTERNET).build(); + NetworkCallback callback = new NetworkCallback(); + mCm.requestNetwork(request, callback); + mCm.unregisterNetworkCallback(callback); + // Verify we cannot request restricted networks: + request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build(); + callback = new NetworkCallback(); + try { + mCm.requestNetwork(request, callback); + fail("No exception thrown when restricted network requested."); + } catch (SecurityException e) { + // Expected. + } + } } From d62c5997f6966ba0e1123eb5badc71917b025f9e Mon Sep 17 00:00:00 2001 From: Aaron Holden Date: Mon, 28 Sep 2015 10:37:27 -0700 Subject: [PATCH 0183/1415] Add WiFi precondition check to 'net' CTS module bug:23939594 Change-Id: I9e625e635fc6942c9eaa95915888f0fe7284a9ea --- tests/cts/net/AndroidTest.xml | 7 ++++ tests/cts/net/preconditions/Android.mk | 39 +++++++++++++++++++ .../cts/net/preconditions/AndroidManifest.xml | 31 +++++++++++++++ .../net/preconditions/PreconditionsTest.java | 39 +++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 tests/cts/net/preconditions/Android.mk create mode 100644 tests/cts/net/preconditions/AndroidManifest.xml create mode 100644 tests/cts/net/preconditions/src/android/net/preconditions/PreconditionsTest.java diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml index ee0d636939..d52214e80a 100644 --- a/tests/cts/net/AndroidTest.xml +++ b/tests/cts/net/AndroidTest.xml @@ -19,4 +19,11 @@

These tests rely on a host-side test to use {@code adb shell cmd netpolicy} to put the device + * in the proper state. In fact, they're more like "assertions" than tests per se - the real test + * logic is done on {@code HostsideNetworkTests}. + */ +public class ConnectivityManagerTest extends InstrumentationTestCase { + private static final String TAG = "ConnectivityManagerTest"; + + private ConnectivityManager mCM; + + @Override + public void setUp() throws Exception { + super.setUp(); + mCM = (ConnectivityManager) getInstrumentation().getContext().getSystemService( + Activity.CONNECTIVITY_SERVICE); + } + + public void testGetRestrictBackgroundStatus_disabled() { + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + } + + public void testGetRestrictBackgroundStatus_whitelisted() { + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + } + + public void testGetRestrictBackgroundStatus_enabled() { + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + } + + private void assertRestrictBackgroundStatus(int expectedStatus) { + final String expected = toString(expectedStatus); + Log.d(TAG, getName() + " (expecting " + expected + ")"); + final @RestrictBackgroundStatus int actualStatus = mCM.getRestrictBackgroundStatus(); + assertEquals("wrong status", expected, toString(actualStatus)); + } + + private String toString(@RestrictBackgroundStatus int status) { + switch (status) { + case RESTRICT_BACKGROUND_STATUS_DISABLED: + return "DISABLED"; + case RESTRICT_BACKGROUND_STATUS_WHITELISTED: + return "WHITELISTED"; + case RESTRICT_BACKGROUND_STATUS_ENABLED: + return "ENABLED"; + default: + return "UNKNOWN_STATUS_" + status; + } + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java index f42de0e4aa..dd2424c13a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java @@ -17,6 +17,7 @@ package com.android.cts.net; import com.android.cts.migration.MigrationHelper; +import com.android.ddmlib.Log; import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; import com.android.ddmlib.testrunner.TestIdentifier; import com.android.ddmlib.testrunner.TestResult; @@ -24,17 +25,20 @@ import com.android.ddmlib.testrunner.TestResult.TestStatus; import com.android.ddmlib.testrunner.TestRunResult; import com.android.tradefed.build.IBuildInfo; import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.result.CollectingTestListener; import com.android.tradefed.testtype.DeviceTestCase; import com.android.tradefed.testtype.IAbi; import com.android.tradefed.testtype.IAbiReceiver; import com.android.tradefed.testtype.IBuildReceiver; -import com.android.tradefed.device.DeviceNotAvailableException; -import com.android.tradefed.device.ITestDevice; -import com.android.tradefed.result.CollectingTestListener; +import java.io.FileNotFoundException; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver { + private static final boolean DEBUG = false; + private static final String TAG = "HostsideNetworkTests"; private static final String TEST_PKG = "com.android.cts.net.hostside"; private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk"; @@ -58,28 +62,130 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver assertNotNull(mAbi); assertNotNull(mCtsBuild); - getDevice().uninstallPackage(TEST_PKG); - - assertNull(getDevice().installPackage( - MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false)); + setRestrictBackground(false); + uninstallTestPackage(false); + installTestPackage(); } @Override protected void tearDown() throws Exception { super.tearDown(); - getDevice().uninstallPackage(TEST_PKG); + uninstallTestPackage(false); + setRestrictBackground(false); } public void testVpn() throws Exception { - runDeviceTests(TEST_PKG, ".VpnTest"); + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest"); + } + + public void testConnectivityManager_getRestrictBackgroundStatus_disabled() throws Exception { + final int uid = getUid(TEST_PKG); + removeRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundStatusDisabled(); + // Sanity check: make sure status is always disabled, never whitelisted + addRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundStatusDisabled(); + } + + public void testConnectivityManager_getRestrictBackgroundStatus_whitelisted() throws Exception { + final int uid = getUid(TEST_PKG); + setRestrictBackground(true); + addRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundStatusWhitelisted(); + } + + public void testConnectivityManager_getRestrictBackgroundStatus_enabled() throws Exception { + final int uid = getUid(TEST_PKG); + setRestrictBackground(true); + removeRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundStatusEnabled(); + } + + public void testConnectivityManager_getRestrictBackgroundStatus_uninstall() throws Exception { + final int uid = getUid(TEST_PKG); + + addRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundWhitelist(uid, true); + + uninstallTestPackage(true); + assertPackageUninstalled(TEST_PKG); + assertRestrictBackgroundWhitelist(uid, false); + + installTestPackage(); + final int newUid = getUid(TEST_PKG); + assertRestrictBackgroundWhitelist(uid, false); + assertRestrictBackgroundWhitelist(newUid, false); + } + + private void installTestPackage() throws DeviceNotAvailableException, FileNotFoundException { + assertNull(getDevice().installPackage( + MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false)); + } + + private void uninstallTestPackage(boolean shouldSucceed) throws DeviceNotAvailableException { + final String result = getDevice().uninstallPackage(TEST_PKG); + if (shouldSucceed) { + assertNull("uninstallPackage failed: " + result, result); + } + } + + private void assertPackageUninstalled(String packageName) throws DeviceNotAvailableException { + final String command = "cmd package list packages -f " + packageName; + final int max_tries = 5; + for (int i = 1; i <= max_tries; i++) { + final String result = runCommand(command); + if (result.trim().isEmpty()) { + return; + } + i++; + Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result + + "); sleeping 1s before polling again"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds"); + } + + private void assertRestrictBackgroundStatusDisabled() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testGetRestrictBackgroundStatus_disabled"); + } + + private void assertRestrictBackgroundStatusWhitelisted() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testGetRestrictBackgroundStatus_whitelisted"); + } + + private void assertRestrictBackgroundStatusEnabled() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testGetRestrictBackgroundStatus_enabled"); } public void runDeviceTests(String packageName, String testClassName) - throws DeviceNotAvailableException { + throws DeviceNotAvailableException { + runDeviceTests(packageName, testClassName, null); + } + + public void runDeviceTests(String packageName, String testClassName, String methodName) + throws DeviceNotAvailableException { RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + if (testClassName != null) { + // TODO: figure out why testRunner.setMethodName() / testRunner.setClassName() doesn't + // work + final StringBuilder runOptions = new StringBuilder("-e class ").append(testClassName); + if (methodName != null) { + runOptions.append('#').append(methodName); + } + Log.i(TAG, "Setting runOptions() as " + runOptions); + testRunner.setRunOptions(runOptions.toString()); + } + final CollectingTestListener listener = new CollectingTestListener(); getDevice().runInstrumentationTests(testRunner, listener); @@ -103,4 +209,57 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver throw new AssertionError(errorBuilder.toString()); } } + + private static final Pattern UID_PATTERN = + Pattern.compile(".*userId=([0-9]+)$", Pattern.MULTILINE); + + private int getUid(String packageName) throws DeviceNotAvailableException { + final String output = runCommand("dumpsys package " + packageName); + final Matcher matcher = UID_PATTERN.matcher(output); + while (matcher.find()) { + final String match = matcher.group(1); + return Integer.parseInt(match); + } + throw new RuntimeException("Did not find regexp '" + UID_PATTERN + "' on adb output\n" + + output); + } + + private void addRestrictBackgroundWhitelist(int uid) throws DeviceNotAvailableException { + runCommand("cmd netpolicy add restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, true); + } + + private void removeRestrictBackgroundWhitelist(int uid) throws DeviceNotAvailableException { + runCommand("cmd netpolicy remove restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, false); + } + + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) + throws DeviceNotAvailableException { + final String output = runCommand("cmd netpolicy list restrict-background-whitelist "); + // TODO: use MoreAsserts + if (expected) { + assertTrue("Did not find uid '" + uid + "' on '" + output + "'", + output.contains(Integer.toString(uid))); + } else { + assertFalse("Found uid '" + uid + "' on '" + output + "'", + output.contains(Integer.toString(uid))); + } + } + + private void setRestrictBackground(boolean enabled) throws DeviceNotAvailableException { + runCommand("cmd netpolicy set restrict-background " + enabled); + final String output = runCommand("cmd netpolicy get restrict-background ").trim(); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + // TODO: use MoreAsserts? + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + + private String runCommand(String command) throws DeviceNotAvailableException { + Log.d(TAG, "Command: '" + command + "'"); + final String output = getDevice().executeShellCommand(command); + if (DEBUG) Log.v(TAG, "Output: " + output.trim()); + return output; + } } From d12935eed8c38baf35189f490e77e1955fbe592c Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 27 Jan 2016 12:34:06 -0800 Subject: [PATCH 0200/1415] Removed reference to hidden annotation. BUG: 26082535 BUG: 26451391 Change-Id: I267010a49df3212ca96f54b65aa7c8a14982a70c --- .../android/cts/net/hostside/ConnectivityManagerTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java index 42196abe7f..5d3812cffa 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java @@ -21,7 +21,6 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import android.app.Activity; import android.net.ConnectivityManager; -import android.net.ConnectivityManager.RestrictBackgroundStatus; import android.test.InstrumentationTestCase; import android.util.Log; @@ -59,11 +58,11 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { private void assertRestrictBackgroundStatus(int expectedStatus) { final String expected = toString(expectedStatus); Log.d(TAG, getName() + " (expecting " + expected + ")"); - final @RestrictBackgroundStatus int actualStatus = mCM.getRestrictBackgroundStatus(); + final int actualStatus = mCM.getRestrictBackgroundStatus(); assertEquals("wrong status", expected, toString(actualStatus)); } - private String toString(@RestrictBackgroundStatus int status) { + private String toString(int status) { switch (status) { case RESTRICT_BACKGROUND_STATUS_DISABLED: return "DISABLED"; From 9980740cb943e22033ec885048de076a1d555866 Mon Sep 17 00:00:00 2001 From: Yi Kong Date: Thu, 21 Jan 2016 20:45:32 +0000 Subject: [PATCH 0201/1415] Wait for network to resume in ConcurrencyTest so that subsequent tests would not fail due to lack of network connection. Bug: 26182816 Change-Id: I6bc89897c9ad8e5966f03db7fc72169d3b973e53 --- .../android/net/wifi/cts/ConcurrencyTest.java | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java index 343c1e6399..a066ba80de 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java @@ -20,12 +20,20 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.net.wifi.p2p.WifiP2pManager; import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_DISABLED; import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_ENABLED; import android.test.AndroidTestCase; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + public class ConcurrencyTest extends AndroidTestCase { private class MySync { int expectedWifiState; @@ -94,10 +102,7 @@ public class ConcurrencyTest extends AndroidTestCase { } mContext.unregisterReceiver(mReceiver); - if (!mWifiManager.isWifiEnabled()) { - assertTrue(mWifiManager.setWifiEnabled(true)); - Thread.sleep(DURATION); - } + enableWifi(); super.tearDown(); } @@ -114,6 +119,33 @@ public class ConcurrencyTest extends AndroidTestCase { } } + /* + * Enables Wifi and block until connection is established. + */ + private void enableWifi() throws InterruptedException { + if (!mWifiManager.isWifiEnabled()) { + assertTrue(mWifiManager.setWifiEnabled(true)); + } + + ConnectivityManager cm = + (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkRequest request = + new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + final CountDownLatch latch = new CountDownLatch(1); + NetworkCallback networkCallback = new NetworkCallback() { + @Override + public void onAvailable(Network network) { + latch.countDown(); + } + }; + cm.registerNetworkCallback(request, networkCallback); + latch.await(DURATION, TimeUnit.MILLISECONDS); + + cm.unregisterNetworkCallback(networkCallback); + } + public void testConcurrency() { // Cannot support p2p alone if (!WifiFeature.isWifiSupported(getContext())) { From f2b8106f8d8dcdf22b28e62a677048f71c228a0a Mon Sep 17 00:00:00 2001 From: Sergio Giro Date: Thu, 28 Jan 2016 14:40:48 +0000 Subject: [PATCH 0202/1415] AbstractVerifierTest: adapt tests to reflect that tabs are preserved by the DN parser Recently in 53f06c0d1dd4c7b48c965a8c6270d6acb12161ca I changed the tests to reflect the fact that tabs and newlines were discarded. I must have made some mistake verifying the change, as tabs seem preserved. Changing the assertion for tabs. Bug: 26517725 Change-Id: I514a3d670019e3e2911e2c69b434d0f577ff9b7a --- .../src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java b/tests/cts/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java index 16d3ac452c..5e2a55e7ec 100644 --- a/tests/cts/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java +++ b/tests/cts/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java @@ -107,7 +107,7 @@ public final class AbstractVerifierTest extends TestCase { public void testGetCns_whitespace() { assertCns("cn= p", "p"); assertCns("cn=\np", "p"); - assertCns("cn=\tp", "p"); + assertCns("cn=\tp", "\tp"); } public void testGetCnsWithOid() { From 5b3513691797f4d7d3e2ed2713a9290b80f868d9 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 27 Jan 2016 14:49:54 -0800 Subject: [PATCH 0203/1415] Added CTS tests for RESTRICT_BACKGROUND_CHANGED. These tests require a second app (besides the test app) that defines a service; the host-side test then launches the service whose only purpose is to define a broadcast receiver, which in turn will count the number of intents received in a shared preferences file. Then the test app will read the shared preferences and assert the proper number of intents have been received. BUG: 26451391 Change-Id: I4c5d5e57c09a0bd57a7f6581820cc9115318dd47 --- tests/cts/hostside/app/AndroidManifest.xml | 3 +- .../net/hostside/ConnectivityManagerTest.java | 49 ++++++- .../android/cts/net/hostside/MyActivity.java | 4 - .../cts/net/hostside/MyVpnService.java | 1 - tests/cts/hostside/app2/Android.mk | 31 +++++ tests/cts/hostside/app2/AndroidManifest.xml | 37 +++++ .../android/cts/net/hostside/app2/Common.java | 23 ++++ .../hostside/app2/MyBroadcastReceiver.java | 51 +++++++ .../cts/net/hostside/app2/MyService.java | 44 ++++++ .../android/cts/net/HostsideNetworkTests.java | 128 +++++++++++++----- 10 files changed, 329 insertions(+), 42 deletions(-) create mode 100644 tests/cts/hostside/app2/Android.mk create mode 100644 tests/cts/hostside/app2/AndroidManifest.xml create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index cdde7dcb34..f44fdd1dfc 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -15,7 +15,8 @@ --> + package="com.android.cts.net.hostside" + android:sharedUserId="com.android.cts.net.hostside.apps"> diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java index 5d3812cffa..300e39d55e 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java @@ -16,10 +16,14 @@ package com.android.cts.net.hostside; +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; + import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.test.InstrumentationTestCase; import android.util.Log; @@ -34,6 +38,9 @@ import android.util.Log; public class ConnectivityManagerTest extends InstrumentationTestCase { private static final String TAG = "ConnectivityManagerTest"; + static final String MANIFEST_RECEIVER = "ManifestReceiver"; + static final String DYNAMIC_RECEIVER = "DynamicReceiver"; + private ConnectivityManager mCM; @Override @@ -41,7 +48,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { super.setUp(); mCM = (ConnectivityManager) getInstrumentation().getContext().getSystemService( Activity.CONNECTIVITY_SERVICE); - } + } public void testGetRestrictBackgroundStatus_disabled() { assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); @@ -55,6 +62,46 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); } + public void testRestrictBackgroundChangedReceivedOnce() throws Exception { + assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 1); + assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); + } + + public void testRestrictBackgroundChangedReceivedTwice() throws Exception { + assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 2); + assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); + } + + private void assertRestrictBackgroundChangedReceived(String receiverName, int expectedCount) + throws Exception { + int attempts = 0; + int count = 0; + final int maxAttempts = 5; + final int sleepTime = 10; + do { + attempts++; + count = getNumberBroadcastsReceived(getInstrumentation().getContext(), receiverName, + ACTION_RESTRICT_BACKGROUND_CHANGED); + if (count == expectedCount) { + break; + } + Log.d(TAG, "Count is " + count + " after " + attempts + " attempts; sleeping " + + sleepTime + " seconds before trying again"); + Thread.sleep(sleepTime * 1000); + } while (attempts <= maxAttempts); + assertEquals("Number of expected broadcasts for " + receiverName + " not reached after " + + maxAttempts * sleepTime + " seconds", expectedCount, count); + } + + static int getNumberBroadcastsReceived(Context context, String receiverName, String action) + throws Exception { + final Context sharedContext = context.createPackageContext( + "com.android.cts.net.hostside.app2", Context.CONTEXT_IGNORE_SECURITY); + final SharedPreferences prefs = sharedContext.getSharedPreferences(receiverName, + Context.MODE_PRIVATE); + return prefs.getInt(action, 0); + } + private void assertRestrictBackgroundStatus(int expectedStatus) { final String expected = toString(expectedStatus); Log.d(TAG, getName() + " (expecting " + expected + ")"); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java index 375c8523c8..0d0bc58504 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java @@ -18,13 +18,9 @@ package com.android.cts.net.hostside; import android.app.Activity; import android.content.Intent; -import android.net.VpnService; import android.os.Bundle; -import android.os.ParcelFileDescriptor; import android.view.WindowManager; -import java.util.Arrays; -import java.util.ArrayList; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java index a3f400c388..90a3ce4b49 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java @@ -26,7 +26,6 @@ import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.ArrayList; public class MyVpnService extends VpnService { diff --git a/tests/cts/hostside/app2/Android.mk b/tests/cts/hostside/app2/Android.mk new file mode 100644 index 0000000000..e330bf7508 --- /dev/null +++ b/tests/cts/hostside/app2/Android.mk @@ -0,0 +1,31 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_SDK_VERSION := current + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := CtsHostsideNetworkTestsApp2 + +LOCAL_PROGUARD_ENABLED := disabled +LOCAL_DEX_PREOPT := false + +include $(BUILD_CTS_SUPPORT_PACKAGE) diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml new file mode 100644 index 0000000000..d69bf56a1c --- /dev/null +++ b/tests/cts/hostside/app2/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java new file mode 100644 index 0000000000..91caeda97d --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +public final class Common { + + static final String TAG = "CtsNetApp2"; + static final String MANIFEST_RECEIVER = "ManifestReceiver"; + static final String DYNAMIC_RECEIVER = "DynamicReceiver"; +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java new file mode 100644 index 0000000000..0cbf360d8f --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; +import static com.android.cts.net.hostside.app2.Common.TAG; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.util.Log; + +/** + * Receiver that stores received broadcasts in a shared preference. + */ +public class MyBroadcastReceiver extends BroadcastReceiver { + + private final String mName; + + public MyBroadcastReceiver() { + this(MANIFEST_RECEIVER); + } + + MyBroadcastReceiver(String name) { + Log.d(TAG, "Constructing MyBroadcastReceiver named " + name); + mName = name; + } + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceive() for " + mName + ": " + intent); + final SharedPreferences prefs = context.getSharedPreferences(mName, Context.MODE_PRIVATE); + final String pref = intent.getAction(); + final int value = prefs.getInt(pref, 0) + 1; + Log.d(TAG, "Setting " + pref + " = " + value); + prefs.edit().putInt(pref, value).apply(); + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java new file mode 100644 index 0000000000..882bb62c2c --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; +import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER; +import static com.android.cts.net.hostside.app2.Common.TAG; +import android.app.Service; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.IBinder; +import android.util.Log; + +/** + * Service used to dynamically register a broadcast receiver. + */ +public class MyService extends Service { + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "onStartCommand: " + intent); + getApplicationContext().registerReceiver(new MyBroadcastReceiver(DYNAMIC_RECEIVER), + new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED)); + return START_STICKY; + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java index dd2424c13a..bedfad61b3 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java @@ -42,6 +42,9 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver private static final String TEST_PKG = "com.android.cts.net.hostside"; private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk"; + private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; + private static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk"; + private IAbi mAbi; private IBuildInfo mCtsBuild; @@ -63,15 +66,22 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver assertNotNull(mCtsBuild); setRestrictBackground(false); - uninstallTestPackage(false); - installTestPackage(); + + uninstallPackage(TEST_PKG, false); + installPackage(TEST_APK); + // TODO: split this class into HostsideVpnTests and HostsideConnectivityManagerTests so + // the former don't need to unnecessarily install app2. + uninstallPackage(TEST_APP2_PKG, false); + installPackage(TEST_APP2_APK); } @Override protected void tearDown() throws Exception { super.tearDown(); - uninstallTestPackage(false); + uninstallPackage(TEST_PKG, true); + uninstallPackage(TEST_APP2_PKG, true); + setRestrictBackground(false); } @@ -80,26 +90,41 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver } public void testConnectivityManager_getRestrictBackgroundStatus_disabled() throws Exception { + startBroadcastReceiverService(); final int uid = getUid(TEST_PKG); + removeRestrictBackgroundWhitelist(uid); assertRestrictBackgroundStatusDisabled(); + assertRestrictBackgroundChangedReceivedOnce(); + // Sanity check: make sure status is always disabled, never whitelisted addRestrictBackgroundWhitelist(uid); assertRestrictBackgroundStatusDisabled(); + assertRestrictBackgroundChangedReceivedTwice(); } public void testConnectivityManager_getRestrictBackgroundStatus_whitelisted() throws Exception { + startBroadcastReceiverService(); final int uid = getUid(TEST_PKG); + setRestrictBackground(true); + assertRestrictBackgroundChangedReceivedOnce(); + addRestrictBackgroundWhitelist(uid); assertRestrictBackgroundStatusWhitelisted(); + assertRestrictBackgroundChangedReceivedTwice(); } public void testConnectivityManager_getRestrictBackgroundStatus_enabled() throws Exception { + startBroadcastReceiverService(); final int uid = getUid(TEST_PKG); + setRestrictBackground(true); + assertRestrictBackgroundChangedReceivedOnce(); + removeRestrictBackgroundWhitelist(uid); assertRestrictBackgroundStatusEnabled(); + assertRestrictBackgroundChangedReceivedTwice(); } public void testConnectivityManager_getRestrictBackgroundStatus_uninstall() throws Exception { @@ -108,44 +133,66 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver addRestrictBackgroundWhitelist(uid); assertRestrictBackgroundWhitelist(uid, true); - uninstallTestPackage(true); + uninstallPackage(TEST_PKG, true); assertPackageUninstalled(TEST_PKG); assertRestrictBackgroundWhitelist(uid, false); - installTestPackage(); + installPackage(TEST_APK); final int newUid = getUid(TEST_PKG); assertRestrictBackgroundWhitelist(uid, false); assertRestrictBackgroundWhitelist(newUid, false); } - private void installTestPackage() throws DeviceNotAvailableException, FileNotFoundException { + private void installPackage(String apk) throws DeviceNotAvailableException, + FileNotFoundException { assertNull(getDevice().installPackage( - MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false)); + MigrationHelper.getTestFile(mCtsBuild, apk), false)); } - private void uninstallTestPackage(boolean shouldSucceed) throws DeviceNotAvailableException { - final String result = getDevice().uninstallPackage(TEST_PKG); + private void uninstallPackage(String packageName, boolean shouldSucceed) + throws DeviceNotAvailableException { + final String result = getDevice().uninstallPackage(packageName); if (shouldSucceed) { - assertNull("uninstallPackage failed: " + result, result); + assertNull("uninstallPackage(" + packageName + ") failed: " + result, result); } } - private void assertPackageUninstalled(String packageName) throws DeviceNotAvailableException { - final String command = "cmd package list packages -f " + packageName; + /** + * Starts a service that will register a broadcast receiver to receive + * {@code RESTRICT_BACKGROUND_CHANGE} intents. + *

+ * The service must run in a separate app because otherwise it would be killed every time + * {@link #runDeviceTests(String, String)} is executed. + */ + private void startBroadcastReceiverService() throws DeviceNotAvailableException { + runCommand("am startservice " + TEST_APP2_PKG + "/.MyService"); + } + + private void assertPackageUninstalled(String packageName) throws Exception { + final String command = "cmd package list packages " + packageName; final int max_tries = 5; for (int i = 1; i <= max_tries; i++) { final String result = runCommand(command); if (result.trim().isEmpty()) { return; } + // 'list packages' filters by substring, so we need to iterate with the results + // and check one by one, otherwise 'com.android.cts.net.hostside' could return + // 'com.android.cts.net.hostside.app2' + boolean found = false; + for (String line : result.split("[\\r\\n]+")) { + if (line.endsWith(packageName)) { + found = true; + break; + } + } + if (!found) { + return; + } i++; Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result + "); sleeping 1s before polling again"); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } + Thread.sleep(1000); } fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds"); } @@ -165,6 +212,16 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver "testGetRestrictBackgroundStatus_enabled"); } + private void assertRestrictBackgroundChangedReceivedOnce() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testRestrictBackgroundChangedReceivedOnce"); + } + + private void assertRestrictBackgroundChangedReceivedTwice() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testRestrictBackgroundChangedReceivedTwice"); + } + public void runDeviceTests(String packageName, String testClassName) throws DeviceNotAvailableException { runDeviceTests(packageName, testClassName, null); @@ -176,14 +233,11 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); if (testClassName != null) { - // TODO: figure out why testRunner.setMethodName() / testRunner.setClassName() doesn't - // work - final StringBuilder runOptions = new StringBuilder("-e class ").append(testClassName); if (methodName != null) { - runOptions.append('#').append(methodName); + testRunner.setMethodName(testClassName, methodName); + } else { + testRunner.setClassName(testClassName); } - Log.i(TAG, "Setting runOptions() as " + runOptions); - testRunner.setRunOptions(runOptions.toString()); } final CollectingTestListener listener = new CollectingTestListener(); @@ -224,27 +278,31 @@ public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver + output); } - private void addRestrictBackgroundWhitelist(int uid) throws DeviceNotAvailableException { + private void addRestrictBackgroundWhitelist(int uid) throws Exception { runCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); } - private void removeRestrictBackgroundWhitelist(int uid) throws DeviceNotAvailableException { + private void removeRestrictBackgroundWhitelist(int uid) throws Exception { runCommand("cmd netpolicy remove restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, false); } - private void assertRestrictBackgroundWhitelist(int uid, boolean expected) - throws DeviceNotAvailableException { - final String output = runCommand("cmd netpolicy list restrict-background-whitelist "); - // TODO: use MoreAsserts - if (expected) { - assertTrue("Did not find uid '" + uid + "' on '" + output + "'", - output.contains(Integer.toString(uid))); - } else { - assertFalse("Found uid '" + uid + "' on '" + output + "'", - output.contains(Integer.toString(uid))); + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { + final int max_tries = 5; + boolean actual = false; + for (int i = 1; i <= max_tries; i++) { + final String output = runCommand("cmd netpolicy list restrict-background-whitelist "); + actual = output.contains(Integer.toString(uid)); + if (expected == actual) { + return; + } + Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected " + + expected + ", got " + actual + "); sleeping 1s before polling again"); + Thread.sleep(1000); } + fail("whitelist check for uid " + uid + " failed: expected " + + expected + ", got " + actual); } private void setRestrictBackground(boolean enabled) throws DeviceNotAvailableException { From 34caa7fc257ac04937a9a356b1190c2190b09a9d Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 4 Feb 2016 12:42:45 -0800 Subject: [PATCH 0204/1415] Renamed and cloned HostsideNetworkTests.java This is a no-op change that will make it easier to split the HostsideNetworkTestCase.java logic into multiple files. In this change, HostsideNetworkTests.java was renamed to HostsideNetworkTestCase.java and copied as-is to HostsideRestrictBackgroundNetworkTests.java; the next change will split the logic in between these class so they can be properly git-diffed. In fact, the only difference between then is the class declarations: diff HostsideNetworkTestCase.java HostsideRestrictBackgroundNetworkTests.java 39c39 < abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiReceiver, --- > public class HostsideRestrictBackgroundNetworkTests extends DeviceTestCase implements IAbiReceiver, BUG: 26685616 Change-Id: I87dadec528eaeff776d55d3382f356066496429a --- ...ests.java => HostsideNetworkTestCase.java} | 5 +- ...ostsideRestrictBackgroundNetworkTests.java | 324 ++++++++++++++++++ 2 files changed, 327 insertions(+), 2 deletions(-) rename tests/cts/hostside/src/com/android/cts/net/{HostsideNetworkTests.java => HostsideNetworkTestCase.java} (98%) create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java similarity index 98% rename from tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java rename to tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index bedfad61b3..7ae842d0ad 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2016 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. @@ -36,7 +36,8 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver { +abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiReceiver, + IBuildReceiver { private static final boolean DEBUG = false; private static final String TAG = "HostsideNetworkTests"; private static final String TEST_PKG = "com.android.cts.net.hostside"; diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java new file mode 100644 index 0000000000..038cd132ec --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net; + +import com.android.cts.migration.MigrationHelper; +import com.android.ddmlib.Log; +import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; +import com.android.ddmlib.testrunner.TestIdentifier; +import com.android.ddmlib.testrunner.TestResult; +import com.android.ddmlib.testrunner.TestResult.TestStatus; +import com.android.ddmlib.testrunner.TestRunResult; +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.result.CollectingTestListener; +import com.android.tradefed.testtype.DeviceTestCase; +import com.android.tradefed.testtype.IAbi; +import com.android.tradefed.testtype.IAbiReceiver; +import com.android.tradefed.testtype.IBuildReceiver; + +import java.io.FileNotFoundException; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HostsideRestrictBackgroundNetworkTests extends DeviceTestCase implements IAbiReceiver, + IBuildReceiver { + private static final boolean DEBUG = false; + private static final String TAG = "HostsideNetworkTests"; + private static final String TEST_PKG = "com.android.cts.net.hostside"; + private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk"; + + private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; + private static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk"; + + private IAbi mAbi; + private IBuildInfo mCtsBuild; + + @Override + public void setAbi(IAbi abi) { + mAbi = abi; + } + + @Override + public void setBuild(IBuildInfo buildInfo) { + mCtsBuild = buildInfo; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + assertNotNull(mAbi); + assertNotNull(mCtsBuild); + + setRestrictBackground(false); + + uninstallPackage(TEST_PKG, false); + installPackage(TEST_APK); + // TODO: split this class into HostsideVpnTests and HostsideConnectivityManagerTests so + // the former don't need to unnecessarily install app2. + uninstallPackage(TEST_APP2_PKG, false); + installPackage(TEST_APP2_APK); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + uninstallPackage(TEST_PKG, true); + uninstallPackage(TEST_APP2_PKG, true); + + setRestrictBackground(false); + } + + public void testVpn() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest"); + } + + public void testConnectivityManager_getRestrictBackgroundStatus_disabled() throws Exception { + startBroadcastReceiverService(); + final int uid = getUid(TEST_PKG); + + removeRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundStatusDisabled(); + assertRestrictBackgroundChangedReceivedOnce(); + + // Sanity check: make sure status is always disabled, never whitelisted + addRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundStatusDisabled(); + assertRestrictBackgroundChangedReceivedTwice(); + } + + public void testConnectivityManager_getRestrictBackgroundStatus_whitelisted() throws Exception { + startBroadcastReceiverService(); + final int uid = getUid(TEST_PKG); + + setRestrictBackground(true); + assertRestrictBackgroundChangedReceivedOnce(); + + addRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundStatusWhitelisted(); + assertRestrictBackgroundChangedReceivedTwice(); + } + + public void testConnectivityManager_getRestrictBackgroundStatus_enabled() throws Exception { + startBroadcastReceiverService(); + final int uid = getUid(TEST_PKG); + + setRestrictBackground(true); + assertRestrictBackgroundChangedReceivedOnce(); + + removeRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundStatusEnabled(); + assertRestrictBackgroundChangedReceivedTwice(); + } + + public void testConnectivityManager_getRestrictBackgroundStatus_uninstall() throws Exception { + final int uid = getUid(TEST_PKG); + + addRestrictBackgroundWhitelist(uid); + assertRestrictBackgroundWhitelist(uid, true); + + uninstallPackage(TEST_PKG, true); + assertPackageUninstalled(TEST_PKG); + assertRestrictBackgroundWhitelist(uid, false); + + installPackage(TEST_APK); + final int newUid = getUid(TEST_PKG); + assertRestrictBackgroundWhitelist(uid, false); + assertRestrictBackgroundWhitelist(newUid, false); + } + + private void installPackage(String apk) throws DeviceNotAvailableException, + FileNotFoundException { + assertNull(getDevice().installPackage( + MigrationHelper.getTestFile(mCtsBuild, apk), false)); + } + + private void uninstallPackage(String packageName, boolean shouldSucceed) + throws DeviceNotAvailableException { + final String result = getDevice().uninstallPackage(packageName); + if (shouldSucceed) { + assertNull("uninstallPackage(" + packageName + ") failed: " + result, result); + } + } + + /** + * Starts a service that will register a broadcast receiver to receive + * {@code RESTRICT_BACKGROUND_CHANGE} intents. + *

+ * The service must run in a separate app because otherwise it would be killed every time + * {@link #runDeviceTests(String, String)} is executed. + */ + private void startBroadcastReceiverService() throws DeviceNotAvailableException { + runCommand("am startservice " + TEST_APP2_PKG + "/.MyService"); + } + + private void assertPackageUninstalled(String packageName) throws Exception { + final String command = "cmd package list packages " + packageName; + final int max_tries = 5; + for (int i = 1; i <= max_tries; i++) { + final String result = runCommand(command); + if (result.trim().isEmpty()) { + return; + } + // 'list packages' filters by substring, so we need to iterate with the results + // and check one by one, otherwise 'com.android.cts.net.hostside' could return + // 'com.android.cts.net.hostside.app2' + boolean found = false; + for (String line : result.split("[\\r\\n]+")) { + if (line.endsWith(packageName)) { + found = true; + break; + } + } + if (!found) { + return; + } + i++; + Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result + + "); sleeping 1s before polling again"); + Thread.sleep(1000); + } + fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds"); + } + + private void assertRestrictBackgroundStatusDisabled() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testGetRestrictBackgroundStatus_disabled"); + } + + private void assertRestrictBackgroundStatusWhitelisted() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testGetRestrictBackgroundStatus_whitelisted"); + } + + private void assertRestrictBackgroundStatusEnabled() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testGetRestrictBackgroundStatus_enabled"); + } + + private void assertRestrictBackgroundChangedReceivedOnce() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testRestrictBackgroundChangedReceivedOnce"); + } + + private void assertRestrictBackgroundChangedReceivedTwice() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testRestrictBackgroundChangedReceivedTwice"); + } + + public void runDeviceTests(String packageName, String testClassName) + throws DeviceNotAvailableException { + runDeviceTests(packageName, testClassName, null); + } + + public void runDeviceTests(String packageName, String testClassName, String methodName) + throws DeviceNotAvailableException { + RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, + "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + + if (testClassName != null) { + if (methodName != null) { + testRunner.setMethodName(testClassName, methodName); + } else { + testRunner.setClassName(testClassName); + } + } + + final CollectingTestListener listener = new CollectingTestListener(); + getDevice().runInstrumentationTests(testRunner, listener); + + final TestRunResult result = listener.getCurrentRunResults(); + if (result.isRunFailure()) { + throw new AssertionError("Failed to successfully run device tests for " + + result.getName() + ": " + result.getRunFailureMessage()); + } + + if (result.hasFailedTests()) { + // build a meaningful error message + StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n"); + for (Map.Entry resultEntry : + result.getTestResults().entrySet()) { + if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) { + errorBuilder.append(resultEntry.getKey().toString()); + errorBuilder.append(":\n"); + errorBuilder.append(resultEntry.getValue().getStackTrace()); + } + } + throw new AssertionError(errorBuilder.toString()); + } + } + + private static final Pattern UID_PATTERN = + Pattern.compile(".*userId=([0-9]+)$", Pattern.MULTILINE); + + private int getUid(String packageName) throws DeviceNotAvailableException { + final String output = runCommand("dumpsys package " + packageName); + final Matcher matcher = UID_PATTERN.matcher(output); + while (matcher.find()) { + final String match = matcher.group(1); + return Integer.parseInt(match); + } + throw new RuntimeException("Did not find regexp '" + UID_PATTERN + "' on adb output\n" + + output); + } + + private void addRestrictBackgroundWhitelist(int uid) throws Exception { + runCommand("cmd netpolicy add restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, true); + } + + private void removeRestrictBackgroundWhitelist(int uid) throws Exception { + runCommand("cmd netpolicy remove restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, false); + } + + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { + final int max_tries = 5; + boolean actual = false; + for (int i = 1; i <= max_tries; i++) { + final String output = runCommand("cmd netpolicy list restrict-background-whitelist "); + actual = output.contains(Integer.toString(uid)); + if (expected == actual) { + return; + } + Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected " + + expected + ", got " + actual + "); sleeping 1s before polling again"); + Thread.sleep(1000); + } + fail("whitelist check for uid " + uid + " failed: expected " + + expected + ", got " + actual); + } + + private void setRestrictBackground(boolean enabled) throws DeviceNotAvailableException { + runCommand("cmd netpolicy set restrict-background " + enabled); + final String output = runCommand("cmd netpolicy get restrict-background ").trim(); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + // TODO: use MoreAsserts? + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + + private String runCommand(String command) throws DeviceNotAvailableException { + Log.d(TAG, "Command: '" + command + "'"); + final String output = getDevice().executeShellCommand(command); + if (DEBUG) Log.v(TAG, "Output: " + output.trim()); + return output; + } +} From 4fc69f6c25f68bfca83256c3b0a367213a251f5a Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 4 Feb 2016 12:46:16 -0800 Subject: [PATCH 0205/1415] Split hostside network tests in multiple classes. Initially HostsideNetworkTests.java was used to just launch VpnTest, but it became more complex with the inclusion of ConnectivityManagerTest, which required hostside logic. By splitting these tests not only the VPN tests will run faster (since it doesn't need the setup/clean from ConnectivityManager), but the ConnectivityManager tests will be cleaner (since it can have more logic on setup and teardown). BUG: 26685616 Change-Id: Ie29c4a3e83956b217d90b84c9b4541690cde0344 --- .../cts/net/HostsideNetworkTestCase.java | 170 ++------------- ...ostsideRestrictBackgroundNetworkTests.java | 196 ++---------------- .../com/android/cts/net/HostsideVpnTests.java | 24 +++ 3 files changed, 55 insertions(+), 335 deletions(-) create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 7ae842d0ad..08fb887932 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -38,13 +38,10 @@ import java.util.regex.Pattern; abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiReceiver, IBuildReceiver { - private static final boolean DEBUG = false; - private static final String TAG = "HostsideNetworkTests"; - private static final String TEST_PKG = "com.android.cts.net.hostside"; - private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk"; - - private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; - private static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk"; + protected static final boolean DEBUG = false; + protected static final String TAG = "HostsideNetworkTests"; + protected static final String TEST_PKG = "com.android.cts.net.hostside"; + protected static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk"; private IAbi mAbi; private IBuildInfo mCtsBuild; @@ -66,14 +63,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec assertNotNull(mAbi); assertNotNull(mCtsBuild); - setRestrictBackground(false); - uninstallPackage(TEST_PKG, false); installPackage(TEST_APK); - // TODO: split this class into HostsideVpnTests and HostsideConnectivityManagerTests so - // the former don't need to unnecessarily install app2. - uninstallPackage(TEST_APP2_PKG, false); - installPackage(TEST_APP2_APK); } @Override @@ -81,76 +72,14 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec super.tearDown(); uninstallPackage(TEST_PKG, true); - uninstallPackage(TEST_APP2_PKG, true); - - setRestrictBackground(false); } - public void testVpn() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest"); + protected void installPackage(String apk) throws FileNotFoundException, + DeviceNotAvailableException { + assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, apk), false)); } - public void testConnectivityManager_getRestrictBackgroundStatus_disabled() throws Exception { - startBroadcastReceiverService(); - final int uid = getUid(TEST_PKG); - - removeRestrictBackgroundWhitelist(uid); - assertRestrictBackgroundStatusDisabled(); - assertRestrictBackgroundChangedReceivedOnce(); - - // Sanity check: make sure status is always disabled, never whitelisted - addRestrictBackgroundWhitelist(uid); - assertRestrictBackgroundStatusDisabled(); - assertRestrictBackgroundChangedReceivedTwice(); - } - - public void testConnectivityManager_getRestrictBackgroundStatus_whitelisted() throws Exception { - startBroadcastReceiverService(); - final int uid = getUid(TEST_PKG); - - setRestrictBackground(true); - assertRestrictBackgroundChangedReceivedOnce(); - - addRestrictBackgroundWhitelist(uid); - assertRestrictBackgroundStatusWhitelisted(); - assertRestrictBackgroundChangedReceivedTwice(); - } - - public void testConnectivityManager_getRestrictBackgroundStatus_enabled() throws Exception { - startBroadcastReceiverService(); - final int uid = getUid(TEST_PKG); - - setRestrictBackground(true); - assertRestrictBackgroundChangedReceivedOnce(); - - removeRestrictBackgroundWhitelist(uid); - assertRestrictBackgroundStatusEnabled(); - assertRestrictBackgroundChangedReceivedTwice(); - } - - public void testConnectivityManager_getRestrictBackgroundStatus_uninstall() throws Exception { - final int uid = getUid(TEST_PKG); - - addRestrictBackgroundWhitelist(uid); - assertRestrictBackgroundWhitelist(uid, true); - - uninstallPackage(TEST_PKG, true); - assertPackageUninstalled(TEST_PKG); - assertRestrictBackgroundWhitelist(uid, false); - - installPackage(TEST_APK); - final int newUid = getUid(TEST_PKG); - assertRestrictBackgroundWhitelist(uid, false); - assertRestrictBackgroundWhitelist(newUid, false); - } - - private void installPackage(String apk) throws DeviceNotAvailableException, - FileNotFoundException { - assertNull(getDevice().installPackage( - MigrationHelper.getTestFile(mCtsBuild, apk), false)); - } - - private void uninstallPackage(String packageName, boolean shouldSucceed) + protected void uninstallPackage(String packageName, boolean shouldSucceed) throws DeviceNotAvailableException { final String result = getDevice().uninstallPackage(packageName); if (shouldSucceed) { @@ -158,18 +87,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec } } - /** - * Starts a service that will register a broadcast receiver to receive - * {@code RESTRICT_BACKGROUND_CHANGE} intents. - *

- * The service must run in a separate app because otherwise it would be killed every time - * {@link #runDeviceTests(String, String)} is executed. - */ - private void startBroadcastReceiverService() throws DeviceNotAvailableException { - runCommand("am startservice " + TEST_APP2_PKG + "/.MyService"); - } - - private void assertPackageUninstalled(String packageName) throws Exception { + protected void assertPackageUninstalled(String packageName) throws DeviceNotAvailableException, + InterruptedException { final String command = "cmd package list packages " + packageName; final int max_tries = 5; for (int i = 1; i <= max_tries; i++) { @@ -198,37 +117,12 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds"); } - private void assertRestrictBackgroundStatusDisabled() throws DeviceNotAvailableException { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", - "testGetRestrictBackgroundStatus_disabled"); - } - - private void assertRestrictBackgroundStatusWhitelisted() throws DeviceNotAvailableException { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", - "testGetRestrictBackgroundStatus_whitelisted"); - } - - private void assertRestrictBackgroundStatusEnabled() throws DeviceNotAvailableException { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", - "testGetRestrictBackgroundStatus_enabled"); - } - - private void assertRestrictBackgroundChangedReceivedOnce() throws DeviceNotAvailableException { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", - "testRestrictBackgroundChangedReceivedOnce"); - } - - private void assertRestrictBackgroundChangedReceivedTwice() throws DeviceNotAvailableException { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", - "testRestrictBackgroundChangedReceivedTwice"); - } - - public void runDeviceTests(String packageName, String testClassName) + protected void runDeviceTests(String packageName, String testClassName) throws DeviceNotAvailableException { runDeviceTests(packageName, testClassName, null); } - public void runDeviceTests(String packageName, String testClassName, String methodName) + protected void runDeviceTests(String packageName, String testClassName, String methodName) throws DeviceNotAvailableException { RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); @@ -268,7 +162,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec private static final Pattern UID_PATTERN = Pattern.compile(".*userId=([0-9]+)$", Pattern.MULTILINE); - private int getUid(String packageName) throws DeviceNotAvailableException { + protected int getUid(String packageName) throws DeviceNotAvailableException { final String output = runCommand("dumpsys package " + packageName); final Matcher matcher = UID_PATTERN.matcher(output); while (matcher.find()) { @@ -279,43 +173,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec + output); } - private void addRestrictBackgroundWhitelist(int uid) throws Exception { - runCommand("cmd netpolicy add restrict-background-whitelist " + uid); - assertRestrictBackgroundWhitelist(uid, true); - } - - private void removeRestrictBackgroundWhitelist(int uid) throws Exception { - runCommand("cmd netpolicy remove restrict-background-whitelist " + uid); - assertRestrictBackgroundWhitelist(uid, false); - } - - private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { - final int max_tries = 5; - boolean actual = false; - for (int i = 1; i <= max_tries; i++) { - final String output = runCommand("cmd netpolicy list restrict-background-whitelist "); - actual = output.contains(Integer.toString(uid)); - if (expected == actual) { - return; - } - Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected " - + expected + ", got " + actual + "); sleeping 1s before polling again"); - Thread.sleep(1000); - } - fail("whitelist check for uid " + uid + " failed: expected " - + expected + ", got " + actual); - } - - private void setRestrictBackground(boolean enabled) throws DeviceNotAvailableException { - runCommand("cmd netpolicy set restrict-background " + enabled); - final String output = runCommand("cmd netpolicy get restrict-background ").trim(); - final String expectedSuffix = enabled ? "enabled" : "disabled"; - // TODO: use MoreAsserts? - assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", - output.endsWith(expectedSuffix)); - } - - private String runCommand(String command) throws DeviceNotAvailableException { + protected String runCommand(String command) throws DeviceNotAvailableException { Log.d(TAG, "Command: '" + command + "'"); final String output = getDevice().executeShellCommand(command); if (DEBUG) Log.v(TAG, "Output: " + output.trim()); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 038cd132ec..9f0bfb8415 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -16,148 +16,78 @@ package com.android.cts.net; -import com.android.cts.migration.MigrationHelper; import com.android.ddmlib.Log; -import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; -import com.android.ddmlib.testrunner.TestIdentifier; -import com.android.ddmlib.testrunner.TestResult; -import com.android.ddmlib.testrunner.TestResult.TestStatus; -import com.android.ddmlib.testrunner.TestRunResult; -import com.android.tradefed.build.IBuildInfo; import com.android.tradefed.device.DeviceNotAvailableException; -import com.android.tradefed.result.CollectingTestListener; -import com.android.tradefed.testtype.DeviceTestCase; -import com.android.tradefed.testtype.IAbi; -import com.android.tradefed.testtype.IAbiReceiver; -import com.android.tradefed.testtype.IBuildReceiver; - -import java.io.FileNotFoundException; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class HostsideRestrictBackgroundNetworkTests extends DeviceTestCase implements IAbiReceiver, - IBuildReceiver { - private static final boolean DEBUG = false; - private static final String TAG = "HostsideNetworkTests"; - private static final String TEST_PKG = "com.android.cts.net.hostside"; - private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk"; +public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase { private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; private static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk"; - private IAbi mAbi; - private IBuildInfo mCtsBuild; - - @Override - public void setAbi(IAbi abi) { - mAbi = abi; - } - - @Override - public void setBuild(IBuildInfo buildInfo) { - mCtsBuild = buildInfo; - } + private int mUid; @Override protected void setUp() throws Exception { super.setUp(); - assertNotNull(mAbi); - assertNotNull(mCtsBuild); - setRestrictBackground(false); - - uninstallPackage(TEST_PKG, false); - installPackage(TEST_APK); - // TODO: split this class into HostsideVpnTests and HostsideConnectivityManagerTests so - // the former don't need to unnecessarily install app2. uninstallPackage(TEST_APP2_PKG, false); installPackage(TEST_APP2_APK); + + startBroadcastReceiverService(); + mUid = getUid(TEST_PKG); } @Override protected void tearDown() throws Exception { super.tearDown(); - uninstallPackage(TEST_PKG, true); uninstallPackage(TEST_APP2_PKG, true); - setRestrictBackground(false); } - public void testVpn() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest"); - } - - public void testConnectivityManager_getRestrictBackgroundStatus_disabled() throws Exception { - startBroadcastReceiverService(); - final int uid = getUid(TEST_PKG); - - removeRestrictBackgroundWhitelist(uid); + public void testGetRestrictBackgroundStatus_disabled() throws Exception { + removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatusDisabled(); assertRestrictBackgroundChangedReceivedOnce(); // Sanity check: make sure status is always disabled, never whitelisted - addRestrictBackgroundWhitelist(uid); + addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatusDisabled(); assertRestrictBackgroundChangedReceivedTwice(); } - public void testConnectivityManager_getRestrictBackgroundStatus_whitelisted() throws Exception { - startBroadcastReceiverService(); - final int uid = getUid(TEST_PKG); - + public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { setRestrictBackground(true); assertRestrictBackgroundChangedReceivedOnce(); - addRestrictBackgroundWhitelist(uid); + addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatusWhitelisted(); assertRestrictBackgroundChangedReceivedTwice(); } - public void testConnectivityManager_getRestrictBackgroundStatus_enabled() throws Exception { - startBroadcastReceiverService(); - final int uid = getUid(TEST_PKG); - + public void testGetRestrictBackgroundStatus_enabled() throws Exception { setRestrictBackground(true); assertRestrictBackgroundChangedReceivedOnce(); - removeRestrictBackgroundWhitelist(uid); + removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatusEnabled(); assertRestrictBackgroundChangedReceivedTwice(); } - public void testConnectivityManager_getRestrictBackgroundStatus_uninstall() throws Exception { - final int uid = getUid(TEST_PKG); - - addRestrictBackgroundWhitelist(uid); - assertRestrictBackgroundWhitelist(uid, true); + public void testGetRestrictBackgroundStatus_uninstall() throws Exception { + addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundWhitelist(mUid, true); uninstallPackage(TEST_PKG, true); assertPackageUninstalled(TEST_PKG); - assertRestrictBackgroundWhitelist(uid, false); + assertRestrictBackgroundWhitelist(mUid, false); installPackage(TEST_APK); final int newUid = getUid(TEST_PKG); - assertRestrictBackgroundWhitelist(uid, false); + assertRestrictBackgroundWhitelist(mUid, false); assertRestrictBackgroundWhitelist(newUid, false); } - private void installPackage(String apk) throws DeviceNotAvailableException, - FileNotFoundException { - assertNull(getDevice().installPackage( - MigrationHelper.getTestFile(mCtsBuild, apk), false)); - } - - private void uninstallPackage(String packageName, boolean shouldSucceed) - throws DeviceNotAvailableException { - final String result = getDevice().uninstallPackage(packageName); - if (shouldSucceed) { - assertNull("uninstallPackage(" + packageName + ") failed: " + result, result); - } - } - /** * Starts a service that will register a broadcast receiver to receive * {@code RESTRICT_BACKGROUND_CHANGE} intents. @@ -169,35 +99,6 @@ public class HostsideRestrictBackgroundNetworkTests extends DeviceTestCase imple runCommand("am startservice " + TEST_APP2_PKG + "/.MyService"); } - private void assertPackageUninstalled(String packageName) throws Exception { - final String command = "cmd package list packages " + packageName; - final int max_tries = 5; - for (int i = 1; i <= max_tries; i++) { - final String result = runCommand(command); - if (result.trim().isEmpty()) { - return; - } - // 'list packages' filters by substring, so we need to iterate with the results - // and check one by one, otherwise 'com.android.cts.net.hostside' could return - // 'com.android.cts.net.hostside.app2' - boolean found = false; - for (String line : result.split("[\\r\\n]+")) { - if (line.endsWith(packageName)) { - found = true; - break; - } - } - if (!found) { - return; - } - i++; - Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result - + "); sleeping 1s before polling again"); - Thread.sleep(1000); - } - fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds"); - } - private void assertRestrictBackgroundStatusDisabled() throws DeviceNotAvailableException { runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", "testGetRestrictBackgroundStatus_disabled"); @@ -223,62 +124,6 @@ public class HostsideRestrictBackgroundNetworkTests extends DeviceTestCase imple "testRestrictBackgroundChangedReceivedTwice"); } - public void runDeviceTests(String packageName, String testClassName) - throws DeviceNotAvailableException { - runDeviceTests(packageName, testClassName, null); - } - - public void runDeviceTests(String packageName, String testClassName, String methodName) - throws DeviceNotAvailableException { - RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, - "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); - - if (testClassName != null) { - if (methodName != null) { - testRunner.setMethodName(testClassName, methodName); - } else { - testRunner.setClassName(testClassName); - } - } - - final CollectingTestListener listener = new CollectingTestListener(); - getDevice().runInstrumentationTests(testRunner, listener); - - final TestRunResult result = listener.getCurrentRunResults(); - if (result.isRunFailure()) { - throw new AssertionError("Failed to successfully run device tests for " - + result.getName() + ": " + result.getRunFailureMessage()); - } - - if (result.hasFailedTests()) { - // build a meaningful error message - StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n"); - for (Map.Entry resultEntry : - result.getTestResults().entrySet()) { - if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) { - errorBuilder.append(resultEntry.getKey().toString()); - errorBuilder.append(":\n"); - errorBuilder.append(resultEntry.getValue().getStackTrace()); - } - } - throw new AssertionError(errorBuilder.toString()); - } - } - - private static final Pattern UID_PATTERN = - Pattern.compile(".*userId=([0-9]+)$", Pattern.MULTILINE); - - private int getUid(String packageName) throws DeviceNotAvailableException { - final String output = runCommand("dumpsys package " + packageName); - final Matcher matcher = UID_PATTERN.matcher(output); - while (matcher.find()) { - final String match = matcher.group(1); - return Integer.parseInt(match); - } - throw new RuntimeException("Did not find regexp '" + UID_PATTERN + "' on adb output\n" - + output); - } - private void addRestrictBackgroundWhitelist(int uid) throws Exception { runCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); @@ -314,11 +159,4 @@ public class HostsideRestrictBackgroundNetworkTests extends DeviceTestCase imple assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", output.endsWith(expectedSuffix)); } - - private String runCommand(String command) throws DeviceNotAvailableException { - Log.d(TAG, "Command: '" + command + "'"); - final String output = getDevice().executeShellCommand(command); - if (DEBUG) Log.v(TAG, "Output: " + output.trim()); - return output; - } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java new file mode 100644 index 0000000000..dc965c50f8 --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net; + +public class HostsideVpnTests extends HostsideNetworkTestCase { + + public void testVpn() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest"); + } +} From c50a6c7d4be14764ed08cd467b6b6053d2d4c161 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 8 Feb 2016 12:16:51 -0800 Subject: [PATCH 0206/1415] Improve CTS tests to really check background network restrictions. BUG: 26685616 Change-Id: If2b1649435b0a4e5b8c383eb3196807a03359d70 --- .../net/hostside/ConnectivityManagerTest.java | 61 +++++++++++++++---- ...ostsideRestrictBackgroundNetworkTests.java | 28 ++++++++- 2 files changed, 76 insertions(+), 13 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java index 300e39d55e..34c8d28f7f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java @@ -25,9 +25,14 @@ import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkInfo; import android.test.InstrumentationTestCase; import android.util.Log; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + /** * Tests for the {@link ConnectivityManager} API. * @@ -38,27 +43,36 @@ import android.util.Log; public class ConnectivityManagerTest extends InstrumentationTestCase { private static final String TAG = "ConnectivityManagerTest"; - static final String MANIFEST_RECEIVER = "ManifestReceiver"; - static final String DYNAMIC_RECEIVER = "DynamicReceiver"; + private static final String MANIFEST_RECEIVER = "ManifestReceiver"; + private static final String DYNAMIC_RECEIVER = "DynamicReceiver"; - private ConnectivityManager mCM; + private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; + private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; + + private ConnectivityManager mCm; + private int mUid; @Override public void setUp() throws Exception { super.setUp(); - mCM = (ConnectivityManager) getInstrumentation().getContext().getSystemService( - Activity.CONNECTIVITY_SERVICE); + final Context context = getInstrumentation().getContext(); + mCm = (ConnectivityManager) context.getSystemService(Activity.CONNECTIVITY_SERVICE); + mUid = context.getPackageManager() + .getPackageInfo(context.getPackageName(), 0).applicationInfo.uid; + final boolean metered = mCm.isActiveNetworkMetered(); + Log.i(TAG, getName() + ": uid=" + mUid + ", metered=" + metered); + assertTrue("Active network is not metered", metered); } - public void testGetRestrictBackgroundStatus_disabled() { + public void testGetRestrictBackgroundStatus_disabled() throws Exception { assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); } - public void testGetRestrictBackgroundStatus_whitelisted() { + public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); } - public void testGetRestrictBackgroundStatus_enabled() { + public void testGetRestrictBackgroundStatus_enabled() throws Exception { assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); } @@ -102,11 +116,34 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { return prefs.getInt(action, 0); } - private void assertRestrictBackgroundStatus(int expectedStatus) { - final String expected = toString(expectedStatus); + private void assertRestrictBackgroundStatus(int expectedApiStatus) throws InterruptedException { + // First asserts the API returns the proper value... + final String expected = toString(expectedApiStatus); Log.d(TAG, getName() + " (expecting " + expected + ")"); - final int actualStatus = mCM.getRestrictBackgroundStatus(); - assertEquals("wrong status", expected, toString(actualStatus)); + final int apiStatus = mCm.getRestrictBackgroundStatus(); + String actualApiStatus = toString(apiStatus); + assertEquals("wrong status", expected, actualApiStatus); + + //...then use a background thread to verify the actual network status. + final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); + new Thread(new Runnable() { + @Override + public void run() { + Log.d(TAG, "Running on thread " + Thread.currentThread().getName()); + final Network network = mCm.getActiveNetwork(); + final NetworkInfo networkInfo = mCm.getActiveNetworkInfo(); + Log.d(TAG, "activeNetwork: " + network + " activeNetworkInfo: " + networkInfo); + final String prefix = network == null ? + STATUS_NETWORK_UNAVAILABLE_PREFIX : STATUS_NETWORK_AVAILABLE_PREFIX; + result.offer(prefix + networkInfo); + } + }, "CheckNetworkThread").start(); + final String actualNetworkStatus = result.poll(10, TimeUnit.SECONDS); + assertNotNull("timeout waiting for background thread", actualNetworkStatus); + final String expectedPrefix = apiStatus == RESTRICT_BACKGROUND_STATUS_ENABLED ? + STATUS_NETWORK_UNAVAILABLE_PREFIX : STATUS_NETWORK_AVAILABLE_PREFIX; + assertTrue("Wrong network status for API status " + actualApiStatus + ": " + + actualNetworkStatus, actualNetworkStatus.startsWith(expectedPrefix)); } private String toString(int status) { diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 9f0bfb8415..2b0b1c16ba 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -18,23 +18,29 @@ package com.android.cts.net; import com.android.ddmlib.Log; import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.device.WifiHelper; public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase { private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; private static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk"; private int mUid; + private WifiHelper mWifiHelper; @Override protected void setUp() throws Exception { super.setUp(); + mUid = getUid(TEST_PKG); + mWifiHelper = new WifiHelper(getDevice()); + + setWifiMeteredStatus(true); setRestrictBackground(false); + uninstallPackage(TEST_APP2_PKG, false); installPackage(TEST_APP2_APK); startBroadcastReceiverService(); - mUid = getUid(TEST_PKG); } @Override @@ -43,6 +49,7 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC uninstallPackage(TEST_APP2_PKG, true); setRestrictBackground(false); + setWifiMeteredStatus(false); } public void testGetRestrictBackgroundStatus_disabled() throws Exception { @@ -151,6 +158,25 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC + expected + ", got " + actual); } + private void setWifiMeteredStatus(boolean metered) throws DeviceNotAvailableException { + mWifiHelper.enableWifi(); + // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests + // to make the actual verification of restrictions optional. + final String netId = mWifiHelper.getSSID(); + assertNotNull("null SSID", netId); + assertFalse("empty SSID", netId.trim().isEmpty()); + + Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); + final String setCommand = "cmd netpolicy set metered-network " + netId + " "+ metered; + final String result = runCommand(setCommand); + assertTrue("Command '" + setCommand + "' failed: " + result, result.trim().isEmpty()); + + // Sanity check. + final String newStatus = runCommand("cmd netpolicy get metered-network " + netId); + assertEquals("Metered status of wi-fi network " + netId + " not set properly", + newStatus.trim(), Boolean.toString(metered)); + } + private void setRestrictBackground(boolean enabled) throws DeviceNotAvailableException { runCommand("cmd netpolicy set restrict-background " + enabled); final String output = runCommand("cmd netpolicy get restrict-background ").trim(); From 38300a564a2b29c72781e421ef3d44a7f6d28291 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 10 Feb 2016 09:50:24 -0800 Subject: [PATCH 0207/1415] Refactored tests to make a real network connection. The current approach assumes that if the active network is null it is blocked for background access, but that's not the case. BUG: 26685616 Change-Id: Ic6990037a2bc503c14512d7303ec71eb178f784b --- .../net/hostside/ConnectivityManagerTest.java | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java index 34c8d28f7f..b27c80a0ad 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java @@ -25,11 +25,12 @@ import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.net.ConnectivityManager; -import android.net.Network; import android.net.NetworkInfo; import android.test.InstrumentationTestCase; import android.util.Log; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -49,6 +50,9 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; + private static final int NETWORK_TIMEOUT_MS = 15000; + private static final int SLEEP_TIME_SEC = 1; + private ConnectivityManager mCm; private int mUid; @@ -91,7 +95,6 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { int attempts = 0; int count = 0; final int maxAttempts = 5; - final int sleepTime = 10; do { attempts++; count = getNumberBroadcastsReceived(getInstrumentation().getContext(), receiverName, @@ -100,13 +103,14 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { break; } Log.d(TAG, "Count is " + count + " after " + attempts + " attempts; sleeping " - + sleepTime + " seconds before trying again"); - Thread.sleep(sleepTime * 1000); + + SLEEP_TIME_SEC + " seconds before trying again"); + Thread.sleep(SLEEP_TIME_SEC * 1000); } while (attempts <= maxAttempts); assertEquals("Number of expected broadcasts for " + receiverName + " not reached after " - + maxAttempts * sleepTime + " seconds", expectedCount, count); + + maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count); } + static int getNumberBroadcastsReceived(Context context, String receiverName, String action) throws Exception { final Context sharedContext = context.createPackageContext( @@ -129,13 +133,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { new Thread(new Runnable() { @Override public void run() { - Log.d(TAG, "Running on thread " + Thread.currentThread().getName()); - final Network network = mCm.getActiveNetwork(); - final NetworkInfo networkInfo = mCm.getActiveNetworkInfo(); - Log.d(TAG, "activeNetwork: " + network + " activeNetworkInfo: " + networkInfo); - final String prefix = network == null ? - STATUS_NETWORK_UNAVAILABLE_PREFIX : STATUS_NETWORK_AVAILABLE_PREFIX; - result.offer(prefix + networkInfo); + result.offer(checkNetworkStatus()); } }, "CheckNetworkThread").start(); final String actualNetworkStatus = result.poll(10, TimeUnit.SECONDS); @@ -146,6 +144,30 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { + actualNetworkStatus, actualNetworkStatus.startsWith(expectedPrefix)); } + protected String checkNetworkStatus() { + // TODO: connect to a hostside server instead + final String address = "http://example.com"; + final NetworkInfo networkInfo = mCm.getActiveNetworkInfo(); + Log.d(TAG, "Running checkNetworkStatus() on thread " + Thread.currentThread().getName() + + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address); + String prefix = STATUS_NETWORK_AVAILABLE_PREFIX; + try { + final URL url = new URL(address); + final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setReadTimeout(NETWORK_TIMEOUT_MS); + conn.setConnectTimeout(NETWORK_TIMEOUT_MS); + conn.setRequestMethod("GET"); + conn.setDoInput(true); + conn.connect(); + final int response = conn.getResponseCode(); + Log.d(TAG, "HTTP response for " + address + ": " + response); + } catch (Exception e) { + Log.d(TAG, "Exception getting " + address + ": " + e); + prefix = STATUS_NETWORK_UNAVAILABLE_PREFIX; + } + return prefix + networkInfo; + } + private String toString(int status) { switch (status) { case RESTRICT_BACKGROUND_STATUS_DISABLED: From a557ba681804c0cab73959c114bdaffe334fff2c Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 11 Feb 2016 11:56:30 -0800 Subject: [PATCH 0208/1415] Updated tests cases after to assert the proper number of notifications. Previously NMPS was broadcasting an intent every time add|removeRestrictBackgroundWhitelistedUid() was called, but that behavior has been changed to just broadcast an intent when there is a change. BUG: 26685616 Change-Id: I4eb7a4fda864a28ea23b661d1a88e18bfb80533d --- .../cts/net/hostside/ConnectivityManagerTest.java | 5 +++++ .../net/HostsideRestrictBackgroundNetworkTests.java | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java index b27c80a0ad..8975dabd3a 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java @@ -80,6 +80,11 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); } + public void testRestrictBackgroundChangedNotReceived() throws Exception { + assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 0); + assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); + } + public void testRestrictBackgroundChangedReceivedOnce() throws Exception { assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 1); assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 2b0b1c16ba..18047406cc 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -55,12 +55,13 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC public void testGetRestrictBackgroundStatus_disabled() throws Exception { removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatusDisabled(); - assertRestrictBackgroundChangedReceivedOnce(); + // From the app's point of view, nothing changed, it still have access + assertRestrictBackgroundChangedNotReceived(); // Sanity check: make sure status is always disabled, never whitelisted addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatusDisabled(); - assertRestrictBackgroundChangedReceivedTwice(); + assertRestrictBackgroundChangedNotReceived(); } public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { @@ -78,7 +79,7 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatusEnabled(); - assertRestrictBackgroundChangedReceivedTwice(); + assertRestrictBackgroundChangedReceivedOnce(); } public void testGetRestrictBackgroundStatus_uninstall() throws Exception { @@ -121,6 +122,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testGetRestrictBackgroundStatus_enabled"); } + private void assertRestrictBackgroundChangedNotReceived() throws DeviceNotAvailableException { + runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + "testRestrictBackgroundChangedNotReceived"); + } + private void assertRestrictBackgroundChangedReceivedOnce() throws DeviceNotAvailableException { runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", "testRestrictBackgroundChangedReceivedOnce"); From a0f49f2384fcbf1dff3b01d8511bd88effb600b6 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 18 Feb 2016 10:43:54 -0800 Subject: [PATCH 0209/1415] Refactored how data is shared between test apps. When running the device-site tests, it's necessary to share state between a second app and the main test app. Currently that's achieved through a shared preference file that is accessed by both apps (since they use a shared id), but this approach will not work on power save mode tests (because the test app will be in foreground and the background restrictions won't be applied in the second app). This change refactors the data sharing mechanism by: - Using an ordered broadcast that is sent from the test app to the secondary app. - Checking for the network status in the secondary app. - Moving the test logic to the client-side tests. BUG: 27127112 Change-Id: I44987701b908b329fdf40e3a7a97e9f30cfadecb --- tests/cts/hostside/app/AndroidManifest.xml | 7 +- .../net/hostside/ConnectivityManagerTest.java | 282 ++++++++++++------ tests/cts/hostside/app2/AndroidManifest.xml | 20 +- .../android/cts/net/hostside/app2/Common.java | 12 + .../hostside/app2/MyBroadcastReceiver.java | 126 +++++++- ...ostsideRestrictBackgroundNetworkTests.java | 133 +-------- 6 files changed, 362 insertions(+), 218 deletions(-) diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index f44fdd1dfc..c7978f8775 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -15,11 +15,12 @@ --> + package="com.android.cts.net.hostside"> - + + + diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java index 8975dabd3a..9a4f318ce8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java @@ -16,24 +16,26 @@ package com.android.cts.net.hostside; +import static android.cts.util.SystemUtil.runShellCommand; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.test.InstrumentationTestCase; -import android.util.Log; - -import java.net.HttpURLConnection; -import java.net.URL; +import java.io.IOException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import android.app.Instrumentation; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiManager; +import android.test.InstrumentationTestCase; +import android.util.Log; + /** * Tests for the {@link ConnectivityManager} API. * @@ -44,54 +46,91 @@ import java.util.concurrent.TimeUnit; public class ConnectivityManagerTest extends InstrumentationTestCase { private static final String TAG = "ConnectivityManagerTest"; + private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; + + private static final int SLEEP_TIME_SEC = 1; + private static final boolean DEBUG = true; + + // Constants below must match values defined on app2's Common.java private static final String MANIFEST_RECEIVER = "ManifestReceiver"; private static final String DYNAMIC_RECEIVER = "DynamicReceiver"; - + private static final String ACTION_GET_COUNTERS = + "com.android.cts.net.hostside.app2.action.GET_COUNTERS"; + private static final String ACTION_CHECK_NETWORK = + "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; + private static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; + private static final String EXTRA_RECEIVER_NAME = + "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; + private static final String RESULT_SEPARATOR = ";"; private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; - private static final int NETWORK_TIMEOUT_MS = 15000; - private static final int SLEEP_TIME_SEC = 1; - + private Context mContext; + private Instrumentation mInstrumentation; private ConnectivityManager mCm; + private WifiManager mWfm; private int mUid; + private boolean mResetMeteredWifi = false; @Override public void setUp() throws Exception { super.setUp(); - final Context context = getInstrumentation().getContext(); - mCm = (ConnectivityManager) context.getSystemService(Activity.CONNECTIVITY_SERVICE); - mUid = context.getPackageManager() - .getPackageInfo(context.getPackageName(), 0).applicationInfo.uid; - final boolean metered = mCm.isActiveNetworkMetered(); - Log.i(TAG, getName() + ": uid=" + mUid + ", metered=" + metered); - assertTrue("Active network is not metered", metered); + mInstrumentation = getInstrumentation(); + mContext = mInstrumentation.getContext(); + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mUid = mContext.getPackageManager().getPackageInfo(TEST_APP2_PKG, 0).applicationInfo.uid; + final int myUid = mContext.getPackageManager() + .getPackageInfo(mContext.getPackageName(), 0).applicationInfo.uid; + + Log.d(TAG, "UIDS: test app=" + myUid + ", app2=" + mUid); + + setRestrictBackground(false); + setMeteredNetwork(); + + registerApp2BroadcastReceiver(); } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + if (mResetMeteredWifi) { + setWifiMeteredStatus(false); + } + } + public void testGetRestrictBackgroundStatus_disabled() throws Exception { + removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertRestrictBackgroundChangedReceived(0); + + // Sanity check: make sure status is always disabled, never whitelisted + addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertRestrictBackgroundChangedReceived(0); } public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(1); + + addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + assertRestrictBackgroundChangedReceived(2); } public void testGetRestrictBackgroundStatus_enabled() throws Exception { + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(1); + + removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertRestrictBackgroundChangedReceived(1); } - public void testRestrictBackgroundChangedNotReceived() throws Exception { - assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 0); - assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); - } - - public void testRestrictBackgroundChangedReceivedOnce() throws Exception { - assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 1); - assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); - } - - public void testRestrictBackgroundChangedReceivedTwice() throws Exception { - assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 2); + public void assertRestrictBackgroundChangedReceived(int expectedCount) throws Exception { + assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, expectedCount); assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); } @@ -102,12 +141,12 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { final int maxAttempts = 5; do { attempts++; - count = getNumberBroadcastsReceived(getInstrumentation().getContext(), receiverName, - ACTION_RESTRICT_BACKGROUND_CHANGED); + count = getNumberBroadcastsReceived(receiverName, ACTION_RESTRICT_BACKGROUND_CHANGED); if (count == expectedCount) { break; } - Log.d(TAG, "Count is " + count + " after " + attempts + " attempts; sleeping " + Log.d(TAG, "Expecting count " + expectedCount + " but actual is " + count + " after " + + attempts + " attempts; sleeping " + SLEEP_TIME_SEC + " seconds before trying again"); Thread.sleep(SLEEP_TIME_SEC * 1000); } while (attempts <= maxAttempts); @@ -115,62 +154,139 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { + maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count); } + private String sendOrderedBroadcast(Intent intent) throws Exception { + final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); + Log.d(TAG, "Sending ordered broadcast: " + intent); + mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { - static int getNumberBroadcastsReceived(Context context, String receiverName, String action) - throws Exception { - final Context sharedContext = context.createPackageContext( - "com.android.cts.net.hostside.app2", Context.CONTEXT_IGNORE_SECURITY); - final SharedPreferences prefs = sharedContext.getSharedPreferences(receiverName, - Context.MODE_PRIVATE); - return prefs.getInt(action, 0); + @Override + public void onReceive(Context context, Intent intent) { + final String resultData = getResultData(); + if (resultData == null) { + Log.e(TAG, "Received null data from ordered intent"); + return; + } + result.offer(resultData); + } + }, null, 0, null, null); + + final String resultData = result.poll(60, TimeUnit.SECONDS); + assertNotNull("timeout waiting for ordered broadcast result", resultData); + Log.d(TAG, "Ordered broadcast response: " + resultData); + return resultData; } - private void assertRestrictBackgroundStatus(int expectedApiStatus) throws InterruptedException { - // First asserts the API returns the proper value... - final String expected = toString(expectedApiStatus); - Log.d(TAG, getName() + " (expecting " + expected + ")"); - final int apiStatus = mCm.getRestrictBackgroundStatus(); - String actualApiStatus = toString(apiStatus); - assertEquals("wrong status", expected, actualApiStatus); + private int getNumberBroadcastsReceived(String receiverName, String action) throws Exception { + final Intent intent = new Intent(ACTION_GET_COUNTERS); + intent.putExtra(EXTRA_ACTION, ACTION_RESTRICT_BACKGROUND_CHANGED); + intent.putExtra(EXTRA_RECEIVER_NAME, receiverName); + final String resultData = sendOrderedBroadcast(intent); + return Integer.valueOf(resultData); + } - //...then use a background thread to verify the actual network status. - final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); - new Thread(new Runnable() { - @Override - public void run() { - result.offer(checkNetworkStatus()); - } - }, "CheckNetworkThread").start(); - final String actualNetworkStatus = result.poll(10, TimeUnit.SECONDS); - assertNotNull("timeout waiting for background thread", actualNetworkStatus); - final String expectedPrefix = apiStatus == RESTRICT_BACKGROUND_STATUS_ENABLED ? - STATUS_NETWORK_UNAVAILABLE_PREFIX : STATUS_NETWORK_AVAILABLE_PREFIX; + private void assertRestrictBackgroundStatus(int expectedApiStatus) throws Exception { + final Intent intent = new Intent(ACTION_CHECK_NETWORK); + final String resultData = sendOrderedBroadcast(intent); + final String[] resultItems = resultData.split(RESULT_SEPARATOR); + final String actualApiStatus = toString(Integer.parseInt(resultItems[0])); + final String actualNetworkStatus = resultItems[1]; + + // First asserts the API returns the proper value... + assertEquals("wrong status", toString(expectedApiStatus), actualApiStatus); + + //...then the actual network status in the background thread. + final String expectedPrefix = expectedApiStatus == RESTRICT_BACKGROUND_STATUS_ENABLED ? + STATUS_NETWORK_UNAVAILABLE_PREFIX : STATUS_NETWORK_AVAILABLE_PREFIX; assertTrue("Wrong network status for API status " + actualApiStatus + ": " + actualNetworkStatus, actualNetworkStatus.startsWith(expectedPrefix)); } - protected String checkNetworkStatus() { - // TODO: connect to a hostside server instead - final String address = "http://example.com"; - final NetworkInfo networkInfo = mCm.getActiveNetworkInfo(); - Log.d(TAG, "Running checkNetworkStatus() on thread " + Thread.currentThread().getName() - + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address); - String prefix = STATUS_NETWORK_AVAILABLE_PREFIX; - try { - final URL url = new URL(address); - final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setReadTimeout(NETWORK_TIMEOUT_MS); - conn.setConnectTimeout(NETWORK_TIMEOUT_MS); - conn.setRequestMethod("GET"); - conn.setDoInput(true); - conn.connect(); - final int response = conn.getResponseCode(); - Log.d(TAG, "HTTP response for " + address + ": " + response); - } catch (Exception e) { - Log.d(TAG, "Exception getting " + address + ": " + e); - prefix = STATUS_NETWORK_UNAVAILABLE_PREFIX; + private String executeShellCommand(String command) throws IOException { + final String result = runShellCommand(mInstrumentation, command).trim(); + if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'"); + return result; + } + + private void setMeteredNetwork() throws IOException { + final NetworkInfo info = mCm.getActiveNetworkInfo(); + final boolean metered = mCm.isActiveNetworkMetered(); + if (metered) { + Log.d(TAG, "Active network already metered: " + info); + return; } - return prefix + networkInfo; + final String netId = setWifiMeteredStatus(true); + assertTrue("Could not set wifi '" + netId + "' as metered (" + + mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered()); + // Set flag so status is reverted on teardown. + mResetMeteredWifi = true; + } + + private String setWifiMeteredStatus(boolean metered) throws IOException { + mWfm.setWifiEnabled(true); + // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests + // to make the actual verification of restrictions optional. + final String ssid = mWfm.getConnectionInfo().getSSID(); + assertNotNull("null SSID", ssid); + final String netId = ssid.trim().replaceAll("\"", ""); // remove quotes, if any. + assertFalse("empty SSID", ssid.isEmpty()); + + Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); + final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered; + final String result = executeShellCommand(setCommand); + assertTrue("Command '" + setCommand + "' failed: " + result, result.isEmpty()); + + // Sanity check. + final String newStatus = executeShellCommand("cmd netpolicy get metered-network " + netId); + assertEquals("Metered status of wi-fi network " + netId + " not set properly", + newStatus.trim(), Boolean.toString(metered)); + return netId; + } + + private void setRestrictBackground(boolean enabled) throws IOException { + executeShellCommand("cmd netpolicy set restrict-background " + enabled); + final String output = executeShellCommand("cmd netpolicy get restrict-background "); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + // TODO: use MoreAsserts? + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + + private void addRestrictBackgroundWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, true); + } + + private void removeRestrictBackgroundWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy remove restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, false); + } + + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { + final int maxTries = 5; + boolean actual = false; + for (int i = 1; i <= maxTries; i++) { + final String output = + executeShellCommand("cmd netpolicy list restrict-background-whitelist "); + actual = output.contains(Integer.toString(uid)); + if (expected == actual) { + return; + } + Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected " + + expected + ", got " + actual + "); sleeping 1s before polling again"); + Thread.sleep(1000); + } + fail("whitelist check for uid " + uid + " failed: expected " + expected + ", got " + actual); + } + + /** + * Starts a service that will register a broadcast receiver to receive + * {@code RESTRICT_BACKGROUND_CHANGE} intents. + *

+ * The service must run in a separate app because otherwise it would be killed every time + * {@link #runDeviceTests(String, String)} is executed. + */ + private void registerApp2BroadcastReceiver() throws IOException { + executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService"); } private String toString(int status) { diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml index d69bf56a1c..fa4cb43d29 100644 --- a/tests/cts/hostside/app2/AndroidManifest.xml +++ b/tests/cts/hostside/app2/AndroidManifest.xml @@ -16,20 +16,28 @@ --> + package="com.android.cts.net.hostside.app2" > - - + + + diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index 91caeda97d..3be4261258 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -18,6 +18,18 @@ package com.android.cts.net.hostside.app2; public final class Common { static final String TAG = "CtsNetApp2"; + + // Constants below must match values defined on app's ConnectivityManagerTest.java static final String MANIFEST_RECEIVER = "ManifestReceiver"; static final String DYNAMIC_RECEIVER = "DynamicReceiver"; + static final String ACTION_GET_COUNTERS = + "com.android.cts.net.hostside.app2.action.GET_COUNTERS"; + static final String ACTION_CHECK_NETWORK = + "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; + static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; + static final String EXTRA_RECEIVER_NAME = + "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; + static final char RESULT_SEPARATOR = ';'; + static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; + static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; } diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 0cbf360d8f..65c7b6009d 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -13,21 +13,44 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.cts.net.hostside.app2; +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; +import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK; +import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS; +import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION; +import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME; import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; +import static com.android.cts.net.hostside.app2.Common.RESULT_SEPARATOR; +import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_AVAILABLE_PREFIX; +import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_UNAVAILABLE_PREFIX; import static com.android.cts.net.hostside.app2.Common.TAG; + +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.util.Log; /** - * Receiver that stores received broadcasts in a shared preference. + * Receiver used to: + *

    + *
  1. Stored received RESTRICT_BACKGROUND_CHANGED broadcasts in a shared preference. + *
  2. Returned the number of RESTRICT_BACKGROUND_CHANGED broadcasts in an ordered broadcast. + *
*/ public class MyBroadcastReceiver extends BroadcastReceiver { + private static final int NETWORK_TIMEOUT_MS = 15 * 1000; + private final String mName; public MyBroadcastReceiver() { @@ -37,15 +60,106 @@ public class MyBroadcastReceiver extends BroadcastReceiver { MyBroadcastReceiver(String name) { Log.d(TAG, "Constructing MyBroadcastReceiver named " + name); mName = name; - } + } @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "onReceive() for " + mName + ": " + intent); + final String action = intent.getAction(); + switch (action) { + case ACTION_RESTRICT_BACKGROUND_CHANGED: + increaseCounter(context, action); + break; + case ACTION_GET_COUNTERS: + setResultDataFromCounter(context, intent); + break; + case ACTION_CHECK_NETWORK: + checkNetwork(context, intent); + break; + default: + Log.e(TAG, "received unexpected action: " + action); + } + } + + private void increaseCounter(Context context, String action) { final SharedPreferences prefs = context.getSharedPreferences(mName, Context.MODE_PRIVATE); - final String pref = intent.getAction(); - final int value = prefs.getInt(pref, 0) + 1; - Log.d(TAG, "Setting " + pref + " = " + value); - prefs.edit().putInt(pref, value).apply(); + final int value = prefs.getInt(action, 0) + 1; + Log.d(TAG, "increaseCounter('" + action + "'): setting '" + mName + "' to " + value); + prefs.edit().putInt(action, value).apply(); + } + + private int getCounter(Context context, String action, String receiverName) { + final SharedPreferences prefs = context.getSharedPreferences(receiverName, + Context.MODE_PRIVATE); + final int value = prefs.getInt(action, 0); + Log.d(TAG, "getCounter('" + action + "', '" + receiverName + "'): " + value); + return value; + } + + private void checkNetwork(final Context context, Intent intent) { + final ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + + final StringBuilder data = new StringBuilder(); + final int apiStatus = cm.getRestrictBackgroundStatus(); + String netStatus; + try { + netStatus = checkNetworkStatus(cm); + } catch (InterruptedException e) { + Log.e(TAG, "Timeout checking network status"); + setResultData(null); + return; + } + data.append(apiStatus).append(RESULT_SEPARATOR).append(netStatus); + Log.d(TAG, "checkNetwork: returning " + data); + setResultData(data.toString()); + } + + private String checkNetworkStatus(final ConnectivityManager cm) throws InterruptedException { + final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); + new Thread(new Runnable() { + + @Override + public void run() { + // TODO: connect to a hostside server instead + final String address = "http://example.com"; + final NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + Log.d(TAG, "Running checkNetworkStatus() on thread " + + Thread.currentThread().getName() + + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address); + String prefix = STATUS_NETWORK_AVAILABLE_PREFIX; + try { + final URL url = new URL(address); + final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setReadTimeout(NETWORK_TIMEOUT_MS); + conn.setConnectTimeout(NETWORK_TIMEOUT_MS); + conn.setRequestMethod("GET"); + conn.setDoInput(true); + conn.connect(); + final int response = conn.getResponseCode(); + Log.d(TAG, "HTTP response for " + address + ": " + response); + } catch (Exception e) { + Log.d(TAG, "Exception getting " + address + ": " + e); + prefix = STATUS_NETWORK_UNAVAILABLE_PREFIX + "Exception " + e + ":"; + } + result.offer(prefix + networkInfo); + } + }, mName).start(); + return result.poll(NETWORK_TIMEOUT_MS * 2, TimeUnit.MILLISECONDS); + } + + private void setResultDataFromCounter(Context context, Intent intent) { + final String action = intent.getStringExtra(EXTRA_ACTION); + if (action == null) { + Log.e(TAG, "Missing extra '" + EXTRA_ACTION + "' on " + intent); + return; + } + final String receiverName = intent.getStringExtra(EXTRA_RECEIVER_NAME); + if (receiverName == null) { + Log.e(TAG, "Missing extra '" + EXTRA_RECEIVER_NAME + "' on " + intent); + return; + } + final int counter = getCounter(context, action, receiverName); + setResultData(String.valueOf(counter)); } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 18047406cc..f2c3b1f7d2 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -17,30 +17,19 @@ package com.android.cts.net; import com.android.ddmlib.Log; -import com.android.tradefed.device.DeviceNotAvailableException; -import com.android.tradefed.device.WifiHelper; public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase { + private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; private static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk"; - private int mUid; - private WifiHelper mWifiHelper; - @Override protected void setUp() throws Exception { super.setUp(); - mUid = getUid(TEST_PKG); - mWifiHelper = new WifiHelper(getDevice()); - - setWifiMeteredStatus(true); - setRestrictBackground(false); - uninstallPackage(TEST_APP2_PKG, false); installPackage(TEST_APP2_APK); - startBroadcastReceiverService(); } @Override @@ -48,103 +37,35 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC super.tearDown(); uninstallPackage(TEST_APP2_PKG, true); - setRestrictBackground(false); - setWifiMeteredStatus(false); } public void testGetRestrictBackgroundStatus_disabled() throws Exception { - removeRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatusDisabled(); - // From the app's point of view, nothing changed, it still have access - assertRestrictBackgroundChangedNotReceived(); - - // Sanity check: make sure status is always disabled, never whitelisted - addRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatusDisabled(); - assertRestrictBackgroundChangedNotReceived(); - } - - public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { - setRestrictBackground(true); - assertRestrictBackgroundChangedReceivedOnce(); - - addRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatusWhitelisted(); - assertRestrictBackgroundChangedReceivedTwice(); - } - - public void testGetRestrictBackgroundStatus_enabled() throws Exception { - setRestrictBackground(true); - assertRestrictBackgroundChangedReceivedOnce(); - - removeRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatusEnabled(); - assertRestrictBackgroundChangedReceivedOnce(); - } - - public void testGetRestrictBackgroundStatus_uninstall() throws Exception { - addRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundWhitelist(mUid, true); - - uninstallPackage(TEST_PKG, true); - assertPackageUninstalled(TEST_PKG); - assertRestrictBackgroundWhitelist(mUid, false); - - installPackage(TEST_APK); - final int newUid = getUid(TEST_PKG); - assertRestrictBackgroundWhitelist(mUid, false); - assertRestrictBackgroundWhitelist(newUid, false); - } - - /** - * Starts a service that will register a broadcast receiver to receive - * {@code RESTRICT_BACKGROUND_CHANGE} intents. - *

- * The service must run in a separate app because otherwise it would be killed every time - * {@link #runDeviceTests(String, String)} is executed. - */ - private void startBroadcastReceiverService() throws DeviceNotAvailableException { - runCommand("am startservice " + TEST_APP2_PKG + "/.MyService"); - } - - private void assertRestrictBackgroundStatusDisabled() throws DeviceNotAvailableException { runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", "testGetRestrictBackgroundStatus_disabled"); } - private void assertRestrictBackgroundStatusWhitelisted() throws DeviceNotAvailableException { + public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", "testGetRestrictBackgroundStatus_whitelisted"); } - private void assertRestrictBackgroundStatusEnabled() throws DeviceNotAvailableException { + public void testGetRestrictBackgroundStatus_enabled() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", "testGetRestrictBackgroundStatus_enabled"); } - private void assertRestrictBackgroundChangedNotReceived() throws DeviceNotAvailableException { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", - "testRestrictBackgroundChangedNotReceived"); - } + public void testGetRestrictBackgroundStatus_uninstall() throws Exception { + final int oldUid = getUid(TEST_PKG); + testGetRestrictBackgroundStatus_whitelisted(); - private void assertRestrictBackgroundChangedReceivedOnce() throws DeviceNotAvailableException { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", - "testRestrictBackgroundChangedReceivedOnce"); - } + uninstallPackage(TEST_PKG, true); + assertPackageUninstalled(TEST_PKG); + assertRestrictBackgroundWhitelist(oldUid, false); - private void assertRestrictBackgroundChangedReceivedTwice() throws DeviceNotAvailableException { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", - "testRestrictBackgroundChangedReceivedTwice"); - } - - private void addRestrictBackgroundWhitelist(int uid) throws Exception { - runCommand("cmd netpolicy add restrict-background-whitelist " + uid); - assertRestrictBackgroundWhitelist(uid, true); - } - - private void removeRestrictBackgroundWhitelist(int uid) throws Exception { - runCommand("cmd netpolicy remove restrict-background-whitelist " + uid); - assertRestrictBackgroundWhitelist(uid, false); + installPackage(TEST_APK); + final int newUid = getUid(TEST_PKG); + assertRestrictBackgroundWhitelist(oldUid, false); + assertRestrictBackgroundWhitelist(newUid, false); } private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { @@ -163,32 +84,4 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC fail("whitelist check for uid " + uid + " failed: expected " + expected + ", got " + actual); } - - private void setWifiMeteredStatus(boolean metered) throws DeviceNotAvailableException { - mWifiHelper.enableWifi(); - // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests - // to make the actual verification of restrictions optional. - final String netId = mWifiHelper.getSSID(); - assertNotNull("null SSID", netId); - assertFalse("empty SSID", netId.trim().isEmpty()); - - Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); - final String setCommand = "cmd netpolicy set metered-network " + netId + " "+ metered; - final String result = runCommand(setCommand); - assertTrue("Command '" + setCommand + "' failed: " + result, result.trim().isEmpty()); - - // Sanity check. - final String newStatus = runCommand("cmd netpolicy get metered-network " + netId); - assertEquals("Metered status of wi-fi network " + netId + " not set properly", - newStatus.trim(), Boolean.toString(metered)); - } - - private void setRestrictBackground(boolean enabled) throws DeviceNotAvailableException { - runCommand("cmd netpolicy set restrict-background " + enabled); - final String output = runCommand("cmd netpolicy get restrict-background ").trim(); - final String expectedSuffix = enabled ? "enabled" : "disabled"; - // TODO: use MoreAsserts? - assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", - output.endsWith(expectedSuffix)); - } } From 0a0857762a05c5b7e80a2fab5142aa4ea91eed18 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 18 Feb 2016 17:22:33 -0800 Subject: [PATCH 0210/1415] Split client-side test in 2 classes so some common code can be used to test Power Save Mode. BUG: 27127112 Change-Id: I6954ce8474da6da678d4bfe194334ed5a08aaeff --- ...actRestrictBackgroundNetworkTestCase.java} | 78 +++++-------------- .../cts/net/hostside/DataSaverModeTest.java | 61 +++++++++++++++ ...ostsideRestrictBackgroundNetworkTests.java | 6 +- 3 files changed, 85 insertions(+), 60 deletions(-) rename tests/cts/hostside/app/src/com/android/cts/net/hostside/{ConnectivityManagerTest.java => AbstractRestrictBackgroundNetworkTestCase.java} (78%) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java similarity index 78% rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java rename to tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 9a4f318ce8..59de7593b2 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -37,14 +37,10 @@ import android.test.InstrumentationTestCase; import android.util.Log; /** - * Tests for the {@link ConnectivityManager} API. - * - *

These tests rely on a host-side test to use {@code adb shell cmd netpolicy} to put the device - * in the proper state. In fact, they're more like "assertions" than tests per se - the real test - * logic is done on {@code HostsideNetworkTests}. + * Superclass for tests related to background network restrictions. */ -public class ConnectivityManagerTest extends InstrumentationTestCase { - private static final String TAG = "ConnectivityManagerTest"; +abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase { + protected static final String TAG = "RestrictBackgroundNetworkTests"; private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; @@ -65,11 +61,11 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; - private Context mContext; - private Instrumentation mInstrumentation; - private ConnectivityManager mCm; - private WifiManager mWfm; - private int mUid; + protected Context mContext; + protected Instrumentation mInstrumentation; + protected ConnectivityManager mCm; + protected WifiManager mWfm; + protected int mUid; private boolean mResetMeteredWifi = false; @Override @@ -85,10 +81,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { Log.d(TAG, "UIDS: test app=" + myUid + ", app2=" + mUid); - setRestrictBackground(false); setMeteredNetwork(); - - registerApp2BroadcastReceiver(); } @Override @@ -100,41 +93,12 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { } } - public void testGetRestrictBackgroundStatus_disabled() throws Exception { - removeRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - assertRestrictBackgroundChangedReceived(0); - - // Sanity check: make sure status is always disabled, never whitelisted - addRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - assertRestrictBackgroundChangedReceived(0); - } - - public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { - setRestrictBackground(true); - assertRestrictBackgroundChangedReceived(1); - - addRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); - assertRestrictBackgroundChangedReceived(2); - } - - public void testGetRestrictBackgroundStatus_enabled() throws Exception { - setRestrictBackground(true); - assertRestrictBackgroundChangedReceived(1); - - removeRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); - assertRestrictBackgroundChangedReceived(1); - } - - public void assertRestrictBackgroundChangedReceived(int expectedCount) throws Exception { + protected void assertRestrictBackgroundChangedReceived(int expectedCount) throws Exception { assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, expectedCount); assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); } - private void assertRestrictBackgroundChangedReceived(String receiverName, int expectedCount) + protected void assertRestrictBackgroundChangedReceived(String receiverName, int expectedCount) throws Exception { int attempts = 0; int count = 0; @@ -154,7 +118,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { + maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count); } - private String sendOrderedBroadcast(Intent intent) throws Exception { + protected String sendOrderedBroadcast(Intent intent) throws Exception { final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); Log.d(TAG, "Sending ordered broadcast: " + intent); mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { @@ -176,7 +140,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { return resultData; } - private int getNumberBroadcastsReceived(String receiverName, String action) throws Exception { + protected int getNumberBroadcastsReceived(String receiverName, String action) throws Exception { final Intent intent = new Intent(ACTION_GET_COUNTERS); intent.putExtra(EXTRA_ACTION, ACTION_RESTRICT_BACKGROUND_CHANGED); intent.putExtra(EXTRA_RECEIVER_NAME, receiverName); @@ -184,7 +148,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { return Integer.valueOf(resultData); } - private void assertRestrictBackgroundStatus(int expectedApiStatus) throws Exception { + protected void assertRestrictBackgroundStatus(int expectedApiStatus) throws Exception { final Intent intent = new Intent(ACTION_CHECK_NETWORK); final String resultData = sendOrderedBroadcast(intent); final String[] resultItems = resultData.split(RESULT_SEPARATOR); @@ -201,13 +165,13 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { + actualNetworkStatus, actualNetworkStatus.startsWith(expectedPrefix)); } - private String executeShellCommand(String command) throws IOException { + protected String executeShellCommand(String command) throws IOException { final String result = runShellCommand(mInstrumentation, command).trim(); if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'"); return result; } - private void setMeteredNetwork() throws IOException { + protected void setMeteredNetwork() throws IOException { final NetworkInfo info = mCm.getActiveNetworkInfo(); final boolean metered = mCm.isActiveNetworkMetered(); if (metered) { @@ -221,7 +185,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { mResetMeteredWifi = true; } - private String setWifiMeteredStatus(boolean metered) throws IOException { + protected String setWifiMeteredStatus(boolean metered) throws IOException { mWfm.setWifiEnabled(true); // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests // to make the actual verification of restrictions optional. @@ -242,7 +206,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { return netId; } - private void setRestrictBackground(boolean enabled) throws IOException { + protected void setRestrictBackground(boolean enabled) throws IOException { executeShellCommand("cmd netpolicy set restrict-background " + enabled); final String output = executeShellCommand("cmd netpolicy get restrict-background "); final String expectedSuffix = enabled ? "enabled" : "disabled"; @@ -251,17 +215,17 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { output.endsWith(expectedSuffix)); } - private void addRestrictBackgroundWhitelist(int uid) throws Exception { + protected void addRestrictBackgroundWhitelist(int uid) throws Exception { executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); } - private void removeRestrictBackgroundWhitelist(int uid) throws Exception { + protected void removeRestrictBackgroundWhitelist(int uid) throws Exception { executeShellCommand("cmd netpolicy remove restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, false); } - private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { + protected void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { final int maxTries = 5; boolean actual = false; for (int i = 1; i <= maxTries; i++) { @@ -285,7 +249,7 @@ public class ConnectivityManagerTest extends InstrumentationTestCase { * The service must run in a separate app because otherwise it would be killed every time * {@link #runDeviceTests(String, String)} is executed. */ - private void registerApp2BroadcastReceiver() throws IOException { + protected void registerApp2BroadcastReceiver() throws IOException { executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService"); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java new file mode 100644 index 0000000000..c62189ed23 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; + +public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { + + @Override + public void setUp() throws Exception { + super.setUp(); + + setRestrictBackground(false); + registerApp2BroadcastReceiver(); + } + + public void testGetRestrictBackgroundStatus_disabled() throws Exception { + removeRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertRestrictBackgroundChangedReceived(0); + + // Sanity check: make sure status is always disabled, never whitelisted + addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertRestrictBackgroundChangedReceived(0); + } + + public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(1); + + addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + assertRestrictBackgroundChangedReceived(2); + } + + public void testGetRestrictBackgroundStatus_enabled() throws Exception { + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(1); + + removeRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertRestrictBackgroundChangedReceived(1); + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index f2c3b1f7d2..21e5aa7f48 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -40,17 +40,17 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC } public void testGetRestrictBackgroundStatus_disabled() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", "testGetRestrictBackgroundStatus_disabled"); } public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", "testGetRestrictBackgroundStatus_whitelisted"); } public void testGetRestrictBackgroundStatus_enabled() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest", + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", "testGetRestrictBackgroundStatus_enabled"); } From 31c9ec9cb4d42cb5bd7bbd7d0a287d9d8e35f481 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 23 Feb 2016 11:24:54 -0800 Subject: [PATCH 0211/1415] Added CTS tests to check background network access while on power save mode. BUG: 27127112 Change-Id: Ifa3019d7b94459d737a9dff80b4b36a2dd43aca5 --- ...ractRestrictBackgroundNetworkTestCase.java | 116 +++++++++++++++--- .../net/hostside/BatterySaverModeTest.java | 55 +++++++++ .../cts/net/hostside/DataSaverModeTest.java | 7 ++ .../hostside/app2/MyBroadcastReceiver.java | 5 +- ...ostsideRestrictBackgroundNetworkTests.java | 62 +++++++++- 5 files changed, 224 insertions(+), 21 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 59de7593b2..3f80b5a406 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -22,7 +22,6 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -import java.io.IOException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -42,7 +41,8 @@ import android.util.Log; abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase { protected static final String TAG = "RestrictBackgroundNetworkTests"; - private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; + protected static final String TEST_PKG = "com.android.cts.net.hostside"; + protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; private static final int SLEEP_TIME_SEC = 1; private static final boolean DEBUG = true; @@ -60,6 +60,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private static final String RESULT_SEPARATOR = ";"; private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; + private static final int NETWORK_TIMEOUT_MS = 15 * 1000; + + // Must be higher than NETWORK_TIMEOUT_MS + private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4; protected Context mContext; protected Instrumentation mInstrumentation; @@ -134,8 +138,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } }, null, 0, null, null); - final String resultData = result.poll(60, TimeUnit.SECONDS); - assertNotNull("timeout waiting for ordered broadcast result", resultData); + final String resultData = result.poll(ORDERED_BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS); Log.d(TAG, "Ordered broadcast response: " + resultData); return resultData; } @@ -145,6 +148,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation intent.putExtra(EXTRA_ACTION, ACTION_RESTRICT_BACKGROUND_CHANGED); intent.putExtra(EXTRA_RECEIVER_NAME, receiverName); final String resultData = sendOrderedBroadcast(intent); + assertNotNull("timeout waiting for ordered broadcast result", resultData); return Integer.valueOf(resultData); } @@ -153,25 +157,73 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final String resultData = sendOrderedBroadcast(intent); final String[] resultItems = resultData.split(RESULT_SEPARATOR); final String actualApiStatus = toString(Integer.parseInt(resultItems[0])); - final String actualNetworkStatus = resultItems[1]; - // First asserts the API returns the proper value... assertEquals("wrong status", toString(expectedApiStatus), actualApiStatus); //...then the actual network status in the background thread. - final String expectedPrefix = expectedApiStatus == RESTRICT_BACKGROUND_STATUS_ENABLED ? - STATUS_NETWORK_UNAVAILABLE_PREFIX : STATUS_NETWORK_AVAILABLE_PREFIX; - assertTrue("Wrong network status for API status " + actualApiStatus + ": " - + actualNetworkStatus, actualNetworkStatus.startsWith(expectedPrefix)); + final String networkStatus = getNetworkStatus(resultItems); + assertNetworkStatus(expectedApiStatus != RESTRICT_BACKGROUND_STATUS_ENABLED, networkStatus); } - protected String executeShellCommand(String command) throws IOException { + protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { + final Intent intent = new Intent(ACTION_CHECK_NETWORK); + final String resultData = sendOrderedBroadcast(intent); + final String[] resultItems = resultData.split(RESULT_SEPARATOR); + final String networkStatus = getNetworkStatus(resultItems); + assertNetworkStatus(expectAllowed, networkStatus); + } + + private String getNetworkStatus(String[] resultItems) { + return resultItems.length < 2 ? null : resultItems[1]; + } + + private void assertNetworkStatus(boolean expectAvailable, String status) throws Exception { + if (status == null) { + Log.d(TAG, "timeout waiting for ordered broadcast"); + if (expectAvailable) { + fail("did not get network status when access was allowed"); + } + return; + } + final String expectedPrefix = expectAvailable ? + STATUS_NETWORK_AVAILABLE_PREFIX : STATUS_NETWORK_UNAVAILABLE_PREFIX; + assertTrue("Wrong network status (" + status + ") when expectedAvailable is " + + expectAvailable, status.startsWith(expectedPrefix)); + } + + protected String executeShellCommand(String command) throws Exception { final String result = runShellCommand(mInstrumentation, command).trim(); if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'"); return result; } - protected void setMeteredNetwork() throws IOException { + /** + * Runs a Shell command which is not expected to generate output. + */ + protected void executeSilentShellCommand(String command) throws Exception { + final String result = executeShellCommand(command); + assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty()); + } + + /** + * Asserts the result of a command, wait and re-running it a couple times if necessary. + */ + protected void assertDelayedShellCommand(String command, String expectedResult) + throws Exception { + final int maxTries = 5; + for (int i = 1; i <= maxTries; i++) { + final String result = executeShellCommand(command).trim(); + if (result.equals(expectedResult)) + return; + Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" + + expectedResult + "' on attempt #; sleeping 1s before polling again"); + Thread.sleep(1000); + } + fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries + + " attempts"); + } + + protected void setMeteredNetwork() throws Exception { final NetworkInfo info = mCm.getActiveNetworkInfo(); final boolean metered = mCm.isActiveNetworkMetered(); if (metered) { @@ -185,7 +237,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mResetMeteredWifi = true; } - protected String setWifiMeteredStatus(boolean metered) throws IOException { + protected String setWifiMeteredStatus(boolean metered) throws Exception { mWfm.setWifiEnabled(true); // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests // to make the actual verification of restrictions optional. @@ -206,7 +258,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return netId; } - protected void setRestrictBackground(boolean enabled) throws IOException { + protected void setRestrictBackground(boolean enabled) throws Exception { executeShellCommand("cmd netpolicy set restrict-background " + enabled); final String output = executeShellCommand("cmd netpolicy get restrict-background "); final String expectedSuffix = enabled ? "enabled" : "disabled"; @@ -242,6 +294,40 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("whitelist check for uid " + uid + " failed: expected " + expected + ", got " + actual); } + protected void assertPowerSaveModeWhitelist(String packageName, boolean expected) + throws Exception { + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + assertDelayedShellCommand("dumpsys deviceidle whitelist =" + packageName, + Boolean.toString(expected)); + } + + protected void addPowerSaveModeWhitelist(String packageName) throws Exception { + Log.i(TAG, "Adding package " + packageName + " to power-save-mode whitelist"); + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + executeShellCommand("dumpsys deviceidle whitelist +" + packageName); + assertPowerSaveModeWhitelist(packageName, true); // Sanity check + } + + protected void removePowerSaveModeWhitelist(String packageName) throws Exception { + Log.i(TAG, "Removing package " + packageName + " from power-save-mode whitelist"); + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + executeShellCommand("dumpsys deviceidle whitelist -" + packageName); + assertPowerSaveModeWhitelist(packageName, false); // Sanity check + } + + protected void setPowerSaveMode(boolean enabled) throws Exception { + Log.i(TAG, "Setting power mode to " + enabled); + if (enabled) { + executeSilentShellCommand("cmd battery unplug"); + executeSilentShellCommand("settings put global low_power 1"); + } else { + executeSilentShellCommand("cmd battery reset"); + } + } + /** * Starts a service that will register a broadcast receiver to receive * {@code RESTRICT_BACKGROUND_CHANGE} intents. @@ -249,7 +335,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation * The service must run in a separate app because otherwise it would be killed every time * {@link #runDeviceTests(String, String)} is executed. */ - protected void registerApp2BroadcastReceiver() throws IOException { + protected void registerApp2BroadcastReceiver() throws Exception { executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService"); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java new file mode 100644 index 0000000000..29a0309bd1 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { + + @Override + public void setUp() throws Exception { + super.setUp(); + + setPowerSaveMode(false); + assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check + registerApp2BroadcastReceiver(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + setPowerSaveMode(false); + } + + public void testBackgroundNetworkAccess_enabled() throws Exception { + setPowerSaveMode(true); + assertBackgroundNetworkAccess(false); + } + + public void testBackgroundNetworkAccess_whitelisted() throws Exception { + setPowerSaveMode(true); + assertBackgroundNetworkAccess(false); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + } + + public void testBackgroundNetworkAccess_disabled() throws Exception { + setPowerSaveMode(false); + assertBackgroundNetworkAccess(true); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index c62189ed23..ccb1fe9600 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -30,6 +30,13 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase registerApp2BroadcastReceiver(); } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + setRestrictBackground(false); + } + public void testGetRestrictBackgroundStatus_disabled() throws Exception { removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 65c7b6009d..f32bd44d79 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -110,7 +110,10 @@ public class MyBroadcastReceiver extends BroadcastReceiver { setResultData(null); return; } - data.append(apiStatus).append(RESULT_SEPARATOR).append(netStatus); + data.append(apiStatus).append(RESULT_SEPARATOR); + if (netStatus != null) { + data.append(netStatus); + } Log.d(TAG, "checkNetwork: returning " + data); setResultData(data.toString()); } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 21e5aa7f48..4786450c42 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -17,6 +17,7 @@ package com.android.cts.net; import com.android.ddmlib.Log; +import com.android.tradefed.device.DeviceNotAvailableException; public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase { @@ -39,24 +40,24 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC uninstallPackage(TEST_APP2_PKG, true); } - public void testGetRestrictBackgroundStatus_disabled() throws Exception { + public void testDataSaverMode_disabled() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", "testGetRestrictBackgroundStatus_disabled"); } - public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { + public void testDataSaverMode_whitelisted() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", "testGetRestrictBackgroundStatus_whitelisted"); } - public void testGetRestrictBackgroundStatus_enabled() throws Exception { + public void testDataSaverMode_enabled() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", "testGetRestrictBackgroundStatus_enabled"); } - public void testGetRestrictBackgroundStatus_uninstall() throws Exception { + public void testDataSaverMode_reinstall() throws Exception { final int oldUid = getUid(TEST_PKG); - testGetRestrictBackgroundStatus_whitelisted(); + testDataSaverMode_whitelisted(); uninstallPackage(TEST_PKG, true); assertPackageUninstalled(TEST_PKG); @@ -68,6 +69,32 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC assertRestrictBackgroundWhitelist(newUid, false); } + public void testBatterySaverMode_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testBatterySaverMode_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testBatterySaverMode_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest", + "testBackgroundNetworkAccess_enabled"); + } + + public void testBatterySaverMode_reinstall() throws Exception { + testBatterySaverMode_whitelisted(); + + uninstallPackage(TEST_PKG, true); + assertPackageUninstalled(TEST_PKG); + assertPowerSaveModeWhitelist(TEST_PKG, false); + + installPackage(TEST_APK); + assertPowerSaveModeWhitelist(TEST_PKG, false); + } + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { final int max_tries = 5; boolean actual = false; @@ -84,4 +111,29 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC fail("whitelist check for uid " + uid + " failed: expected " + expected + ", got " + actual); } + + private void assertPowerSaveModeWhitelist(String packageName, boolean expected) + throws Exception { + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + assertDelayedCommand("dumpsys deviceidle whitelist =" + packageName, + Boolean.toString(expected)); + } + + /** + * Asserts the result of a command, wait and re-running it a couple times if necessary. + */ + private void assertDelayedCommand(String command, String expectedResult) + throws InterruptedException, DeviceNotAvailableException { + final int maxTries = 5; + for (int i = 1; i <= maxTries; i++) { + final String result = runCommand(command).trim(); + if (result.equals(expectedResult)) return; + Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" + + expectedResult + "' on attempt #; sleeping 1s before polling again"); + Thread.sleep(1000); + } + fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries + + " attempts"); + } } From 4b05fbd1e7201b15aba4b9ac490a3cc065004147 Mon Sep 17 00:00:00 2001 From: Edward Savage-Jones Date: Thu, 25 Feb 2016 00:36:09 +0100 Subject: [PATCH 0212/1415] Swapped memset params memset bug Change-Id: Icf173de400ae1cfcffd590b3fb789c54f6a55bae --- tests/cts/net/jni/NativeDnsJni.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 4eb3c7aebc..352c0c52cc 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -126,7 +126,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas return JNI_FALSE; } - memset(buf, sizeof(buf), 0); + memset(buf, 0, sizeof(buf)); res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, From a9e563cf831498fd7d0788610ca22e0c64815d9b Mon Sep 17 00:00:00 2001 From: Stuart Scott Date: Thu, 18 Feb 2016 19:25:52 -0800 Subject: [PATCH 0213/1415] Switch to CTSv2 bug:21762834 Change-Id: Ie51a0ed4560b46c2f360e14980e5fab7fe6479fe --- tests/cts/hostside/Android.mk | 6 +++--- tests/cts/hostside/app/Android.mk | 4 ++-- tests/cts/net/Android.mk | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/cts/hostside/Android.mk b/tests/cts/hostside/Android.mk index b4e1e3dafe..ad97ecdc6b 100644 --- a/tests/cts/hostside/Android.mk +++ b/tests/cts/hostside/Android.mk @@ -21,14 +21,14 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_MODULE := CtsHostsideNetworkTests -LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt +LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork -# Tag this module as a cts_v2 test artifact -LOCAL_COMPATIBILITY_SUITE := cts_v2 +# Tag this module as a cts test artifact +LOCAL_COMPATIBILITY_SUITE := cts include $(BUILD_CTS_HOST_JAVA_LIBRARY) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index b64c4c95f2..7f8da07943 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -29,7 +29,7 @@ LOCAL_PACKAGE_NAME := CtsHostsideNetworkTestsApp LOCAL_PROGUARD_ENABLED := disabled LOCAL_DEX_PREOPT := false -# Tag this module as a cts_v2 test artifact -LOCAL_COMPATIBILITY_SUITE := cts_v2 +# Tag this module as a cts test artifact +LOCAL_COMPATIBILITY_SUITE := cts include $(BUILD_CTS_SUPPORT_PACKAGE) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 608ea47bc7..c553a9bb2e 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -40,8 +40,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support ctsdeviceutil \ # uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current -# Tag this module as a cts_v2 test artifact -LOCAL_COMPATIBILITY_SUITE := cts_v2 +# Tag this module as a cts test artifact +LOCAL_COMPATIBILITY_SUITE := cts include $(BUILD_CTS_PACKAGE) From d207fe5bebdba93d0d65a54dadaa45dea33b6023 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 1 Mar 2016 16:31:58 -0800 Subject: [PATCH 0214/1415] Tagged app2 as a CTS test artifact. BUG: 27436960 Change-Id: I4e97b6341dae3361f4efdaec3132a7aa9a38dece --- tests/cts/hostside/app2/Android.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/hostside/app2/Android.mk b/tests/cts/hostside/app2/Android.mk index e330bf7508..3b59f8f6ce 100644 --- a/tests/cts/hostside/app2/Android.mk +++ b/tests/cts/hostside/app2/Android.mk @@ -28,4 +28,7 @@ LOCAL_PACKAGE_NAME := CtsHostsideNetworkTestsApp2 LOCAL_PROGUARD_ENABLED := disabled LOCAL_DEX_PREOPT := false +# Tag this module as a cts test artifact +LOCAL_COMPATIBILITY_SUITE := cts + include $(BUILD_CTS_SUPPORT_PACKAGE) From 37c0bf0477fe4f087ae0b65152f3459ed267193b Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 1 Mar 2016 13:53:27 -0800 Subject: [PATCH 0215/1415] Added CTS tests for apps that are blacklisted for restricted background data. BUG: 27432317 Change-Id: Ie9156ab4f2fa7c639d8e9a978954e09b322d6187 --- ...ractRestrictBackgroundNetworkTestCase.java | 54 ++++++++++++++++--- .../cts/net/hostside/DataSaverModeTest.java | 24 +++++++++ .../android/cts/net/hostside/app2/Common.java | 5 +- .../hostside/app2/MyBroadcastReceiver.java | 6 +++ .../cts/net/hostside/app2/MyService.java | 10 +++- ...ostsideRestrictBackgroundNetworkTests.java | 5 ++ 6 files changed, 93 insertions(+), 11 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 3f80b5a406..73a5d57e42 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -54,13 +54,16 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation "com.android.cts.net.hostside.app2.action.GET_COUNTERS"; private static final String ACTION_CHECK_NETWORK = "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; + private static final String ACTION_RECEIVER_READY = + "com.android.cts.net.hostside.app2.action.RECEIVER_READY"; private static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; private static final String EXTRA_RECEIVER_NAME = "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; private static final String RESULT_SEPARATOR = ";"; private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; - private static final int NETWORK_TIMEOUT_MS = 15 * 1000; + private static final int SECOND_IN_MS = 1000; + private static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; // Must be higher than NETWORK_TIMEOUT_MS private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4; @@ -116,13 +119,17 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation Log.d(TAG, "Expecting count " + expectedCount + " but actual is " + count + " after " + attempts + " attempts; sleeping " + SLEEP_TIME_SEC + " seconds before trying again"); - Thread.sleep(SLEEP_TIME_SEC * 1000); + Thread.sleep(SLEEP_TIME_SEC * SECOND_IN_MS); } while (attempts <= maxAttempts); assertEquals("Number of expected broadcasts for " + receiverName + " not reached after " + maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count); } protected String sendOrderedBroadcast(Intent intent) throws Exception { + return sendOrderedBroadcast(intent, ORDERED_BROADCAST_TIMEOUT_MS); + } + + protected String sendOrderedBroadcast(Intent intent, int timeoutMs) throws Exception { final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); Log.d(TAG, "Sending ordered broadcast: " + intent); mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { @@ -138,7 +145,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } }, null, 0, null, null); - final String resultData = result.poll(ORDERED_BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS); + final String resultData = result.poll(timeoutMs, TimeUnit.MILLISECONDS); Log.d(TAG, "Ordered broadcast response: " + resultData); return resultData; } @@ -217,7 +224,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return; Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" + expectedResult + "' on attempt #; sleeping 1s before polling again"); - Thread.sleep(1000); + Thread.sleep(SECOND_IN_MS); } fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries + " attempts"); @@ -278,20 +285,38 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { + assertRestrictBackground("restrict-background-whitelist", uid, expected); + } + + protected void addRestrictBackgroundBlacklist(int uid) throws Exception { + executeShellCommand("cmd netpolicy add restrict-background-blacklist " + uid); + assertRestrictBackgroundBlacklist(uid, true); + } + + protected void removeRestrictBackgroundBlacklist(int uid) throws Exception { + executeShellCommand("cmd netpolicy remove restrict-background-blacklist " + uid); + assertRestrictBackgroundBlacklist(uid, false); + } + + protected void assertRestrictBackgroundBlacklist(int uid, boolean expected) throws Exception { + assertRestrictBackground("restrict-background-blacklist", uid, expected); + } + + private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception { final int maxTries = 5; boolean actual = false; for (int i = 1; i <= maxTries; i++) { final String output = - executeShellCommand("cmd netpolicy list restrict-background-whitelist "); + executeShellCommand("cmd netpolicy list " + list); actual = output.contains(Integer.toString(uid)); if (expected == actual) { return; } - Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected " + Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected " + expected + ", got " + actual + "); sleeping 1s before polling again"); - Thread.sleep(1000); + Thread.sleep(SECOND_IN_MS); } - fail("whitelist check for uid " + uid + " failed: expected " + expected + ", got " + actual); + fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual); } protected void assertPowerSaveModeWhitelist(String packageName, boolean expected) @@ -337,6 +362,19 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation */ protected void registerApp2BroadcastReceiver() throws Exception { executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService"); + // Wait until receiver is ready. + final int maxTries = 5; + for (int i = 1; i <= maxTries; i++) { + final String message = + sendOrderedBroadcast(new Intent(ACTION_RECEIVER_READY), SECOND_IN_MS); + Log.d(TAG, "app2 receiver acked: " + message); + if (message != null) { + return; + } + Log.v(TAG, "app2 receiver is not ready yet; sleeping 1s before polling again"); + Thread.sleep(SECOND_IN_MS); + } + fail("app2 receiver is not ready"); } private String toString(int status) { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index ccb1fe9600..61593a1226 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -65,4 +65,28 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); assertRestrictBackgroundChangedReceived(1); } + + public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { + addRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(1); + + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + + // TODO: currently whitelist is prevailing, hence remaining of the test below is disabled + if (true) return; + + // Make sure blacklist prevails over whitelist. + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(2); + addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + + // Check status after removing blacklist. + removeRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + assertRestrictBackgroundChangedReceived(3); + setRestrictBackground(false); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertRestrictBackgroundChangedReceived(4); + } } diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index 3be4261258..f5f5fafa31 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -19,13 +19,16 @@ public final class Common { static final String TAG = "CtsNetApp2"; - // Constants below must match values defined on app's ConnectivityManagerTest.java + // Constants below must match values defined on app's + // AbstractRestrictBackgroundNetworkTestCase.java static final String MANIFEST_RECEIVER = "ManifestReceiver"; static final String DYNAMIC_RECEIVER = "DynamicReceiver"; static final String ACTION_GET_COUNTERS = "com.android.cts.net.hostside.app2.action.GET_COUNTERS"; static final String ACTION_CHECK_NETWORK = "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; + static final String ACTION_RECEIVER_READY = + "com.android.cts.net.hostside.app2.action.RECEIVER_READY"; static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; static final String EXTRA_RECEIVER_NAME = "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index f32bd44d79..94ec6af7ee 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -19,6 +19,7 @@ package com.android.cts.net.hostside.app2; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK; import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS; +import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION; import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME; import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; @@ -76,6 +77,11 @@ public class MyBroadcastReceiver extends BroadcastReceiver { case ACTION_CHECK_NETWORK: checkNetwork(context, intent); break; + case ACTION_RECEIVER_READY: + final String message = mName + " is ready to rumble"; + Log.d(TAG, message); + setResultData(message); + break; default: Log.e(TAG, "received unexpected action: " + action); } diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java index 882bb62c2c..55249f2208 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java @@ -16,9 +16,12 @@ package com.android.cts.net.hostside.app2; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; +import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER; import static com.android.cts.net.hostside.app2.Common.TAG; + import android.app.Service; +import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; @@ -37,8 +40,11 @@ public class MyService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: " + intent); - getApplicationContext().registerReceiver(new MyBroadcastReceiver(DYNAMIC_RECEIVER), - new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED)); + final Context context = getApplicationContext(); + final MyBroadcastReceiver myReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER); + context.registerReceiver(myReceiver, new IntentFilter(ACTION_RECEIVER_READY)); + context.registerReceiver(myReceiver, new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED)); + Log.d(TAG, "receiver registered"); return START_STICKY; } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 4786450c42..eade26184d 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -55,6 +55,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testGetRestrictBackgroundStatus_enabled"); } + public void testDataSaverMode_blacklisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", + "testGetRestrictBackgroundStatus_blacklisted"); + } + public void testDataSaverMode_reinstall() throws Exception { final int oldUid = getUid(TEST_PKG); testDataSaverMode_whitelisted(); From d7f1dbef6694f4389d0df76ed292b84f746b4ae0 Mon Sep 17 00:00:00 2001 From: Wally Yau Date: Mon, 7 Mar 2016 16:16:09 -0800 Subject: [PATCH 0216/1415] Fixed test for lingering traffic data. Change-Id: I7d68a518e25e17dbbaa57b12e2af4dc57b8df8d3 --- tests/cts/net/src/android/net/cts/TrafficStatsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 5b93beead5..a8dd8acecc 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -215,7 +215,7 @@ public class TrafficStatsTest extends AndroidTestCase { if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); // Make sure that not too many non-localhost packets are accounted for - assertTrue("too many non-localhost packets on the sam UID", deltaTxOtherPackets + deltaTxOtherPackets < 20); + assertTrue("too many non-localhost packets on the same UID", deltaTxOtherPackets + deltaRxOtherPackets < 20); } assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + From b3cc6ef3ae22dcee15910db24e840edcd0931acd Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 7 Mar 2016 15:20:58 -0800 Subject: [PATCH 0217/1415] Added tests for battery save mode on non-metered networks. BUG: 27127112 Change-Id: I4a05194a32294d15badfaa4156606e728f943a9a --- ...ractRestrictBackgroundNetworkTestCase.java | 2 - .../BatterySaverModeNonMeteredTest.java | 56 +++++++++++++++++++ .../net/hostside/BatterySaverModeTest.java | 2 + .../cts/net/hostside/DataSaverModeTest.java | 1 + ...ostsideRestrictBackgroundNetworkTests.java | 15 +++++ 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 73a5d57e42..def3439eef 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -87,8 +87,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation .getPackageInfo(mContext.getPackageName(), 0).applicationInfo.uid; Log.d(TAG, "UIDS: test app=" + myUid + ", app2=" + mUid); - - setMeteredNetwork(); } @Override diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java new file mode 100644 index 0000000000..5181057d85 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +//TODO: move this and BatterySaverModeTest's logic into a common superclass +public class BatterySaverModeNonMeteredTest extends AbstractRestrictBackgroundNetworkTestCase { + + @Override + public void setUp() throws Exception { + super.setUp(); + + setPowerSaveMode(false); + assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check + registerApp2BroadcastReceiver(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + setPowerSaveMode(false); + } + + public void testBackgroundNetworkAccess_enabled() throws Exception { + setPowerSaveMode(true); + assertBackgroundNetworkAccess(false); + } + + public void testBackgroundNetworkAccess_whitelisted() throws Exception { + setPowerSaveMode(true); + assertBackgroundNetworkAccess(false); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + } + + public void testBackgroundNetworkAccess_disabled() throws Exception { + setPowerSaveMode(false); + assertBackgroundNetworkAccess(true); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java index 29a0309bd1..18e2b3e054 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java @@ -16,12 +16,14 @@ package com.android.cts.net.hostside; +//TODO: move this and BatterySaverModeNonMeteredTest's logic into a common superclass public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { @Override public void setUp() throws Exception { super.setUp(); + setMeteredNetwork(); setPowerSaveMode(false); assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check registerApp2BroadcastReceiver(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 61593a1226..b9fca39312 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -26,6 +26,7 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase public void setUp() throws Exception { super.setUp(); + setMeteredNetwork(); setRestrictBackground(false); registerApp2BroadcastReceiver(); } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index eade26184d..2bd76e6c93 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -100,6 +100,21 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC assertPowerSaveModeWhitelist(TEST_PKG, false); } + public void testBatteryBatterySaverModeNonMeteredTest_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testBatteryBatterySaverModeNonMeteredTest_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testBatteryBatterySaverModeNonMeteredTest_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { final int max_tries = 5; boolean actual = false; From f448ccd08d7795b319ca00985a2fed54947f65be Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 9 Mar 2016 12:28:36 -0800 Subject: [PATCH 0218/1415] Print uid when running network checks. BUG: 27570398 Change-Id: I4dcbd4e41641c406c687a0e29e2637581d91b17c --- .../com/android/cts/net/hostside/app2/Common.java | 13 +++++++++++++ .../cts/net/hostside/app2/MyBroadcastReceiver.java | 12 ++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index f5f5fafa31..668669bc2e 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -15,6 +15,10 @@ */ package com.android.cts.net.hostside.app2; +import android.content.Context; +import android.content.pm.PackageManager.NameNotFoundException; +import android.util.Log; + public final class Common { static final String TAG = "CtsNetApp2"; @@ -35,4 +39,13 @@ public final class Common { static final char RESULT_SEPARATOR = ';'; static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; + + static int getUid(Context context) { + final String packageName = context.getPackageName(); + try { + return context.getPackageManager().getPackageUid(packageName, 0); + } catch (NameNotFoundException e) { + throw new IllegalStateException("Could not get UID for " + packageName, e); + } + } } diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 94ec6af7ee..07f717b192 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -27,6 +27,7 @@ import static com.android.cts.net.hostside.app2.Common.RESULT_SEPARATOR; import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_AVAILABLE_PREFIX; import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_UNAVAILABLE_PREFIX; import static com.android.cts.net.hostside.app2.Common.TAG; +import static com.android.cts.net.hostside.app2.Common.getUid; import java.net.HttpURLConnection; import java.net.URL; @@ -110,7 +111,7 @@ public class MyBroadcastReceiver extends BroadcastReceiver { final int apiStatus = cm.getRestrictBackgroundStatus(); String netStatus; try { - netStatus = checkNetworkStatus(cm); + netStatus = checkNetworkStatus(context, cm); } catch (InterruptedException e) { Log.e(TAG, "Timeout checking network status"); setResultData(null); @@ -124,7 +125,8 @@ public class MyBroadcastReceiver extends BroadcastReceiver { setResultData(data.toString()); } - private String checkNetworkStatus(final ConnectivityManager cm) throws InterruptedException { + private String checkNetworkStatus(final Context context, final ConnectivityManager cm) + throws InterruptedException { final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); new Thread(new Runnable() { @@ -134,7 +136,7 @@ public class MyBroadcastReceiver extends BroadcastReceiver { final String address = "http://example.com"; final NetworkInfo networkInfo = cm.getActiveNetworkInfo(); Log.d(TAG, "Running checkNetworkStatus() on thread " - + Thread.currentThread().getName() + + Thread.currentThread().getName() + " for UID " + getUid(context) + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address); String prefix = STATUS_NETWORK_AVAILABLE_PREFIX; try { @@ -151,7 +153,9 @@ public class MyBroadcastReceiver extends BroadcastReceiver { Log.d(TAG, "Exception getting " + address + ": " + e); prefix = STATUS_NETWORK_UNAVAILABLE_PREFIX + "Exception " + e + ":"; } - result.offer(prefix + networkInfo); + final String netInfo = prefix + networkInfo; + Log.d(TAG, "Offering " + netInfo); + result.offer(netInfo); } }, mName).start(); return result.poll(NETWORK_TIMEOUT_MS * 2, TimeUnit.MILLISECONDS); From 2bbc892a8081a59e434c423c5e6c9d6bb6651907 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 14 Mar 2016 12:07:07 -0700 Subject: [PATCH 0219/1415] Wifi Cts: Set 'disableOthers' flag in enableNetwork Wifi framework only enables a network if it is going to connect to it which is not the case when 'disableOthers' flag is false. BUG: 27567420 Change-Id: I45d39f4f8efebd7e19fd0bcf5bd97a68d08217ee --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 4478bd4c52..55fd1f5722 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -373,7 +373,7 @@ public class WifiManagerTest extends AndroidTestCase { assertTrue(notExist != pos); // Enable & disable network - boolean disableOthers = false; + boolean disableOthers = true; assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); assertDisableOthers(wifiConfiguration, disableOthers); From 744f5e2688d7ab24c7c960acf7a3ee46ebd4f761 Mon Sep 17 00:00:00 2001 From: Kevin Ma Date: Mon, 14 Mar 2016 13:10:02 -0700 Subject: [PATCH 0220/1415] Add Airplane mode test. Change-Id: If3bfa92828cdc878b2f994beafc41faba7398feb --- tests/cts/net/AndroidManifest.xml | 1 + .../src/android/net/cts/AirplaneModeTest.java | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/AirplaneModeTest.java diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 001e2946b1..848ed995b6 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -28,6 +28,7 @@ + diff --git a/tests/cts/net/src/android/net/cts/AirplaneModeTest.java b/tests/cts/net/src/android/net/cts/AirplaneModeTest.java new file mode 100644 index 0000000000..0a3146cbcc --- /dev/null +++ b/tests/cts/net/src/android/net/cts/AirplaneModeTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 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 android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.lang.Thread; + +public class AirplaneModeTest extends AndroidTestCase { + private static final String TAG = "AirplaneModeTest"; + private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; + private static final String FEATURE_WIFI = "android.hardware.wifi"; + private static final int TIMEOUT_MS = 10 * 1000; + private boolean mHasFeature; + private Context mContext; + private ContentResolver resolver; + + public void setup() { + mContext= getContext(); + resolver = mContext.getContentResolver(); + mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH) + || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI)); + } + + public void testAirplaneMode() { + setup(); + if (!mHasFeature) { + Log.i(TAG, "The device doesn't support network bluetooth or wifi feature"); + return; + } + + for (int testCount = 0; testCount < 2; testCount++) { + if (!doOneTest()) { + fail("Airplane mode failed to change in " + TIMEOUT_MS + "msec"); + return; + } + } + } + + private boolean doOneTest() { + boolean airplaneModeOn = isAirplaneModeOn(); + setAirplaneModeOn(!airplaneModeOn); + + try { + Thread.sleep(TIMEOUT_MS); + } catch (InterruptedException e) { + Log.e(TAG, "Sleep time interrupted.", e); + } + + if (airplaneModeOn == isAirplaneModeOn()) { + return false; + } + return true; + } + + private void setAirplaneModeOn(boolean enabling) { + // Change the system setting for airplane mode + Settings.Global.putInt(resolver, Settings.Global.AIRPLANE_MODE_ON, enabling ? 1 : 0); + } + + private boolean isAirplaneModeOn() { + // Read the system setting for airplane mode + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) != 0; + } +} From d857ae7745c7b865a1fdbfbf1754c3840fbdc705 Mon Sep 17 00:00:00 2001 From: Kevin Ma Date: Mon, 14 Mar 2016 13:59:21 -0700 Subject: [PATCH 0221/1415] Add theater mode test. Change-Id: Ie4c4d690fc1b10e917104536e7224c667365db6e --- .../src/android/net/cts/TheaterModeTest.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/TheaterModeTest.java diff --git a/tests/cts/net/src/android/net/cts/TheaterModeTest.java b/tests/cts/net/src/android/net/cts/TheaterModeTest.java new file mode 100644 index 0000000000..10fca6fd74 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/TheaterModeTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 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 android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.lang.Thread; + +public class TheaterModeTest extends AndroidTestCase { + private static final String TAG = "TheaterModeTest"; + private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; + private static final String FEATURE_WIFI = "android.hardware.wifi"; + private static final int TIMEOUT_MS = 10 * 1000; + private boolean mHasFeature; + private Context mContext; + private ContentResolver resolver; + + public void setup() { + mContext= getContext(); + resolver = mContext.getContentResolver(); + mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH) + || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI)); + } + + public void testTheaterMode() { + setup(); + if (!mHasFeature) { + Log.i(TAG, "The device doesn't support network bluetooth or wifi feature"); + return; + } + + for (int testCount = 0; testCount < 2; testCount++) { + if (!doOneTest()) { + fail("Theater mode failed to change in " + TIMEOUT_MS + "msec"); + return; + } + } + } + + private boolean doOneTest() { + boolean theaterModeOn = isTheaterModeOn(); + + setTheaterModeOn(!theaterModeOn); + try { + Thread.sleep(TIMEOUT_MS); + } catch (InterruptedException e) { + Log.e(TAG, "Sleep time interrupted.", e); + } + + if (theaterModeOn == isTheaterModeOn()) { + return false; + } + return true; + } + + private void setTheaterModeOn(boolean enabling) { + // Change the system setting for theater mode + Settings.Global.putInt(resolver, Settings.Global.THEATER_MODE_ON, enabling ? 1 : 0); + } + + private boolean isTheaterModeOn() { + // Read the system setting for theater mode + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0) != 0; + } +} From 104fd51f871d99cb7ccf64ff0decc6071b7d2630 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Wed, 16 Mar 2016 09:44:34 -0700 Subject: [PATCH 0222/1415] WifiManagerTest#testWifiWatchdog: Disambiguate failures There is nothing in the WifiWatchdog test that supports the assumption that the device under test is pre-configured with a working WiFi network configuration. This CL makes it possible from the test stack trace whether the test failed at the beginning or during the reconnections. Bug: 27638295 Change-Id: Iff1bd398c74076fb1a969741818562ea582e868e --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 55fd1f5722..5497454bfd 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -484,6 +484,9 @@ public class WifiManagerTest extends AndroidTestCase { } assertTrue(mWifiManager.isWifiEnabled()); + // This will generate a distinct stack trace if the initial connection fails. + connectWifi(); + int i = 0; for (; i < 15; i++) { // Wait for a WiFi connection From 275d05f0d3efa8d90670883786bf14b2b4364c27 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 17 Mar 2016 14:08:46 -0700 Subject: [PATCH 0223/1415] Re-try commands that set/get metered networks. BUG: 27671582 Change-Id: I9160a964b44e6d48d8932dc1e1ea7702a5359885 --- .../AbstractRestrictBackgroundNetworkTestCase.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index def3439eef..adaaf84848 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -221,7 +221,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (result.equals(expectedResult)) return; Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" - + expectedResult + "' on attempt #; sleeping 1s before polling again"); + + expectedResult + "' on attempt #" + i + "; sleeping 1s before trying again"); Thread.sleep(SECOND_IN_MS); } fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries @@ -253,13 +253,12 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered; - final String result = executeShellCommand(setCommand); - assertTrue("Command '" + setCommand + "' failed: " + result, result.isEmpty()); + assertDelayedShellCommand(setCommand, ""); // Sanity check. - final String newStatus = executeShellCommand("cmd netpolicy get metered-network " + netId); - assertEquals("Metered status of wi-fi network " + netId + " not set properly", - newStatus.trim(), Boolean.toString(metered)); + final String getCommand = "cmd netpolicy get metered-network " + netId; + assertDelayedShellCommand(getCommand, Boolean.toString(metered)); + return netId; } From a55231798284f72b3869aa74fcbe627209dcc40a Mon Sep 17 00:00:00 2001 From: Nicholas Sauer Date: Fri, 18 Mar 2016 17:08:24 -0700 Subject: [PATCH 0224/1415] [CTS] - Set test runtimes bug: 27747405 Change-Id: If08ec156678d5435c88d9f179d3bacd064493aff --- tests/cts/hostside/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 4b6994a082..9945805252 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -16,5 +16,6 @@ From ebbfd8ce11d6c82404860874b89d4f7c8c2f43f2 Mon Sep 17 00:00:00 2001 From: Ningyuan Wang Date: Tue, 22 Mar 2016 16:20:27 -0700 Subject: [PATCH 0225/1415] handle null mScanResult for CTS test This adds one more assert statement to ensure the ScanResult variable is not null before we proceed. Bug: 27744749 TEST=run cts test without error Change-Id: I48f3c5369792d3a55b594b71250b0dfdf0d5282b --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 5497454bfd..897e5cfe8e 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -296,6 +296,8 @@ public class WifiManagerTest extends AndroidTestCase { for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) { startScan(); // Make sure at least one AP is found. + assertTrue("mScanResult should not be null. This may be due to a scan timeout", + mScanResults != null); assertFalse("empty scan results!", mScanResults.isEmpty()); long nowMillis = SystemClock.elapsedRealtime(); // Keep track of how many APs are fresh in one scan. From 10788e7864f750e276814342ae647cb0caac5679 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Wed, 16 Mar 2016 10:56:48 -0700 Subject: [PATCH 0226/1415] Test that we can set and read txt records. Bug: 27696905 Change-Id: I494665adeb8a859791bb5d08fe5b6ee73f20ac8d --- .../android/net/wifi/cts/NsdManagerTest.java | 146 +++++++++++++++++- 1 file changed, 140 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java index e132cce25f..2e2e75b359 100644 --- a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java @@ -24,6 +24,7 @@ import android.util.Log; import java.io.IOException; import java.net.ServerSocket; +import java.util.Arrays; import java.util.Random; import java.util.List; import java.util.ArrayList; @@ -41,6 +42,7 @@ public class NsdManagerTest extends AndroidTestCase { NsdManager.RegistrationListener mRegistrationListener; NsdManager.DiscoveryListener mDiscoveryListener; NsdManager.ResolveListener mResolveListener; + private NsdServiceInfo mResolvedService; public NsdManagerTest() { initRegistrationListener(); @@ -119,6 +121,7 @@ public class NsdManagerTest extends AndroidTestCase { @Override public void onServiceResolved(NsdServiceInfo serviceInfo) { + mResolvedService = serviceInfo; setEvent("onServiceResolved", serviceInfo); } }; @@ -254,14 +257,87 @@ public class NsdManagerTest extends AndroidTestCase { if (DBG) Log.d(TAG, "Tear down test ..."); } - public void runTest() throws Exception { + public void testNDSManager() throws Exception { + EventData lastEvent = null; + + if (DBG) Log.d(TAG, "Starting test ..."); + NsdServiceInfo si = new NsdServiceInfo(); si.setServiceType(SERVICE_TYPE); si.setServiceName(mServiceName); - EventData lastEvent = null; + byte testByteArray[] = new byte[] {-128, 127, 2, 1, 0, 1, 2}; + String String256 = "1_________2_________3_________4_________5_________6_________" + + "7_________8_________9_________10________11________12________13________" + + "14________15________16________17________18________19________20________" + + "21________22________23________24________25________123456"; - if (DBG) Log.d(TAG, "Starting test ..."); + // Illegal attributes + try { + si.setAttribute(null, (String) null); + fail("Could set null key"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + si.setAttribute("", (String) null); + fail("Could set empty key"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + si.setAttribute(String256, (String) null); + fail("Could set key with 255 characters"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + si.setAttribute("key", String256.substring(3)); + fail("Could set key+value combination with more than 255 characters"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + si.setAttribute("key", String256.substring(4)); + fail("Could set key+value combination with 255 characters"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + si.setAttribute(new String(new byte[]{0x19}), (String) null); + fail("Could set key with invalid character"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + si.setAttribute("=", (String) null); + fail("Could set key with invalid character"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + si.setAttribute(new String(new byte[]{0x7F}), (String) null); + fail("Could set key with invalid character"); + } catch (IllegalArgumentException e) { + // expected + } + + // Allowed attributes + si.setAttribute("booleanAttr", (String) null); + si.setAttribute("keyValueAttr", "value"); + si.setAttribute("keyEqualsAttr", "="); + si.setAttribute(" whiteSpaceKeyValueAttr ", " value "); + si.setAttribute("binaryDataAttr", testByteArray); + si.setAttribute("nullBinaryDataAttr", (byte[]) null); + si.setAttribute("emptyBinaryDataAttr", new byte[]{}); + si.setAttribute("longkey", String256.substring(9)); ServerSocket socket; int localPort; @@ -347,6 +423,25 @@ public class NsdManagerTest extends AndroidTestCase { mNsdManager.resolveService(si, mResolveListener); lastEvent = waitForCallback("onServiceResolved"); // id = 4 + assertNotNull(mResolvedService); + + // Check Txt attributes + assertEquals(8, mResolvedService.getAttributes().size()); + assertTrue(mResolvedService.getAttributes().containsKey("booleanAttr")); + assertNull(mResolvedService.getAttributes().get("booleanAttr")); + assertEquals("value", new String(mResolvedService.getAttributes().get("keyValueAttr"))); + assertEquals("=", new String(mResolvedService.getAttributes().get("keyEqualsAttr"))); + assertEquals(" value ", new String(mResolvedService.getAttributes() + .get(" whiteSpaceKeyValueAttr "))); + assertEquals(String256.substring(9), new String(mResolvedService.getAttributes() + .get("longkey"))); + assertTrue(Arrays.equals(testByteArray, + mResolvedService.getAttributes().get("binaryDataAttr"))); + assertTrue(mResolvedService.getAttributes().containsKey("nullBinaryDataAttr")); + assertNull(mResolvedService.getAttributes().get("nullBinaryDataAttr")); + assertTrue(mResolvedService.getAttributes().containsKey("emptyBinaryDataAttr")); + assertNull(mResolvedService.getAttributes().get("emptyBinaryDataAttr")); + assertTrue(lastEvent != null); assertTrue(lastEvent.mSucceeded); @@ -394,7 +489,41 @@ public class NsdManagerTest extends AndroidTestCase { registeredName = lastEvent.mInfo.getServiceName(); // Expect a record to be discovered - lastEvent = waitForCallback("onServiceFound"); // id = 8 + // Expect a service record to be discovered (and filter the ones + // that are unrelated to this test) + found = false; + for (int i = 0; i < 32; i++) { + + lastEvent = waitForCallback("onServiceFound"); // id = 8 + if (lastEvent == null) { + // no more onServiceFound events are being reported! + break; + } + + assertTrue(lastEvent.mSucceeded); + + if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + + lastEvent.mInfo.getServiceName()); + + if (lastEvent.mInfo.getServiceName().equals(registeredName)) { + // Save it, as it will get overwritten with new serviceFound events + si = lastEvent.mInfo; + found = true; + } + + // Remove this event from the event cache, so it won't be found by subsequent + // calls to waitForCallback + synchronized (mEventCache) { + mEventCache.remove(lastEvent); + } + } + + assertTrue(found); + + // Resolve the service + clearEventCache(); + mNsdManager.resolveService(si, mResolveListener); + lastEvent = waitForCallback("onServiceResolved"); // id = 9 assertTrue(lastEvent != null); assertTrue(lastEvent.mSucceeded); @@ -404,11 +533,16 @@ public class NsdManagerTest extends AndroidTestCase { assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); + assertNotNull(mResolvedService); + + // Check that we don't have any TXT records + assertEquals(0, mResolvedService.getAttributes().size()); + checkForAdditionalEvents(); clearEventCache(); mNsdManager.stopServiceDiscovery(mDiscoveryListener); - lastEvent = waitForCallback("onDiscoveryStopped"); // id = 9 + lastEvent = waitForCallback("onDiscoveryStopped"); // id = 10 assertTrue(lastEvent != null); assertTrue(lastEvent.mSucceeded); assertTrue(checkCacheSize(1)); @@ -418,7 +552,7 @@ public class NsdManagerTest extends AndroidTestCase { mNsdManager.unregisterService(mRegistrationListener); - lastEvent = waitForCallback("onServiceUnregistered"); // id = 10 + lastEvent = waitForCallback("onServiceUnregistered"); // id = 11 assertTrue(lastEvent != null); assertTrue(lastEvent.mSucceeded); assertTrue(checkCacheSize(1)); From de7cbcf6ee5954c3385e7ac3ca84f8266be7b95c Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Fri, 25 Mar 2016 17:17:33 -0700 Subject: [PATCH 0227/1415] Added sanity check to verify process state. BUG: 26776313 BUG: 27324964 Change-Id: I209c04d5c6d89acdac9b5bdaee5a4dbd7700c53e --- ...ractRestrictBackgroundNetworkTestCase.java | 44 ++++++++++++++++++- .../cts/net/hostside/DataSaverModeTest.java | 6 +++ ...ostsideRestrictBackgroundNetworkTests.java | 1 - 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index adaaf84848..68be6a5b5b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -25,6 +25,7 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELI import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import android.app.ActivityManager; import android.app.Instrumentation; import android.content.BroadcastReceiver; import android.content.Context; @@ -86,7 +87,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final int myUid = mContext.getPackageManager() .getPackageInfo(mContext.getPackageName(), 0).applicationInfo.uid; - Log.d(TAG, "UIDS: test app=" + myUid + ", app2=" + mUid); + Log.i(TAG, "Apps status on " + getName() + ":\n" + + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" + + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); } @Override @@ -158,6 +161,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected void assertRestrictBackgroundStatus(int expectedApiStatus) throws Exception { + assertBackgroundState(); // Sanity check. final Intent intent = new Intent(ACTION_CHECK_NETWORK); final String resultData = sendOrderedBroadcast(intent); final String[] resultItems = resultData.split(RESULT_SEPARATOR); @@ -171,6 +175,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { + assertBackgroundState(); // Sanity check. final Intent intent = new Intent(ACTION_CHECK_NETWORK); final String resultData = sendOrderedBroadcast(intent); final String[] resultItems = resultData.split(RESULT_SEPARATOR); @@ -178,6 +183,20 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertNetworkStatus(expectAllowed, networkStatus); } + protected final void assertBackgroundState() throws Exception { + final ProcessState state = getProcessStateByUid(mUid); + Log.v(TAG, "assertBackgroundState(): status for app2 (" + mUid + "): " + state); + final boolean isBackground = isBackground(state.state); + assertTrue("App2 is not on background state: " + state, isBackground); + } + + /** + * Returns whether an app state should be considered "background" for restriction purposes. + */ + protected boolean isBackground(int state) { + return state > 4; // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; + } + private String getNetworkStatus(String[] resultItems) { return resultItems.length < 2 ? null : resultItems[1]; } @@ -386,4 +405,27 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return "UNKNOWN_STATUS_" + status; } } + + private ProcessState getProcessStateByUid(int uid) throws Exception { + return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid)); + } + + private static class ProcessState { + private final String fullState; + final int state; + + ProcessState(String fullState) { + this.fullState = fullState; + try { + this.state = Integer.parseInt(fullState.split(" ")[0]); + } catch (Exception e) { + throw new IllegalArgumentException("Could not parse " + fullState); + } + } + + @Override + public String toString() { + return fullState; + } + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index b9fca39312..de75a49935 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,6 +20,12 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +/* + * TODO: need to add more scenarios: + * - test access on foreground app + * - test access on foreground service app + * - make sure it tests transition of data saver status while app is on foreground + */ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { @Override diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 2bd76e6c93..15a4e0a84f 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -30,7 +30,6 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC uninstallPackage(TEST_APP2_PKG, false); installPackage(TEST_APP2_APK); - } @Override From c3d29ebf21d3d168374b3f083832eb6a05146401 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 29 Mar 2016 14:29:55 -0700 Subject: [PATCH 0228/1415] Refactored method to get UIDs. BUG: 27904062 Change-Id: Ib0d3911f40e0a5deed833f71e75abd10a224768f --- .../AbstractRestrictBackgroundNetworkTestCase.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index adaaf84848..824624313b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -82,9 +82,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mContext = mInstrumentation.getContext(); mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - mUid = mContext.getPackageManager().getPackageInfo(TEST_APP2_PKG, 0).applicationInfo.uid; - final int myUid = mContext.getPackageManager() - .getPackageInfo(mContext.getPackageName(), 0).applicationInfo.uid; + mUid = getUid(TEST_APP2_PKG); + final int myUid = getUid(mContext.getPackageName()); Log.d(TAG, "UIDS: test app=" + myUid + ", app2=" + mUid); } @@ -98,6 +97,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } } + protected int getUid(String packageName) throws Exception { + return mContext.getPackageManager().getPackageUid(packageName, 0); + } + protected void assertRestrictBackgroundChangedReceived(int expectedCount) throws Exception { assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, expectedCount); assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); From 9a4643cd0e2167c362465a51e75a18ac8c9cfb36 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Fri, 25 Mar 2016 17:51:45 -0700 Subject: [PATCH 0229/1415] Improved test case for blacklist access. BUG: 27127112 BUG: 26685616 Change-Id: I8b183cdb1cf5ebbc446176a042e4196ab063f1a3 --- .../cts/net/hostside/DataSaverModeTest.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index de75a49935..2971f9dfee 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -24,7 +24,10 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELI * TODO: need to add more scenarios: * - test access on foreground app * - test access on foreground service app - * - make sure it tests transition of data saver status while app is on foreground + * - make sure it works when app is on foreground and state is transitioned: + * - data saver is enabled + * - app is added/removed to blacklist + * */ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { @@ -46,13 +49,13 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase public void testGetRestrictBackgroundStatus_disabled() throws Exception { removeRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); assertRestrictBackgroundChangedReceived(0); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted addRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); assertRestrictBackgroundChangedReceived(0); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); } public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { @@ -60,40 +63,39 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(1); addRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); assertRestrictBackgroundChangedReceived(2); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); } public void testGetRestrictBackgroundStatus_enabled() throws Exception { setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); removeRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); assertRestrictBackgroundChangedReceived(1); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); } public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { addRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(1); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); - // TODO: currently whitelist is prevailing, hence remaining of the test below is disabled - if (true) return; - // Make sure blacklist prevails over whitelist. setRestrictBackground(true); assertRestrictBackgroundChangedReceived(2); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundChangedReceived(3); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); // Check status after removing blacklist. removeRestrictBackgroundBlacklist(mUid); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); - assertRestrictBackgroundChangedReceived(3); - setRestrictBackground(false); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); assertRestrictBackgroundChangedReceived(4); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + setRestrictBackground(false); + assertRestrictBackgroundChangedReceived(5); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); } } From eb7e5053c14775439f7df880462c53344080f60c Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 29 Mar 2016 17:31:25 -0700 Subject: [PATCH 0230/1415] Test network restrictions while on foreground service state. BUG: 27324964 BUG: 26776313 Change-Id: Idcd0a391333d243d17b6bd68c67becaad2b37fdd --- ...ractRestrictBackgroundNetworkTestCase.java | 18 +++++++- .../BatterySaverModeNonMeteredTest.java | 6 ++- .../net/hostside/BatterySaverModeTest.java | 7 ++- .../cts/net/hostside/DataSaverModeTest.java | 8 +++- tests/cts/hostside/app2/AndroidManifest.xml | 1 + .../hostside/app2/MyForegroundService.java | 44 +++++++++++++++++++ .../cts/net/hostside/app2/MyService.java | 2 +- 7 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index a701c66225..4c272ee747 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -65,6 +65,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; private static final int SECOND_IN_MS = 1000; private static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; + private static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; + // Must be higher than NETWORK_TIMEOUT_MS private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4; @@ -193,11 +195,18 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertTrue("App2 is not on background state: " + state, isBackground); } + protected final void assertForegroundServiceState() throws Exception { + final ProcessState state = getProcessState(mUid); + Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + "): " + state); + assertEquals("App2 is not on foreground service state: " + state, + PROCESS_STATE_FOREGROUND_SERVICE, state.state); + } + /** * Returns whether an app state should be considered "background" for restriction purposes. */ protected boolean isBackground(int state) { - return state > 4; // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; + return state >= PROCESS_STATE_FOREGROUND_SERVICE; } private String getNetworkStatus(String[] resultItems) { @@ -379,7 +388,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation * The service must run in a separate app because otherwise it would be killed every time * {@link #runDeviceTests(String, String)} is executed. */ - protected void registerApp2BroadcastReceiver() throws Exception { + protected void registerBroadcastReceiver() throws Exception { executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService"); // Wait until receiver is ready. final int maxTries = 5; @@ -396,6 +405,11 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("app2 receiver is not ready"); } + protected void startForegroundService() throws Exception { + executeShellCommand( + "am startservice com.android.cts.net.hostside.app2/.MyForegroundService"); + } + private String toString(int status) { switch (status) { case RESTRICT_BACKGROUND_STATUS_DISABLED: diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index 5181057d85..8e83fa2b7f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -25,7 +25,7 @@ public class BatterySaverModeNonMeteredTest extends AbstractRestrictBackgroundNe setPowerSaveMode(false); assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check - registerApp2BroadcastReceiver(); + registerBroadcastReceiver(); } @Override @@ -38,6 +38,10 @@ public class BatterySaverModeNonMeteredTest extends AbstractRestrictBackgroundNe public void testBackgroundNetworkAccess_enabled() throws Exception { setPowerSaveMode(true); assertBackgroundNetworkAccess(false); + // Make sure app is allowed if running a foreground service. + startForegroundService(); + assertForegroundServiceState(); + assertBackgroundNetworkAccess(true); } public void testBackgroundNetworkAccess_whitelisted() throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java index 18e2b3e054..6a8540a526 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java @@ -26,7 +26,7 @@ public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestC setMeteredNetwork(); setPowerSaveMode(false); assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check - registerApp2BroadcastReceiver(); + registerBroadcastReceiver(); } @Override @@ -39,6 +39,11 @@ public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestC public void testBackgroundNetworkAccess_enabled() throws Exception { setPowerSaveMode(true); assertBackgroundNetworkAccess(false); + + // Make sure app is allowed if running a foreground service. + startForegroundService(); + assertForegroundServiceState(); + assertBackgroundNetworkAccess(true); } public void testBackgroundNetworkAccess_whitelisted() throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 2971f9dfee..ff68090d3e 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -37,7 +37,7 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase setMeteredNetwork(); setRestrictBackground(false); - registerApp2BroadcastReceiver(); + registerBroadcastReceiver(); } @Override @@ -75,6 +75,12 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(1); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + + // Make sure app is allowed if running a foreground service. + assertBackgroundNetworkAccess(false); + startForegroundService(); + assertForegroundServiceState(); + assertBackgroundNetworkAccess(true); } public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml index fa4cb43d29..9ce57817de 100644 --- a/tests/cts/hostside/app2/AndroidManifest.xml +++ b/tests/cts/hostside/app2/AndroidManifest.xml @@ -32,6 +32,7 @@ --> + diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java new file mode 100644 index 0000000000..bbafd4c274 --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import static com.android.cts.net.hostside.app2.Common.TAG; +import android.R; +import android.app.Notification; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.util.Log; + +/** + * Service used to change app state to FOREGROUND_SERVICE. + */ +public class MyForegroundService extends Service { + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "MyForegroundService.onStartCommand: " + intent); + startForeground(42, new Notification.Builder(this) + .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine + .build()); + return START_STICKY; + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java index 55249f2208..e6454c7be0 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java @@ -39,7 +39,7 @@ public class MyService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "onStartCommand: " + intent); + Log.d(TAG, "MyService.onStartCommand: " + intent); final Context context = getApplicationContext(); final MyBroadcastReceiver myReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER); context.registerReceiver(myReceiver, new IntentFilter(ACTION_RECEIVER_READY)); From bbb00ffc0fe58ca94feaa0e940aaba5949572e00 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 30 Mar 2016 16:37:24 -0700 Subject: [PATCH 0231/1415] Fixed build broken by bad merge. BUG: 27324964 Change-Id: Idbe6f8237b560db31eb949971358db41ac00d530 --- .../net/hostside/AbstractRestrictBackgroundNetworkTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 4c272ee747..f33d4341c3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -196,7 +196,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected final void assertForegroundServiceState() throws Exception { - final ProcessState state = getProcessState(mUid); + final ProcessState state = getProcessStateByUid(mUid); Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + "): " + state); assertEquals("App2 is not on foreground service state: " + state, PROCESS_STATE_FOREGROUND_SERVICE, state.state); From eac0fe6ab18c5a8c243a2c738979abc0189e7eaa Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 30 Mar 2016 18:06:09 -0700 Subject: [PATCH 0232/1415] Moved wi-fi switch to hostside. BUG: 27808364 Change-Id: I89bca5f5ba90a7dc145d2ac170fd505161fd073d --- .../AbstractRestrictBackgroundNetworkTestCase.java | 12 +++++++++--- .../com/android/cts/net/HostsideNetworkTestCase.java | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index f33d4341c3..41fd63853a 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -247,8 +247,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void assertDelayedShellCommand(String command, String expectedResult) throws Exception { final int maxTries = 5; + String result = ""; for (int i = 1; i <= maxTries; i++) { - final String result = executeShellCommand(command).trim(); + result = executeShellCommand(command).trim(); if (result.equals(expectedResult)) return; Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" @@ -256,7 +257,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation Thread.sleep(SECOND_IN_MS); } fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries - + " attempts"); + + " attempts. Last result: '" + result + "'"); } protected void setMeteredNetwork() throws Exception { @@ -265,6 +266,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (metered) { Log.d(TAG, "Active network already metered: " + info); return; + } else { + Log.w(TAG, "Active network not metered: " + info); } final String netId = setWifiMeteredStatus(true); assertTrue("Could not set wifi '" + netId + "' as metered (" @@ -274,7 +277,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected String setWifiMeteredStatus(boolean metered) throws Exception { - mWfm.setWifiEnabled(true); + // We could call setWifiEnabled() here, but it might take sometime to be in a consistent + // state (for example, if one of the saved network is not properly authenticated), so it's + // better to let the hostside test take care of that. + assertTrue("wi-fi is disabled", mWfm.isWifiEnabled()); // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests // to make the actual verification of restrictions optional. final String ssid = mWfm.getConnectionInfo().getSSID(); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 08fb887932..ab1b7d699a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -63,6 +63,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec assertNotNull(mAbi); assertNotNull(mCtsBuild); + assertTrue("device not connected to network", getDevice().checkConnectivity()); + uninstallPackage(TEST_PKG, false); installPackage(TEST_APK); } From 52be3a68ad31901aa2bf98a8698a4a634eabe080 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Fri, 1 Apr 2016 15:40:41 -0700 Subject: [PATCH 0233/1415] Refactored tests to use 'list wifi-networks'. BUG: 27808364 Change-Id: Ife3f35e9c3c6a4285b671eeb7d7d0223be908a1b --- ...ractRestrictBackgroundNetworkTestCase.java | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 41fd63853a..360257a8e1 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -244,19 +244,36 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation /** * Asserts the result of a command, wait and re-running it a couple times if necessary. */ - protected void assertDelayedShellCommand(String command, String expectedResult) + protected void assertDelayedShellCommand(String command, final String expectedResult) + throws Exception { + assertDelayedShellCommand(command, new ExpectResultChecker() { + + @Override + public boolean isExpected(String result) { + return expectedResult.equals(result); + } + + @Override + public String getExpected() { + return expectedResult; + } + }); + } + + protected void assertDelayedShellCommand(String command, ExpectResultChecker checker) throws Exception { final int maxTries = 5; String result = ""; for (int i = 1; i <= maxTries; i++) { result = executeShellCommand(command).trim(); - if (result.equals(expectedResult)) - return; + if (checker.isExpected(result)) return; Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" - + expectedResult + "' on attempt #" + i + "; sleeping 1s before trying again"); + + checker.getExpected() + "' on attempt #" + i + + "; sleeping 1s before trying again"); Thread.sleep(SECOND_IN_MS); } - fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries + fail("Command '" + command + "' did not return '" + checker.getExpected() + "' after " + + maxTries + " attempts. Last result: '" + result + "'"); } @@ -274,9 +291,11 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation + mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered()); // Set flag so status is reverted on teardown. mResetMeteredWifi = true; + // Sanity check. + assertMeteredNetwork(netId, true); } - protected String setWifiMeteredStatus(boolean metered) throws Exception { + private String setWifiMeteredStatus(boolean metered) throws Exception { // We could call setWifiEnabled() here, but it might take sometime to be in a consistent // state (for example, if one of the saved network is not properly authenticated), so it's // better to let the hostside test take care of that. @@ -292,13 +311,26 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered; assertDelayedShellCommand(setCommand, ""); - // Sanity check. - final String getCommand = "cmd netpolicy get metered-network " + netId; - assertDelayedShellCommand(getCommand, Boolean.toString(metered)); - return netId; } + private void assertMeteredNetwork(String netId, boolean status) throws Exception { + final String command = "cmd netpolicy list wifi-networks"; + final String expectedLine = netId + ";" + status; + assertDelayedShellCommand(command, new ExpectResultChecker() { + + @Override + public boolean isExpected(String result) { + return result.contains(expectedLine); + } + + @Override + public String getExpected() { + return "line containing " + expectedLine; + } + }); + } + protected void setRestrictBackground(boolean enabled) throws Exception { executeShellCommand("cmd netpolicy set restrict-background " + enabled); final String output = executeShellCommand("cmd netpolicy get restrict-background "); @@ -451,4 +483,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return fullState; } } + + protected static interface ExpectResultChecker { + boolean isExpected(String result); + String getExpected(); + } } From 8d422e8c57ce8c45c6a11e46caa9b835e0bbbad6 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Fri, 1 Apr 2016 14:50:20 +0900 Subject: [PATCH 0234/1415] Extend CTS test coverage to include registerDefaultNetworkRequest() Change-Id: I36491c2697ed1510da38c06324d2e4ddf653bc4e --- .../net/cts/ConnectivityManagerTest.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 9a99c22c07..6ed43680a8 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -265,13 +265,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { } // We will register for a WIFI network being available or lost. - NetworkRequest request = new NetworkRequest.Builder() + final NetworkRequest request = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); - TestNetworkCallback callback = new TestNetworkCallback(); + final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(request, callback); - boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); + final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultTrackingCallback); + + final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); try { // Make sure WiFi is connected to an access point to start with. @@ -284,12 +287,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { // is registered. assertTrue("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI", callback.waitForAvailable()); + + assertTrue("Did not receive NetworkCallback.onAvailable for any default network", + defaultTrackingCallback.waitForAvailable()); } catch (InterruptedException e) { fail("Broadcast receiver or NetworkCallback wait was interrupted."); } finally { mCm.unregisterNetworkCallback(callback); + mCm.unregisterNetworkCallback(defaultTrackingCallback); - // Return WiFI to its original enabled/disabled state. + // Return WiFi to its original enabled/disabled state. if (!previousWifiEnabledState) { disconnectFromWifi(); } @@ -327,7 +334,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { .build(); mCm.registerNetworkCallback(request, pendingIntent); - boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); + final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); try { // Make sure WiFi is connected to an access point to start with. @@ -347,7 +354,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { pendingIntent.cancel(); mContext.unregisterReceiver(receiver); - // Return WiFI to its original enabled/disabled state. + // Return WiFi to its original enabled/disabled state. if (!previousWifiEnabledState) { disconnectFromWifi(); } From d5dc8fe740d6a09a282e0f8711c580f52ebf55d7 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 13 Apr 2016 16:24:29 -0700 Subject: [PATCH 0235/1415] Test for issue #28156248: Receiving connectivity receiver... ...broadcasts in Android N New test to verify that modern apps can't receive CONNECTIVITY_CHANGE. Change-Id: I9c5b6e99d14b782b3857460d8297f6a405545d87 --- tests/cts/net/AndroidManifest.xml | 6 ++ .../net/cts/ConnectivityManagerTest.java | 30 ++++++++ .../android/net/cts/ConnectivityReceiver.java | 69 +++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/ConnectivityReceiver.java diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index f8daabf02e..dd310a1cac 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -33,6 +33,12 @@ + + + + + + Date: Thu, 14 Apr 2016 15:54:44 +0100 Subject: [PATCH 0236/1415] Added assertion message to testDns failures Identify tests that fail testDns because of no network connection. Bug:26560000 Change-Id: I7683d54d2932ec46c5850bf360c602f6548b179e --- tests/cts/net/src/android/net/cts/DnsTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index 0377d048e7..7d485a619e 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -62,7 +62,8 @@ public class DnsTest extends AndroidTestCase { try { addrs = InetAddress.getAllByName("www.google.com"); } catch (UnknownHostException e) {} - assertTrue(addrs.length != 0); + assertTrue("[RERUN] DNS could not resolve www.gooogle.com. Check internet connection", + addrs.length != 0); boolean foundV4 = false, foundV6 = false; for (InetAddress addr : addrs) { if (addr instanceof Inet4Address) foundV4 = true; From c408601c24b419f7c63b67d256ea3050cbc46bcc Mon Sep 17 00:00:00 2001 From: Owain Davies Date: Thu, 14 Apr 2016 16:12:38 +0100 Subject: [PATCH 0237/1415] Add assertion message if testDns ipv6 lookup reutrns ipv4. Some partner test networks connect by VPN and if the connection fails during the testing this test will fail as the local internet provider intercepts the DNS request and returns an ipv4 address. Added a message to check the network configuration and rerun the test. Bug: 26560000 Change-Id: I54e4976b2cef549bfe9fd55ff9609ba2e6513239 --- tests/cts/net/src/android/net/cts/DnsTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index 0377d048e7..6dd8520395 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -96,7 +96,8 @@ public class DnsTest extends AndroidTestCase { if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString()); } - assertTrue(foundV4 == false); + assertTrue("[RERUN] ipv6.google.com returned an ipv4 address, check your network's DNS connection.", + foundV4 == false); assertTrue(foundV6 == true); assertTrue(testNativeDns()); From f744474a281cc7fd98e4f17a3233131f91c93fb7 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 14 Apr 2016 11:47:34 -0700 Subject: [PATCH 0238/1415] Improvements on test case setup. - On hostside, checks if wi-fi is on instead of checking for connectivity (which can be very slow). - Don't automatically reset metered network on superclass' tearDown(). - Make sure tearDown() cleans up all state changes. BUG: 27808364 Change-Id: I4818047c5fb8f6f430b0aab5ecfa77717f860db3 --- ...ractRestrictBackgroundNetworkTestCase.java | 29 +++++++++++-------- .../net/hostside/BatterySaverModeTest.java | 6 +++- .../cts/net/hostside/DataSaverModeTest.java | 6 +++- .../cts/net/HostsideNetworkTestCase.java | 2 +- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 360257a8e1..2b7dd39c00 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -76,11 +76,12 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected ConnectivityManager mCm; protected WifiManager mWfm; protected int mUid; - private boolean mResetMeteredWifi = false; + private String mMeteredWifi; @Override public void setUp() throws Exception { super.setUp(); + mInstrumentation = getInstrumentation(); mContext = mInstrumentation.getContext(); mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); @@ -93,15 +94,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - - if (mResetMeteredWifi) { - setWifiMeteredStatus(false); - } - } - protected int getUid(String packageName) throws Exception { return mContext.getPackageManager().getPackageUid(packageName, 0); } @@ -289,12 +281,21 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final String netId = setWifiMeteredStatus(true); assertTrue("Could not set wifi '" + netId + "' as metered (" + mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered()); - // Set flag so status is reverted on teardown. - mResetMeteredWifi = true; + // Set flag so status is reverted on resetMeteredNetwork(); + mMeteredWifi = netId; // Sanity check. assertMeteredNetwork(netId, true); } + protected void resetMeteredNetwork() throws Exception { + if (mMeteredWifi == null) { + Log.d(TAG, "resetMeteredNetwork(): wifi not set as metered"); + return; + } + Log.i(TAG, "resetMeteredNetwork(): resetting " + mMeteredWifi); + setWifiMeteredStatus(mMeteredWifi, false); + } + private String setWifiMeteredStatus(boolean metered) throws Exception { // We could call setWifiEnabled() here, but it might take sometime to be in a consistent // state (for example, if one of the saved network is not properly authenticated), so it's @@ -303,6 +304,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests // to make the actual verification of restrictions optional. final String ssid = mWfm.getConnectionInfo().getSSID(); + return setWifiMeteredStatus(ssid, metered); + } + + private String setWifiMeteredStatus(String ssid, boolean metered) throws Exception { assertNotNull("null SSID", ssid); final String netId = ssid.trim().replaceAll("\"", ""); // remove quotes, if any. assertFalse("empty SSID", ssid.isEmpty()); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java index 6a8540a526..d1217b4ed7 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java @@ -33,7 +33,11 @@ public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestC protected void tearDown() throws Exception { super.tearDown(); - setPowerSaveMode(false); + try { + resetMeteredNetwork(); + } finally { + setPowerSaveMode(false); + } } public void testBackgroundNetworkAccess_enabled() throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index ff68090d3e..62f670ed43 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -44,7 +44,11 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase protected void tearDown() throws Exception { super.tearDown(); - setRestrictBackground(false); + try { + resetMeteredNetwork(); + } finally { + setRestrictBackground(false); + } } public void testGetRestrictBackgroundStatus_disabled() throws Exception { diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index ab1b7d699a..39b5652c76 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -63,7 +63,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec assertNotNull(mAbi); assertNotNull(mCtsBuild); - assertTrue("device not connected to network", getDevice().checkConnectivity()); + assertTrue("wi-fi not enabled", getDevice().isWifiEnabled()); uninstallPackage(TEST_PKG, false); installPackage(TEST_APK); From 0e47422a47489a8eea8fa7cd8b56ae94ac4f123c Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 14 Apr 2016 12:45:34 -0700 Subject: [PATCH 0239/1415] Changed order of metered network check. BUG: 27808364 Change-Id: I8a1088673cdd2c310a787a0b0708ad58876e9ac0 --- .../AbstractRestrictBackgroundNetworkTestCase.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 2b7dd39c00..27d4a2b2ef 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -279,12 +279,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation Log.w(TAG, "Active network not metered: " + info); } final String netId = setWifiMeteredStatus(true); - assertTrue("Could not set wifi '" + netId + "' as metered (" - + mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered()); + // Set flag so status is reverted on resetMeteredNetwork(); mMeteredWifi = netId; // Sanity check. - assertMeteredNetwork(netId, true); + assertWifiMeteredStatus(netId, true); + assertTrue("Could not set wifi '" + netId + "' as metered (" + + mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered()); } protected void resetMeteredNetwork() throws Exception { @@ -319,7 +320,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return netId; } - private void assertMeteredNetwork(String netId, boolean status) throws Exception { + private void assertWifiMeteredStatus(String netId, boolean status) throws Exception { final String command = "cmd netpolicy list wifi-networks"; final String expectedLine = netId + ";" + status; assertDelayedShellCommand(command, new ExpectResultChecker() { From bac071b74f0a0a7c20db21cc30c7b21b432eb948 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Wed, 20 Apr 2016 13:34:40 -0700 Subject: [PATCH 0240/1415] Rewrite X509TrustManagerExtensionsTest X509TrustManagerExtensionsTest used internal implementation details to test X509TrustManagerExtensions#isUserAddedCertificate, these implementation details are no longer the same and so this test failed to catch the API being broken and then incorrectly flagged the fixed API as broken. To ensure that isUserAddedCertificate is properly covered the tests for the API are split into two places: X509TrustManagerExtensionsTest covers tests for the default case where there are no added CAs and CaCertManagementTest to test the behavior when CAs have been added. Bug:28262103 Change-Id: I14f3211c277fdc9c8bfc3d4ac932be375961fa28 --- .../cts/X509TrustManagerExtensionsTest.java | 72 +++++++------------ 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/tests/cts/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java b/tests/cts/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java index 9c0d7744c7..99de614d80 100644 --- a/tests/cts/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java +++ b/tests/cts/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java @@ -17,61 +17,39 @@ package android.net.http.cts; import android.net.http.X509TrustManagerExtensions; -import android.util.Base64; - -import java.io.File; -import java.io.ByteArrayInputStream; import java.security.KeyStore; -import java.security.cert.CertificateFactory; +import java.security.cert.Certificate; import java.security.cert.X509Certificate; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + import junit.framework.TestCase; -import com.android.org.conscrypt.TrustedCertificateStore; -import com.android.org.conscrypt.TrustManagerImpl; - public class X509TrustManagerExtensionsTest extends TestCase { - public void testIsUserAddedCert() throws Exception { - final String testCert = - "MIICfjCCAeegAwIBAgIJAMefIzKHY5H4MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV" + - "BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEPMA0G" + - "A1UECgwGR2V3Z3VsMRMwEQYDVQQDDApnZXdndWwuY29tMB4XDTEzMTEwNTAwNDE0" + - "MFoXDTEzMTIwNTAwNDE0MFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYw" + - "FAYDVQQHDA1Nb3VudGFpbiBWaWV3MQ8wDQYDVQQKDAZHZXdndWwxEzARBgNVBAMM" + - "Cmdld2d1bC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKpc/I0Ss4sm" + - "yV2iX5xRMM7+XXAhiWrceGair4MpvDrGIa1kFj2phtx4IqTfDnNU7AhRJYkDYmJQ" + - "fUJ8i6F+I08uNiGVO4DtPJbZcBXg9ME9EMaJCslm995ueeNWSw1Ky8zM0tt4p+94" + - "BcXJ7PC3N2WgkvtE8xwNbaeUfhGPzJKXAgMBAAGjUDBOMB0GA1UdDgQWBBQQ/iW7" + - "JCkSI2sbn4nTBiZ9PSiO8zAfBgNVHSMEGDAWgBQQ/iW7JCkSI2sbn4nTBiZ9PSiO" + - "8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBABQBrUOWTCSIl3vkRR3w" + - "3bPzh3BpqDmxH9xe4rZr+MVKKjpGjY1z2m2EEtyNz3tbgVQym5+si00DUHFL0IP1" + - "SuRULmPyEpTBVbV+PA5Kc967ZcDgYt4JtdMcCeKbIFaU6r8oEYEL2PTlNZmgbunM" + - "pXktkhVvNxZeSa8yM9bPhXkN"; + private static X509TrustManager getFirstX509TrustManager(TrustManagerFactory tmf) + throws Exception { + for (TrustManager trustManager : tmf.getTrustManagers()) { + if (trustManager instanceof X509TrustManager) { + return (X509TrustManager) trustManager; + } + } + fail("Unable to find X509TrustManager"); + return null; + } - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate)cf.generateCertificate( - new ByteArrayInputStream(Base64.decode(testCert, Base64.DEFAULT))); - - // Test without adding cert to keystore. - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - X509TrustManagerExtensions tmeNegative = - new X509TrustManagerExtensions(new TrustManagerImpl(keyStore)); - assertEquals(false, tmeNegative.isUserAddedCertificate(cert)); - - // Test with cert added to keystore. - final File DIR_TEMP = new File(System.getProperty("java.io.tmpdir")); - final File DIR_TEST = new File(DIR_TEMP, "test"); - final File system = new File(DIR_TEST, "system-test"); - final File added = new File(DIR_TEST, "added-test"); - final File deleted = new File(DIR_TEST, "deleted-test"); - - TrustedCertificateStore tcs = new TrustedCertificateStore(system, added, deleted); - added.mkdirs(); - tcs.installCertificate(cert); - X509TrustManagerExtensions tmePositive = - new X509TrustManagerExtensions(new TrustManagerImpl(keyStore, null, tcs)); - assertEquals(true, tmePositive.isUserAddedCertificate(cert)); + public void testIsUserAddedCertificateDefaults() throws Exception { + final TrustManagerFactory tmf = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); + X509TrustManager tm = getFirstX509TrustManager(tmf); + X509TrustManagerExtensions xtm = new X509TrustManagerExtensions(tm); + // Verify that all the default system provided CAs are not marked as user added. + for (Certificate cert : tm.getAcceptedIssuers()) { + assertFalse(xtm.isUserAddedCertificate((X509Certificate) cert)); + } } } From 8a14c224e30ee4a76fd83cb92c47e00bb5f4abea Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 19 Apr 2016 13:00:51 +0900 Subject: [PATCH 0241/1415] Add more test coverage to ConnectivityManagerTest. 1. Test NetworkCallbacks as well as CONNECTIVITY_ACTION, since we are moving away from CONNECTIVITY_ACTION. 2. Use the Network objects we get back to test Network#getSocketFactory(). 3. Check that TCP connections are closed with ECONNABORTED when a network disconnects. Bug: 28251576 Change-Id: I41a438b82ef9251e52866332f3445f1bf876e04f --- .../net/cts/ConnectivityManagerTest.java | 156 +++++++++++++++--- 1 file changed, 134 insertions(+), 22 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 4112466877..231db97d2b 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -38,9 +38,16 @@ import android.net.wifi.WifiManager; import android.test.AndroidTestCase; import android.util.Log; import android.os.SystemProperties; +import android.system.Os; +import android.system.OsConstants; import com.android.internal.telephony.PhoneConstants; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -57,7 +64,15 @@ public class ConnectivityManagerTest extends AndroidTestCase { public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; + private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 + private static final String TEST_HOST = "connectivitycheck.gstatic.com"; + private static final int SOCKET_TIMEOUT_MS = 2000; + private static final int HTTP_PORT = 80; + private static final String HTTP_REQUEST = + "GET /generate_204 HTTP/1.0\r\n" + + "Host: " + TEST_HOST + "\r\n" + + "Connection: keep-alive\r\n\r\n"; // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. private static final String NETWORK_CALLBACK_ACTION = @@ -249,6 +264,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { mCm.getBackgroundDataSetting(); } + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + /** * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to * see if we get a callback for the TRANSPORT_WIFI transport type being available. @@ -265,16 +286,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } // We will register for a WIFI network being available or lost. - final NetworkRequest request = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build(); final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(request, callback); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultTrackingCallback); final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); + Network wifiNetwork = null; try { // Make sure WiFi is connected to an access point to start with. @@ -285,10 +304,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Now we should expect to get a network callback about availability of the wifi // network even if it was already connected as a state-based action when the callback // is registered. - assertTrue("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI", - callback.waitForAvailable()); + wifiNetwork = callback.waitForAvailable(); + assertNotNull("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI", + wifiNetwork); - assertTrue("Did not receive NetworkCallback.onAvailable for any default network", + assertNotNull("Did not receive NetworkCallback.onAvailable for any default network", defaultTrackingCallback.waitForAvailable()); } catch (InterruptedException e) { fail("Broadcast receiver or NetworkCallback wait was interrupted."); @@ -298,7 +318,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Return WiFi to its original enabled/disabled state. if (!previousWifiEnabledState) { - disconnectFromWifi(); + disconnectFromWifi(wifiNetwork); } } } @@ -329,10 +349,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); // We will register for a WIFI network being available or lost. - NetworkRequest request = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build(); - mCm.registerNetworkCallback(request, pendingIntent); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent); final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); @@ -356,7 +373,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Return WiFi to its original enabled/disabled state. if (!previousWifiEnabledState) { - disconnectFromWifi(); + disconnectFromWifi(null); } } } @@ -370,8 +387,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { // We will toggle the state of wifi to generate a connectivity change. final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); + if (previousWifiEnabledState) { - disconnectFromWifi(); + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); } else { connectToWifi(); } @@ -387,12 +406,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (previousWifiEnabledState) { connectToWifi(); } else { - disconnectFromWifi(); + disconnectFromWifi(null); } } /** Enable WiFi and wait for it to become connected to a network. */ - private void connectToWifi() { + private Network connectToWifi() { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network wifiNetwork = null; + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); IntentFilter filter = new IntentFilter(); @@ -402,36 +425,94 @@ public class ConnectivityManagerTest extends AndroidTestCase { boolean connected = false; try { assertTrue(mWifiManager.setWifiEnabled(true)); + // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. + wifiNetwork = callback.waitForAvailable(); + assertNotNull(wifiNetwork); connected = receiver.waitForState(); } catch (InterruptedException ex) { fail("connectToWifi was interrupted"); } finally { + mCm.unregisterNetworkCallback(callback); mContext.unregisterReceiver(receiver); } assertTrue("Wifi must be configured to connect to an access point for this test.", connected); + return wifiNetwork; + } + + private Socket getBoundSocket(Network network, String host, int port) throws IOException { + InetSocketAddress addr = new InetSocketAddress(host, port); + Socket s = network.getSocketFactory().createSocket(); + try { + s.setSoTimeout(SOCKET_TIMEOUT_MS); + s.connect(addr, SOCKET_TIMEOUT_MS); + } catch (IOException e) { + s.close(); + throw e; + } + return s; + } + + private void testHttpRequest(Socket s) throws IOException { + OutputStream out = s.getOutputStream(); + InputStream in = s.getInputStream(); + + final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + byte[] responseBytes = new byte[4096]; + out.write(requestBytes); + in.read(responseBytes); + assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); } /** Disable WiFi and wait for it to become disconnected from the network. */ - private void disconnectFromWifi() { + private void disconnectFromWifi(Network wifiNetworkToCheck) { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network lostWifiNetwork = null; + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(receiver, filter); + // Assert that we can establish a TCP connection on wifi. + Socket wifiBoundSocket = null; + if (wifiNetworkToCheck != null) { + try { + wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); + testHttpRequest(wifiBoundSocket); + } catch (IOException e) { + fail("HTTP request before wifi disconnected failed with: " + e); + } + } + boolean disconnected = false; try { assertTrue(mWifiManager.setWifiEnabled(false)); + // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. + lostWifiNetwork = callback.waitForLost(); + assertNotNull(lostWifiNetwork); disconnected = receiver.waitForState(); } catch (InterruptedException ex) { fail("disconnectFromWifi was interrupted"); } finally { + mCm.unregisterNetworkCallback(callback); mContext.unregisterReceiver(receiver); } assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); + + // Check that the socket is closed when wifi disconnects. + if (wifiBoundSocket != null) { + try { + testHttpRequest(wifiBoundSocket); + fail("HTTP request should not succeed after wifi disconnects"); + } catch (IOException expected) { + assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); + } + } } /** @@ -498,15 +579,48 @@ public class ConnectivityManagerTest extends AndroidTestCase { */ private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { private final CountDownLatch mAvailableLatch = new CountDownLatch(1); + private final CountDownLatch mLostLatch = new CountDownLatch(1); - public boolean waitForAvailable() throws InterruptedException { - return mAvailableLatch.await(30, TimeUnit.SECONDS); + public Network currentNetwork; + public Network lastLostNetwork; + + public Network waitForAvailable() throws InterruptedException { + return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; + } + + public Network waitForLost() throws InterruptedException { + return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; } @Override public void onAvailable(Network network) { + currentNetwork = network; mAvailableLatch.countDown(); } + + @Override + public void onLost(Network network) { + lastLostNetwork = network; + if (network.equals(currentNetwork)) { + currentNetwork = null; + } + mLostLatch.countDown(); + } + } + + private Network getWifiNetwork() { + TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network network = null; + try { + network = callback.waitForAvailable(); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + } + assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); + return network; } /** Verify restricted networks cannot be requested. */ @@ -523,8 +637,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { try { mCm.requestNetwork(request, callback); fail("No exception thrown when restricted network requested."); - } catch (SecurityException e) { - // Expected. - } + } catch (SecurityException expected) {} } } From 335856c1d39eed0974be2f28dbb8aace83d847c8 Mon Sep 17 00:00:00 2001 From: Marcus Nascimento Date: Tue, 26 Apr 2016 11:32:30 +0100 Subject: [PATCH 0242/1415] Add assertion messages to testStartUsingNetworkFeature_enableHipri. testStartUsingNetworkFeature_enableHipri should be able to reconnect to Wifi Network. Added a prefix to the already defined error message to rerun the test. The ConnectivityManager's startUsingNetworkFeature will fail without SIM card and/or signal. Changed the error message to check SIM card and signal and rerun the test. Bug: 28264205 Change-Id: Ia1b35cab11afa65ae93ea7dab2f7cc3a330d8471 --- .../cts/net/src/android/net/cts/ConnectivityManagerTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 9daf3c421b..120f9984c7 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -283,7 +283,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue("Couldn't start using the HIPRI feature.", result != -1); // Check that the ConnectivityManager reported that it connected using hipri... - assertTrue("Couldn't connect using hipri...", receiver.waitForConnection()); + assertTrue("[RERUN] Couldn't connect using hipri. Check signal and SIM.", + receiver.waitForConnection()); assertTrue("Couldn't requestRouteToHost using HIPRI.", mCm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, HOST_ADDRESS)); @@ -311,7 +312,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { mContext.registerReceiver(receiver, filter); assertTrue(mWifiManager.setWifiEnabled(true)); - assertTrue("Wifi must be configured to connect to an access point for this test.", + assertTrue("[RERUN] Wifi must be configured to connect to an access point for this test.", receiver.waitForConnection()); mContext.unregisterReceiver(receiver); From 51eb8c19a00ea5d4973431822d24d43c75dbbed9 Mon Sep 17 00:00:00 2001 From: Marcus Nascimento Date: Tue, 26 Apr 2016 11:30:30 +0100 Subject: [PATCH 0243/1415] Add assertion message to assertions for testExecute_withMobile. Some partner test devices without a SIM Card or with no signal, thus without mobile network data connection. Added a message to check signal and SIM card and rerun the test. Also added a verification that the network type is supported in the event of a Connectivity Action's timeout. Unsuported network type could be caused by a network stack crash. Bug: 28207677 Change-Id: Ibca50359df7d5fb8371f4f4037fc81f029f48b30 --- .../net/http/cts/ApacheHttpClientTest.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java b/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java index 7d9189ff33..91b65b6967 100644 --- a/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java +++ b/tests/cts/net/src/android/net/http/cts/ApacheHttpClientTest.java @@ -146,7 +146,8 @@ public class ApacheHttpClientTest extends AndroidTestCase { mContext.registerReceiver(receiver, filter); assertTrue(mWifiManager.setWifiEnabled(true)); - assertTrue("Wifi must be configured to connect to an access point for this test.", + assertTrue( + "[RERUN] Wifi must be configured to connect to an access point for this test.", receiver.waitForStateChange()); mContext.unregisterReceiver(receiver); @@ -165,9 +166,11 @@ public class ApacheHttpClientTest extends AndroidTestCase { mContext.registerReceiver(connectMobileReceiver, filter); mContext.registerReceiver(disconnectWifiReceiver, filter); - assertTrue(mWifiManager.setWifiEnabled(false)); - assertTrue(disconnectWifiReceiver.waitForStateChange()); - assertTrue(connectMobileReceiver.waitForStateChange()); + assertTrue("Wifi did not disconnect.", mWifiManager.setWifiEnabled(false)); + assertTrue("Timeout waiting for wifi to disconnect.", + disconnectWifiReceiver.waitForStateChange()); + assertTrue("[RERUN] Timeout waiting for mobile network. Check signal and SIM.", + connectMobileReceiver.waitForStateChange()); mContext.unregisterReceiver(connectMobileReceiver); mContext.unregisterReceiver(disconnectWifiReceiver); @@ -204,7 +207,10 @@ public class ApacheHttpClientTest extends AndroidTestCase { } private boolean hasExpectedState() { - return mExpectedState == mConnectivityManager.getNetworkInfo(mNetworkType).getState(); + NetworkInfo network = mConnectivityManager.getNetworkInfo(mNetworkType); + assertNotNull("Network type should be supported but it is not. Type: " + mNetworkType, + network); + return mExpectedState == network.getState(); } } } From fa8e24c3e68264eaf6444d203567f7a579290422 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 27 Apr 2016 17:01:31 -0700 Subject: [PATCH 0244/1415] Added test for required packages whitelisted for Data Saver Mode. Also fixed code that checks for whitelist uids, otherwise it would pass when the required uid is missing but a superset was present (for example, when asking for 1009 but 10090 was whitelisted). BUG: 28431507 Change-Id: Iaaa67e586907dba215496460445ad627ba7b63c5 --- ...ractRestrictBackgroundNetworkTestCase.java | 14 +++++++---- .../cts/net/hostside/DataSaverModeTest.java | 24 +++++++++++++++++++ ...ostsideRestrictBackgroundNetworkTests.java | 5 ++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 27d4a2b2ef..ce9d9704cd 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -377,18 +377,24 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception { final int maxTries = 5; boolean actual = false; + final String expectedUid = Integer.toString(uid); + String uids = ""; for (int i = 1; i <= maxTries; i++) { final String output = executeShellCommand("cmd netpolicy list " + list); - actual = output.contains(Integer.toString(uid)); - if (expected == actual) { - return; + uids = output.split(":")[1]; + for (String candidate : uids.split(" ")) { + actual = candidate.trim().equals(expectedUid); + if (expected == actual) { + return; + } } Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected " + expected + ", got " + actual + "); sleeping 1s before polling again"); Thread.sleep(SECOND_IN_MS); } - fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual); + fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual + + ". Full list: " + uids); } protected void assertPowerSaveModeWhitelist(String packageName, boolean expected) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 62f670ed43..d7604755fe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -31,6 +31,10 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELI */ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { + private static final String[] REQUIRED_WHITELISTED_PACKAGES = { + "com.android.providers.downloads" + }; + @Override public void setUp() throws Exception { super.setUp(); @@ -108,4 +112,24 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(5); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); } + + public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { + final StringBuilder error = new StringBuilder(); + for (String packageName : REQUIRED_WHITELISTED_PACKAGES) { + int uid = -1; + try { + uid = getUid(packageName); + assertRestrictBackgroundWhitelist(uid, true); + } catch (Throwable t) { + error.append("\nFailed for '").append(packageName).append("'"); + if (uid > 0) { + error.append(" (uid ").append(uid).append(")"); + } + error.append(": ").append(t).append("\n"); + } + } + if (error.length() > 0) { + fail(error.toString()); + } + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 15a4e0a84f..ca535bc6d2 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -73,6 +73,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC assertRestrictBackgroundWhitelist(newUid, false); } + public void testDataSaverMode_requiredWhitelistedPackages() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", + "testGetRestrictBackgroundStatus_requiredWhitelistedPackages"); + } + public void testBatterySaverMode_disabled() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest", "testBackgroundNetworkAccess_disabled"); From 50bce69fabb711b48ec7e4502cfa9115a31fc1e0 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Fri, 29 Apr 2016 15:23:34 -0700 Subject: [PATCH 0245/1415] Improved connectivity check by also asserting NetworkInfo states. BUG: 28473659 BUG: 26571724 Change-Id: Iba687003431ed5c353412268726967a798f538da --- ...ractRestrictBackgroundNetworkTestCase.java | 41 +++++++++----- .../net/hostside/BatterySaverModeTest.java | 1 + .../android/cts/net/hostside/app2/Common.java | 3 - .../hostside/app2/MyBroadcastReceiver.java | 55 +++++++++++++++---- ...ostsideRestrictBackgroundNetworkTests.java | 6 +- 5 files changed, 76 insertions(+), 30 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index ce9d9704cd..08df9e1bbc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -25,13 +25,14 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELI import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import android.app.ActivityManager; import android.app.Instrumentation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; import android.test.InstrumentationTestCase; import android.util.Log; @@ -61,8 +62,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private static final String EXTRA_RECEIVER_NAME = "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; private static final String RESULT_SEPARATOR = ";"; - private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; - private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; + private static final String NETWORK_STATUS_SEPARATOR = "\\|"; private static final int SECOND_IN_MS = 1000; private static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; @@ -144,7 +144,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation }, null, 0, null, null); final String resultData = result.poll(timeoutMs, TimeUnit.MILLISECONDS); - Log.d(TAG, "Ordered broadcast response: " + resultData); + Log.d(TAG, "Ordered broadcast response after " + timeoutMs + "ms: " + resultData ); return resultData; } @@ -206,17 +206,30 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } private void assertNetworkStatus(boolean expectAvailable, String status) throws Exception { - if (status == null) { - Log.d(TAG, "timeout waiting for ordered broadcast"); - if (expectAvailable) { - fail("did not get network status when access was allowed"); - } - return; + assertNotNull("timeout waiting for ordered broadcast", status); + + // Network status format is described on MyBroadcastReceiver.checkNetworkStatus() + final String[] parts = status.split(NETWORK_STATUS_SEPARATOR); + assertEquals("Wrong network status: " + status, 5, parts.length); // Sanity check + final State state = State.valueOf(parts[0]); + final DetailedState detailedState = DetailedState.valueOf(parts[1]); + final boolean connected = Boolean.valueOf(parts[2]); + final String connectionCheckDetails = parts[3]; + final String networkInfo = parts[4]; + + if (expectAvailable) { + assertTrue("should be connected: " + connectionCheckDetails + + " (network info: " + networkInfo + ")", connected); + assertEquals("wrong state for " + networkInfo, State.CONNECTED, state); + assertEquals("wrong detailed state for " + networkInfo, + DetailedState.CONNECTED, detailedState); + } else { + assertFalse("should not be connected: " + connectionCheckDetails + + " (network info: " + networkInfo + ")", connected); + assertEquals("wrong state for " + networkInfo, State.DISCONNECTED, state); + assertEquals("wrong detailed state for " + networkInfo, + DetailedState.BLOCKED, detailedState); } - final String expectedPrefix = expectAvailable ? - STATUS_NETWORK_AVAILABLE_PREFIX : STATUS_NETWORK_UNAVAILABLE_PREFIX; - assertTrue("Wrong network status (" + status + ") when expectedAvailable is " - + expectAvailable, status.startsWith(expectedPrefix)); } protected String executeShellCommand(String command) throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java index d1217b4ed7..e5466cdbb9 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java @@ -42,6 +42,7 @@ public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestC public void testBackgroundNetworkAccess_enabled() throws Exception { setPowerSaveMode(true); + assertBackgroundNetworkAccess(false); // Make sure app is allowed if running a foreground service. diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index 668669bc2e..d247c3177c 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -17,7 +17,6 @@ package com.android.cts.net.hostside.app2; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; -import android.util.Log; public final class Common { @@ -37,8 +36,6 @@ public final class Common { static final String EXTRA_RECEIVER_NAME = "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; static final char RESULT_SEPARATOR = ';'; - static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:"; - static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:"; static int getUid(Context context) { final String packageName = context.getPackageName(); diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 07f717b192..e8a959c41e 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -24,8 +24,6 @@ import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION; import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME; import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; import static com.android.cts.net.hostside.app2.Common.RESULT_SEPARATOR; -import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_AVAILABLE_PREFIX; -import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_UNAVAILABLE_PREFIX; import static com.android.cts.net.hostside.app2.Common.TAG; import static com.android.cts.net.hostside.app2.Common.getUid; @@ -125,6 +123,38 @@ public class MyBroadcastReceiver extends BroadcastReceiver { setResultData(data.toString()); } + + private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s"; + + /** + * Checks whether the network is available and return a string which can then be send as a + * result data for the ordered broadcast. + * + *

+ * The string has the following format: + * + *


+     * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo
+     * 
+ * + *

Where: + * + *

    + *
  • {@code NetinfoState}: enum value of {@link NetworkInfo.State}. + *
  • {@code NetinfoDetailedState}: enum value of {@link NetworkInfo.DetailedState}. + *
  • {@code RealConnectionCheck}: boolean value of a real connection check (i.e., an attempt + * to access an external website. + *
  • {@code RealConnectionCheckDetails}: if HTTP output core or exception string of the real + * connection attempt + *
  • {@code Netinfo}: string representation of the {@link NetworkInfo}. + *
+ * + * For example, if the connection was established fine, the result would be something like: + *


+     * CONNECTED|CONNECTED|true|200|[type: WIFI[], state: CONNECTED/CONNECTED, reason: ...]
+     * 
+ * + */ private String checkNetworkStatus(final Context context, final ConnectivityManager cm) throws InterruptedException { final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); @@ -138,24 +168,29 @@ public class MyBroadcastReceiver extends BroadcastReceiver { Log.d(TAG, "Running checkNetworkStatus() on thread " + Thread.currentThread().getName() + " for UID " + getUid(context) + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address); - String prefix = STATUS_NETWORK_AVAILABLE_PREFIX; + boolean checkStatus = false; + String checkDetails = "N/A"; try { final URL url = new URL(address); final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(NETWORK_TIMEOUT_MS); - conn.setConnectTimeout(NETWORK_TIMEOUT_MS); + conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2); conn.setRequestMethod("GET"); conn.setDoInput(true); conn.connect(); final int response = conn.getResponseCode(); - Log.d(TAG, "HTTP response for " + address + ": " + response); + checkStatus = true; + checkDetails = "HTTP response for " + address + ": " + response; } catch (Exception e) { - Log.d(TAG, "Exception getting " + address + ": " + e); - prefix = STATUS_NETWORK_UNAVAILABLE_PREFIX + "Exception " + e + ":"; + checkStatus = false; + checkDetails = "Exception getting " + address + ": " + e; } - final String netInfo = prefix + networkInfo; - Log.d(TAG, "Offering " + netInfo); - result.offer(netInfo); + Log.d(TAG, checkDetails); + final String status = String.format(NETWORK_STATUS_TEMPLATE, + networkInfo.getState().name(), networkInfo.getDetailedState().name(), + Boolean.toString(checkStatus), checkDetails, networkInfo); + Log.d(TAG, "Offering " + status); + result.offer(status); } }, mName).start(); return result.poll(NETWORK_TIMEOUT_MS * 2, TimeUnit.MILLISECONDS); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index ca535bc6d2..435e201ec1 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -104,17 +104,17 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC assertPowerSaveModeWhitelist(TEST_PKG, false); } - public void testBatteryBatterySaverModeNonMeteredTest_disabled() throws Exception { + public void testBatterySaverModeNonMetered_disabled() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", "testBackgroundNetworkAccess_disabled"); } - public void testBatteryBatterySaverModeNonMeteredTest_whitelisted() throws Exception { + public void testBatterySaverModeNonMeteredt_whitelisted() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", "testBackgroundNetworkAccess_whitelisted"); } - public void testBatteryBatterySaverModeNonMeteredTest_enabled() throws Exception { + public void testBatterySaverModeNonMetered_enabled() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", "testBackgroundNetworkAccess_enabled"); } From 691e85def733e6c8c3066c25448e51edad47f1dd Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 4 May 2016 11:46:08 -0700 Subject: [PATCH 0246/1415] Temporarily disable NetworkInfo check. There are known issues that cause these check to fail, and the fix has not been submitted yet. BUG: 28473659 BUG: 28521946 Change-Id: I26dfbebc2d07396ef89ac78230645e4791c708ee --- ...tractRestrictBackgroundNetworkTestCase.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 08df9e1bbc..08c8fdbcee 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -71,6 +71,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // Must be higher than NETWORK_TIMEOUT_MS private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4; + private static final boolean ASSERT_NETWORK_INFO_STATE = false; + protected Context mContext; protected Instrumentation mInstrumentation; protected ConnectivityManager mCm; @@ -220,15 +222,19 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (expectAvailable) { assertTrue("should be connected: " + connectionCheckDetails + " (network info: " + networkInfo + ")", connected); - assertEquals("wrong state for " + networkInfo, State.CONNECTED, state); - assertEquals("wrong detailed state for " + networkInfo, - DetailedState.CONNECTED, detailedState); + if (ASSERT_NETWORK_INFO_STATE) { + assertEquals("wrong state for " + networkInfo, State.CONNECTED, state); + assertEquals("wrong detailed state for " + networkInfo, + DetailedState.CONNECTED, detailedState); + } } else { assertFalse("should not be connected: " + connectionCheckDetails + " (network info: " + networkInfo + ")", connected); - assertEquals("wrong state for " + networkInfo, State.DISCONNECTED, state); - assertEquals("wrong detailed state for " + networkInfo, - DetailedState.BLOCKED, detailedState); + if (ASSERT_NETWORK_INFO_STATE) { + assertEquals("wrong state for " + networkInfo, State.DISCONNECTED, state); + assertEquals("wrong detailed state for " + networkInfo, + DetailedState.BLOCKED, detailedState); + } } } From aa2e8ea1d8b62ea6b6ffd3a507f7f3b797a33c1e Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 5 May 2016 14:46:53 -0700 Subject: [PATCH 0247/1415] Assert whitelists are revoked on uninstall. BUG: 28616418 Change-Id: I909fd4c6024afe5b42560090c6e2f11b43c220de --- .../cts/net/hostside/DataSaverModeTest.java | 6 ++- ...ostsideRestrictBackgroundNetworkTests.java | 39 +++++++++++++------ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index d7604755fe..60c2b9ba6c 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -73,7 +73,11 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(2); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); - } + + removeRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundChangedReceived(3); + assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + } public void testGetRestrictBackgroundStatus_enabled() throws Exception { setRestrictBackground(true); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 435e201ec1..ece09c84f5 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -60,15 +60,17 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC } public void testDataSaverMode_reinstall() throws Exception { - final int oldUid = getUid(TEST_PKG); - testDataSaverMode_whitelisted(); + final int oldUid = getUid(TEST_APP2_PKG); - uninstallPackage(TEST_PKG, true); - assertPackageUninstalled(TEST_PKG); + // Make sure whitelist is revoked when package is removed + addRestrictBackgroundWhitelist(oldUid); + + uninstallPackage(TEST_APP2_PKG, true); + assertPackageUninstalled(TEST_APP2_PKG); assertRestrictBackgroundWhitelist(oldUid, false); - installPackage(TEST_APK); - final int newUid = getUid(TEST_PKG); + installPackage(TEST_APP2_APK); + final int newUid = getUid(TEST_APP2_PKG); assertRestrictBackgroundWhitelist(oldUid, false); assertRestrictBackgroundWhitelist(newUid, false); } @@ -94,14 +96,14 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC } public void testBatterySaverMode_reinstall() throws Exception { - testBatterySaverMode_whitelisted(); + addPowerSaveModeWhitelist(TEST_APP2_PKG); - uninstallPackage(TEST_PKG, true); - assertPackageUninstalled(TEST_PKG); - assertPowerSaveModeWhitelist(TEST_PKG, false); + uninstallPackage(TEST_APP2_PKG, true); + assertPackageUninstalled(TEST_APP2_PKG); + assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); - installPackage(TEST_APK); - assertPowerSaveModeWhitelist(TEST_PKG, false); + installPackage(TEST_APP2_APK); + assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); } public void testBatterySaverModeNonMetered_disabled() throws Exception { @@ -160,4 +162,17 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries + " attempts"); } + + protected void addRestrictBackgroundWhitelist(int uid) throws Exception { + runCommand("cmd netpolicy add restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, true); + } + + private void addPowerSaveModeWhitelist(String packageName) throws Exception { + Log.i(TAG, "Adding package " + packageName + " to power-save-mode whitelist"); + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + runCommand("dumpsys deviceidle whitelist +" + packageName); + assertPowerSaveModeWhitelist(packageName, true); // Sanity check + } } From 6cd41f6d03936d4c64cea805b347f691735c0d82 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Fri, 29 Apr 2016 16:48:14 -0700 Subject: [PATCH 0248/1415] Asserts foreground apps always have network access. BUG: 28473659 Change-Id: Iea6933a4630ff2e9c00a2d2e9e4a6f1a51de70f2 --- ...ractRestrictBackgroundNetworkTestCase.java | 117 +++++++++++------- .../BatterySaverModeNonMeteredTest.java | 13 ++ .../net/hostside/BatterySaverModeTest.java | 12 ++ .../cts/net/hostside/DataSaverModeTest.java | 46 +++++-- tests/cts/hostside/app2/AndroidManifest.xml | 2 + .../android/cts/net/hostside/app2/Common.java | 2 + .../cts/net/hostside/app2/MyActivity.java | 38 ++++++ .../hostside/app2/MyBroadcastReceiver.java | 27 ++-- ...ostsideRestrictBackgroundNetworkTests.java | 2 +- 9 files changed, 188 insertions(+), 71 deletions(-) create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 08c8fdbcee..3ee2f6868e 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -54,6 +54,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private static final String DYNAMIC_RECEIVER = "DynamicReceiver"; private static final String ACTION_GET_COUNTERS = "com.android.cts.net.hostside.app2.action.GET_COUNTERS"; + private static final String ACTION_GET_RESTRICT_BACKGROUND_STATUS = + "com.android.cts.net.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS"; private static final String ACTION_CHECK_NETWORK = "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; private static final String ACTION_RECEIVER_READY = @@ -61,7 +63,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; private static final String EXTRA_RECEIVER_NAME = "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; - private static final String RESULT_SEPARATOR = ";"; private static final String NETWORK_STATUS_SEPARATOR = "\\|"; private static final int SECOND_IN_MS = 1000; private static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; @@ -71,8 +72,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // Must be higher than NETWORK_TIMEOUT_MS private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4; - private static final boolean ASSERT_NETWORK_INFO_STATE = false; - protected Context mContext; protected Instrumentation mInstrumentation; protected ConnectivityManager mCm; @@ -159,27 +158,22 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return Integer.valueOf(resultData); } - protected void assertRestrictBackgroundStatus(int expectedApiStatus) throws Exception { - assertBackgroundState(); // Sanity check. - final Intent intent = new Intent(ACTION_CHECK_NETWORK); + protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { + final Intent intent = new Intent(ACTION_GET_RESTRICT_BACKGROUND_STATUS); final String resultData = sendOrderedBroadcast(intent); - final String[] resultItems = resultData.split(RESULT_SEPARATOR); - final String actualApiStatus = toString(Integer.parseInt(resultItems[0])); - // First asserts the API returns the proper value... - assertEquals("wrong status", toString(expectedApiStatus), actualApiStatus); - - //...then the actual network status in the background thread. - final String networkStatus = getNetworkStatus(resultItems); - assertNetworkStatus(expectedApiStatus != RESTRICT_BACKGROUND_STATUS_ENABLED, networkStatus); + assertNotNull("timeout waiting for ordered broadcast result", resultData); + final String actualStatus = toString(Integer.parseInt(resultData)); + assertEquals("wrong status", toString(expectedStatus), actualStatus); } protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { assertBackgroundState(); // Sanity check. - final Intent intent = new Intent(ACTION_CHECK_NETWORK); - final String resultData = sendOrderedBroadcast(intent); - final String[] resultItems = resultData.split(RESULT_SEPARATOR); - final String networkStatus = getNetworkStatus(resultItems); - assertNetworkStatus(expectAllowed, networkStatus); + assertNetworkAccess(expectAllowed); + } + + protected void assertForegroundNetworkAccess() throws Exception { + assertForegroundState(); // Sanity check. + assertNetworkAccess(true); } protected final void assertBackgroundState() throws Exception { @@ -189,6 +183,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertTrue("App2 is not on background state: " + state, isBackground); } + protected final void assertForegroundState() throws Exception { + final ProcessState state = getProcessStateByUid(mUid); + Log.v(TAG, "assertForegroundState(): status for app2 (" + mUid + "): " + state); + final boolean isForeground = !isBackground(state.state); + assertTrue("App2 is not on foreground state: " + state, isForeground); + } + protected final void assertForegroundServiceState() throws Exception { final ProcessState state = getProcessStateByUid(mUid); Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + "): " + state); @@ -203,39 +204,54 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return state >= PROCESS_STATE_FOREGROUND_SERVICE; } - private String getNetworkStatus(String[] resultItems) { - return resultItems.length < 2 ? null : resultItems[1]; - } + private void assertNetworkAccess(boolean expectAvailable) throws Exception { + final Intent intent = new Intent(ACTION_CHECK_NETWORK); - private void assertNetworkStatus(boolean expectAvailable, String status) throws Exception { - assertNotNull("timeout waiting for ordered broadcast", status); + // When the network info state change, it's possible the app still get the previous value, + // so we need to retry a couple times. + final int maxTries = 5; + String resultData = null; + for (int i = 1; i <= maxTries; i++) { + resultData = sendOrderedBroadcast(intent); + assertNotNull("timeout waiting for ordered broadcast", resultData); - // Network status format is described on MyBroadcastReceiver.checkNetworkStatus() - final String[] parts = status.split(NETWORK_STATUS_SEPARATOR); - assertEquals("Wrong network status: " + status, 5, parts.length); // Sanity check - final State state = State.valueOf(parts[0]); - final DetailedState detailedState = DetailedState.valueOf(parts[1]); - final boolean connected = Boolean.valueOf(parts[2]); - final String connectionCheckDetails = parts[3]; - final String networkInfo = parts[4]; + // Network status format is described on MyBroadcastReceiver.checkNetworkStatus() + final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR); + assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check + final State state = State.valueOf(parts[0]); + final DetailedState detailedState = DetailedState.valueOf(parts[1]); + final boolean connected = Boolean.valueOf(parts[2]); + final String connectionCheckDetails = parts[3]; + final String networkInfo = parts[4]; - if (expectAvailable) { - assertTrue("should be connected: " + connectionCheckDetails - + " (network info: " + networkInfo + ")", connected); - if (ASSERT_NETWORK_INFO_STATE) { - assertEquals("wrong state for " + networkInfo, State.CONNECTED, state); - assertEquals("wrong detailed state for " + networkInfo, - DetailedState.CONNECTED, detailedState); - } - } else { - assertFalse("should not be connected: " + connectionCheckDetails - + " (network info: " + networkInfo + ")", connected); - if (ASSERT_NETWORK_INFO_STATE) { - assertEquals("wrong state for " + networkInfo, State.DISCONNECTED, state); - assertEquals("wrong detailed state for " + networkInfo, - DetailedState.BLOCKED, detailedState); + if (expectAvailable) { + assertTrue("should be connected: " + connectionCheckDetails + + " (network info: " + networkInfo + ")", connected); + if (state != State.CONNECTED) { + Log.d(TAG, "State (" + state + ") not set to CONNECTED on attempt #" + i + + "; sleeping 1s before trying again"); + Thread.sleep(SECOND_IN_MS); + } else { + assertEquals("wrong detailed state for " + networkInfo, + DetailedState.CONNECTED, detailedState); + return; + } + return; + } else { + assertFalse("should not be connected: " + connectionCheckDetails + + " (network info: " + networkInfo + ")", connected); + if (state != State.DISCONNECTED) { + Log.d(TAG, "State (" + state + ") not set to DISCONNECTED on attempt #" + i + + "; sleeping 1s before trying again"); + Thread.sleep(SECOND_IN_MS); + } else { + assertEquals("wrong detailed state for " + networkInfo, + DetailedState.BLOCKED, detailedState); + return; + } } } + fail("Invalid state after " + maxTries + " attempts. Last data: " + resultData); } protected String executeShellCommand(String command) throws Exception { @@ -479,6 +495,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation "am startservice com.android.cts.net.hostside.app2/.MyForegroundService"); } + /** + * Launches an activity on app2 so its process is elevated to foreground status. + */ + protected void launchApp2Activity() throws Exception { + executeShellCommand("am start com.android.cts.net.hostside.app2/.MyActivity"); + } + private String toString(int status) { switch (status) { case RESTRICT_BACKGROUND_STATUS_DISABLED: diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index 8e83fa2b7f..5f5f80bf2c 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -38,10 +38,15 @@ public class BatterySaverModeNonMeteredTest extends AbstractRestrictBackgroundNe public void testBackgroundNetworkAccess_enabled() throws Exception { setPowerSaveMode(true); assertBackgroundNetworkAccess(false); + // Make sure app is allowed if running a foreground service. startForegroundService(); assertForegroundServiceState(); assertBackgroundNetworkAccess(true); + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); } public void testBackgroundNetworkAccess_whitelisted() throws Exception { @@ -51,10 +56,18 @@ public class BatterySaverModeNonMeteredTest extends AbstractRestrictBackgroundNe assertBackgroundNetworkAccess(true); removePowerSaveModeWhitelist(TEST_APP2_PKG); assertBackgroundNetworkAccess(false); + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); } public void testBackgroundNetworkAccess_disabled() throws Exception { setPowerSaveMode(false); assertBackgroundNetworkAccess(true); + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java index e5466cdbb9..539c598c08 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java @@ -49,6 +49,10 @@ public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestC startForegroundService(); assertForegroundServiceState(); assertBackgroundNetworkAccess(true); + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); } public void testBackgroundNetworkAccess_whitelisted() throws Exception { @@ -58,10 +62,18 @@ public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestC assertBackgroundNetworkAccess(true); removePowerSaveModeWhitelist(TEST_APP2_PKG); assertBackgroundNetworkAccess(false); + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); } public void testBackgroundNetworkAccess_disabled() throws Exception { setPowerSaveMode(false); assertBackgroundNetworkAccess(true); + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 60c2b9ba6c..09717701d8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -58,12 +58,16 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase public void testGetRestrictBackgroundStatus_disabled() throws Exception { removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(0); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(0); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); } public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { @@ -72,49 +76,64 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(2); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED); removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(3); assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); - } + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); + } public void testGetRestrictBackgroundStatus_enabled() throws Exception { setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(1); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); // Make sure app is allowed if running a foreground service. assertBackgroundNetworkAccess(false); startForegroundService(); assertForegroundServiceState(); assertBackgroundNetworkAccess(true); + + // Should always have access when running on foreground + launchApp2Activity(); + assertForegroundNetworkAccess(); } public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { addRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(1); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); // Make sure blacklist prevails over whitelist. setRestrictBackground(true); assertRestrictBackgroundChangedReceived(2); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(3); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); // Check status after removing blacklist. removeRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(4); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED); setRestrictBackground(false); assertRestrictBackgroundChangedReceived(5); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); + + // Should always have access when running on foreground + addRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(6); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + launchApp2Activity(); + assertForegroundNetworkAccess(); } public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { @@ -136,4 +155,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase fail(error.toString()); } } + + private void assertDataSaverStatusOnBackground(int expectedStatus) throws Exception { + assertRestrictBackgroundStatus(expectedStatus); + assertBackgroundNetworkAccess(expectedStatus != RESTRICT_BACKGROUND_STATUS_ENABLED); + } } diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml index 9ce57817de..9c4884b525 100644 --- a/tests/cts/hostside/app2/AndroidManifest.xml +++ b/tests/cts/hostside/app2/AndroidManifest.xml @@ -31,6 +31,7 @@ test app. --> + @@ -38,6 +39,7 @@ + diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index d247c3177c..ed58184576 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -28,6 +28,8 @@ public final class Common { static final String DYNAMIC_RECEIVER = "DynamicReceiver"; static final String ACTION_GET_COUNTERS = "com.android.cts.net.hostside.app2.action.GET_COUNTERS"; + static final String ACTION_GET_RESTRICT_BACKGROUND_STATUS = + "com.android.cts.net.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS"; static final String ACTION_CHECK_NETWORK = "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; static final String ACTION_RECEIVER_READY = diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java new file mode 100644 index 0000000000..7c6b50494d --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import static com.android.cts.net.hostside.app2.Common.TAG; +import android.app.Activity; +import android.util.Log; + +/** + * Activity used to bring process to foreground. + */ +public class MyActivity extends Activity { + + @Override + protected void onStart() { + super.onStart(); + Log.d(TAG, "MyActivity.onStart()"); + } + + @Override + protected void onDestroy() { + Log.d(TAG, "MyActivity.onDestroy()"); + super.onDestroy(); + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index e8a959c41e..b876276899 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -19,6 +19,7 @@ package com.android.cts.net.hostside.app2; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK; import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS; +import static com.android.cts.net.hostside.app2.Common.ACTION_GET_RESTRICT_BACKGROUND_STATUS; import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION; import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME; @@ -73,6 +74,9 @@ public class MyBroadcastReceiver extends BroadcastReceiver { case ACTION_GET_COUNTERS: setResultDataFromCounter(context, intent); break; + case ACTION_GET_RESTRICT_BACKGROUND_STATUS: + getRestrictBackgroundStatus(context, intent); + break; case ACTION_CHECK_NETWORK: checkNetwork(context, intent); break; @@ -101,31 +105,30 @@ public class MyBroadcastReceiver extends BroadcastReceiver { return value; } + private void getRestrictBackgroundStatus(Context context, Intent intent) { + final ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + final int apiStatus = cm.getRestrictBackgroundStatus(); + Log.d(TAG, "getRestrictBackgroundStatus: returning " + apiStatus); + setResultData(Integer.toString(apiStatus)); + } + private void checkNetwork(final Context context, Intent intent) { final ConnectivityManager cm = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); - final StringBuilder data = new StringBuilder(); - final int apiStatus = cm.getRestrictBackgroundStatus(); - String netStatus; + String netStatus = null; try { netStatus = checkNetworkStatus(context, cm); } catch (InterruptedException e) { Log.e(TAG, "Timeout checking network status"); - setResultData(null); - return; } - data.append(apiStatus).append(RESULT_SEPARATOR); - if (netStatus != null) { - data.append(netStatus); - } - Log.d(TAG, "checkNetwork: returning " + data); - setResultData(data.toString()); + Log.d(TAG, "checkNetwork(): returning " + netStatus); + setResultData(netStatus); } private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s"; - /** * Checks whether the network is available and return a string which can then be send as a * result data for the ordered broadcast. diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index ece09c84f5..38802d7549 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -111,7 +111,7 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_disabled"); } - public void testBatterySaverModeNonMeteredt_whitelisted() throws Exception { + public void testBatterySaverModeNonMetered_whitelisted() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", "testBackgroundNetworkAccess_whitelisted"); } From ed64e61b5fce76e6eabcf45641021f1fd169e213 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Fri, 6 May 2016 14:38:06 -0700 Subject: [PATCH 0249/1415] Covers more corner cases on restricted network modes: - Tests what happens on foreground applications when a restriction (like Data Saver or Battery Saver modes) is turned on (prior tests would turn the restriction on *before* switching the app to foreground). - Tests multiple restrictions simultaneously enabled. Also improved existing code: - Fixed background state check. - Reused some common checks in helper methods. - Retries checks for process state. BUG: 28473659 Change-Id: Ifcf9cc6d895ccde0ab5177f9f5d8c347ce53b811 --- ...ractRestrictBackgroundNetworkTestCase.java | 98 ++++++++-- .../BatterySaverModeNonMeteredTest.java | 41 ++-- .../net/hostside/BatterySaverModeTest.java | 42 ++-- .../cts/net/hostside/DataSaverModeTest.java | 67 ++++--- .../cts/net/hostside/MixedModesTest.java | 179 ++++++++++++++++++ .../android/cts/net/hostside/app2/Common.java | 3 +- .../cts/net/hostside/app2/MyActivity.java | 19 ++ .../hostside/app2/MyBroadcastReceiver.java | 2 +- .../hostside/app2/MyForegroundService.java | 2 +- ...ostsideRestrictBackgroundNetworkTests.java | 10 + 10 files changed, 383 insertions(+), 80 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 3ee2f6868e..f2a69f2f14 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -176,34 +176,90 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertNetworkAccess(true); } + protected void assertForegroundServiceNetworkAccess() throws Exception { + assertForegroundServiceState(); // Sanity check. + assertNetworkAccess(true); + } + + /** + * Asserts that an app always have access while on foreground or running a foreground service. + * + *

This method will launch an activity and a foreground service to make the assertion, but + * will finish the activity / stop the service afterwards. + */ + protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception{ + // Checks foreground first. + launchActivity(); + assertForegroundNetworkAccess(); + finishActivity(); + + // Then foreground service + startForegroundService(); + assertForegroundServiceNetworkAccess(); + stopForegroundService(); + } + protected final void assertBackgroundState() throws Exception { - final ProcessState state = getProcessStateByUid(mUid); - Log.v(TAG, "assertBackgroundState(): status for app2 (" + mUid + "): " + state); - final boolean isBackground = isBackground(state.state); - assertTrue("App2 is not on background state: " + state, isBackground); + final int maxTries = 30; + ProcessState state = null; + for (int i = 1; i <= maxTries; i++) { + state = getProcessStateByUid(mUid); + Log.v(TAG, "assertBackgroundState(): status for app2 (" + mUid + ") on attempt #" + i + + ": " + state); + if (isBackground(state.state)) { + return; + } + Log.d(TAG, "App not on background state on attempt #" + i + + "; sleeping 1s before trying again"); + Thread.sleep(SECOND_IN_MS); + } + fail("App2 is not on background state after " + maxTries + " attempts: " + state ); } protected final void assertForegroundState() throws Exception { - final ProcessState state = getProcessStateByUid(mUid); - Log.v(TAG, "assertForegroundState(): status for app2 (" + mUid + "): " + state); - final boolean isForeground = !isBackground(state.state); - assertTrue("App2 is not on foreground state: " + state, isForeground); + final int maxTries = 30; + ProcessState state = null; + for (int i = 1; i <= maxTries; i++) { + state = getProcessStateByUid(mUid); + Log.v(TAG, "assertForegroundState(): status for app2 (" + mUid + ") on attempt #" + i + + ": " + state); + if (!isBackground(state.state)) { + return; + } + Log.d(TAG, "App not on foreground state on attempt #" + i + + "; sleeping 1s before trying again"); + Thread.sleep(SECOND_IN_MS); + } + fail("App2 is not on foreground state after " + maxTries + " attempts: " + state ); } protected final void assertForegroundServiceState() throws Exception { - final ProcessState state = getProcessStateByUid(mUid); - Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + "): " + state); - assertEquals("App2 is not on foreground service state: " + state, - PROCESS_STATE_FOREGROUND_SERVICE, state.state); + final int maxTries = 30; + ProcessState state = null; + for (int i = 1; i <= maxTries; i++) { + state = getProcessStateByUid(mUid); + Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + ") on attempt #" + + i + ": " + state); + if (state.state == PROCESS_STATE_FOREGROUND_SERVICE) { + return; + } + Log.d(TAG, "App not on foreground service state on attempt #" + i + + "; sleeping 1s before trying again"); + Thread.sleep(SECOND_IN_MS); + } + fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state ); } /** * Returns whether an app state should be considered "background" for restriction purposes. */ protected boolean isBackground(int state) { - return state >= PROCESS_STATE_FOREGROUND_SERVICE; + return state > PROCESS_STATE_FOREGROUND_SERVICE; } + /** + * Asserts whether the active network is available or not. + */ private void assertNetworkAccess(boolean expectAvailable) throws Exception { final Intent intent = new Intent(ACTION_CHECK_NETWORK); @@ -495,13 +551,27 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation "am startservice com.android.cts.net.hostside.app2/.MyForegroundService"); } + protected void stopForegroundService() throws Exception { + executeShellCommand( + "am stopservice com.android.cts.net.hostside.app2/.MyForegroundService"); + } + /** * Launches an activity on app2 so its process is elevated to foreground status. */ - protected void launchApp2Activity() throws Exception { + protected void launchActivity() throws Exception { executeShellCommand("am start com.android.cts.net.hostside.app2/.MyActivity"); } + /** + * Finishes an activity on app2 so its process is demoted fromforeground status. + */ + protected void finishActivity() throws Exception { + executeShellCommand("am broadcast -a " + + " com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY " + + "--receiver-foreground --receiver-registered-only"); + } + private String toString(int status) { switch (status) { case RESTRICT_BACKGROUND_STATUS_DISABLED: diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index 5f5f80bf2c..d1db01c3b2 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -23,8 +23,10 @@ public class BatterySaverModeNonMeteredTest extends AbstractRestrictBackgroundNe public void setUp() throws Exception { super.setUp(); + // Set initial state. + removePowerSaveModeWhitelist(TEST_APP2_PKG); setPowerSaveMode(false); - assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check + registerBroadcastReceiver(); } @@ -39,35 +41,46 @@ public class BatterySaverModeNonMeteredTest extends AbstractRestrictBackgroundNe setPowerSaveMode(true); assertBackgroundNetworkAccess(false); - // Make sure app is allowed if running a foreground service. - startForegroundService(); - assertForegroundServiceState(); - assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); - // Should always have access when running on foreground - launchApp2Activity(); + // Make sure foreground app doesn't lose access upon enabling it. + setPowerSaveMode(false); + launchActivity(); assertForegroundNetworkAccess(); + setPowerSaveMode(true); + assertForegroundNetworkAccess(); + finishActivity(); + assertBackgroundNetworkAccess(false); + + // Same for foreground service. + setPowerSaveMode(false); + startForegroundService(); + assertForegroundNetworkAccess(); + setPowerSaveMode(true); + assertForegroundNetworkAccess(); + stopForegroundService(); + assertBackgroundNetworkAccess(false); } public void testBackgroundNetworkAccess_whitelisted() throws Exception { setPowerSaveMode(true); assertBackgroundNetworkAccess(false); + addPowerSaveModeWhitelist(TEST_APP2_PKG); assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); assertBackgroundNetworkAccess(false); - // Should always have access when running on foreground - launchApp2Activity(); - assertForegroundNetworkAccess(); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); } public void testBackgroundNetworkAccess_disabled() throws Exception { - setPowerSaveMode(false); assertBackgroundNetworkAccess(true); - // Should always have access when running on foreground - launchApp2Activity(); - assertForegroundNetworkAccess(); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java index 539c598c08..22b876ac3f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java @@ -23,9 +23,11 @@ public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestC public void setUp() throws Exception { super.setUp(); + // Set initial state. setMeteredNetwork(); + removePowerSaveModeWhitelist(TEST_APP2_PKG); setPowerSaveMode(false); - assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check + registerBroadcastReceiver(); } @@ -42,38 +44,48 @@ public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestC public void testBackgroundNetworkAccess_enabled() throws Exception { setPowerSaveMode(true); - assertBackgroundNetworkAccess(false); - // Make sure app is allowed if running a foreground service. - startForegroundService(); - assertForegroundServiceState(); - assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); - // Should always have access when running on foreground - launchApp2Activity(); + // Make sure foreground app doesn't lose access upon enabling it. + setPowerSaveMode(false); + launchActivity(); assertForegroundNetworkAccess(); + setPowerSaveMode(true); + assertForegroundNetworkAccess(); + finishActivity(); + assertBackgroundNetworkAccess(false); + + // Same for foreground service. + setPowerSaveMode(false); + startForegroundService(); + assertForegroundNetworkAccess(); + setPowerSaveMode(true); + assertForegroundNetworkAccess(); + stopForegroundService(); + assertBackgroundNetworkAccess(false); } public void testBackgroundNetworkAccess_whitelisted() throws Exception { setPowerSaveMode(true); assertBackgroundNetworkAccess(false); + addPowerSaveModeWhitelist(TEST_APP2_PKG); assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); assertBackgroundNetworkAccess(false); - // Should always have access when running on foreground - launchApp2Activity(); - assertForegroundNetworkAccess(); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); } public void testBackgroundNetworkAccess_disabled() throws Exception { - setPowerSaveMode(false); assertBackgroundNetworkAccess(true); - // Should always have access when running on foreground - launchApp2Activity(); - assertForegroundNetworkAccess(); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 09717701d8..189515683c 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,15 +20,6 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -/* - * TODO: need to add more scenarios: - * - test access on foreground app - * - test access on foreground service app - * - make sure it works when app is on foreground and state is transitioned: - * - data saver is enabled - * - app is added/removed to blacklist - * - */ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { @@ -39,9 +30,14 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase public void setUp() throws Exception { super.setUp(); + // Set initial state. setMeteredNetwork(); setRestrictBackground(false); + removeRestrictBackgroundWhitelist(mUid); + removeRestrictBackgroundBlacklist(mUid); + registerBroadcastReceiver(); + assertRestrictBackgroundChangedReceived(0); } @Override @@ -56,8 +52,6 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } public void testGetRestrictBackgroundStatus_disabled() throws Exception { - removeRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundChangedReceived(0); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted @@ -65,14 +59,14 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(0); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); - // Should always have access when running on foreground - launchApp2Activity(); - assertForegroundNetworkAccess(); + assertsForegroundAlwaysHasNetworkAccess(); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); } public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(2); @@ -80,11 +74,10 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase removeRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(3); - assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); - // Should always have access when running on foreground - launchApp2Activity(); - assertForegroundNetworkAccess(); + assertsForegroundAlwaysHasNetworkAccess(); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); } public void testGetRestrictBackgroundStatus_enabled() throws Exception { @@ -92,19 +85,26 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); - removeRestrictBackgroundWhitelist(mUid); - assertRestrictBackgroundChangedReceived(1); + assertsForegroundAlwaysHasNetworkAccess(); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); - // Make sure app is allowed if running a foreground service. - assertBackgroundNetworkAccess(false); - startForegroundService(); - assertForegroundServiceState(); - assertBackgroundNetworkAccess(true); - - // Should always have access when running on foreground - launchApp2Activity(); + // Make sure foreground app doesn't lose access upon enabling it. + setRestrictBackground(false); + launchActivity(); assertForegroundNetworkAccess(); + setRestrictBackground(true); + assertForegroundNetworkAccess(); + finishActivity(); + assertBackgroundNetworkAccess(false); + + // Same for foreground service. + setRestrictBackground(false); + startForegroundService(); + assertForegroundNetworkAccess(); + setRestrictBackground(true); + assertForegroundNetworkAccess(); + stopForegroundService(); + assertBackgroundNetworkAccess(false); } public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { @@ -112,6 +112,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertsForegroundAlwaysHasNetworkAccess(); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + // Make sure blacklist prevails over whitelist. setRestrictBackground(true); assertRestrictBackgroundChangedReceived(2); @@ -128,12 +131,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(5); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); - // Should always have access when running on foreground - addRestrictBackgroundBlacklist(mUid); - assertRestrictBackgroundChangedReceived(6); - assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); - launchApp2Activity(); - assertForegroundNetworkAccess(); + assertsForegroundAlwaysHasNetworkAccess(); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); } public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java new file mode 100644 index 0000000000..140d1354bf --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import android.util.Log; + +/** + * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode + * and Data Saver Mode) are applied simultaneously. + *

+ * NOTE: it might sound like the test methods on this class are testing too much, + * which would make it harder to diagnose individual failures, but the assumption is that such + * failure most likely will happen when the restriction is tested individually as well. + */ +public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { + private static final String TAG = "MixedModesTest"; + + @Override + public void setUp() throws Exception { + super.setUp(); + + // Set initial state. + removeRestrictBackgroundWhitelist(mUid); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + registerBroadcastReceiver(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + try { + setRestrictBackground(false); + } finally { + setPowerSaveMode(false); + } + } + + /** + * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. + */ + public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); + setMeteredNetwork(); + + try { + setRestrictBackground(true); + setPowerSaveMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } finally { + resetMeteredNetwork(); + } + } + + /** + * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered + * networks. + */ + public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + if (mCm.isActiveNetworkMetered()) { + Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network" + + " is metered"); + return; + } + Log.i(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() tests"); + setRestrictBackground(true); + setPowerSaveMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index ed58184576..d827921654 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -34,10 +34,11 @@ public final class Common { "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; static final String ACTION_RECEIVER_READY = "com.android.cts.net.hostside.app2.action.RECEIVER_READY"; + static final String ACTION_FINISH_ACTIVITY = + "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY"; static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; static final String EXTRA_RECEIVER_NAME = "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; - static final char RESULT_SEPARATOR = ';'; static int getUid(Context context) { final String packageName = context.getPackageName(); diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java index 7c6b50494d..444b696962 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java @@ -15,8 +15,15 @@ */ package com.android.cts.net.hostside.app2; +import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_ACTIVITY; import static com.android.cts.net.hostside.app2.Common.TAG; + import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; import android.util.Log; /** @@ -24,6 +31,18 @@ import android.util.Log; */ public class MyActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + registerReceiver(new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "Finishing MyActivity"); + MyActivity.this.finish(); + }}, new IntentFilter(ACTION_FINISH_ACTIVITY)); + } + @Override protected void onStart() { super.onStart(); diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index b876276899..114d5c11d9 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -17,6 +17,7 @@ package com.android.cts.net.hostside.app2; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; + import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK; import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS; import static com.android.cts.net.hostside.app2.Common.ACTION_GET_RESTRICT_BACKGROUND_STATUS; @@ -24,7 +25,6 @@ import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION; import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME; import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; -import static com.android.cts.net.hostside.app2.Common.RESULT_SEPARATOR; import static com.android.cts.net.hostside.app2.Common.TAG; import static com.android.cts.net.hostside.app2.Common.getUid; diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java index bbafd4c274..1afc3d6c41 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java @@ -35,7 +35,7 @@ public class MyForegroundService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "MyForegroundService.onStartCommand: " + intent); + Log.d(TAG, "MyForegroundService.onStartCommand(): " + intent); startForeground(42, new Notification.Builder(this) .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine .build()); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 38802d7549..ec375d6a47 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -121,6 +121,16 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDataAndBatterySaverModes_meteredNetwork"); + } + + public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDataAndBatterySaverModes_nonMeteredNetwork"); + } + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { final int max_tries = 5; boolean actual = false; From 3361c861477020ec85d230fe8d342627e4352f4b Mon Sep 17 00:00:00 2001 From: Aaron Holden Date: Tue, 10 May 2016 15:58:46 -0700 Subject: [PATCH 0250/1415] Remove module-level WifiCheck preparers As WifiCheck is now declared in the CTS config, remove declarations in the module configs. Also downgrade TargetSetupErrors on failure to logged errors bug:28234985 Change-Id: I2e1a369bc26aeca922686c4c3d8c033bb7f9fbc7 --- tests/cts/net/AndroidTest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml index dc803397d9..5194da37d2 100644 --- a/tests/cts/net/AndroidTest.xml +++ b/tests/cts/net/AndroidTest.xml @@ -13,7 +13,6 @@ limitations under the License. --> -

By default is empty - it's up to subclasses to override. + */ + protected void setUpMeteredNetwork() throws Exception { + } + + /** + * Resets the (non) metered network state. + * + *

By default is empty - it's up to subclasses to override. + */ + protected void tearDownMeteredNetwork() throws Exception { + } + + public void testBackgroundNetworkAccess_enabled() throws Exception { + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + // Make sure foreground app doesn't lose access upon enabling it. + setAppIdle(true); + launchActivity(); + assertAppIdle(false); // Sanity check - not idle anymore, since activity was launched... + assertForegroundNetworkAccess(); + finishActivity(); + assertAppIdle(false); // Sanity check - not idle anymore, since activity was launched... + assertBackgroundNetworkAccess(true); + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + // Same for foreground service. + setAppIdle(true); + startForegroundService(); + assertAppIdle(true); // Sanity check - still idle + assertForegroundServiceNetworkAccess(); + stopForegroundService(); + assertAppIdle(true); + assertBackgroundNetworkAccess(false); + } + + public void testBackgroundNetworkAccess_whitelisted() throws Exception { + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertAppIdle(false); // Sanity check - not idle anymore, since whitelisted + assertBackgroundNetworkAccess(true); + + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertAppIdle(true); // Sanity check - idle again, once whitelisted was removed + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + + // Sanity check - no whitelist, no access! + setAppIdle(true); + assertBackgroundNetworkAccess(false); + } + + public void testBackgroundNetworkAccess_disabled() throws Exception { + assertBackgroundNetworkAccess(true); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java similarity index 68% rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java rename to tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index 22b876ac3f..2acc670800 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -16,60 +16,78 @@ package com.android.cts.net.hostside; -//TODO: move this and BatterySaverModeNonMeteredTest's logic into a common superclass -public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { +/** + * Base class for metered and non-metered Battery Saver Mode tests. + */ +abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { @Override - public void setUp() throws Exception { + protected final void setUp() throws Exception { super.setUp(); // Set initial state. - setMeteredNetwork(); + setUpMeteredNetwork(); removePowerSaveModeWhitelist(TEST_APP2_PKG); - setPowerSaveMode(false); + setBatterySaverMode(false); registerBroadcastReceiver(); } @Override - protected void tearDown() throws Exception { + protected final void tearDown() throws Exception { super.tearDown(); try { - resetMeteredNetwork(); + tearDownMeteredNetwork(); } finally { - setPowerSaveMode(false); + setBatterySaverMode(false); } } + /** + * Sets the initial (non) metered network state. + * + *

By default is empty - it's up to subclasses to override. + */ + protected void setUpMeteredNetwork() throws Exception { + } + + /** + * Resets the (non) metered network state. + * + *

By default is empty - it's up to subclasses to override. + */ + protected void tearDownMeteredNetwork() throws Exception { + } + public void testBackgroundNetworkAccess_enabled() throws Exception { - setPowerSaveMode(true); + setBatterySaverMode(true); assertBackgroundNetworkAccess(false); assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(false); // Make sure foreground app doesn't lose access upon enabling it. - setPowerSaveMode(false); + setBatterySaverMode(false); launchActivity(); assertForegroundNetworkAccess(); - setPowerSaveMode(true); + setBatterySaverMode(true); assertForegroundNetworkAccess(); finishActivity(); assertBackgroundNetworkAccess(false); // Same for foreground service. - setPowerSaveMode(false); + setBatterySaverMode(false); startForegroundService(); assertForegroundNetworkAccess(); - setPowerSaveMode(true); + setBatterySaverMode(true); assertForegroundNetworkAccess(); stopForegroundService(); assertBackgroundNetworkAccess(false); } public void testBackgroundNetworkAccess_whitelisted() throws Exception { - setPowerSaveMode(true); + setBatterySaverMode(true); assertBackgroundNetworkAccess(false); addPowerSaveModeWhitelist(TEST_APP2_PKG); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java new file mode 100644 index 0000000000..f3c49353f6 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +/** + * Base class for metered and non-metered Doze Mode tests. + */ +abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { + + @Override + protected final void setUp() throws Exception { + super.setUp(); + + // Set initial state. + setUpMeteredNetwork(); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + setDozeMode(false); + + registerBroadcastReceiver(); + } + + @Override + protected final void tearDown() throws Exception { + super.tearDown(); + + try { + tearDownMeteredNetwork(); + } finally { + setDozeMode(false); + } + } + + /** + * Sets the initial (non) metered network state. + * + *

By default is empty - it's up to subclasses to override. + */ + protected void setUpMeteredNetwork() throws Exception { + } + + /** + * Resets the (non) metered network state. + * + *

By default is empty - it's up to subclasses to override. + */ + protected void tearDownMeteredNetwork() throws Exception { + } + + public void testBackgroundNetworkAccess_enabled() throws Exception { + setDozeMode(true); + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + // Make sure foreground service doesn't lose network access upon enabling doze. + setDozeMode(false); + startForegroundService(); + assertForegroundNetworkAccess(); + setDozeMode(true); + assertForegroundNetworkAccess(); + stopForegroundService(); + assertBackgroundState(); + assertBackgroundNetworkAccess(false); + } + + public void testBackgroundNetworkAccess_whitelisted() throws Exception { + setDozeMode(true); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + } + + public void testBackgroundNetworkAccess_disabled() throws Exception { + assertBackgroundNetworkAccess(true); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + } + + // Must override so it only tests foreground service - once an app goes to foreground, device + // leaves Doze Mode. + @Override + protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception { + startForegroundService(); + assertForegroundServiceNetworkAccess(); + stopForegroundService(); + assertBackgroundState(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index f2a69f2f14..17480e2efe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -80,7 +80,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private String mMeteredWifi; @Override - public void setUp() throws Exception { + protected void setUp() throws Exception { super.setUp(); mInstrumentation = getInstrumentation(); @@ -329,7 +329,12 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation */ protected void assertDelayedShellCommand(String command, final String expectedResult) throws Exception { - assertDelayedShellCommand(command, new ExpectResultChecker() { + assertDelayedShellCommand(command, 5, 1, expectedResult); + } + + protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, + final String expectedResult) throws Exception { + assertDelayedShellCommand(command, maxTries, napTimeSeconds, new ExpectResultChecker() { @Override public boolean isExpected(String result) { @@ -345,21 +350,28 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void assertDelayedShellCommand(String command, ExpectResultChecker checker) throws Exception { - final int maxTries = 5; + assertDelayedShellCommand(command, 5, 1, checker); + } + protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, + ExpectResultChecker checker) throws Exception { String result = ""; for (int i = 1; i <= maxTries; i++) { result = executeShellCommand(command).trim(); if (checker.isExpected(result)) return; Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" + checker.getExpected() + "' on attempt #" + i - + "; sleeping 1s before trying again"); - Thread.sleep(SECOND_IN_MS); + + "; sleeping " + napTimeSeconds + "s before trying again"); + Thread.sleep(napTimeSeconds * SECOND_IN_MS); } fail("Command '" + command + "' did not return '" + checker.getExpected() + "' after " + maxTries + " attempts. Last result: '" + result + "'"); } + /** + * Puts the device in a state where the active network is metered, or fail if it can't achieve + * that state. + */ protected void setMeteredNetwork() throws Exception { final NetworkInfo info = mCm.getActiveNetworkInfo(); final boolean metered = mCm.isActiveNetworkMetered(); @@ -375,17 +387,37 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mMeteredWifi = netId; // Sanity check. assertWifiMeteredStatus(netId, true); - assertTrue("Could not set wifi '" + netId + "' as metered (" - + mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered()); + assertActiveNetworkMetered(true); } + /** + * Puts the device in a state where the active network is not metered, or fail if it can't + * achieve that state. + *

It assumes the device has a valid WI-FI connection. + */ protected void resetMeteredNetwork() throws Exception { - if (mMeteredWifi == null) { - Log.d(TAG, "resetMeteredNetwork(): wifi not set as metered"); - return; + if (mMeteredWifi != null) { + Log.i(TAG, "resetMeteredNetwork(): SID '" + mMeteredWifi + + "' was set as metered by test case; resetting it"); + setWifiMeteredStatus(mMeteredWifi, false); + } else { + final NetworkInfo info = mCm.getActiveNetworkInfo(); + assertNotNull("Could not get active network", info); + if (!info.isMetered()) { + Log.d(TAG, "Active network is not metered: " + info); + } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { + Log.i(TAG, "Setting active WI-FI network as metered: " + info ); + setWifiMeteredStatus(false); + } else { + fail("Active network is not WI-FI hence cannot be set as non-metered: " + info); + } } - Log.i(TAG, "resetMeteredNetwork(): resetting " + mMeteredWifi); - setWifiMeteredStatus(mMeteredWifi, false); + assertActiveNetworkMetered(false); // Sanity check. + } + + private void assertActiveNetworkMetered(boolean expected) { + final NetworkInfo info = mCm.getActiveNetworkInfo(); + assertEquals("Wrong metered status for active network " + info, expected, info.isMetered()); } private String setWifiMeteredStatus(boolean metered) throws Exception { @@ -512,16 +544,63 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertPowerSaveModeWhitelist(packageName, false); // Sanity check } - protected void setPowerSaveMode(boolean enabled) throws Exception { - Log.i(TAG, "Setting power mode to " + enabled); + protected void turnBatteryOff() throws Exception { + executeSilentShellCommand("cmd battery unplug"); + } + + protected void turnBatteryOn() throws Exception { + executeSilentShellCommand("cmd battery reset"); + } + + protected void turnScreenOff() throws Exception { + executeSilentShellCommand("input keyevent KEYCODE_SLEEP"); + } + + protected void turnScreenOn() throws Exception { + executeSilentShellCommand("input keyevent KEYCODE_WAKEUP"); + executeSilentShellCommand("wm dismiss-keyguard"); + } + + protected void setBatterySaverMode(boolean enabled) throws Exception { + Log.i(TAG, "Setting Battery Saver Mode to " + enabled); if (enabled) { + turnBatteryOff(); executeSilentShellCommand("cmd battery unplug"); executeSilentShellCommand("settings put global low_power 1"); } else { - executeSilentShellCommand("cmd battery reset"); + turnBatteryOn(); } } + protected void setDozeMode(boolean enabled) throws Exception { + Log.i(TAG, "Setting Doze Mode to " + enabled); + if (enabled) { + turnBatteryOff(); + turnScreenOff(); + executeShellCommand("dumpsys deviceidle force-idle deep"); + } else { + turnScreenOn(); + turnBatteryOn(); + executeShellCommand("dumpsys deviceidle unforce"); + } + // Sanity check. + assertDozeMode(enabled); + } + + protected void assertDozeMode(boolean enabled) throws Exception { + assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE"); + } + + protected void setAppIdle(boolean enabled) throws Exception { + Log.i(TAG, "Setting app idle to " + enabled); + executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); + assertAppIdle(enabled); // Sanity check + } + + protected void assertAppIdle(boolean enabled) throws Exception { + assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 10, 2, "Idle=" + enabled); + } + /** * Starts a service that will register a broadcast receiver to receive * {@code RESTRICT_BACKGROUND_CHANGE} intents. @@ -548,19 +627,23 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void startForegroundService() throws Exception { executeShellCommand( - "am startservice com.android.cts.net.hostside.app2/.MyForegroundService"); + "am startservice -f 1 com.android.cts.net.hostside.app2/.MyForegroundService"); + assertForegroundServiceState(); } protected void stopForegroundService() throws Exception { executeShellCommand( - "am stopservice com.android.cts.net.hostside.app2/.MyForegroundService"); + "am startservice -f 2 com.android.cts.net.hostside.app2/.MyForegroundService"); + // NOTE: cannot assert state because it depends on whether activity was on top before. } /** * Launches an activity on app2 so its process is elevated to foreground status. */ protected void launchActivity() throws Exception { + turnScreenOn(); executeShellCommand("am start com.android.cts.net.hostside.app2/.MyActivity"); + assertForegroundState(); } /** @@ -608,8 +691,17 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } } + /** + * Helper class used to assert the result of a Shell command. + */ protected static interface ExpectResultChecker { + /** + * Checkes whether the result of the command matched the expectation. + */ boolean isExpected(String result); + /** + * Gets the expected result so it's displayed on log and failure messages. + */ String getExpected(); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java new file mode 100644 index 0000000000..e008c695bb --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +public class AppIdleMeteredTest extends AbstractAppIdleTestCase { + + @Override + protected void setUpMeteredNetwork() throws Exception { + setMeteredNetwork(); + } + + @Override + protected void tearDownMeteredNetwork() throws Exception { + resetMeteredNetwork(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java new file mode 100644 index 0000000000..633dc81c95 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase { + + @Override + protected void setUpMeteredNetwork() throws Exception { + resetMeteredNetwork(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java new file mode 100644 index 0000000000..3a88bbd1ad --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase { + + @Override + protected void setUpMeteredNetwork() throws Exception { + setMeteredNetwork(); + } + + @Override + protected void tearDownMeteredNetwork() throws Exception { + resetMeteredNetwork(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index d1db01c3b2..646c4b993a 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -16,71 +16,10 @@ package com.android.cts.net.hostside; -//TODO: move this and BatterySaverModeTest's logic into a common superclass -public class BatterySaverModeNonMeteredTest extends AbstractRestrictBackgroundNetworkTestCase { +public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { @Override - public void setUp() throws Exception { - super.setUp(); - - // Set initial state. - removePowerSaveModeWhitelist(TEST_APP2_PKG); - setPowerSaveMode(false); - - registerBroadcastReceiver(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - - setPowerSaveMode(false); - } - - public void testBackgroundNetworkAccess_enabled() throws Exception { - setPowerSaveMode(true); - assertBackgroundNetworkAccess(false); - - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - - // Make sure foreground app doesn't lose access upon enabling it. - setPowerSaveMode(false); - launchActivity(); - assertForegroundNetworkAccess(); - setPowerSaveMode(true); - assertForegroundNetworkAccess(); - finishActivity(); - assertBackgroundNetworkAccess(false); - - // Same for foreground service. - setPowerSaveMode(false); - startForegroundService(); - assertForegroundNetworkAccess(); - setPowerSaveMode(true); - assertForegroundNetworkAccess(); - stopForegroundService(); - assertBackgroundNetworkAccess(false); - } - - public void testBackgroundNetworkAccess_whitelisted() throws Exception { - setPowerSaveMode(true); - assertBackgroundNetworkAccess(false); - - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - } - - public void testBackgroundNetworkAccess_disabled() throws Exception { - assertBackgroundNetworkAccess(true); - - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); + protected void setUpMeteredNetwork() throws Exception { + resetMeteredNetwork(); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java new file mode 100644 index 0000000000..656d274c52 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +public class DozeModeMeteredTest extends AbstractDozeModeTestCase { + + @Override + protected void setUpMeteredNetwork() throws Exception { + setMeteredNetwork(); + } + + @Override + protected void tearDownMeteredNetwork() throws Exception { + resetMeteredNetwork(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java new file mode 100644 index 0000000000..c76123822f --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { + + @Override + protected void setUpMeteredNetwork() throws Exception { + resetMeteredNetwork(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index 140d1354bf..c97a0f91f3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -47,7 +47,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { try { setRestrictBackground(false); } finally { - setPowerSaveMode(false); + setBatterySaverMode(false); } } @@ -60,7 +60,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { try { setRestrictBackground(true); - setPowerSaveMode(true); + setBatterySaverMode(true); Log.v(TAG, "Not whitelisted for any."); assertBackgroundNetworkAccess(false); @@ -126,7 +126,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } Log.i(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() tests"); setRestrictBackground(true); - setPowerSaveMode(true); + setBatterySaverMode(true); Log.v(TAG, "Not whitelisted for any."); assertBackgroundNetworkAccess(false); diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java index 1afc3d6c41..b88c45dbb4 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java @@ -28,6 +28,9 @@ import android.util.Log; */ public class MyForegroundService extends Service { + private static final int FLAG_START_FOREGROUND = 1; + private static final int FLAG_STOP_FOREGROUND = 2; + @Override public IBinder onBind(Intent intent) { return null; @@ -35,10 +38,21 @@ public class MyForegroundService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "MyForegroundService.onStartCommand(): " + intent); - startForeground(42, new Notification.Builder(this) - .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine - .build()); + Log.v(TAG, "MyForegroundService.onStartCommand(): " + intent); + switch (intent.getFlags()) { + case FLAG_START_FOREGROUND: + Log.d(TAG, "Starting foreground"); + startForeground(42, new Notification.Builder(this) + .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine + .build()); + break; + case FLAG_STOP_FOREGROUND: + Log.d(TAG, "Stopping foreground"); + stopForeground(true); + break; + default: + Log.wtf(TAG, "Invalid flag on intent " + intent); + } return START_STICKY; } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index ec375d6a47..04a02ea90b 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -39,6 +39,10 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC uninstallPackage(TEST_APP2_PKG, true); } + /************************** + * Data Saver Mode tests. * + **************************/ + public void testDataSaverMode_disabled() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", "testGetRestrictBackgroundStatus_disabled"); @@ -80,18 +84,22 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testGetRestrictBackgroundStatus_requiredWhitelistedPackages"); } - public void testBatterySaverMode_disabled() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest", + /***************************** + * Battery Saver Mode tests. * + *****************************/ + + public void testBatterySaverModeMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest", "testBackgroundNetworkAccess_disabled"); } - public void testBatterySaverMode_whitelisted() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest", + public void testBatterySaverModeMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest", "testBackgroundNetworkAccess_whitelisted"); } - public void testBatterySaverMode_enabled() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest", + public void testBatterySaverModeMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest", "testBackgroundNetworkAccess_enabled"); } @@ -121,6 +129,88 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + /******************* + * App idle tests. * + *******************/ + + public void testAppIdleMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testAppIdleMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testAppIdleMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + // TODO: currently power-save mode and idle uses the same whitelist, so this test would be + // redundant (as it would be testing the same as testBatterySaverMode_reinstall()) + // public void testAppIdle_reinstall() throws Exception { + // } + + public void testAppIdleNonMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testAppIdleNonMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testAppIdleNonMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + /******************** + * Doze Mode tests. * + ********************/ + + public void testDozeModeMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testDozeModeMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testDozeModeMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + // TODO: currently power-save mode and idle uses the same whitelist, so this test would be + // redundant (as it would be testing the same as testBatterySaverMode_reinstall()) + // public void testDozeMode_reinstall() throws Exception { + // } + + public void testDozeModeNonMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testDozeModeNonMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testDozeModeNonMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + /********************** + * Mixed modes tests. * + **********************/ + public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", "testDataAndBatterySaverModes_meteredNetwork"); @@ -131,6 +221,10 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testDataAndBatterySaverModes_nonMeteredNetwork"); } + /******************* + * Helper methods. * + *******************/ + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { final int max_tries = 5; boolean actual = false; From cbcfb98dd8c062ddb4c5c85d8e2d7525532b383d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 15 Apr 2016 16:27:49 +0900 Subject: [PATCH 0252/1415] Add a test for closing sockets when a VPN comes up. Bug: 28251576 Change-Id: Iab0a8643cff3c54eb04168a7cdfa116c0b8e30b1 --- tests/cts/hostside/aidl/Android.mk | 22 +++++ .../net/hostside/IRemoteSocketFactory.aidl | 25 +++++ tests/cts/hostside/app/Android.mk | 3 +- .../hostside/RemoteSocketFactoryClient.java | 91 +++++++++++++++++++ .../com/android/cts/net/hostside/VpnTest.java | 91 ++++++++++++++++++- tests/cts/hostside/app2/Android.mk | 1 + tests/cts/hostside/app2/AndroidManifest.xml | 6 +- .../app2/RemoteSocketFactoryService.java | 63 +++++++++++++ .../cts/net/HostsideNetworkTestCase.java | 2 + ...ostsideRestrictBackgroundNetworkTests.java | 3 - .../com/android/cts/net/HostsideVpnTests.java | 27 +++++- 11 files changed, 323 insertions(+), 11 deletions(-) create mode 100644 tests/cts/hostside/aidl/Android.mk create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java diff --git a/tests/cts/hostside/aidl/Android.mk b/tests/cts/hostside/aidl/Android.mk new file mode 100644 index 0000000000..a7ec6efb31 --- /dev/null +++ b/tests/cts/hostside/aidl/Android.mk @@ -0,0 +1,22 @@ +# Copyright (C) 2016 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests +LOCAL_SDK_VERSION := current +LOCAL_SRC_FILES := com/android/cts/net/hostside/IRemoteSocketFactory.aidl +LOCAL_MODULE := CtsHostsideNetworkTestsAidl +include $(BUILD_JAVA_LIBRARY) diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl new file mode 100644 index 0000000000..68176ad80d --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import android.os.ParcelFileDescriptor; + +interface IRemoteSocketFactory { + ParcelFileDescriptor openSocketFd(String host, int port, int timeoutMs); + String getPackageName(); + int getUid(); +} diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index 7f8da07943..9519ec5242 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -20,7 +20,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current -LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator +LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator \ + CtsHostsideNetworkTestsAidl LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java new file mode 100644 index 0000000000..799fe50ebe --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.ConditionVariable; +import android.os.IBinder; +import android.os.RemoteException; + +import com.android.cts.net.hostside.IRemoteSocketFactory; + +import java.io.FileDescriptor; + +public class RemoteSocketFactoryClient { + private static final int TIMEOUT_MS = 5000; + private static final String PACKAGE = RemoteSocketFactoryClient.class.getPackage().getName(); + private static final String APP2_PACKAGE = PACKAGE + ".app2"; + private static final String SERVICE_NAME = APP2_PACKAGE + ".RemoteSocketFactoryService"; + + private Context mContext; + private ServiceConnection mServiceConnection; + private IRemoteSocketFactory mService; + + public RemoteSocketFactoryClient(Context context) { + mContext = context; + } + + public void bind() { + if (mService != null) { + throw new IllegalStateException("Already bound"); + } + + final ConditionVariable cv = new ConditionVariable(); + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IRemoteSocketFactory.Stub.asInterface(service); + cv.open(); + } + @Override + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + }; + + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(APP2_PACKAGE, SERVICE_NAME)); + mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); + cv.block(TIMEOUT_MS); + if (mService == null) { + throw new IllegalStateException( + "Could not bind to RemoteSocketFactory service after " + TIMEOUT_MS + "ms"); + } + } + + public void unbind() { + if (mService != null) { + mContext.unbindService(mServiceConnection); + } + } + + public FileDescriptor openSocketFd( + String host, int port, int timeoutMs) throws RemoteException { + return mService.openSocketFd(host, port, timeoutMs).getFileDescriptor(); + } + + public String getPackageName() throws RemoteException { + return mService.getPackageName(); + } + + public int getUid() throws RemoteException { + return mService.getUid(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index 5045cc26b4..12fe625370 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -27,6 +27,8 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.VpnService; +import android.os.ParcelFileDescriptor; +import android.os.Process; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; @@ -40,11 +42,18 @@ import android.test.MoreAsserts; import android.text.TextUtils; import android.util.Log; +import com.android.cts.net.hostside.IRemoteSocketFactory; + +import java.io.BufferedReader; import java.io.Closeable; import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.FileInputStream; +import java.io.InputStreamReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintWriter; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Inet6Address; @@ -52,6 +61,8 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketException; +import java.nio.charset.StandardCharsets; import java.util.Random; /** @@ -79,11 +90,14 @@ public class VpnTest extends InstrumentationTestCase { public static String TAG = "VpnTest"; public static int TIMEOUT_MS = 3 * 1000; public static int SOCKET_TIMEOUT_MS = 100; + public static String TEST_HOST = "connectivitycheck.gstatic.com"; private UiDevice mDevice; private MyActivity mActivity; private String mPackageName; private ConnectivityManager mCM; + private RemoteSocketFactoryClient mRemoteSocketFactoryClient; + Network mNetwork; NetworkCallback mCallback; final Object mLock = new Object(); @@ -107,11 +121,14 @@ public class VpnTest extends InstrumentationTestCase { MyActivity.class, null); mPackageName = mActivity.getPackageName(); mCM = (ConnectivityManager) mActivity.getSystemService(mActivity.CONNECTIVITY_SERVICE); + mRemoteSocketFactoryClient = new RemoteSocketFactoryClient(mActivity); + mRemoteSocketFactoryClient.bind(); mDevice.waitForIdle(); } @Override public void tearDown() throws Exception { + mRemoteSocketFactoryClient.unbind(); if (mCallback != null) { mCM.unregisterNetworkCallback(mCallback); } @@ -441,7 +458,7 @@ public class VpnTest extends InstrumentationTestCase { } } - private void checkTrafficOnVpn() throws IOException, ErrnoException { + private void checkTrafficOnVpn() throws Exception { checkUdpEcho("192.0.2.251", "192.0.2.2"); checkUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); checkPing("2001:db8:dead:beef::f00"); @@ -449,29 +466,88 @@ public class VpnTest extends InstrumentationTestCase { checkTcpReflection("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); } - private void checkNoTrafficOnVpn() throws IOException, ErrnoException { + private void checkNoTrafficOnVpn() throws Exception { checkUdpEcho("192.0.2.251", null); checkUdpEcho("2001:db8:dead:beef::f00", null); checkTcpReflection("192.0.2.252", null); checkTcpReflection("2001:db8:dead:beef::f00", null); } + private FileDescriptor openSocketFd(String host, int port, int timeoutMs) throws Exception { + Socket s = new Socket(host, port); + s.setSoTimeout(timeoutMs); + return ParcelFileDescriptor.fromSocket(s).getFileDescriptor(); + } + + private FileDescriptor openSocketFdInOtherApp( + String host, int port, int timeoutMs) throws Exception { + Log.d(TAG, String.format("Creating test socket in UID=%d, my UID=%d", + mRemoteSocketFactoryClient.getUid(), Os.getuid())); + FileDescriptor fd = mRemoteSocketFactoryClient.openSocketFd(host, port, TIMEOUT_MS); + return fd; + } + + private void sendRequest(FileDescriptor fd, String host) throws Exception { + String request = "GET /generate_204 HTTP/1.1\r\n" + + "Host: " + host + "\r\n" + + "Connection: keep-alive\r\n\r\n"; + byte[] requestBytes = request.getBytes(StandardCharsets.UTF_8); + int ret = Os.write(fd, requestBytes, 0, requestBytes.length); + Log.d(TAG, "Wrote " + ret + "bytes"); + + String expected = "HTTP/1.1 204 No Content\r\n"; + byte[] response = new byte[expected.length()]; + Os.read(fd, response, 0, response.length); + + String actual = new String(response, StandardCharsets.UTF_8); + assertEquals(expected, actual); + Log.d(TAG, "Got response: " + actual); + } + + private void assertSocketStillOpen(FileDescriptor fd, String host) throws Exception { + try { + sendRequest(fd, host); + } finally { + Os.close(fd); + } + } + + private void assertSocketClosed(FileDescriptor fd, String host) throws Exception { + try { + sendRequest(fd, host); + fail("Socket opened before VPN connects should be closed when VPN connects"); + } catch (ErrnoException expected) { + assertEquals(ECONNABORTED, expected.errno); + } finally { + Os.close(fd); + } + } + public void testDefault() throws Exception { if (!supportedHardware()) return; + FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"0.0.0.0/0", "::/0"}, "", ""); + assertSocketClosed(fd, TEST_HOST); + checkTrafficOnVpn(); } public void testAppAllowed() throws Exception { if (!supportedHardware()) return; + FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + + String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, - mPackageName, ""); + allowedApps, ""); + + assertSocketClosed(fd, TEST_HOST); checkTrafficOnVpn(); } @@ -479,9 +555,16 @@ public class VpnTest extends InstrumentationTestCase { public void testAppDisallowed() throws Exception { if (!supportedHardware()) return; + FileDescriptor localFd = openSocketFd(TEST_HOST, 80, TIMEOUT_MS); + FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + + String disallowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, - "", mPackageName); + "", disallowedApps); + + assertSocketStillOpen(localFd, TEST_HOST); + assertSocketStillOpen(remoteFd, TEST_HOST); checkNoTrafficOnVpn(); } diff --git a/tests/cts/hostside/app2/Android.mk b/tests/cts/hostside/app2/Android.mk index 3b59f8f6ce..706455d563 100644 --- a/tests/cts/hostside/app2/Android.mk +++ b/tests/cts/hostside/app2/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current +LOCAL_STATIC_JAVA_LIBRARIES := CtsHostsideNetworkTestsAidl LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml index 9c4884b525..80b669d4eb 100644 --- a/tests/cts/hostside/app2/AndroidManifest.xml +++ b/tests/cts/hostside/app2/AndroidManifest.xml @@ -29,11 +29,15 @@ The manifest-defined listener also handles ordered broadcasts used to share data with the test app. + + This application also provides a service, RemoteSocketFactoryService, that the test app can + use to open sockets to remote hosts as a different user ID. --> + @@ -45,4 +49,4 @@ - \ No newline at end of file + diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java new file mode 100644 index 0000000000..b1b7d77ae1 --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.util.Log; + +import com.android.cts.net.hostside.IRemoteSocketFactory; + +import java.net.Socket; + + +public class RemoteSocketFactoryService extends Service { + + private static final String TAG = RemoteSocketFactoryService.class.getSimpleName(); + + private IRemoteSocketFactory.Stub mBinder = new IRemoteSocketFactory.Stub() { + @Override + public ParcelFileDescriptor openSocketFd(String host, int port, int timeoutMs) { + try { + Socket s = new Socket(host, port); + s.setSoTimeout(timeoutMs); + return ParcelFileDescriptor.fromSocket(s); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public String getPackageName() { + return RemoteSocketFactoryService.this.getPackageName(); + } + + @Override + public int getUid() { + return Process.myUid(); + } + }; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 39b5652c76..6642512758 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -42,6 +42,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected static final String TAG = "HostsideNetworkTests"; protected static final String TEST_PKG = "com.android.cts.net.hostside"; protected static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk"; + protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; + protected static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk"; private IAbi mAbi; private IBuildInfo mCtsBuild; diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index ec375d6a47..1a8634e584 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -21,9 +21,6 @@ import com.android.tradefed.device.DeviceNotAvailableException; public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase { - private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; - private static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk"; - @Override protected void setUp() throws Exception { super.setUp(); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java index dc965c50f8..69b07af193 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -18,7 +18,30 @@ package com.android.cts.net; public class HostsideVpnTests extends HostsideNetworkTestCase { - public void testVpn() throws Exception { - runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest"); + @Override + protected void setUp() throws Exception { + super.setUp(); + + uninstallPackage(TEST_APP2_PKG, false); + installPackage(TEST_APP2_APK); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + uninstallPackage(TEST_APP2_PKG, true); + } + + public void testDefault() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testDefault"); + } + + public void testAppAllowed() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppAllowed"); + } + + public void testAppDisallowed() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppDisallowed"); } } From 36f05df51f4ce35069fc80f19d66f961838c4211 Mon Sep 17 00:00:00 2001 From: Phil Weaver Date: Tue, 17 May 2016 14:40:21 -0700 Subject: [PATCH 0253/1415] CTS coverage: connectivity change, photo, + video Confirming that connectivity change broadcasts can be received when explicitly registering for them in N, and via the manifest pre-N. Confirming that new_photo and new_video broadcasts are not received. Bug: 28122277 Change-Id: Icfc27364a41ee8f4a55920e295ba658a367bb7d2 --- tests/cts/net/AndroidTest.xml | 1 + tests/cts/net/appForApi23/Android.mk | 38 ++++++++ tests/cts/net/appForApi23/AndroidManifest.xml | 47 +++++++++ .../ConnectivityListeningActivity.java | 22 +++++ .../cts/appForApi23/ConnectivityReceiver.java | 38 ++++++++ .../net/cts/ConnectivityManagerTest.java | 97 ++++++++++++++----- 6 files changed, 218 insertions(+), 25 deletions(-) create mode 100644 tests/cts/net/appForApi23/Android.mk create mode 100644 tests/cts/net/appForApi23/AndroidManifest.xml create mode 100644 tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityListeningActivity.java create mode 100644 tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml index 5194da37d2..389b926f83 100644 --- a/tests/cts/net/AndroidTest.xml +++ b/tests/cts/net/AndroidTest.xml @@ -16,6 +16,7 @@

    @@ -85,6 +90,9 @@ public class MyBroadcastReceiver extends BroadcastReceiver { Log.d(TAG, message); setResultData(message); break; + case ACTION_SEND_NOTIFICATION: + sendNotification(context, intent); + break; default: Log.e(TAG, "received unexpected action: " + action); } @@ -213,4 +221,23 @@ public class MyBroadcastReceiver extends BroadcastReceiver { final int counter = getCounter(context, action, receiverName); setResultData(String.valueOf(counter)); } + + /** + * Sends a system notification containing actions with pending intents to launch the app's + * main activitiy or service. + */ + private void sendNotification(Context context, Intent intent) { + final int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1); + final Intent serviceIntent = new Intent(context, MyService.class); + final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, 0); + + final Notification notification = new Notification.Builder(context) + .setSmallIcon(R.drawable.ic_notification) + .setContentTitle("Light, Cameras...") + .setContentIntent(pendingIntent) + .addAction(R.drawable.ic_notification, "ACTION", pendingIntent) + .build(); + ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) + .notify(notificationId, notification); + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 8152e55297..c741b12fd0 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -184,6 +184,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + public void testDozeModeMetered_enabledButWhitelistedOnNotificationAction() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest", + "testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction"); + } + // TODO: currently power-save mode and idle uses the same whitelist, so this test would be // redundant (as it would be testing the same as testBatterySaverMode_reinstall()) // public void testDozeMode_reinstall() throws Exception { @@ -204,6 +209,12 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + public void testDozeModeNonMetered_enabledButWhitelistedOnNotificationAction() + throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest", + "testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction"); + } + /********************** * Mixed modes tests. * **********************/ From b9b85ce0cd8126e63445d13f94fd3a7732f39c83 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 2 Jun 2016 09:08:49 -0700 Subject: [PATCH 0258/1415] Add flakyness check when a valid connection is expected. BUG: 29082308 Change-Id: Iadb9a0bd7fbd307d799af7a7a5dabc0ed000bc6d --- ...stractRestrictBackgroundNetworkTestCase.java | 17 ++++++++++++----- .../net/hostside/app2/MyBroadcastReceiver.java | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index ba383a88b7..3125dfa50b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -269,8 +269,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private void assertNetworkAccess(boolean expectAvailable) throws Exception { final Intent intent = new Intent(ACTION_CHECK_NETWORK); - // When the network info state change, it's possible the app still get the previous value, - // so we need to retry a couple times. final int maxTries = 5; String resultData = null; for (int i = 1; i <= maxTries; i++) { @@ -287,8 +285,14 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final String networkInfo = parts[4]; if (expectAvailable) { - assertTrue("should be connected: " + connectionCheckDetails - + " (network info: " + networkInfo + ")", connected); + if (!connected) { + // Since it's establishing a connection to an external site, it could be flaky. + Log.w(TAG, "Failed to connect to an external site on attempt #" + i + + " (error: " + connectionCheckDetails + ", NetworkInfo: " + networkInfo + + "); sleeping " + NETWORK_TIMEOUT_MS + "ms before trying again"); + SystemClock.sleep(NETWORK_TIMEOUT_MS); + continue; + } if (state != State.CONNECTED) { Log.d(TAG, "State (" + state + ") not set to CONNECTED on attempt #" + i + "; sleeping 1s before trying again"); @@ -303,6 +307,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertFalse("should not be connected: " + connectionCheckDetails + " (network info: " + networkInfo + ")", connected); if (state != State.DISCONNECTED) { + // When the network info state change, it's possible the app still get the + // previous value, so we need to retry a couple times. Log.d(TAG, "State (" + state + ") not set to DISCONNECTED on attempt #" + i + "; sleeping 1s before trying again"); SystemClock.sleep(SECOND_IN_MS); @@ -313,7 +319,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } } } - fail("Invalid state after " + maxTries + " attempts. Last data: " + resultData); + fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries + + " attempts. Last data: " + resultData); } protected String executeShellCommand(String command) throws Exception { diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 96e9d2bab4..0eff6abdf8 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -174,7 +174,7 @@ public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void run() { // TODO: connect to a hostside server instead - final String address = "http://example.com"; + final String address = "http://google.com"; final NetworkInfo networkInfo = cm.getActiveNetworkInfo(); Log.d(TAG, "Running checkNetworkStatus() on thread " + Thread.currentThread().getName() + " for UID " + getUid(context) From d1f3d68694f49339397a3046c77bf0ee30d8d14f Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 2 Jun 2016 12:01:26 -0700 Subject: [PATCH 0259/1415] Skip Doze Mode-related tests when device does not support it. Fixes: 29072117 Change-Id: I7ca37eae58258c021ed6297a9f1ee3b2749da7d7 --- .../net/hostside/AbstractAppIdleTestCase.java | 22 +++++++++++++++++ .../AbstractBatterySaverModeTestCase.java | 22 +++++++++++++++++ .../hostside/AbstractDozeModeTestCase.java | 23 ++++++++++++++++++ ...ractRestrictBackgroundNetworkTestCase.java | 24 +++++++++++++++++++ .../cts/net/hostside/DataSaverModeTest.java | 14 +++++++++++ .../cts/net/hostside/MixedModesTest.java | 20 ++++++++++++++++ ...ostsideRestrictBackgroundNetworkTests.java | 11 +++++++++ 7 files changed, 136 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 13ce6cee0a..ba56665fbc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -16,6 +16,8 @@ package com.android.cts.net.hostside; +import android.util.Log; + /** * Base class for metered and non-metered tests on idle apps. */ @@ -25,6 +27,8 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork protected final void setUp() throws Exception { super.setUp(); + if (!isSupported()) return; + // Set initial state. setUpMeteredNetwork(); removePowerSaveModeWhitelist(TEST_APP2_PKG); @@ -38,6 +42,8 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork protected final void tearDown() throws Exception { super.tearDown(); + if (!isSupported()) return; + try { tearDownMeteredNetwork(); } finally { @@ -46,6 +52,16 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork } } + @Override + protected boolean isSupported() throws Exception { + boolean supported = isDozeModeEnabled(); + if (!supported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Doze Mode"); + } + return supported; + } + /** * Sets the initial (non) metered network state. * @@ -63,6 +79,8 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork } public void testBackgroundNetworkAccess_enabled() throws Exception { + if (!isSupported()) return; + setAppIdle(true); assertBackgroundNetworkAccess(false); @@ -92,6 +110,8 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork } public void testBackgroundNetworkAccess_whitelisted() throws Exception { + if (!isSupported()) return; + setAppIdle(true); assertBackgroundNetworkAccess(false); @@ -111,6 +131,8 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork } public void testBackgroundNetworkAccess_disabled() throws Exception { + if (!isSupported()) return; + assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index 2acc670800..c1c91dac80 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -16,6 +16,8 @@ package com.android.cts.net.hostside; +import android.util.Log; + /** * Base class for metered and non-metered Battery Saver Mode tests. */ @@ -25,6 +27,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou protected final void setUp() throws Exception { super.setUp(); + if (!isSupported()) return; + // Set initial state. setUpMeteredNetwork(); removePowerSaveModeWhitelist(TEST_APP2_PKG); @@ -37,6 +41,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou protected final void tearDown() throws Exception { super.tearDown(); + if (!isSupported()) return; + try { tearDownMeteredNetwork(); } finally { @@ -44,6 +50,16 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou } } + @Override + protected boolean isSupported() throws Exception { + boolean supported = isDozeModeEnabled(); + if (!supported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Doze Mode"); + } + return supported; + } + /** * Sets the initial (non) metered network state. * @@ -61,6 +77,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou } public void testBackgroundNetworkAccess_enabled() throws Exception { + if (!isSupported()) return; + setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -87,6 +105,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou } public void testBackgroundNetworkAccess_whitelisted() throws Exception { + if (!isSupported()) return; + setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -101,6 +121,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou } public void testBackgroundNetworkAccess_disabled() throws Exception { + if (!isSupported()) return; + assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index e0ba76b866..b89cf93b99 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -17,6 +17,7 @@ package com.android.cts.net.hostside; import android.os.SystemClock; +import android.util.Log; /** * Base class for metered and non-metered Doze Mode tests. @@ -27,6 +28,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor protected final void setUp() throws Exception { super.setUp(); + if (!isSupported()) return; + // Set initial state. setUpMeteredNetwork(); removePowerSaveModeWhitelist(TEST_APP2_PKG); @@ -39,6 +42,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor protected final void tearDown() throws Exception { super.tearDown(); + if (!isSupported()) return; + try { tearDownMeteredNetwork(); } finally { @@ -46,6 +51,16 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor } } + @Override + protected boolean isSupported() throws Exception { + boolean supported = isDozeModeEnabled(); + if (!supported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Doze Mode"); + } + return supported; + } + /** * Sets the initial (non) metered network state. * @@ -63,6 +78,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor } public void testBackgroundNetworkAccess_enabled() throws Exception { + if (!isSupported()) return; + setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -81,6 +98,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor } public void testBackgroundNetworkAccess_whitelisted() throws Exception { + if (!isSupported()) return; + setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -95,6 +114,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor } public void testBackgroundNetworkAccess_disabled() throws Exception { + if (!isSupported()) return; + assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); @@ -103,6 +124,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() throws Exception { + if (!isSupported()) return; + setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); try { registerNotificationListenerService(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 3125dfa50b..439fbbe0c9 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -187,6 +187,22 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertNetworkAccess(true); } + /** + * Whether this device suport this type of test. + * + *

    Should be overridden when necessary, and explicitly used before each test. Example: + * + *

    
    +     * public void testSomething() {
    +     *    if (!isSupported()) return;
    +     * 
    + * + * @return {@code true} by default. + */ + protected boolean isSupported() throws Exception { + return true; + } + /** * Asserts that an app always have access while on foreground or running a foreground service. * @@ -598,6 +614,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected void setDozeMode(boolean enabled) throws Exception { + // Sanity check, since tests should check beforehand.... + assertTrue("Device does not support Doze Mode", isDozeModeEnabled()); + Log.i(TAG, "Setting Doze Mode to " + enabled); if (enabled) { turnBatteryOff(); @@ -616,6 +635,11 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE"); } + protected boolean isDozeModeEnabled() throws Exception { + final String result = executeShellCommand("cmd deviceidle enabled deep").trim(); + return result.equals("1"); + } + protected void setAppIdle(boolean enabled) throws Exception { Log.i(TAG, "Setting app idle to " + enabled); executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 189515683c..3e6bd3320a 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -30,6 +30,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase public void setUp() throws Exception { super.setUp(); + if (!isSupported()) return; + // Set initial state. setMeteredNetwork(); setRestrictBackground(false); @@ -44,6 +46,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase protected void tearDown() throws Exception { super.tearDown(); + if (!isSupported()) return; + try { resetMeteredNetwork(); } finally { @@ -52,6 +56,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } public void testGetRestrictBackgroundStatus_disabled() throws Exception { + if (!isSupported()) return; + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted @@ -64,6 +70,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { + if (!isSupported()) return; + setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -81,6 +89,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } public void testGetRestrictBackgroundStatus_enabled() throws Exception { + if (!isSupported()) return; + setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -108,6 +118,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { + if (!isSupported()) return; + addRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -136,6 +148,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { + if (!isSupported()) return; + final StringBuilder error = new StringBuilder(); for (String packageName : REQUIRED_WHITELISTED_PACKAGES) { int uid = -1; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index c97a0f91f3..af52eeece4 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -32,6 +32,8 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { public void setUp() throws Exception { super.setUp(); + if (!isSupported()) return; + // Set initial state. removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); @@ -44,6 +46,8 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { protected void tearDown() throws Exception { super.tearDown(); + if (!isSupported()) return; + try { setRestrictBackground(false); } finally { @@ -55,6 +59,14 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + if (!isSupported()) return; + + if (!isDozeModeEnabled()) { + Log.w(TAG, "testDataAndBatterySaverModes_meteredNetwork() skipped because " + + "device does not support Doze Mode"); + return; + } + Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); setMeteredNetwork(); @@ -119,6 +131,14 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * networks. */ public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + if (!isSupported()) return; + + if (!isDozeModeEnabled()) { + Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because " + + "device does not support Doze Mode"); + return; + } + if (mCm.isActiveNetworkMetered()) { Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network" + " is metered"); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index c741b12fd0..7d5f817798 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -101,6 +101,12 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC } public void testBatterySaverMode_reinstall() throws Exception { + if (!isDozeModeEnabled()) { + Log.w(TAG, "testBatterySaverMode_reinstall() skipped because device does not support " + + "Doze Mode"); + return; + } + addPowerSaveModeWhitelist(TEST_APP2_PKG); uninstallPackage(TEST_APP2_PKG, true); @@ -287,4 +293,9 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC runCommand("dumpsys deviceidle whitelist +" + packageName); assertPowerSaveModeWhitelist(packageName, true); // Sanity check } + + protected boolean isDozeModeEnabled() throws Exception { + final String result = runCommand("cmd deviceidle enabled deep").trim(); + return result.equals("1"); + } } From 829443c140d65ab2d352539d3c67dbd9f669f3c3 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 6 Jun 2016 09:02:09 -0700 Subject: [PATCH 0260/1415] Changed network check URL. It cannot use google.com because it's blocked in some countries where CTS tests are run. BUG: 29082308 Change-Id: I749659ec2cd33248fddbe5b4ab02bd6e90f24a67 --- .../com/android/cts/net/hostside/app2/MyBroadcastReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 0eff6abdf8..96e9d2bab4 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -174,7 +174,7 @@ public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void run() { // TODO: connect to a hostside server instead - final String address = "http://google.com"; + final String address = "http://example.com"; final NetworkInfo networkInfo = cm.getActiveNetworkInfo(); Log.d(TAG, "Running checkNetworkStatus() on thread " + Thread.currentThread().getName() + " for UID " + getUid(context) From 1d75845bd564bc36171e0f697c8306d65b967229 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 9 Jun 2016 14:23:21 +0900 Subject: [PATCH 0261/1415] Log the address of the IPv4 address that causes the test to fail. Bug: 29231261 Change-Id: I6aac389d2c234091a284486422ee663119d021a9 --- tests/cts/net/src/android/net/cts/DnsTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index fed0a8dee8..c6a8962748 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -89,17 +89,15 @@ public class DnsTest extends AndroidTestCase { addrs = InetAddress.getAllByName("ipv6.google.com"); } catch (UnknownHostException e) {} assertTrue(addrs.length != 0); - foundV4 = false; foundV6 = false; for (InetAddress addr : addrs) { - if (addr instanceof Inet4Address) foundV4 = true; - else if (addr instanceof Inet6Address) foundV6 = true; + assertFalse ("[RERUN] ipv6.google.com returned IPv4 address: " + addr.getHostAddress() + + ", check your network's DNS connection", addr instanceof Inet4Address); + foundV6 |= (addr instanceof Inet6Address); if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString()); } - assertTrue("[RERUN] ipv6.google.com returned an ipv4 address, check your network's DNS connection.", - foundV4 == false); - assertTrue(foundV6 == true); + assertTrue(foundV6); assertTrue(testNativeDns()); } From c3a9008e3d8d45c754a4ad6733984d95fd1c4e2b Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 16 Jun 2016 10:03:27 -0700 Subject: [PATCH 0262/1415] Add non-parcelable extras to notification to make sure it does not crash the app. BUG: 29402928 Change-Id: I4fc47535ae14e71c50b25285b2fe5375abdb4f11 --- .../cts/net/hostside/app2/MyBroadcastReceiver.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 96e9d2bab4..60e5de1b9a 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -31,6 +31,7 @@ import static com.android.cts.net.hostside.app2.Common.TAG; import static com.android.cts.net.hostside.app2.Common.getUid; import android.app.Notification; +import android.app.Notification.Action; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -39,6 +40,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.os.Bundle; import android.util.Log; import java.net.HttpURLConnection; @@ -230,12 +232,18 @@ public class MyBroadcastReceiver extends BroadcastReceiver { final int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1); final Intent serviceIntent = new Intent(context, MyService.class); final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, 0); + final Bundle badBundle = new Bundle(); + badBundle.putCharSequence("parcelable", "I am not"); + final Action action = new Action.Builder( + R.drawable.ic_notification, "ACTION", pendingIntent) + .addExtras(badBundle) + .build(); final Notification notification = new Notification.Builder(context) .setSmallIcon(R.drawable.ic_notification) .setContentTitle("Light, Cameras...") .setContentIntent(pendingIntent) - .addAction(R.drawable.ic_notification, "ACTION", pendingIntent) + .addAction(action) .build(); ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) .notify(notificationId, notification); From 349f7ed040a1c291a6b32e9112484d1c6636db76 Mon Sep 17 00:00:00 2001 From: Jun Tahara Date: Mon, 20 Jun 2016 14:47:29 +0900 Subject: [PATCH 0263/1415] Remove non-CTS packets assertion code Symptom: testTrafficStatsForLocalhost fails when applications or services except CTS are using network. Root cause: testTrafficStatsForLocalhost can't calculate the number of non-localhost packets for CTS. It includes the all of packets for applications/services except CTS and non-localhost packets for CTS. Solution: Remove this assertion and only logging the number of packets. Change-Id: I49243d59f359f3a543c6bdb46f6a2645cde8f292 --- tests/cts/net/src/android/net/cts/TrafficStatsTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index a8dd8acecc..930c74255d 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -214,8 +214,6 @@ public class TrafficStatsTest extends AndroidTestCase { long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) - uidRxDeltaPackets; if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); - // Make sure that not too many non-localhost packets are accounted for - assertTrue("too many non-localhost packets on the same UID", deltaTxOtherPackets + deltaRxOtherPackets < 20); } assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + From abc35d5527b1621e4e672768688f1b9461cbe14a Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 21 Jun 2016 10:53:07 +0900 Subject: [PATCH 0264/1415] Clear local test results across DNS lookups. If InetAddress.getAllByName("ipv6.google.com") throws UnknownHostException, the test silently ignores it. This causes a misleading failure, because the test then reuses the addrs variable that is left over from the previous DNS query for "www.google.com", and fails because it has an IPv4 address. Fixes: 12210306 Bug: 29231261 Change-Id: I1dde945765d40a84eba139055306b07ebc97d0ec --- tests/cts/net/src/android/net/cts/DnsTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index c6a8962748..8575c338dd 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -62,8 +62,8 @@ public class DnsTest extends AndroidTestCase { try { addrs = InetAddress.getAllByName("www.google.com"); } catch (UnknownHostException e) {} - assertTrue("[RERUN] DNS could not resolve www.gooogle.com. Check internet connection", - addrs.length != 0); + assertTrue("[RERUN] DNS could not resolve www.google.com. Check internet connection", + addrs.length != 0); boolean foundV4 = false, foundV6 = false; for (InetAddress addr : addrs) { if (addr instanceof Inet4Address) foundV4 = true; @@ -71,11 +71,8 @@ public class DnsTest extends AndroidTestCase { if (DBG) Log.e(TAG, "www.google.com gave " + addr.toString()); } - // assertTrue(foundV4); - // assertTrue(foundV6); - // We should have at least one of the addresses to connect! - assertTrue(foundV4 || foundV6); + assertTrue("www.google.com must have IPv4 and/or IPv6 address", foundV4 || foundV6); // Skip the rest of the test if the active network for watch is PROXY. // TODO: Check NetworkInfo type in addition to type name once ag/601257 is merged. @@ -85,14 +82,17 @@ public class DnsTest extends AndroidTestCase { return; } + // Clear test state so we don't get confused with the previous results. + addrs = new InetAddress[0]; + foundV4 = foundV6 = false; try { addrs = InetAddress.getAllByName("ipv6.google.com"); } catch (UnknownHostException e) {} - assertTrue(addrs.length != 0); - foundV6 = false; + assertTrue("[RERUN] DNS could not resolve ipv6.google.com, check the network supports IPv6", + addrs.length != 0); for (InetAddress addr : addrs) { assertFalse ("[RERUN] ipv6.google.com returned IPv4 address: " + addr.getHostAddress() + - ", check your network's DNS connection", addr instanceof Inet4Address); + ", check your network's DNS server", addr instanceof Inet4Address); foundV6 |= (addr instanceof Inet6Address); if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString()); } From 60bd0b56fb447fa1021f9f48008297479dcc3d4f Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Thu, 9 Jun 2016 13:32:31 -0700 Subject: [PATCH 0265/1415] Fix misc-macro-parentheses warnings in cts. Add parentheses around macro arguments used beside operators. Use 'aoto' type to avoid clang-tidy warnings of missing parentheses of 'TYPE *'. Bug: 28705665 Change-Id: I5d2c3b2bdfb7775200f31a011758b9a35b14794d --- tests/cts/net/jni/NativeMultinetworkJni.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index ad56b510c3..6990efa452 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -30,7 +30,7 @@ #include #include -#define UNUSED(X) ((void) X) +#define UNUSED(X) ((void) (X)) static const char kHostname[] = "connectivitycheck.android.com"; From 0d7d1da50366788ed999c3d28e1ee0d87cfda838 Mon Sep 17 00:00:00 2001 From: Phil Weaver Date: Wed, 22 Jun 2016 16:50:38 -0700 Subject: [PATCH 0266/1415] CTS: Only listen to wifi events when toggling wifi When counting all connectivity changed events, we were failing on devices with sim cards because we were counting both wifi and mobile connectivity changes the same. Since the test only toggles wifi, changing the listener only to pay attention to wifi changes. Bug: 29346253 Change-Id: I1ed3b976bc21419218c780d4afc4a5e73f128496 --- tests/cts/net/appForApi23/AndroidManifest.xml | 2 +- .../net/cts/appForApi23/ConnectivityReceiver.java | 15 +++++++++------ .../android/net/cts/ConnectivityManagerTest.java | 8 ++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/cts/net/appForApi23/AndroidManifest.xml b/tests/cts/net/appForApi23/AndroidManifest.xml index 7203ea553f..ed4cedbc1d 100644 --- a/tests/cts/net/appForApi23/AndroidManifest.xml +++ b/tests/cts/net/appForApi23/AndroidManifest.xml @@ -28,7 +28,7 @@ - + diff --git a/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java b/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java index 5dd77e85dd..8039a4f943 100644 --- a/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java +++ b/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java @@ -21,18 +21,21 @@ import android.content.Intent; import android.net.ConnectivityManager; public class ConnectivityReceiver extends BroadcastReceiver { - public static String GET_CONNECTIVITY_ACTION_COUNT = - "android.net.cts.appForApi23.getConnectivityActionCount"; + public static String GET_WIFI_CONNECTIVITY_ACTION_COUNT = + "android.net.cts.appForApi23.getWifiConnectivityActionCount"; - private static int sConnectivityActionCount = 0; + private static int sWifiConnectivityActionCount = 0; @Override public void onReceive(Context context, Intent intent) { if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { - sConnectivityActionCount++; + int networkType = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 0); + if (networkType == ConnectivityManager.TYPE_WIFI) { + sWifiConnectivityActionCount++; + } } - if (GET_CONNECTIVITY_ACTION_COUNT.equals(intent.getAction())) { - setResultCode(sConnectivityActionCount); + if (GET_WIFI_CONNECTIVITY_ACTION_COUNT.equals(intent.getAction())) { + setResultCode(sWifiConnectivityActionCount); } } } diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index df2baac17e..b8478d246b 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -77,9 +77,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; - // Intent string to get the number of CONNECTIVITY_ACTION callbacks the test app has seen - public static final String GET_CONNECTIVITY_ACTION_COUNT = - "android.net.cts.appForApi23.getConnectivityActionCount"; + // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen + public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT = + "android.net.cts.appForApi23.getWifiConnectivityActionCount"; // device could have only one interface: data, wifi. private static final int MIN_NUM_NETWORK_TYPES = 1; @@ -423,7 +423,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { toggleWifi(); - Intent getConnectivityCount = new Intent(GET_CONNECTIVITY_ACTION_COUNT); + Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT); assertEquals(2, sendOrderedBroadcastAndReturnResultCode( getConnectivityCount, SEND_BROADCAST_TIMEOUT)); } From e928006e6785b91d8b1e92125536ca979071bb09 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 27 Jun 2016 16:13:18 -0700 Subject: [PATCH 0267/1415] Cover more PendingIntent whitelist scenarios. BUG: 29480440 Change-Id: I961b765f40135efc06fbb3e5a4a94e8e333453da --- .../hostside/AbstractDozeModeTestCase.java | 23 ++++-- ...ractRestrictBackgroundNetworkTestCase.java | 18 ++++- .../MyNotificationListenerService.java | 72 +++++++++++++++-- .../android/cts/net/hostside/app2/Common.java | 10 +++ .../hostside/app2/MyBroadcastReceiver.java | 80 ++++++++++++++++--- 5 files changed, 175 insertions(+), 28 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index b89cf93b99..6669af5edd 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -132,16 +132,29 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor setDozeMode(true); assertBackgroundNetworkAccess(false); - sendNotification(42); - assertBackgroundNetworkAccess(true); - // Make sure access is disabled after it expires - SystemClock.sleep(NETWORK_TIMEOUT_MS); - assertBackgroundNetworkAccess(false); + testNotification(4, NOTIFICATION_TYPE_CONTENT); + testNotification(8, NOTIFICATION_TYPE_DELETE); + testNotification(15, NOTIFICATION_TYPE_FULL_SCREEN); + testNotification(16, NOTIFICATION_TYPE_BUNDLE); + testNotification(23, NOTIFICATION_TYPE_ACTION); + testNotification(42, NOTIFICATION_TYPE_ACTION_BUNDLE); + testNotification(108, NOTIFICATION_TYPE_ACTION_REMOTE_INPUT); } finally { resetDeviceIdleSettings(); } } + private void testNotification(int id, String type) throws Exception { + sendNotification(id, type); + assertBackgroundNetworkAccess(true); + if (type.equals(NOTIFICATION_TYPE_ACTION)) { + // Make sure access is disabled after it expires. Since this check considerably slows + // downs the CTS tests, do it just once. + SystemClock.sleep(NETWORK_TIMEOUT_MS); + assertBackgroundNetworkAccess(false); + } + } + // Must override so it only tests foreground service - once an app goes to foreground, device // leaves Doze Mode. @Override diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 439fbbe0c9..d04aa0f0db 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -69,6 +69,18 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; private static final String EXTRA_NOTIFICATION_ID = "com.android.cts.net.hostside.app2.extra.NOTIFICATION_ID"; + private static final String EXTRA_NOTIFICATION_TYPE = + "com.android.cts.net.hostside.app2.extra.NOTIFICATION_TYPE"; + + protected static final String NOTIFICATION_TYPE_CONTENT = "CONTENT"; + protected static final String NOTIFICATION_TYPE_DELETE = "DELETE"; + protected static final String NOTIFICATION_TYPE_FULL_SCREEN = "FULL_SCREEN"; + protected static final String NOTIFICATION_TYPE_BUNDLE = "BUNDLE"; + protected static final String NOTIFICATION_TYPE_ACTION = "ACTION"; + protected static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE"; + protected static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT"; + + private static final String NETWORK_STATUS_SEPARATOR = "\\|"; private static final int SECOND_IN_MS = 1000; static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; @@ -735,10 +747,12 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation + "--receiver-foreground --receiver-registered-only"); } - protected void sendNotification(int notificationId) { + protected void sendNotification(int notificationId, String notificationType) { final Intent intent = new Intent(ACTION_SEND_NOTIFICATION); intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId); - Log.d(TAG, "Sending broadcast: " + intent); + intent.putExtra(EXTRA_NOTIFICATION_TYPE, notificationType); + Log.d(TAG, "Sending notification broadcast (id=" + notificationId + ", type=" + + notificationType + ": " + intent); mContext.sendBroadcast(intent); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java index b9c303107c..0893511071 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java @@ -16,7 +16,10 @@ package com.android.cts.net.hostside; import android.app.Notification; +import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; +import android.app.RemoteInput; +import android.os.Bundle; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.util.Log; @@ -40,22 +43,75 @@ public class MyNotificationListenerService extends NotificationListenerService { Log.v(TAG, "ignoring notification from a different package"); return; } + final PendingIntentSender sender = new PendingIntentSender(); final Notification notification = sbn.getNotification(); - if (notification.actions == null) { - Log.w(TAG, "ignoring notification without an action"); + if (notification.contentIntent != null) { + sender.send("content", notification.contentIntent); } - for (Notification.Action action : notification.actions) { - Log.i(TAG, "Sending pending intent " + action.actionIntent); - try { - action.actionIntent.send(); - } catch (CanceledException e) { - Log.w(TAG, "Pending Intent canceled"); + if (notification.deleteIntent != null) { + sender.send("delete", notification.deleteIntent); + } + if (notification.fullScreenIntent != null) { + sender.send("full screen", notification.fullScreenIntent); + } + if (notification.actions != null) { + for (Notification.Action action : notification.actions) { + sender.send("action", action.actionIntent); + sender.send("action extras", action.getExtras()); + final RemoteInput[] remoteInputs = action.getRemoteInputs(); + if (remoteInputs != null && remoteInputs.length > 0) { + for (RemoteInput remoteInput : remoteInputs) { + sender.send("remote input extras", remoteInput.getExtras()); + } + } } } + sender.send("notification extras", notification.extras); } static String getId() { return String.format("%s/%s", MyNotificationListenerService.class.getPackage().getName(), MyNotificationListenerService.class.getName()); } + + private static final class PendingIntentSender { + private PendingIntent mSentIntent = null; + private String mReason = null; + + private void send(String reason, PendingIntent pendingIntent) { + if (pendingIntent == null) { + // Could happen on action that only has extras + Log.v(TAG, "Not sending null pending intent for " + reason); + return; + } + if (mSentIntent != null || mReason != null) { + // Sanity check: make sure test case set up just one pending intent in the + // notification, otherwise it could pass because another pending intent caused the + // whitelisting. + throw new IllegalStateException("Already sent a PendingIntent (" + mSentIntent + + ") for reason '" + mReason + "' when requested another for '" + reason + + "' (" + pendingIntent + ")"); + } + Log.i(TAG, "Sending pending intent for " + reason + ":" + pendingIntent); + try { + pendingIntent.send(); + mSentIntent = pendingIntent; + mReason = reason; + } catch (CanceledException e) { + Log.w(TAG, "Pending intent " + pendingIntent + " canceled"); + } + } + + private void send(String reason, Bundle extras) { + if (extras != null) { + for (String key : extras.keySet()) { + Object value = extras.get(key); + if (value instanceof PendingIntent) { + send(reason + " with key '" + key + "'", (PendingIntent) value); + } + } + } + } + + } } diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index f02f651f06..8806e3b970 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -43,6 +43,16 @@ public final class Common { "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; static final String EXTRA_NOTIFICATION_ID = "com.android.cts.net.hostside.app2.extra.NOTIFICATION_ID"; + static final String EXTRA_NOTIFICATION_TYPE = + "com.android.cts.net.hostside.app2.extra.NOTIFICATION_TYPE"; + + static final String NOTIFICATION_TYPE_CONTENT = "CONTENT"; + static final String NOTIFICATION_TYPE_DELETE = "DELETE"; + static final String NOTIFICATION_TYPE_FULL_SCREEN = "FULL_SCREEN"; + static final String NOTIFICATION_TYPE_BUNDLE = "BUNDLE"; + static final String NOTIFICATION_TYPE_ACTION = "ACTION"; + static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE"; + static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT"; static int getUid(Context context) { final String packageName = context.getPackageName(); diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 60e5de1b9a..3b82f42a67 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -25,8 +25,16 @@ import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.ACTION_SEND_NOTIFICATION; import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION; import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_ID; +import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_TYPE; import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME; import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_REMOTE_INPUT; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_BUNDLE; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_CONTENT; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_DELETE; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_FULL_SCREEN; import static com.android.cts.net.hostside.app2.Common.TAG; import static com.android.cts.net.hostside.app2.Common.getUid; @@ -34,6 +42,7 @@ import android.app.Notification; import android.app.Notification.Action; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.RemoteInput; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -230,21 +239,66 @@ public class MyBroadcastReceiver extends BroadcastReceiver { */ private void sendNotification(Context context, Intent intent) { final int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1); + final String notificationType = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE); + Log.d(TAG, "sendNotification: id=" + notificationId + ", type=" + notificationType + + ", intent=" + intent); final Intent serviceIntent = new Intent(context, MyService.class); - final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, 0); - final Bundle badBundle = new Bundle(); - badBundle.putCharSequence("parcelable", "I am not"); - final Action action = new Action.Builder( - R.drawable.ic_notification, "ACTION", pendingIntent) - .addExtras(badBundle) - .build(); + final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, + notificationId); + final Bundle bundle = new Bundle(); + bundle.putCharSequence("parcelable", "I am not"); - final Notification notification = new Notification.Builder(context) - .setSmallIcon(R.drawable.ic_notification) - .setContentTitle("Light, Cameras...") - .setContentIntent(pendingIntent) - .addAction(action) - .build(); + final Notification.Builder builder = new Notification.Builder(context) + .setSmallIcon(R.drawable.ic_notification); + + Action action = null; + switch (notificationType) { + case NOTIFICATION_TYPE_CONTENT: + builder + .setContentTitle("Light, Cameras...") + .setContentIntent(pendingIntent); + break; + case NOTIFICATION_TYPE_DELETE: + builder.setDeleteIntent(pendingIntent); + break; + case NOTIFICATION_TYPE_FULL_SCREEN: + builder.setFullScreenIntent(pendingIntent, true); + break; + case NOTIFICATION_TYPE_BUNDLE: + bundle.putParcelable("Magnum P.I. (Pending Intent)", pendingIntent); + builder.setExtras(bundle); + break; + case NOTIFICATION_TYPE_ACTION: + action = new Action.Builder( + R.drawable.ic_notification, "ACTION", pendingIntent) + .build(); + builder.addAction(action); + break; + case NOTIFICATION_TYPE_ACTION_BUNDLE: + bundle.putParcelable("Magnum A.P.I. (Action Pending Intent)", pendingIntent); + action = new Action.Builder( + R.drawable.ic_notification, "ACTION WITH BUNDLE", null) + .addExtras(bundle) + .build(); + builder.addAction(action); + break; + case NOTIFICATION_TYPE_ACTION_REMOTE_INPUT: + bundle.putParcelable("Magnum R.I. (Remote Input)", null); + final RemoteInput remoteInput = new RemoteInput.Builder("RI") + .addExtras(bundle) + .build(); + action = new Action.Builder( + R.drawable.ic_notification, "ACTION WITH REMOTE INPUT", pendingIntent) + .addRemoteInput(remoteInput) + .build(); + builder.addAction(action); + break; + default: + Log.e(TAG, "Unknown notification type: " + notificationType); + return; + } + + final Notification notification = builder.build(); ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) .notify(notificationId, notification); } From a87e5240cc29979270520dca070b43f54e82c5a6 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Tue, 28 Jun 2016 18:24:20 +0100 Subject: [PATCH 0268/1415] Initialize MockWebServer in setUp() not construction time Should be a no-op but makes test suite creation cheaper. Bug: 29820565 Change-Id: Ieee5568a6f477d591436275be4d4e7e3d5dbd322 --- .../net/src/android/net/http/cts/HttpResponseCacheTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java index 545541d68b..7987a50eb9 100644 --- a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java +++ b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java @@ -38,10 +38,11 @@ import java.util.UUID; public final class HttpResponseCacheTest extends TestCase { private File cacheDir; - private MockWebServer server = new MockWebServer(); + private MockWebServer server; @Override public void setUp() throws Exception { super.setUp(); + server = new MockWebServer(); String tmp = System.getProperty("java.io.tmpdir"); cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); cacheDir.mkdirs(); From 9c1322683f2257b311d2ee8d26a05458f32150c7 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 1 Aug 2016 16:01:09 -0700 Subject: [PATCH 0269/1415] Improvements on retry mechanism on network tests: - Retry on all cases (not only when expecting connected). - Uses exponential back-off for timeout. BUG: 27803922 Fixes: 30509643 Change-Id: I42454f43158598a72e30f290c27c5a02e80ea6d2 --- ...ractRestrictBackgroundNetworkTestCase.java | 111 ++++++++++-------- .../hostside/app2/MyBroadcastReceiver.java | 2 +- 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index d04aa0f0db..ab643a0e81 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -295,60 +295,75 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation * Asserts whether the active network is available or not. */ private void assertNetworkAccess(boolean expectAvailable) throws Exception { - final Intent intent = new Intent(ACTION_CHECK_NETWORK); - final int maxTries = 5; - String resultData = null; + String error = null; + int timeoutMs = 500; + for (int i = 1; i <= maxTries; i++) { - resultData = sendOrderedBroadcast(intent); - assertNotNull("timeout waiting for ordered broadcast", resultData); + error = checkNetworkAccess(expectAvailable); - // Network status format is described on MyBroadcastReceiver.checkNetworkStatus() - final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR); - assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check - final State state = State.valueOf(parts[0]); - final DetailedState detailedState = DetailedState.valueOf(parts[1]); - final boolean connected = Boolean.valueOf(parts[2]); - final String connectionCheckDetails = parts[3]; - final String networkInfo = parts[4]; + if (error.isEmpty()) return; - if (expectAvailable) { - if (!connected) { - // Since it's establishing a connection to an external site, it could be flaky. - Log.w(TAG, "Failed to connect to an external site on attempt #" + i + - " (error: " + connectionCheckDetails + ", NetworkInfo: " + networkInfo - + "); sleeping " + NETWORK_TIMEOUT_MS + "ms before trying again"); - SystemClock.sleep(NETWORK_TIMEOUT_MS); - continue; - } - if (state != State.CONNECTED) { - Log.d(TAG, "State (" + state + ") not set to CONNECTED on attempt #" + i - + "; sleeping 1s before trying again"); - SystemClock.sleep(SECOND_IN_MS); - } else { - assertEquals("wrong detailed state for " + networkInfo, - DetailedState.CONNECTED, detailedState); - return; - } - return; - } else { - assertFalse("should not be connected: " + connectionCheckDetails - + " (network info: " + networkInfo + ")", connected); - if (state != State.DISCONNECTED) { - // When the network info state change, it's possible the app still get the - // previous value, so we need to retry a couple times. - Log.d(TAG, "State (" + state + ") not set to DISCONNECTED on attempt #" + i - + "; sleeping 1s before trying again"); - SystemClock.sleep(SECOND_IN_MS); - } else { - assertEquals("wrong detailed state for " + networkInfo, - DetailedState.BLOCKED, detailedState); - return; - } - } + // TODO: ideally, it should retry only when it cannot connect to an external site, + // or no retry at all! But, currently, the initial change fails almost always on + // battery saver tests because the netd changes are made asynchronously. + // Once b/27803922 is fixed, this retry mechanism should be revisited. + + Log.w(TAG, "Network status didn't match for expectAvailable=" + expectAvailable + + " on attempt #" + i + ": " + error + "\n" + + "Sleeping " + timeoutMs + "ms before trying again"); + SystemClock.sleep(timeoutMs); + // Exponential back-off. + timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS); } fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries - + " attempts. Last data: " + resultData); + + " attempts.\nLast error: " + error); + } + + /** + * Checks whether the network is available as expected. + * + * @return error message with the mismatch (or empty if assertion passed). + */ + private String checkNetworkAccess(boolean expectAvailable) throws Exception { + String resultData = sendOrderedBroadcast(new Intent(ACTION_CHECK_NETWORK)); + if (resultData == null) { + return "timeout waiting for ordered broadcast"; + } + // Network status format is described on MyBroadcastReceiver.checkNetworkStatus() + final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR); + assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check + final State state = State.valueOf(parts[0]); + final DetailedState detailedState = DetailedState.valueOf(parts[1]); + final boolean connected = Boolean.valueOf(parts[2]); + final String connectionCheckDetails = parts[3]; + final String networkInfo = parts[4]; + + final StringBuilder errors = new StringBuilder(); + final State expectedState; + final DetailedState expectedDetailedState; + if (expectAvailable) { + expectedState = State.CONNECTED; + expectedDetailedState = DetailedState.CONNECTED; + } else { + expectedState = State.DISCONNECTED; + expectedDetailedState = DetailedState.BLOCKED; + } + + if (expectAvailable != connected) { + errors.append(String.format("External site connection failed: expected %s, got %s\n", + expectAvailable, connected)); + } + if (expectedState != state || expectedDetailedState != detailedState) { + errors.append(String.format("Connection state mismatch: expected %s/%s, got %s/%s\n", + expectedState, expectedDetailedState, state, detailedState)); + } + + if (errors.length() > 0) { + errors.append("\tnetworkInfo: " + networkInfo + "\n"); + errors.append("\tconnectionCheckDetails: " + connectionCheckDetails + "\n"); + } + return errors.toString(); } protected String executeShellCommand(String command) throws Exception { diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 3b82f42a67..6d01b1554b 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -66,7 +66,7 @@ import java.util.concurrent.TimeUnit; */ public class MyBroadcastReceiver extends BroadcastReceiver { - private static final int NETWORK_TIMEOUT_MS = 15 * 1000; + private static final int NETWORK_TIMEOUT_MS = 5 * 1000; private final String mName; From e9ef06260e28a0a44a0c38d4cfc4d199a2537077 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 10 Aug 2016 13:16:15 -0700 Subject: [PATCH 0270/1415] Added tests for network restrictions while the screen is off. BUG: 30785671 Change-Id: I1b211e545ff234272ff6acadfda9ce97765695a9 --- .../hostside/AbstractBatterySaverModeTestCase.java | 12 ++++++++++-- .../AbstractRestrictBackgroundNetworkTestCase.java | 2 +- .../android/cts/net/hostside/DataSaverModeTest.java | 12 ++++++++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index c1c91dac80..50bcc6058e 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -85,16 +85,24 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(false); - // Make sure foreground app doesn't lose access upon enabling it. + // Make sure foreground app doesn't lose access upon Battery Saver. setBatterySaverMode(false); launchActivity(); assertForegroundNetworkAccess(); setBatterySaverMode(true); assertForegroundNetworkAccess(); + + // Although it should not have access while the screen is off. + turnScreenOff(); + assertBackgroundNetworkAccess(false); + turnScreenOn(); + assertForegroundNetworkAccess(); + + // Goes back to background state. finishActivity(); assertBackgroundNetworkAccess(false); - // Same for foreground service. + // Make sure foreground service doesn't lose access upon enabling Battery Saver. setBatterySaverMode(false); startForegroundService(); assertForegroundNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index ab643a0e81..157e9f4365 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -243,7 +243,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (isBackground(state.state)) { return; } - Log.d(TAG, "App not on background state on attempt #" + i + Log.d(TAG, "App not on background state (" + state + ") on attempt #" + i + "; sleeping 1s before trying again"); SystemClock.sleep(SECOND_IN_MS); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 3e6bd3320a..881b3b4759 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -98,16 +98,24 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); - // Make sure foreground app doesn't lose access upon enabling it. + // Make sure foreground app doesn't lose access upon enabling Data Saver. setRestrictBackground(false); launchActivity(); assertForegroundNetworkAccess(); setRestrictBackground(true); assertForegroundNetworkAccess(); + + // Although it should not have access while the screen is off. + turnScreenOff(); + assertBackgroundNetworkAccess(false); + turnScreenOn(); + assertForegroundNetworkAccess(); + + // Goes back to background state. finishActivity(); assertBackgroundNetworkAccess(false); - // Same for foreground service. + // Make sure foreground service doesn't lose access upon enabling Data Saver. setRestrictBackground(false); startForegroundService(); assertForegroundNetworkAccess(); From a871a99ebc7834209d029b67b6ea9b27f9d3e9c8 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 15 Aug 2016 15:28:14 -0700 Subject: [PATCH 0271/1415] Improve check for activity on top after launch. BUG: 30875754 Fixes: 30868243 Change-Id: I8b7624e35caef107743d61f312e220f8bc21b9b8 --- .../AbstractRestrictBackgroundNetworkTestCase.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 439fbbe0c9..9980327bbe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -73,6 +73,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private static final int SECOND_IN_MS = 1000; static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; + private static final int PROCESS_STATE_TOP = 2; // Must be higher than NETWORK_TIMEOUT_MS @@ -723,7 +724,17 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void launchActivity() throws Exception { turnScreenOn(); executeShellCommand("am start com.android.cts.net.hostside.app2/.MyActivity"); - assertForegroundState(); + final int maxTries = 30; + ProcessState state = null; + for (int i = 1; i <= maxTries; i++) { + state = getProcessStateByUid(mUid); + if (state.state == PROCESS_STATE_TOP) return; + Log.w(TAG, "launchActivity(): uid " + mUid + " not on TOP state on attempt #" + i + + "; turning screen on and sleeping 1s before checking again"); + turnScreenOn(); + SystemClock.sleep(SECOND_IN_MS); + } + fail("App2 is not on foreground state after " + maxTries + " attempts: " + state); } /** From 9d8c5ba97eb55e9ea53f3324f09ad3818fef7526 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 15 Aug 2016 15:28:14 -0700 Subject: [PATCH 0272/1415] DO NOT MERGE:Improve check for activity on top after launch. BUG: 30875754 Fixes: 30868243 Change-Id: Iad3d6ce80fcf24281e98251799c23abc9b83b52d Change-Id: I8b7624e35caef107743d6 1f312e220f8bc21b9b8 --- .../AbstractRestrictBackgroundNetworkTestCase.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 439fbbe0c9..9980327bbe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -73,6 +73,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private static final int SECOND_IN_MS = 1000; static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; + private static final int PROCESS_STATE_TOP = 2; // Must be higher than NETWORK_TIMEOUT_MS @@ -723,7 +724,17 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void launchActivity() throws Exception { turnScreenOn(); executeShellCommand("am start com.android.cts.net.hostside.app2/.MyActivity"); - assertForegroundState(); + final int maxTries = 30; + ProcessState state = null; + for (int i = 1; i <= maxTries; i++) { + state = getProcessStateByUid(mUid); + if (state.state == PROCESS_STATE_TOP) return; + Log.w(TAG, "launchActivity(): uid " + mUid + " not on TOP state on attempt #" + i + + "; turning screen on and sleeping 1s before checking again"); + turnScreenOn(); + SystemClock.sleep(SECOND_IN_MS); + } + fail("App2 is not on foreground state after " + maxTries + " attempts: " + state); } /** From 2882cd2a7a47d413bde8d891b37fa59d7db05d85 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 10 Aug 2016 13:16:15 -0700 Subject: [PATCH 0273/1415] Added tests for network restrictions while the screen is off. BUG: 30785671 Change-Id: I1b211e545ff234272ff6acadfda9ce97765695a9 (cherry picked from commit b80a93061aa7d0a19b47a7dbb82f0dc06e3afb7e) --- .../hostside/AbstractBatterySaverModeTestCase.java | 12 ++++++++++-- .../AbstractRestrictBackgroundNetworkTestCase.java | 2 +- .../android/cts/net/hostside/DataSaverModeTest.java | 12 ++++++++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index c1c91dac80..50bcc6058e 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -85,16 +85,24 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(false); - // Make sure foreground app doesn't lose access upon enabling it. + // Make sure foreground app doesn't lose access upon Battery Saver. setBatterySaverMode(false); launchActivity(); assertForegroundNetworkAccess(); setBatterySaverMode(true); assertForegroundNetworkAccess(); + + // Although it should not have access while the screen is off. + turnScreenOff(); + assertBackgroundNetworkAccess(false); + turnScreenOn(); + assertForegroundNetworkAccess(); + + // Goes back to background state. finishActivity(); assertBackgroundNetworkAccess(false); - // Same for foreground service. + // Make sure foreground service doesn't lose access upon enabling Battery Saver. setBatterySaverMode(false); startForegroundService(); assertForegroundNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 8be16214c5..9245a6f3d0 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -244,7 +244,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (isBackground(state.state)) { return; } - Log.d(TAG, "App not on background state on attempt #" + i + Log.d(TAG, "App not on background state (" + state + ") on attempt #" + i + "; sleeping 1s before trying again"); SystemClock.sleep(SECOND_IN_MS); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 3e6bd3320a..881b3b4759 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -98,16 +98,24 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); - // Make sure foreground app doesn't lose access upon enabling it. + // Make sure foreground app doesn't lose access upon enabling Data Saver. setRestrictBackground(false); launchActivity(); assertForegroundNetworkAccess(); setRestrictBackground(true); assertForegroundNetworkAccess(); + + // Although it should not have access while the screen is off. + turnScreenOff(); + assertBackgroundNetworkAccess(false); + turnScreenOn(); + assertForegroundNetworkAccess(); + + // Goes back to background state. finishActivity(); assertBackgroundNetworkAccess(false); - // Same for foreground service. + // Make sure foreground service doesn't lose access upon enabling Data Saver. setRestrictBackground(false); startForegroundService(); assertForegroundNetworkAccess(); From 6784786c0a3c1eef558259cc69624449743afa1a Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 22 Aug 2016 11:45:21 -0700 Subject: [PATCH 0274/1415] Updated Data Saver blacklist assumptions. On Android N, Data Saver's whitelist and blacklist UIDs were stored separately, hence it would be possible for app to be present in both (although only through adb commands - the UI only allows one state). Now the both lists are stored in the same data structure (UID policies), hence they comply with the Highlander rule: There Can Be Only One. Test: cts-tradefed run commandAndExit cts --skip-device-info --skip-system-status-check com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker --skip-preconditions -m CtsHostsideNetworkTests --abi armeabi-v7a -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests BUG: 28791717 Change-Id: I8649972088b439a2ef87f8630269033f116866bf --- ...bstractRestrictBackgroundNetworkTestCase.java | 6 ++++++ .../cts/net/hostside/DataSaverModeTest.java | 16 +++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 9245a6f3d0..6c0a3c030f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -541,6 +541,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void addRestrictBackgroundWhitelist(int uid) throws Exception { executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); + // UID policies live by the Highlander rule: "There can be only one". + // Hence, if app is whitelisted, it should not be blacklisted. + assertRestrictBackgroundBlacklist(uid, false); } protected void removeRestrictBackgroundWhitelist(int uid) throws Exception { @@ -555,6 +558,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void addRestrictBackgroundBlacklist(int uid) throws Exception { executeShellCommand("cmd netpolicy add restrict-background-blacklist " + uid); assertRestrictBackgroundBlacklist(uid, true); + // UID policies live by the Highlander rule: "There can be only one". + // Hence, if app is blacklisted, it should not be whitelisted. + assertRestrictBackgroundWhitelist(uid, false); } protected void removeRestrictBackgroundBlacklist(int uid) throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 881b3b4759..63a66da3a9 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -135,24 +135,30 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); - // Make sure blacklist prevails over whitelist. + // UID policies live by the Highlander rule: "There can be only one". + // Hence, if app is whitelisted, it should not be blacklisted anymore. setRestrictBackground(true); assertRestrictBackgroundChangedReceived(2); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); addRestrictBackgroundWhitelist(mUid); assertRestrictBackgroundChangedReceived(3); - assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED); // Check status after removing blacklist. + // ...re-enables first + addRestrictBackgroundBlacklist(mUid); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertsForegroundAlwaysHasNetworkAccess(); + // ... remove blacklist - access's still rejected because Data Saver is on removeRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(4); - assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertsForegroundAlwaysHasNetworkAccess(); + // ... finally, disable Data Saver setRestrictBackground(false); assertRestrictBackgroundChangedReceived(5); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); - assertsForegroundAlwaysHasNetworkAccess(); - assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); } public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { From d5f707225cdd4182b31af25d171425e24f29e00f Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 24 Aug 2016 14:57:57 -0700 Subject: [PATCH 0275/1415] Fixed number wrong number of expected intents. Test: cts-tradefed run commandAndExit cts --skip-device-info --skip-system-status-check com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker --skip-preconditions -m CtsHostsideNetworkTests --abi armeabi-v7a -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests BUG: 28791717 Change-Id: I5f3db14723cc94057715f241579922c5dbf2db8f --- .../src/com/android/cts/net/hostside/DataSaverModeTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 63a66da3a9..8efea01844 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -151,12 +151,12 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); // ... remove blacklist - access's still rejected because Data Saver is on removeRestrictBackgroundBlacklist(mUid); - assertRestrictBackgroundChangedReceived(4); + assertRestrictBackgroundChangedReceived(3); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); assertsForegroundAlwaysHasNetworkAccess(); // ... finally, disable Data Saver setRestrictBackground(false); - assertRestrictBackgroundChangedReceived(5); + assertRestrictBackgroundChangedReceived(4); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); assertsForegroundAlwaysHasNetworkAccess(); } From 52376fc1c8ce135fdc6dccf44a6b2770834b0682 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Wed, 31 Aug 2016 11:30:13 +0100 Subject: [PATCH 0276/1415] Add CTS tests for LocalSocket read/write timeouts The behavior was not previous covered and broke in N due to commit c80af6d8. There is an associated fix in frameworks/base. Some refactoring of existing tests to reduce duplication and tidy up sockets after tests. Test: Ran the new CTS test (before and after related fix) Bug: 31205169 Change-Id: Ie94335bc535beefcc5301d5469de6b8211af0bab --- .../src/android/net/cts/LocalSocketTest.java | 196 ++++++++++++++---- 1 file changed, 159 insertions(+), 37 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 77f0a44705..0ff4a3080b 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -22,12 +22,18 @@ import android.net.Credentials; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; +import android.system.Os; +import android.system.OsConstants; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class LocalSocketTest extends TestCase { @@ -177,58 +183,114 @@ public class LocalSocketTest extends TestCase { socket.close(); } + // http://b/31205169 + public void testSetSoTimeout_readTimeout() throws Exception { + String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + final LocalSocket clientSocket = socketPair.clientSocket; + + // Set the timeout in millis. + int timeoutMillis = 1000; + clientSocket.setSoTimeout(timeoutMillis); + + // Avoid blocking the test run if timeout doesn't happen by using a separate thread. + Callable reader = () -> { + try { + clientSocket.getInputStream().read(); + return Result.noException("Did not block"); + } catch (IOException e) { + return Result.exception(e); + } + }; + // Allow the configured timeout, plus some slop. + int allowedTime = timeoutMillis + 2000; + Result result = runInSeparateThread(allowedTime, reader); + + // Check the message was a timeout, it's all we have to go on. + String expectedMessage = Os.strerror(OsConstants.EAGAIN); + result.assertThrewIOException(expectedMessage); + } + } + + // http://b/31205169 + public void testSetSoTimeout_writeTimeout() throws Exception { + String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + final LocalSocket clientSocket = socketPair.clientSocket; + + // Set the timeout in millis. + int timeoutMillis = 1000; + clientSocket.setSoTimeout(timeoutMillis); + + // Set a small buffer size so we know we can flood it. + clientSocket.setSendBufferSize(100); + final int bufferSize = clientSocket.getSendBufferSize(); + + // Avoid blocking the test run if timeout doesn't happen by using a separate thread. + Callable writer = () -> { + try { + byte[] toWrite = new byte[bufferSize * 2]; + clientSocket.getOutputStream().write(toWrite); + return Result.noException("Did not block"); + } catch (IOException e) { + return Result.exception(e); + } + }; + // Allow the configured timeout, plus some slop. + int allowedTime = timeoutMillis + 2000; + + Result result = runInSeparateThread(allowedTime, writer); + + // Check the message was a timeout, it's all we have to go on. + String expectedMessage = Os.strerror(OsConstants.EAGAIN); + result.assertThrewIOException(expectedMessage); + } + } + public void testAvailable() throws Exception { String address = ADDRESS_PREFIX + "_testAvailable"; - LocalServerSocket localServerSocket = new LocalServerSocket(address); - LocalSocket clientSocket = new LocalSocket(); - // establish connection between client and server - LocalSocketAddress locSockAddr = new LocalSocketAddress(address); - clientSocket.connect(locSockAddr); - assertTrue(clientSocket.isConnected()); - LocalSocket serverSocket = localServerSocket.accept(); + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + LocalSocket clientSocket = socketPair.clientSocket; + LocalSocket serverSocket = socketPair.serverSocket.accept(); - OutputStream clientOutputStream = clientSocket.getOutputStream(); - InputStream serverInputStream = serverSocket.getInputStream(); - assertEquals(0, serverInputStream.available()); + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + assertEquals(0, serverInputStream.available()); - byte[] buffer = new byte[50]; - clientOutputStream.write(buffer); - assertEquals(50, serverInputStream.available()); + byte[] buffer = new byte[50]; + clientOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); - InputStream clientInputStream = clientSocket.getInputStream(); - OutputStream serverOutputStream = serverSocket.getOutputStream(); - assertEquals(0, clientInputStream.available()); - serverOutputStream.write(buffer); - assertEquals(50, serverInputStream.available()); + InputStream clientInputStream = clientSocket.getInputStream(); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + assertEquals(0, clientInputStream.available()); + serverOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); - clientSocket.close(); - serverSocket.close(); - localServerSocket.close(); + serverSocket.close(); + } } public void testFlush() throws Exception { String address = ADDRESS_PREFIX + "_testFlush"; - LocalServerSocket localServerSocket = new LocalServerSocket(address); - LocalSocket clientSocket = new LocalSocket(); - // establish connection between client and server - LocalSocketAddress locSockAddr = new LocalSocketAddress(address); - clientSocket.connect(locSockAddr); - assertTrue(clientSocket.isConnected()); - LocalSocket serverSocket = localServerSocket.accept(); + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + LocalSocket clientSocket = socketPair.clientSocket; + LocalSocket serverSocket = socketPair.serverSocket.accept(); - OutputStream clientOutputStream = clientSocket.getOutputStream(); - InputStream serverInputStream = serverSocket.getInputStream(); - testFlushWorks(clientOutputStream, serverInputStream); + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + testFlushWorks(clientOutputStream, serverInputStream); - OutputStream serverOutputStream = serverSocket.getOutputStream(); - InputStream clientInputStream = clientSocket.getInputStream(); - testFlushWorks(serverOutputStream, clientInputStream); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + InputStream clientInputStream = clientSocket.getInputStream(); + testFlushWorks(serverOutputStream, clientInputStream); - clientSocket.close(); - serverSocket.close(); - localServerSocket.close(); + serverSocket.close(); + } } private void testFlushWorks(OutputStream outputStream, InputStream inputStream) @@ -296,4 +358,64 @@ public class LocalSocketTest extends TestCase { assertEquals(expected, bytesRead); } } + + private static class Result { + private final String type; + private final Exception e; + + private Result(String type, Exception e) { + this.type = type; + this.e = e; + } + + static Result noException(String description) { + return new Result(description, null); + } + + static Result exception(Exception e) { + return new Result(e.getClass().getName(), e); + } + + void assertThrewIOException(String expectedMessage) { + assertEquals("Unexpected result type", IOException.class.getName(), type); + assertEquals("Unexpected exception message", expectedMessage, e.getMessage()); + } + } + + private static Result runInSeparateThread(int allowedTime, final Callable callable) + throws Exception { + ExecutorService service = Executors.newSingleThreadScheduledExecutor(); + Future future = service.submit(callable); + Result result = future.get(allowedTime, TimeUnit.MILLISECONDS); + if (!future.isDone()) { + fail("Worker thread appears blocked"); + } + return result; + } + + private static class LocalSocketPair implements AutoCloseable { + static LocalSocketPair createConnectedSocketPair(String address) throws Exception { + LocalServerSocket localServerSocket = new LocalServerSocket(address); + final LocalSocket clientSocket = new LocalSocket(); + + // Establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(address); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + return new LocalSocketPair(localServerSocket, clientSocket); + } + + final LocalServerSocket serverSocket; + final LocalSocket clientSocket; + + LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) { + this.serverSocket = serverSocket; + this.clientSocket = clientSocket; + } + + public void close() throws Exception { + serverSocket.close(); + clientSocket.close(); + } + } } From a8574413edaaa9bd6bf6eb57cf6fcab68b75529c Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Wed, 31 Aug 2016 11:30:13 +0100 Subject: [PATCH 0277/1415] Add CTS tests for LocalSocket read/write timeouts The behavior was not previous covered and broke in N due to commit c80af6d8. There is an associated fix in frameworks/base. Some refactoring of existing tests to reduce duplication and tidy up sockets after tests. Test: Ran the new CTS test (before and after related fix) Bug: 31205169 (cherry picked from commit 52376fc1c8ce135fdc6dccf44a6b2770834b0682) Change-Id: I9ee96a91abbdaaba64c2f6daf49c92d1b23352e2 --- .../src/android/net/cts/LocalSocketTest.java | 196 ++++++++++++++---- 1 file changed, 159 insertions(+), 37 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 77f0a44705..0ff4a3080b 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -22,12 +22,18 @@ import android.net.Credentials; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; +import android.system.Os; +import android.system.OsConstants; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class LocalSocketTest extends TestCase { @@ -177,58 +183,114 @@ public class LocalSocketTest extends TestCase { socket.close(); } + // http://b/31205169 + public void testSetSoTimeout_readTimeout() throws Exception { + String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + final LocalSocket clientSocket = socketPair.clientSocket; + + // Set the timeout in millis. + int timeoutMillis = 1000; + clientSocket.setSoTimeout(timeoutMillis); + + // Avoid blocking the test run if timeout doesn't happen by using a separate thread. + Callable reader = () -> { + try { + clientSocket.getInputStream().read(); + return Result.noException("Did not block"); + } catch (IOException e) { + return Result.exception(e); + } + }; + // Allow the configured timeout, plus some slop. + int allowedTime = timeoutMillis + 2000; + Result result = runInSeparateThread(allowedTime, reader); + + // Check the message was a timeout, it's all we have to go on. + String expectedMessage = Os.strerror(OsConstants.EAGAIN); + result.assertThrewIOException(expectedMessage); + } + } + + // http://b/31205169 + public void testSetSoTimeout_writeTimeout() throws Exception { + String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + final LocalSocket clientSocket = socketPair.clientSocket; + + // Set the timeout in millis. + int timeoutMillis = 1000; + clientSocket.setSoTimeout(timeoutMillis); + + // Set a small buffer size so we know we can flood it. + clientSocket.setSendBufferSize(100); + final int bufferSize = clientSocket.getSendBufferSize(); + + // Avoid blocking the test run if timeout doesn't happen by using a separate thread. + Callable writer = () -> { + try { + byte[] toWrite = new byte[bufferSize * 2]; + clientSocket.getOutputStream().write(toWrite); + return Result.noException("Did not block"); + } catch (IOException e) { + return Result.exception(e); + } + }; + // Allow the configured timeout, plus some slop. + int allowedTime = timeoutMillis + 2000; + + Result result = runInSeparateThread(allowedTime, writer); + + // Check the message was a timeout, it's all we have to go on. + String expectedMessage = Os.strerror(OsConstants.EAGAIN); + result.assertThrewIOException(expectedMessage); + } + } + public void testAvailable() throws Exception { String address = ADDRESS_PREFIX + "_testAvailable"; - LocalServerSocket localServerSocket = new LocalServerSocket(address); - LocalSocket clientSocket = new LocalSocket(); - // establish connection between client and server - LocalSocketAddress locSockAddr = new LocalSocketAddress(address); - clientSocket.connect(locSockAddr); - assertTrue(clientSocket.isConnected()); - LocalSocket serverSocket = localServerSocket.accept(); + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + LocalSocket clientSocket = socketPair.clientSocket; + LocalSocket serverSocket = socketPair.serverSocket.accept(); - OutputStream clientOutputStream = clientSocket.getOutputStream(); - InputStream serverInputStream = serverSocket.getInputStream(); - assertEquals(0, serverInputStream.available()); + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + assertEquals(0, serverInputStream.available()); - byte[] buffer = new byte[50]; - clientOutputStream.write(buffer); - assertEquals(50, serverInputStream.available()); + byte[] buffer = new byte[50]; + clientOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); - InputStream clientInputStream = clientSocket.getInputStream(); - OutputStream serverOutputStream = serverSocket.getOutputStream(); - assertEquals(0, clientInputStream.available()); - serverOutputStream.write(buffer); - assertEquals(50, serverInputStream.available()); + InputStream clientInputStream = clientSocket.getInputStream(); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + assertEquals(0, clientInputStream.available()); + serverOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); - clientSocket.close(); - serverSocket.close(); - localServerSocket.close(); + serverSocket.close(); + } } public void testFlush() throws Exception { String address = ADDRESS_PREFIX + "_testFlush"; - LocalServerSocket localServerSocket = new LocalServerSocket(address); - LocalSocket clientSocket = new LocalSocket(); - // establish connection between client and server - LocalSocketAddress locSockAddr = new LocalSocketAddress(address); - clientSocket.connect(locSockAddr); - assertTrue(clientSocket.isConnected()); - LocalSocket serverSocket = localServerSocket.accept(); + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + LocalSocket clientSocket = socketPair.clientSocket; + LocalSocket serverSocket = socketPair.serverSocket.accept(); - OutputStream clientOutputStream = clientSocket.getOutputStream(); - InputStream serverInputStream = serverSocket.getInputStream(); - testFlushWorks(clientOutputStream, serverInputStream); + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + testFlushWorks(clientOutputStream, serverInputStream); - OutputStream serverOutputStream = serverSocket.getOutputStream(); - InputStream clientInputStream = clientSocket.getInputStream(); - testFlushWorks(serverOutputStream, clientInputStream); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + InputStream clientInputStream = clientSocket.getInputStream(); + testFlushWorks(serverOutputStream, clientInputStream); - clientSocket.close(); - serverSocket.close(); - localServerSocket.close(); + serverSocket.close(); + } } private void testFlushWorks(OutputStream outputStream, InputStream inputStream) @@ -296,4 +358,64 @@ public class LocalSocketTest extends TestCase { assertEquals(expected, bytesRead); } } + + private static class Result { + private final String type; + private final Exception e; + + private Result(String type, Exception e) { + this.type = type; + this.e = e; + } + + static Result noException(String description) { + return new Result(description, null); + } + + static Result exception(Exception e) { + return new Result(e.getClass().getName(), e); + } + + void assertThrewIOException(String expectedMessage) { + assertEquals("Unexpected result type", IOException.class.getName(), type); + assertEquals("Unexpected exception message", expectedMessage, e.getMessage()); + } + } + + private static Result runInSeparateThread(int allowedTime, final Callable callable) + throws Exception { + ExecutorService service = Executors.newSingleThreadScheduledExecutor(); + Future future = service.submit(callable); + Result result = future.get(allowedTime, TimeUnit.MILLISECONDS); + if (!future.isDone()) { + fail("Worker thread appears blocked"); + } + return result; + } + + private static class LocalSocketPair implements AutoCloseable { + static LocalSocketPair createConnectedSocketPair(String address) throws Exception { + LocalServerSocket localServerSocket = new LocalServerSocket(address); + final LocalSocket clientSocket = new LocalSocket(); + + // Establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(address); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + return new LocalSocketPair(localServerSocket, clientSocket); + } + + final LocalServerSocket serverSocket; + final LocalSocket clientSocket; + + LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) { + this.serverSocket = serverSocket; + this.clientSocket = clientSocket; + } + + public void close() throws Exception { + serverSocket.close(); + clientSocket.close(); + } + } } From 0118f0329c1df2853a55291bb0a936085779d468 Mon Sep 17 00:00:00 2001 From: "sj.cha" Date: Mon, 29 Aug 2016 16:21:54 +0900 Subject: [PATCH 0278/1415] Add some failure comments in VpnTest Symptom : Sockets are not instantly destroyed during VpnTest. Root Cause : If CONFIG_INET_DIAG_DESTROY kernel config is not set in Android N, when network interface going to down, sockets are not instantly destroyed. Solution : Enable CONFIG_INET_DIAG_DESTROY kernel feature. But developer cannot check all of configurations on kernel, so adding some comments in VpnTest. Signed-off-by: SangJin Cha Change-Id: Ib97b93dfbfb62fe61bd3688ea7545708ec3ea2a2 --- .../app/src/com/android/cts/net/hostside/VpnTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index 12fe625370..a8ad2b868e 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -84,6 +84,11 @@ import java.util.Random; * https://android-review.googlesource.com/#/c/99225/ * https://android-review.googlesource.com/#/c/100557/ * + * To ensure that the kernel has the required commits, run the kernel unit + * tests described at: + * + * https://source.android.com/devices/tech/config/kernel_network_tests.html + * */ public class VpnTest extends InstrumentationTestCase { From f1bb48635dfbed57d74c342942eff50a207610eb Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 7 Sep 2016 08:56:45 -0700 Subject: [PATCH 0279/1415] CtsNetTests: Fix WifiInfoTest According to the public documentation of WifiInfo.getSSID(), the returned value can be one of the following: 1. Hex digits if the SSID cannot be decoded as UTF-8. 2. String surrounded by double quotes if the SSID can be decoded as UTF-8. 3. , if not connected. Fix the test to check for all these 3 string values. BUG: 31272462 TEST: The failing CTS test passes now. Change-Id: I26e12d28994e3cdb4cd1bd9e999633b327ad5830 --- tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 8719b6b029..696d215649 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -26,6 +26,7 @@ import android.net.wifi.SupplicantState; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; +import android.net.wifi.WifiSsid; import android.test.AndroidTestCase; import java.util.concurrent.Callable; @@ -123,7 +124,7 @@ public class WifiInfoTest extends AndroidTestCase { SupplicantState.isValidState(wifiInfo.getSupplicantState()); WifiInfo.getDetailedStateOf(SupplicantState.DISCONNECTED); String ssid = wifiInfo.getSSID(); - if (ssid.startsWith("0x") == false) { + if (!ssid.startsWith("0x") && !ssid.equals(WifiSsid.NONE)) { // Non-hex string should be quoted assertTrue(ssid.charAt(0) == '"'); assertTrue(ssid.charAt(ssid.length() - 1) == '"'); From 03ee9869ac7ef7cc5e6f854e09e9a8f8ff7519b3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 26 May 2016 11:57:41 -0700 Subject: [PATCH 0280/1415] Fix to CtsHostsideNetworkTestsAidl Java library kind. Fixes Error Prone build. Bug: 27723540 (cherry picked from commit ad015ac64d0e510cc040a83b1d545e3a1405b1f7) Change-Id: I150aefde61615023e86e19645a46e432a0183705 --- tests/cts/hostside/aidl/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/hostside/aidl/Android.mk b/tests/cts/hostside/aidl/Android.mk index a7ec6efb31..4aa55b6a08 100644 --- a/tests/cts/hostside/aidl/Android.mk +++ b/tests/cts/hostside/aidl/Android.mk @@ -19,4 +19,4 @@ LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current LOCAL_SRC_FILES := com/android/cts/net/hostside/IRemoteSocketFactory.aidl LOCAL_MODULE := CtsHostsideNetworkTestsAidl -include $(BUILD_JAVA_LIBRARY) +include $(BUILD_STATIC_JAVA_LIBRARY) From 0e42d0c0adf3e7e9bf72474e0a869e4bb586635e Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 8 Sep 2016 09:50:50 -0700 Subject: [PATCH 0281/1415] Restore right number of expected intents. They were changed during a refactoring, which is now finished. Test: cts-tradefed run commandAndExit cts -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testDataSaverMode_enabled Fixes: 28791717 Change-Id: Ia5e99c0c3d421b7d3b58e11ddde4da222d5f8c15 --- .../src/com/android/cts/net/hostside/DataSaverModeTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 8efea01844..7ca302f52a 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -133,6 +133,7 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); assertsForegroundAlwaysHasNetworkAccess(); + assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); // UID policies live by the Highlander rule: "There can be only one". @@ -147,16 +148,17 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase // Check status after removing blacklist. // ...re-enables first addRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(4); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); assertsForegroundAlwaysHasNetworkAccess(); // ... remove blacklist - access's still rejected because Data Saver is on removeRestrictBackgroundBlacklist(mUid); - assertRestrictBackgroundChangedReceived(3); + assertRestrictBackgroundChangedReceived(4); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); assertsForegroundAlwaysHasNetworkAccess(); // ... finally, disable Data Saver setRestrictBackground(false); - assertRestrictBackgroundChangedReceived(4); + assertRestrictBackgroundChangedReceived(5); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); assertsForegroundAlwaysHasNetworkAccess(); } From 36c0f02d94b46950fbfb5ab7525e5d02183cf77d Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Tue, 13 Sep 2016 13:52:20 +0800 Subject: [PATCH 0282/1415] PacketReflector: Ignore IPv6 flow labels in ICMPv6 test Since Linux kernel 4.2, net.ipv6.auto_flowlabels is set by default, and therefore the request and reply may have different IPv6 flow label. Bug: 31444338 Test: On a kernel 4.4 board, run com.android.cts.net.HostsideNetworkTests#testVpn Test: On a kernel 3.18 board, run echo 1 > /proc/sys/net/ipv6/auto_flowlabels, then com.android.cts.net.HostsideNetworkTests#testVpn Change-Id: I913bbf91574239a24cb32ae908834eb951ea2010 --- .../com/android/cts/net/hostside/PacketReflector.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java index dd0f792b21..a4a2956d3a 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java @@ -151,6 +151,15 @@ public class PacketReflector extends Thread { request[hdrLen] = buf[hdrLen]; // Type. request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1. request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2. + + // Since Linux kernel 4.2, net.ipv6.auto_flowlabels is set by default, and therefore + // the request and reply may have different IPv6 flow label: ignore that as well. + if (version == 6) { + request[1] = (byte)(request[1] & 0xf0 | buf[1] & 0x0f); + request[2] = buf[2]; + request[3] = buf[3]; + } + for (int i = 0; i < len; i++) { if (buf[i] != request[i]) { Log.i(TAG, "Received non-matching packet when expecting ping response."); From 07f9388e4fe84f13fd3f345e4db9dc9b49d982ed Mon Sep 17 00:00:00 2001 From: Stephen Li Date: Wed, 14 Sep 2016 22:25:06 +0000 Subject: [PATCH 0283/1415] Revert "Manually merge commit '9be9d5865ba2584a251642359710c074061dee5e' into nyc-dev" This reverts commit 253fdc667a18ec0cfdc511c7d21e3b308ecb9cfb. Change-Id: If8862e289eb6693650713ff819c8b05f65cdeda5 --- tests/cts/net/jni/NativeDnsJni.c | 2 +- tests/cts/net/jni/NativeMultinetworkJni.c | 2 +- .../src/android/net/cts/LocalSocketTest.java | 196 ++++-------------- .../net/http/cts/HttpResponseCacheTest.java | 3 +- 4 files changed, 40 insertions(+), 163 deletions(-) diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 352c0c52cc..4eb3c7aebc 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -126,7 +126,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas return JNI_FALSE; } - memset(buf, 0, sizeof(buf)); + memset(buf, sizeof(buf), 0); res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index 6990efa452..ad56b510c3 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -30,7 +30,7 @@ #include #include -#define UNUSED(X) ((void) (X)) +#define UNUSED(X) ((void) X) static const char kHostname[] = "connectivitycheck.android.com"; diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 0ff4a3080b..77f0a44705 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -22,18 +22,12 @@ import android.net.Credentials; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; -import android.system.Os; -import android.system.OsConstants; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class LocalSocketTest extends TestCase { @@ -183,114 +177,58 @@ public class LocalSocketTest extends TestCase { socket.close(); } - // http://b/31205169 - public void testSetSoTimeout_readTimeout() throws Exception { - String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout"; - - try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { - final LocalSocket clientSocket = socketPair.clientSocket; - - // Set the timeout in millis. - int timeoutMillis = 1000; - clientSocket.setSoTimeout(timeoutMillis); - - // Avoid blocking the test run if timeout doesn't happen by using a separate thread. - Callable reader = () -> { - try { - clientSocket.getInputStream().read(); - return Result.noException("Did not block"); - } catch (IOException e) { - return Result.exception(e); - } - }; - // Allow the configured timeout, plus some slop. - int allowedTime = timeoutMillis + 2000; - Result result = runInSeparateThread(allowedTime, reader); - - // Check the message was a timeout, it's all we have to go on. - String expectedMessage = Os.strerror(OsConstants.EAGAIN); - result.assertThrewIOException(expectedMessage); - } - } - - // http://b/31205169 - public void testSetSoTimeout_writeTimeout() throws Exception { - String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout"; - - try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { - final LocalSocket clientSocket = socketPair.clientSocket; - - // Set the timeout in millis. - int timeoutMillis = 1000; - clientSocket.setSoTimeout(timeoutMillis); - - // Set a small buffer size so we know we can flood it. - clientSocket.setSendBufferSize(100); - final int bufferSize = clientSocket.getSendBufferSize(); - - // Avoid blocking the test run if timeout doesn't happen by using a separate thread. - Callable writer = () -> { - try { - byte[] toWrite = new byte[bufferSize * 2]; - clientSocket.getOutputStream().write(toWrite); - return Result.noException("Did not block"); - } catch (IOException e) { - return Result.exception(e); - } - }; - // Allow the configured timeout, plus some slop. - int allowedTime = timeoutMillis + 2000; - - Result result = runInSeparateThread(allowedTime, writer); - - // Check the message was a timeout, it's all we have to go on. - String expectedMessage = Os.strerror(OsConstants.EAGAIN); - result.assertThrewIOException(expectedMessage); - } - } - public void testAvailable() throws Exception { String address = ADDRESS_PREFIX + "_testAvailable"; + LocalServerSocket localServerSocket = new LocalServerSocket(address); + LocalSocket clientSocket = new LocalSocket(); - try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { - LocalSocket clientSocket = socketPair.clientSocket; - LocalSocket serverSocket = socketPair.serverSocket.accept(); + // establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(address); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + LocalSocket serverSocket = localServerSocket.accept(); - OutputStream clientOutputStream = clientSocket.getOutputStream(); - InputStream serverInputStream = serverSocket.getInputStream(); - assertEquals(0, serverInputStream.available()); + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + assertEquals(0, serverInputStream.available()); - byte[] buffer = new byte[50]; - clientOutputStream.write(buffer); - assertEquals(50, serverInputStream.available()); + byte[] buffer = new byte[50]; + clientOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); - InputStream clientInputStream = clientSocket.getInputStream(); - OutputStream serverOutputStream = serverSocket.getOutputStream(); - assertEquals(0, clientInputStream.available()); - serverOutputStream.write(buffer); - assertEquals(50, serverInputStream.available()); + InputStream clientInputStream = clientSocket.getInputStream(); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + assertEquals(0, clientInputStream.available()); + serverOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); - serverSocket.close(); - } + clientSocket.close(); + serverSocket.close(); + localServerSocket.close(); } public void testFlush() throws Exception { String address = ADDRESS_PREFIX + "_testFlush"; + LocalServerSocket localServerSocket = new LocalServerSocket(address); + LocalSocket clientSocket = new LocalSocket(); - try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { - LocalSocket clientSocket = socketPair.clientSocket; - LocalSocket serverSocket = socketPair.serverSocket.accept(); + // establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(address); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + LocalSocket serverSocket = localServerSocket.accept(); - OutputStream clientOutputStream = clientSocket.getOutputStream(); - InputStream serverInputStream = serverSocket.getInputStream(); - testFlushWorks(clientOutputStream, serverInputStream); + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + testFlushWorks(clientOutputStream, serverInputStream); - OutputStream serverOutputStream = serverSocket.getOutputStream(); - InputStream clientInputStream = clientSocket.getInputStream(); - testFlushWorks(serverOutputStream, clientInputStream); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + InputStream clientInputStream = clientSocket.getInputStream(); + testFlushWorks(serverOutputStream, clientInputStream); - serverSocket.close(); - } + clientSocket.close(); + serverSocket.close(); + localServerSocket.close(); } private void testFlushWorks(OutputStream outputStream, InputStream inputStream) @@ -358,64 +296,4 @@ public class LocalSocketTest extends TestCase { assertEquals(expected, bytesRead); } } - - private static class Result { - private final String type; - private final Exception e; - - private Result(String type, Exception e) { - this.type = type; - this.e = e; - } - - static Result noException(String description) { - return new Result(description, null); - } - - static Result exception(Exception e) { - return new Result(e.getClass().getName(), e); - } - - void assertThrewIOException(String expectedMessage) { - assertEquals("Unexpected result type", IOException.class.getName(), type); - assertEquals("Unexpected exception message", expectedMessage, e.getMessage()); - } - } - - private static Result runInSeparateThread(int allowedTime, final Callable callable) - throws Exception { - ExecutorService service = Executors.newSingleThreadScheduledExecutor(); - Future future = service.submit(callable); - Result result = future.get(allowedTime, TimeUnit.MILLISECONDS); - if (!future.isDone()) { - fail("Worker thread appears blocked"); - } - return result; - } - - private static class LocalSocketPair implements AutoCloseable { - static LocalSocketPair createConnectedSocketPair(String address) throws Exception { - LocalServerSocket localServerSocket = new LocalServerSocket(address); - final LocalSocket clientSocket = new LocalSocket(); - - // Establish connection between client and server - LocalSocketAddress locSockAddr = new LocalSocketAddress(address); - clientSocket.connect(locSockAddr); - assertTrue(clientSocket.isConnected()); - return new LocalSocketPair(localServerSocket, clientSocket); - } - - final LocalServerSocket serverSocket; - final LocalSocket clientSocket; - - LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) { - this.serverSocket = serverSocket; - this.clientSocket = clientSocket; - } - - public void close() throws Exception { - serverSocket.close(); - clientSocket.close(); - } - } } diff --git a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java index 7987a50eb9..545541d68b 100644 --- a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java +++ b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java @@ -38,11 +38,10 @@ import java.util.UUID; public final class HttpResponseCacheTest extends TestCase { private File cacheDir; - private MockWebServer server; + private MockWebServer server = new MockWebServer(); @Override public void setUp() throws Exception { super.setUp(); - server = new MockWebServer(); String tmp = System.getProperty("java.io.tmpdir"); cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); cacheDir.mkdirs(); From 2855028c8ec28b263e495c22d12f3781ae586a99 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Mon, 19 Sep 2016 09:27:06 -0700 Subject: [PATCH 0284/1415] Tests for idle parole when charging Make sure that when switching between idle, paroled and battery saver, the network availability of the app is correctly updated. Bug: 31399882 Test: cts-tradefed run commandAndExit cts -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testAppIdleNonMetered_whenCharging Test: cts-tradefed run commandAndExit cts -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testAppIdleMetered_whenCharging Change-Id: I060a0d5f9c3297430b5b623b389c1afdf6abde87 --- .../net/hostside/AbstractAppIdleTestCase.java | 24 +++++++++++++++++++ ...ostsideRestrictBackgroundNetworkTests.java | 10 ++++++++ 2 files changed, 34 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index ba56665fbc..e7e551cdbb 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -138,4 +138,28 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(true); } + + public void testAppIdleNetworkAccess_whenCharging() throws Exception { + if (!isSupported()) return; + + // Check that app is paroled when charging + setAppIdle(true); + assertBackgroundNetworkAccess(false); + turnBatteryOn(); + assertBackgroundNetworkAccess(true); + turnBatteryOff(); + assertBackgroundNetworkAccess(false); + + // Check that app is restricted when not idle but power-save is on + setAppIdle(false); + assertBackgroundNetworkAccess(true); + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + turnBatteryOn(); + assertBackgroundNetworkAccess(true); + + // And when no longer charging, it still has network access, since it's not idle + turnBatteryOff(); + assertBackgroundNetworkAccess(true); + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 7d5f817798..dbf8acabea 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -171,6 +171,16 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + public void testAppIdleNonMetered_whenCharging() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testAppIdleNetworkAccess_whenCharging"); + } + + public void testAppIdleMetered_whenCharging() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testAppIdleNetworkAccess_whenCharging"); + } + /******************** * Doze Mode tests. * ********************/ From 4a0758045c63c50a34f90d3eccd69133b03697da Mon Sep 17 00:00:00 2001 From: Dan Willemsen Date: Mon, 19 Sep 2016 21:27:59 -0700 Subject: [PATCH 0285/1415] DO NOT MERGE ANYWHERE Actually fix cts in nyc-dev-plus-aosp I did this manually first, but came up with a much better way that produced a slightly better result (verified the diffs against the next branch). Sequence of commands: # Checkout the last good commit (right before the first bad merge) git checkout aa76e8b6fc8515bfc65d4b75456b74c26ee32f1e^ # Reset the HEAD pointer to the last bad merge, but not the worktree git reset 3c197891b50d9ac5e5016f55551b6dff82f62f33 # Update the index git add -A # Apply all the changes that mattered between the above to commits git cherry-pick -n 29cb19b774b6e0cb73851feb6877da5e42bba78e git cherry-pick -n 0e9d107fcfbd3421b7988a4252a9965896019aba git cherry-pick -n f19496887beb974c3bc9df9a57f6214a696417b1 git cherry-pick -n 939e2b253b798386ce53954626fd8044ecb18db6 git cherry-pick -n 02f07b5d5994b8345ebc86546e5f66524ac04dac # Commit the changes git commit # Rebase the diffs on top of the latest nyc-dev-plus-aosp, since some # changes have been manually applied, there will be a few merge # conflicts git rebase goog/nyc-dev-plus-aosp All the SHA-1s above were discovered using a combination of this command to find the changes actually submitted into nyc-dev-plus-aosp itself: git log --oneline --first-parent goog/nyc-dev-plus-aosp and then to find the original commits (that weren't marked as DO NOT MERGE ANYWHERE): git log --oneline --no-merges --stat aa76e8b..goog/nyc-dev-plus-aosp Change-Id: Iec12619678cb8d011d2c6df26a34ce26e042b854 --- tests/cts/net/jni/NativeDnsJni.c | 2 +- tests/cts/net/jni/NativeMultinetworkJni.c | 2 +- .../src/android/net/cts/LocalSocketTest.java | 196 ++++++++++++++---- .../net/http/cts/HttpResponseCacheTest.java | 3 +- 4 files changed, 163 insertions(+), 40 deletions(-) diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 4eb3c7aebc..352c0c52cc 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -126,7 +126,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas return JNI_FALSE; } - memset(buf, sizeof(buf), 0); + memset(buf, 0, sizeof(buf)); res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index ad56b510c3..6990efa452 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -30,7 +30,7 @@ #include #include -#define UNUSED(X) ((void) X) +#define UNUSED(X) ((void) (X)) static const char kHostname[] = "connectivitycheck.android.com"; diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 77f0a44705..0ff4a3080b 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -22,12 +22,18 @@ import android.net.Credentials; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; +import android.system.Os; +import android.system.OsConstants; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class LocalSocketTest extends TestCase { @@ -177,58 +183,114 @@ public class LocalSocketTest extends TestCase { socket.close(); } + // http://b/31205169 + public void testSetSoTimeout_readTimeout() throws Exception { + String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + final LocalSocket clientSocket = socketPair.clientSocket; + + // Set the timeout in millis. + int timeoutMillis = 1000; + clientSocket.setSoTimeout(timeoutMillis); + + // Avoid blocking the test run if timeout doesn't happen by using a separate thread. + Callable reader = () -> { + try { + clientSocket.getInputStream().read(); + return Result.noException("Did not block"); + } catch (IOException e) { + return Result.exception(e); + } + }; + // Allow the configured timeout, plus some slop. + int allowedTime = timeoutMillis + 2000; + Result result = runInSeparateThread(allowedTime, reader); + + // Check the message was a timeout, it's all we have to go on. + String expectedMessage = Os.strerror(OsConstants.EAGAIN); + result.assertThrewIOException(expectedMessage); + } + } + + // http://b/31205169 + public void testSetSoTimeout_writeTimeout() throws Exception { + String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + final LocalSocket clientSocket = socketPair.clientSocket; + + // Set the timeout in millis. + int timeoutMillis = 1000; + clientSocket.setSoTimeout(timeoutMillis); + + // Set a small buffer size so we know we can flood it. + clientSocket.setSendBufferSize(100); + final int bufferSize = clientSocket.getSendBufferSize(); + + // Avoid blocking the test run if timeout doesn't happen by using a separate thread. + Callable writer = () -> { + try { + byte[] toWrite = new byte[bufferSize * 2]; + clientSocket.getOutputStream().write(toWrite); + return Result.noException("Did not block"); + } catch (IOException e) { + return Result.exception(e); + } + }; + // Allow the configured timeout, plus some slop. + int allowedTime = timeoutMillis + 2000; + + Result result = runInSeparateThread(allowedTime, writer); + + // Check the message was a timeout, it's all we have to go on. + String expectedMessage = Os.strerror(OsConstants.EAGAIN); + result.assertThrewIOException(expectedMessage); + } + } + public void testAvailable() throws Exception { String address = ADDRESS_PREFIX + "_testAvailable"; - LocalServerSocket localServerSocket = new LocalServerSocket(address); - LocalSocket clientSocket = new LocalSocket(); - // establish connection between client and server - LocalSocketAddress locSockAddr = new LocalSocketAddress(address); - clientSocket.connect(locSockAddr); - assertTrue(clientSocket.isConnected()); - LocalSocket serverSocket = localServerSocket.accept(); + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + LocalSocket clientSocket = socketPair.clientSocket; + LocalSocket serverSocket = socketPair.serverSocket.accept(); - OutputStream clientOutputStream = clientSocket.getOutputStream(); - InputStream serverInputStream = serverSocket.getInputStream(); - assertEquals(0, serverInputStream.available()); + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + assertEquals(0, serverInputStream.available()); - byte[] buffer = new byte[50]; - clientOutputStream.write(buffer); - assertEquals(50, serverInputStream.available()); + byte[] buffer = new byte[50]; + clientOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); - InputStream clientInputStream = clientSocket.getInputStream(); - OutputStream serverOutputStream = serverSocket.getOutputStream(); - assertEquals(0, clientInputStream.available()); - serverOutputStream.write(buffer); - assertEquals(50, serverInputStream.available()); + InputStream clientInputStream = clientSocket.getInputStream(); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + assertEquals(0, clientInputStream.available()); + serverOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); - clientSocket.close(); - serverSocket.close(); - localServerSocket.close(); + serverSocket.close(); + } } public void testFlush() throws Exception { String address = ADDRESS_PREFIX + "_testFlush"; - LocalServerSocket localServerSocket = new LocalServerSocket(address); - LocalSocket clientSocket = new LocalSocket(); - // establish connection between client and server - LocalSocketAddress locSockAddr = new LocalSocketAddress(address); - clientSocket.connect(locSockAddr); - assertTrue(clientSocket.isConnected()); - LocalSocket serverSocket = localServerSocket.accept(); + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + LocalSocket clientSocket = socketPair.clientSocket; + LocalSocket serverSocket = socketPair.serverSocket.accept(); - OutputStream clientOutputStream = clientSocket.getOutputStream(); - InputStream serverInputStream = serverSocket.getInputStream(); - testFlushWorks(clientOutputStream, serverInputStream); + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + testFlushWorks(clientOutputStream, serverInputStream); - OutputStream serverOutputStream = serverSocket.getOutputStream(); - InputStream clientInputStream = clientSocket.getInputStream(); - testFlushWorks(serverOutputStream, clientInputStream); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + InputStream clientInputStream = clientSocket.getInputStream(); + testFlushWorks(serverOutputStream, clientInputStream); - clientSocket.close(); - serverSocket.close(); - localServerSocket.close(); + serverSocket.close(); + } } private void testFlushWorks(OutputStream outputStream, InputStream inputStream) @@ -296,4 +358,64 @@ public class LocalSocketTest extends TestCase { assertEquals(expected, bytesRead); } } + + private static class Result { + private final String type; + private final Exception e; + + private Result(String type, Exception e) { + this.type = type; + this.e = e; + } + + static Result noException(String description) { + return new Result(description, null); + } + + static Result exception(Exception e) { + return new Result(e.getClass().getName(), e); + } + + void assertThrewIOException(String expectedMessage) { + assertEquals("Unexpected result type", IOException.class.getName(), type); + assertEquals("Unexpected exception message", expectedMessage, e.getMessage()); + } + } + + private static Result runInSeparateThread(int allowedTime, final Callable callable) + throws Exception { + ExecutorService service = Executors.newSingleThreadScheduledExecutor(); + Future future = service.submit(callable); + Result result = future.get(allowedTime, TimeUnit.MILLISECONDS); + if (!future.isDone()) { + fail("Worker thread appears blocked"); + } + return result; + } + + private static class LocalSocketPair implements AutoCloseable { + static LocalSocketPair createConnectedSocketPair(String address) throws Exception { + LocalServerSocket localServerSocket = new LocalServerSocket(address); + final LocalSocket clientSocket = new LocalSocket(); + + // Establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(address); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + return new LocalSocketPair(localServerSocket, clientSocket); + } + + final LocalServerSocket serverSocket; + final LocalSocket clientSocket; + + LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) { + this.serverSocket = serverSocket; + this.clientSocket = clientSocket; + } + + public void close() throws Exception { + serverSocket.close(); + clientSocket.close(); + } + } } diff --git a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java index 545541d68b..7987a50eb9 100644 --- a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java +++ b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java @@ -38,10 +38,11 @@ import java.util.UUID; public final class HttpResponseCacheTest extends TestCase { private File cacheDir; - private MockWebServer server = new MockWebServer(); + private MockWebServer server; @Override public void setUp() throws Exception { super.setUp(); + server = new MockWebServer(); String tmp = System.getProperty("java.io.tmpdir"); cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); cacheDir.mkdirs(); From 87c10012b4c7ba76c6d5ae87edba359ee873a096 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 21 Sep 2016 11:45:30 -0700 Subject: [PATCH 0286/1415] Test to ensure a toast doesn't affect app standby Put an app in standby, make it show a toast and ensure that it doesn't come out of standby. This is to test for a bug fix for the same behavior. Bug: 31544592 Test: cts-tradefed run commandAndExit cts -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testAppIdle_toast Change-Id: I796ecde8e346c308a27969d873e3ce384414fee3 --- .../cts/net/hostside/AbstractAppIdleTestCase.java | 13 +++++++++++++ .../AbstractRestrictBackgroundNetworkTestCase.java | 13 +++++++++++++ tests/cts/hostside/app2/AndroidManifest.xml | 1 + .../com/android/cts/net/hostside/app2/Common.java | 2 ++ .../cts/net/hostside/app2/MyBroadcastReceiver.java | 10 ++++++++++ .../net/HostsideRestrictBackgroundNetworkTests.java | 6 ++++++ 6 files changed, 45 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index e7e551cdbb..78ba4b9514 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -16,6 +16,7 @@ package com.android.cts.net.hostside; +import android.os.SystemClock; import android.util.Log; /** @@ -162,4 +163,16 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork turnBatteryOff(); assertBackgroundNetworkAccess(true); } + + public void testAppIdle_toast() throws Exception { + if (!isSupported()) return; + + setAppIdle(true); + assertAppIdle(true); + assertEquals("Shown", showToast()); + assertAppIdle(true); + // Wait for a couple of seconds for the toast to actually be shown + SystemClock.sleep(2000); + assertAppIdle(true); + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 9245a6f3d0..9c9ec0b021 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -64,6 +64,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation "com.android.cts.net.hostside.app2.action.RECEIVER_READY"; static final String ACTION_SEND_NOTIFICATION = "com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION"; + static final String ACTION_SHOW_TOAST = + "com.android.cts.net.hostside.app2.action.SHOW_TOAST"; private static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; private static final String EXTRA_RECEIVER_NAME = "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; @@ -782,6 +784,17 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mContext.sendBroadcast(intent); } + protected String showToast() { + final Intent intent = new Intent(ACTION_SHOW_TOAST); + intent.setPackage(TEST_APP2_PKG); + Log.d(TAG, "Sending request to show toast"); + try { + return sendOrderedBroadcast(intent, 3 * SECOND_IN_MS); + } catch (Exception e) { + return ""; + } + } + private String toString(int status) { switch (status) { case RESTRICT_BACKGROUND_STATUS_DISABLED: diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml index 1fa49ba837..adf0045d9f 100644 --- a/tests/cts/hostside/app2/AndroidManifest.xml +++ b/tests/cts/hostside/app2/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index 8806e3b970..e07c0f50d5 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -38,6 +38,8 @@ public final class Common { "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY"; static final String ACTION_SEND_NOTIFICATION = "com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION"; + static final String ACTION_SHOW_TOAST = + "com.android.cts.net.hostside.app2.action.SHOW_TOAST"; static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; static final String EXTRA_RECEIVER_NAME = "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 6d01b1554b..733c3aa6a0 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -23,6 +23,7 @@ import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS; import static com.android.cts.net.hostside.app2.Common.ACTION_GET_RESTRICT_BACKGROUND_STATUS; import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.ACTION_SEND_NOTIFICATION; +import static com.android.cts.net.hostside.app2.Common.ACTION_SHOW_TOAST; import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION; import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_ID; import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_TYPE; @@ -51,6 +52,7 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.util.Log; +import android.widget.Toast; import java.net.HttpURLConnection; import java.net.URL; @@ -104,6 +106,9 @@ public class MyBroadcastReceiver extends BroadcastReceiver { case ACTION_SEND_NOTIFICATION: sendNotification(context, intent); break; + case ACTION_SHOW_TOAST: + showToast(context); + break; default: Log.e(TAG, "received unexpected action: " + action); } @@ -302,4 +307,9 @@ public class MyBroadcastReceiver extends BroadcastReceiver { ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) .notify(notificationId, notification); } + + private void showToast(Context context) { + Toast.makeText(context, "Toast from CTS test", Toast.LENGTH_SHORT).show(); + setResultData("Shown"); + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index dbf8acabea..faf75d9d32 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -181,6 +181,12 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testAppIdleNetworkAccess_whenCharging"); } + public void testAppIdle_toast() throws Exception { + // Check that showing a toast doesn't bring an app out of standby + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testAppIdle_toast"); + } + /******************** * Doze Mode tests. * ********************/ From af7c4201f988357beb1f0720c23c1fd6ba6981fe Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 6 Oct 2016 17:17:10 -0700 Subject: [PATCH 0287/1415] Uses bound service instead of ordered broadcast for IPC. BUG: 32017623 Test: m -j 32 cts && cts-tradefed run commandAndExit cts -m CtsHostsideNetworkTests Change-Id: Ibdb84048b04405f234aa5ad9124eb70e9e592498 --- tests/cts/hostside/aidl/Android.mk | 4 +- .../android/cts/net/hostside/IMyService.aidl | 25 +++ ...ractRestrictBackgroundNetworkTestCase.java | 64 +++----- .../cts/net/hostside/MyServiceClient.java | 101 ++++++++++++ .../android/cts/net/hostside/app2/Common.java | 16 +- .../hostside/app2/MyBroadcastReceiver.java | 151 ++++++------------ .../cts/net/hostside/app2/MyService.java | 65 ++++++-- 7 files changed, 263 insertions(+), 163 deletions(-) create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java diff --git a/tests/cts/hostside/aidl/Android.mk b/tests/cts/hostside/aidl/Android.mk index 4aa55b6a08..58be21f608 100644 --- a/tests/cts/hostside/aidl/Android.mk +++ b/tests/cts/hostside/aidl/Android.mk @@ -17,6 +17,8 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current -LOCAL_SRC_FILES := com/android/cts/net/hostside/IRemoteSocketFactory.aidl +LOCAL_SRC_FILES := \ + com/android/cts/net/hostside/IMyService.aidl \ + com/android/cts/net/hostside/IRemoteSocketFactory.aidl LOCAL_MODULE := CtsHostsideNetworkTestsAidl include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl new file mode 100644 index 0000000000..72d105990e --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +interface IMyService { + void registerBroadcastReceiver(); + int getCounters(String receiverName, String action); + String checkNetworkStatus(); + String getRestrictBackgroundStatus(); + void sendNotification(int notificationId, String notificationType); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 6db9877463..7497758a70 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -54,25 +54,11 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // Constants below must match values defined on app2's Common.java private static final String MANIFEST_RECEIVER = "ManifestReceiver"; private static final String DYNAMIC_RECEIVER = "DynamicReceiver"; - private static final String ACTION_GET_COUNTERS = - "com.android.cts.net.hostside.app2.action.GET_COUNTERS"; - private static final String ACTION_GET_RESTRICT_BACKGROUND_STATUS = - "com.android.cts.net.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS"; - private static final String ACTION_CHECK_NETWORK = - "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; + private static final String ACTION_RECEIVER_READY = "com.android.cts.net.hostside.app2.action.RECEIVER_READY"; - static final String ACTION_SEND_NOTIFICATION = - "com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION"; static final String ACTION_SHOW_TOAST = "com.android.cts.net.hostside.app2.action.SHOW_TOAST"; - private static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; - private static final String EXTRA_RECEIVER_NAME = - "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; - private static final String EXTRA_NOTIFICATION_ID = - "com.android.cts.net.hostside.app2.extra.NOTIFICATION_ID"; - private static final String EXTRA_NOTIFICATION_TYPE = - "com.android.cts.net.hostside.app2.extra.NOTIFICATION_TYPE"; protected static final String NOTIFICATION_TYPE_CONTENT = "CONTENT"; protected static final String NOTIFICATION_TYPE_DELETE = "DELETE"; @@ -99,6 +85,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private String mMeteredWifi; + private MyServiceClient mServiceClient; @Override protected void setUp() throws Exception { @@ -110,12 +97,21 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); final int myUid = getUid(mContext.getPackageName()); + mServiceClient = new MyServiceClient(mContext); + mServiceClient.bind(); Log.i(TAG, "Apps status on " + getName() + ":\n" + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); } + @Override + protected void tearDown() throws Exception { + mServiceClient.unbind(); + + super.tearDown(); + } + protected int getUid(String packageName) throws Exception { return mContext.getPackageManager().getPackageUid(packageName, 0); } @@ -171,19 +167,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected int getNumberBroadcastsReceived(String receiverName, String action) throws Exception { - final Intent intent = new Intent(ACTION_GET_COUNTERS); - intent.putExtra(EXTRA_ACTION, ACTION_RESTRICT_BACKGROUND_CHANGED); - intent.putExtra(EXTRA_RECEIVER_NAME, receiverName); - final String resultData = sendOrderedBroadcast(intent); - assertNotNull("timeout waiting for ordered broadcast result", resultData); - return Integer.valueOf(resultData); + return mServiceClient.getCounters(receiverName, action); } protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { - final Intent intent = new Intent(ACTION_GET_RESTRICT_BACKGROUND_STATUS); - final String resultData = sendOrderedBroadcast(intent); - assertNotNull("timeout waiting for ordered broadcast result", resultData); - final String actualStatus = toString(Integer.parseInt(resultData)); + final String status = mServiceClient.getRestrictBackgroundStatus(); + assertNotNull("didn't get API status from app2", status); + final String actualStatus = toString(Integer.parseInt(status)); assertEquals("wrong status", toString(expectedStatus), actualStatus); } @@ -329,15 +319,15 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation * @return error message with the mismatch (or empty if assertion passed). */ private String checkNetworkAccess(boolean expectAvailable) throws Exception { - String resultData = sendOrderedBroadcast(new Intent(ACTION_CHECK_NETWORK)); + final String resultData = mServiceClient.checkNetworkStatus(); if (resultData == null) { - return "timeout waiting for ordered broadcast"; + return "did not get network status from app2"; } // Network status format is described on MyBroadcastReceiver.checkNetworkStatus() final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR); assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check - final State state = State.valueOf(parts[0]); - final DetailedState detailedState = DetailedState.valueOf(parts[1]); + final State state = parts[0].equals("null") ? null : State.valueOf(parts[0]); + final DetailedState detailedState = parts[1].equals("null") ? null : DetailedState.valueOf(parts[1]); final boolean connected = Boolean.valueOf(parts[2]); final String connectionCheckDetails = parts[3]; final String networkInfo = parts[4]; @@ -694,9 +684,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation * {@link #runDeviceTests(String, String)} is executed. */ protected void registerBroadcastReceiver() throws Exception { - executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService"); + mServiceClient.registerBroadcastReceiver(); + // Wait until receiver is ready. - final int maxTries = 5; + final int maxTries = 10; for (int i = 1; i <= maxTries; i++) { final String message = sendOrderedBroadcast(new Intent(ACTION_RECEIVER_READY), SECOND_IN_MS); @@ -781,13 +772,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation + "--receiver-foreground --receiver-registered-only"); } - protected void sendNotification(int notificationId, String notificationType) { - final Intent intent = new Intent(ACTION_SEND_NOTIFICATION); - intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId); - intent.putExtra(EXTRA_NOTIFICATION_TYPE, notificationType); - Log.d(TAG, "Sending notification broadcast (id=" + notificationId + ", type=" - + notificationType + ": " + intent); - mContext.sendBroadcast(intent); + protected void sendNotification(int notificationId, String notificationType) throws Exception { + Log.d(TAG, "Sending notification broadcast (id=" + notificationId + + ", type=" + notificationType); + mServiceClient.sendNotification(notificationId, notificationType); } protected String showToast() { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java new file mode 100644 index 0000000000..ff05d8c2fc --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.ConditionVariable; +import android.os.IBinder; +import android.os.RemoteException; + +import com.android.cts.net.hostside.IMyService; + +import java.io.FileDescriptor; + +public class MyServiceClient { + private static final int TIMEOUT_MS = 5000; + private static final String PACKAGE = MyServiceClient.class.getPackage().getName(); + private static final String APP2_PACKAGE = PACKAGE + ".app2"; + private static final String SERVICE_NAME = APP2_PACKAGE + ".MyService"; + + private Context mContext; + private ServiceConnection mServiceConnection; + private IMyService mService; + + public MyServiceClient(Context context) { + mContext = context; + } + + public void bind() { + if (mService != null) { + throw new IllegalStateException("Already bound"); + } + + final ConditionVariable cv = new ConditionVariable(); + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IMyService.Stub.asInterface(service); + cv.open(); + } + @Override + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + }; + + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(APP2_PACKAGE, SERVICE_NAME)); + // Needs to use BIND_ALLOW_OOM_MANAGEMENT and BIND_NOT_FOREGROUND so app2 does not run in + // the same process state as app + mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE + | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_FOREGROUND); + cv.block(TIMEOUT_MS); + if (mService == null) { + throw new IllegalStateException( + "Could not bind to MyService service after " + TIMEOUT_MS + "ms"); + } + } + + public void unbind() { + if (mService != null) { + mContext.unbindService(mServiceConnection); + } + } + + public void registerBroadcastReceiver() throws RemoteException { + mService.registerBroadcastReceiver(); + } + + public int getCounters(String receiverName, String action) throws RemoteException { + return mService.getCounters(receiverName, action); + } + + public String checkNetworkStatus() throws RemoteException { + return mService.checkNetworkStatus(); + } + + public String getRestrictBackgroundStatus() throws RemoteException { + return mService.getRestrictBackgroundStatus(); + } + + public void sendNotification(int notificationId, String notificationType) throws RemoteException { + mService.sendNotification(notificationId, notificationType); + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index e07c0f50d5..dc9a63036a 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -26,27 +26,13 @@ public final class Common { // AbstractRestrictBackgroundNetworkTestCase.java static final String MANIFEST_RECEIVER = "ManifestReceiver"; static final String DYNAMIC_RECEIVER = "DynamicReceiver"; - static final String ACTION_GET_COUNTERS = - "com.android.cts.net.hostside.app2.action.GET_COUNTERS"; - static final String ACTION_GET_RESTRICT_BACKGROUND_STATUS = - "com.android.cts.net.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS"; - static final String ACTION_CHECK_NETWORK = - "com.android.cts.net.hostside.app2.action.CHECK_NETWORK"; + static final String ACTION_RECEIVER_READY = "com.android.cts.net.hostside.app2.action.RECEIVER_READY"; static final String ACTION_FINISH_ACTIVITY = "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY"; - static final String ACTION_SEND_NOTIFICATION = - "com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION"; static final String ACTION_SHOW_TOAST = "com.android.cts.net.hostside.app2.action.SHOW_TOAST"; - static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION"; - static final String EXTRA_RECEIVER_NAME = - "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME"; - static final String EXTRA_NOTIFICATION_ID = - "com.android.cts.net.hostside.app2.extra.NOTIFICATION_ID"; - static final String EXTRA_NOTIFICATION_TYPE = - "com.android.cts.net.hostside.app2.extra.NOTIFICATION_TYPE"; static final String NOTIFICATION_TYPE_CONTENT = "CONTENT"; static final String NOTIFICATION_TYPE_DELETE = "DELETE"; diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index 733c3aa6a0..f59cba1252 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -18,16 +18,8 @@ package com.android.cts.net.hostside.app2; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; -import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK; -import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS; -import static com.android.cts.net.hostside.app2.Common.ACTION_GET_RESTRICT_BACKGROUND_STATUS; import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; -import static com.android.cts.net.hostside.app2.Common.ACTION_SEND_NOTIFICATION; import static com.android.cts.net.hostside.app2.Common.ACTION_SHOW_TOAST; -import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION; -import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_ID; -import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_TYPE; -import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME; import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION; import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE; @@ -56,14 +48,12 @@ import android.widget.Toast; import java.net.HttpURLConnection; import java.net.URL; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; /** * Receiver used to: *
      - *
    1. Stored received RESTRICT_BACKGROUND_CHANGED broadcasts in a shared preference. - *
    2. Returned the number of RESTRICT_BACKGROUND_CHANGED broadcasts in an ordered broadcast. + *
    3. Count number of {@code RESTRICT_BACKGROUND_CHANGED} broadcasts received. + *
    4. Show a toast. *
    */ public class MyBroadcastReceiver extends BroadcastReceiver { @@ -89,23 +79,11 @@ public class MyBroadcastReceiver extends BroadcastReceiver { case ACTION_RESTRICT_BACKGROUND_CHANGED: increaseCounter(context, action); break; - case ACTION_GET_COUNTERS: - setResultDataFromCounter(context, intent); - break; - case ACTION_GET_RESTRICT_BACKGROUND_STATUS: - getRestrictBackgroundStatus(context, intent); - break; - case ACTION_CHECK_NETWORK: - checkNetwork(context, intent); - break; case ACTION_RECEIVER_READY: final String message = mName + " is ready to rumble"; Log.d(TAG, message); setResultData(message); break; - case ACTION_SEND_NOTIFICATION: - sendNotification(context, intent); - break; case ACTION_SHOW_TOAST: showToast(context); break; @@ -114,14 +92,20 @@ public class MyBroadcastReceiver extends BroadcastReceiver { } } + @Override + public String toString() { + return "[MyBroadcastReceiver: mName=" + mName + "]"; + } + private void increaseCounter(Context context, String action) { - final SharedPreferences prefs = context.getSharedPreferences(mName, Context.MODE_PRIVATE); + final SharedPreferences prefs = context.getApplicationContext() + .getSharedPreferences(mName, Context.MODE_PRIVATE); final int value = prefs.getInt(action, 0) + 1; Log.d(TAG, "increaseCounter('" + action + "'): setting '" + mName + "' to " + value); prefs.edit().putInt(action, value).apply(); } - private int getCounter(Context context, String action, String receiverName) { + static int getCounter(Context context, String action, String receiverName) { final SharedPreferences prefs = context.getSharedPreferences(receiverName, Context.MODE_PRIVATE); final int value = prefs.getInt(action, 0); @@ -129,29 +113,14 @@ public class MyBroadcastReceiver extends BroadcastReceiver { return value; } - private void getRestrictBackgroundStatus(Context context, Intent intent) { + static String getRestrictBackgroundStatus(Context context) { final ConnectivityManager cm = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); final int apiStatus = cm.getRestrictBackgroundStatus(); Log.d(TAG, "getRestrictBackgroundStatus: returning " + apiStatus); - setResultData(Integer.toString(apiStatus)); + return String.valueOf(apiStatus); } - private void checkNetwork(final Context context, Intent intent) { - final ConnectivityManager cm = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - - String netStatus = null; - try { - netStatus = checkNetworkStatus(context, cm); - } catch (InterruptedException e) { - Log.e(TAG, "Timeout checking network status"); - } - Log.d(TAG, "checkNetwork(): returning " + netStatus); - setResultData(netStatus); - } - - private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s"; /** * Checks whether the network is available and return a string which can then be send as a @@ -182,71 +151,53 @@ public class MyBroadcastReceiver extends BroadcastReceiver { * * */ - private String checkNetworkStatus(final Context context, final ConnectivityManager cm) - throws InterruptedException { - final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); - new Thread(new Runnable() { - - @Override - public void run() { - // TODO: connect to a hostside server instead - final String address = "http://example.com"; - final NetworkInfo networkInfo = cm.getActiveNetworkInfo(); - Log.d(TAG, "Running checkNetworkStatus() on thread " - + Thread.currentThread().getName() + " for UID " + getUid(context) - + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address); - boolean checkStatus = false; - String checkDetails = "N/A"; - try { - final URL url = new URL(address); - final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setReadTimeout(NETWORK_TIMEOUT_MS); - conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2); - conn.setRequestMethod("GET"); - conn.setDoInput(true); - conn.connect(); - final int response = conn.getResponseCode(); - checkStatus = true; - checkDetails = "HTTP response for " + address + ": " + response; - } catch (Exception e) { - checkStatus = false; - checkDetails = "Exception getting " + address + ": " + e; - } - Log.d(TAG, checkDetails); - final String status = String.format(NETWORK_STATUS_TEMPLATE, - networkInfo.getState().name(), networkInfo.getDetailedState().name(), - Boolean.toString(checkStatus), checkDetails, networkInfo); - Log.d(TAG, "Offering " + status); - result.offer(status); - } - }, mName).start(); - return result.poll(NETWORK_TIMEOUT_MS * 2, TimeUnit.MILLISECONDS); - } - - private void setResultDataFromCounter(Context context, Intent intent) { - final String action = intent.getStringExtra(EXTRA_ACTION); - if (action == null) { - Log.e(TAG, "Missing extra '" + EXTRA_ACTION + "' on " + intent); - return; + // TODO: now that it uses Binder, it counl return a Bundle with the data parts instead... + static String checkNetworkStatus(Context context) { + final ConnectivityManager cm = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + // TODO: connect to a hostside server instead + final String address = "http://example.com"; + final NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + Log.d(TAG, "Running checkNetworkStatus() on thread " + + Thread.currentThread().getName() + " for UID " + getUid(context) + + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address); + boolean checkStatus = false; + String checkDetails = "N/A"; + try { + final URL url = new URL(address); + final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setReadTimeout(NETWORK_TIMEOUT_MS); + conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2); + conn.setRequestMethod("GET"); + conn.setDoInput(true); + conn.connect(); + final int response = conn.getResponseCode(); + checkStatus = true; + checkDetails = "HTTP response for " + address + ": " + response; + } catch (Exception e) { + checkStatus = false; + checkDetails = "Exception getting " + address + ": " + e; } - final String receiverName = intent.getStringExtra(EXTRA_RECEIVER_NAME); - if (receiverName == null) { - Log.e(TAG, "Missing extra '" + EXTRA_RECEIVER_NAME + "' on " + intent); - return; + Log.d(TAG, checkDetails); + final String state, detailedState; + if (networkInfo != null) { + state = networkInfo.getState().name(); + detailedState = networkInfo.getDetailedState().name(); + } else { + state = detailedState = "null"; } - final int counter = getCounter(context, action, receiverName); - setResultData(String.valueOf(counter)); + final String status = String.format(NETWORK_STATUS_TEMPLATE, state, detailedState, + Boolean.valueOf(checkStatus), checkDetails, networkInfo); + Log.d(TAG, "Offering " + status); + return status; } /** * Sends a system notification containing actions with pending intents to launch the app's * main activitiy or service. */ - private void sendNotification(Context context, Intent intent) { - final int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1); - final String notificationType = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE); - Log.d(TAG, "sendNotification: id=" + notificationId + ", type=" + notificationType - + ", intent=" + intent); + static void sendNotification(Context context, int notificationId, String notificationType ) { + Log.d(TAG, "sendNotification: id=" + notificationId + ", type=" + notificationType); final Intent serviceIntent = new Intent(context, MyService.class); final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, notificationId); diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java index e6454c7be0..9c19e50238 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java @@ -24,27 +24,74 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.os.IBinder; +import android.os.Looper; import android.util.Log; +import android.widget.Toast; + +import com.android.cts.net.hostside.IMyService; /** * Service used to dynamically register a broadcast receiver. */ public class MyService extends Service { + private MyBroadcastReceiver mReceiver; + + // TODO: move MyBroadcast static functions here - they were kept there to make git diff easier. + + private IMyService.Stub mBinder = + new IMyService.Stub() { + + @Override + public void registerBroadcastReceiver() { + if (mReceiver != null) { + Log.d(TAG, "receiver already registered: " + mReceiver); + return; + } + final Context context = getApplicationContext(); + mReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER); + context.registerReceiver(mReceiver, new IntentFilter(ACTION_RECEIVER_READY)); + context.registerReceiver(mReceiver, + new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED)); + Log.d(TAG, "receiver registered"); + } + + @Override + public int getCounters(String receiverName, String action) { + return MyBroadcastReceiver.getCounter(getApplicationContext(), action, receiverName); + } + + @Override + public String checkNetworkStatus() { + return MyBroadcastReceiver.checkNetworkStatus(getApplicationContext()); + } + + @Override + public String getRestrictBackgroundStatus() { + return MyBroadcastReceiver.getRestrictBackgroundStatus(getApplicationContext()); + } + + @Override + public void sendNotification(int notificationId, String notificationType) { + MyBroadcastReceiver + .sendNotification(getApplicationContext(), notificationId, notificationType); + } + }; + @Override public IBinder onBind(Intent intent) { - return null; + return mBinder; } @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "MyService.onStartCommand: " + intent); - final Context context = getApplicationContext(); - final MyBroadcastReceiver myReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER); - context.registerReceiver(myReceiver, new IntentFilter(ACTION_RECEIVER_READY)); - context.registerReceiver(myReceiver, new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED)); - Log.d(TAG, "receiver registered"); - return START_STICKY; + public void onDestroy() { + if (mReceiver != null) { + Log.d(TAG, "onDestroy(): unregistering " + mReceiver); + getApplicationContext().unregisterReceiver(mReceiver); + } + + super.onDestroy(); } } From 2ecad8d87dafed4ff5d671eff8bb811020b744df Mon Sep 17 00:00:00 2001 From: peter_li Date: Tue, 4 Oct 2016 13:36:03 +0800 Subject: [PATCH 0288/1415] =?UTF-8?q?[CTS]It=20should=20be=20more=20reason?= =?UTF-8?q?able=20to=20control=20battery=20saver=20function=20from=20setti?= =?UTF-8?q?ng=20DB=20instead=20of=20plugging/unplugging=20charger=20for=20?= =?UTF-8?q?=E2=80=9CCtsHostsideNetworkTests=E2=80=9D=20test=20case.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symptom: It should be more reasonable to control battery saver function from setting DB instead of plugging/unplugging charger for “CtsHostsideNetworkTests” test case. Root Cause: The test function “setBatterySaverMode” of “CtsHostsideNetworkTests” use command to set setting DB when trying to turn on battery saver. But while trying to turn off battery saver, it only use charger plug-in event. It should be more reasonable to turn off battery saver through similar DB setting as this function did at turning on. Solution: To control battery saver function from setting DB. Project: Note: Test done by RD: Futher testing need Q team's support: Bug: 31897608 Change-Id: Id70ba458e85f98393d7652bb4e79bd182172c60f --- .../net/hostside/AbstractRestrictBackgroundNetworkTestCase.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 9980327bbe..70fc51acfc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -610,6 +610,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation executeSilentShellCommand("cmd battery unplug"); executeSilentShellCommand("settings put global low_power 1"); } else { + executeSilentShellCommand("settings put global low_power 0"); turnBatteryOn(); } } From 22b355560e02135721fc5799338700145909f59a Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Wed, 19 Oct 2016 10:41:16 -0700 Subject: [PATCH 0289/1415] CtsNetTests: Add a test for b/25624963 Ensure that password is not output in toString() for an enterprise credential. Bug: 25624963 Test: Run this CTS test: run cts --module CtsNetTestCases --test android.net.wifi.cts.WifiEnterpriseConfigTest#testEnterpriseConfigDoesNotPrintPassword Change-Id: I84a62ae5d37aa7d397203f41362dadb8ceba1e62 --- .../net/wifi/cts/WifiEnterpriseConfigTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java index f3eb4e9587..a074f14c8d 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java @@ -532,4 +532,15 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { } return false; } + + public void testEnterpriseConfigDoesNotPrintPassword() { + WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); + final String identity = "IdentityIsOkayToBeDisplayedHere"; + final String password = "PasswordIsNotOkayToBeDisplayedHere"; + enterpriseConfig.setIdentity(identity); + enterpriseConfig.setPassword(password); + final String stringRepresentation = enterpriseConfig.toString(); + assertTrue(stringRepresentation.contains(identity)); + assertFalse(stringRepresentation.contains(password)); + } } From a84bb771d1f0c46f9505f31c2b18400f6ab9c352 Mon Sep 17 00:00:00 2001 From: Chris Manton Date: Fri, 14 Oct 2016 17:30:15 -0700 Subject: [PATCH 0290/1415] Include Wear device idle settings Certain tests interacting with device idle must set correctly both the normal and wear device idle setting space. Bug: 32183373 Test: Run on wear device and Nexus6P run cts --skip-device-info -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testDozeModeMetered_enabledButWhitelistedOnNotificationAction run cts --skip-device-info -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testDozeModeNonMetered_enabledButWhitelistedOnNotificationAction Change-Id: I6a53d29021a7d4a257b102a4d3bd5d2cc845c16f --- ...ractRestrictBackgroundNetworkTestCase.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index b4d7d9db78..cbd8feaa72 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -29,6 +29,7 @@ import android.app.Instrumentation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -99,6 +100,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private String mMeteredWifi; + private boolean mHasWatch; + private String mDeviceIdleConstantsSetting; @Override protected void setUp() throws Exception { @@ -110,7 +113,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); final int myUid = getUid(mContext.getPackageName()); - + mHasWatch = mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WATCH); + if (mHasWatch) { + mDeviceIdleConstantsSetting = "device_idle_constants_watch"; + } else { + mDeviceIdleConstantsSetting = "device_idle_constants"; + } Log.i(TAG, "Apps status on " + getName() + ":\n" + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -726,14 +735,14 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected void setPendingIntentWhitelistDuration(int durationMs) throws Exception { - final String command = String.format( - "settings put global device_idle_constants %s=%d", - "notification_whitelist_duration", durationMs); - executeSilentShellCommand(command); + executeSilentShellCommand(String.format( + "settings put global %s %s=%d", mDeviceIdleConstantsSetting, + "notification_whitelist_duration", durationMs)); } protected void resetDeviceIdleSettings() throws Exception { - executeShellCommand("settings delete global device_idle_constants"); + executeShellCommand(String.format("settings delete global %s", + mDeviceIdleConstantsSetting)); } protected void startForegroundService() throws Exception { From c6ce1d051ed57281923afb0c64d71ad0f8b0fe2a Mon Sep 17 00:00:00 2001 From: Chris Manton Date: Fri, 14 Oct 2016 17:30:15 -0700 Subject: [PATCH 0291/1415] Include Wear device idle settings Certain tests interacting with device idle must set correctly both the normal and wear device idle setting space. Bug: 32183373 Test: Run on wear device and Nexus6P run cts --skip-device-info -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testDozeModeMetered_enabledButWhitelistedOnNotificationAction run cts --skip-device-info -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testDozeModeNonMetered_enabledButWhitelistedOnNotificationAction Change-Id: I6a53d29021a7d4a257b102a4d3bd5d2cc845c16f (cherry picked from commit a84bb771d1f0c46f9505f31c2b18400f6ab9c352) --- ...ractRestrictBackgroundNetworkTestCase.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index b4d7d9db78..cbd8feaa72 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -29,6 +29,7 @@ import android.app.Instrumentation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -99,6 +100,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private String mMeteredWifi; + private boolean mHasWatch; + private String mDeviceIdleConstantsSetting; @Override protected void setUp() throws Exception { @@ -110,7 +113,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); final int myUid = getUid(mContext.getPackageName()); - + mHasWatch = mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WATCH); + if (mHasWatch) { + mDeviceIdleConstantsSetting = "device_idle_constants_watch"; + } else { + mDeviceIdleConstantsSetting = "device_idle_constants"; + } Log.i(TAG, "Apps status on " + getName() + ":\n" + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -726,14 +735,14 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected void setPendingIntentWhitelistDuration(int durationMs) throws Exception { - final String command = String.format( - "settings put global device_idle_constants %s=%d", - "notification_whitelist_duration", durationMs); - executeSilentShellCommand(command); + executeSilentShellCommand(String.format( + "settings put global %s %s=%d", mDeviceIdleConstantsSetting, + "notification_whitelist_duration", durationMs)); } protected void resetDeviceIdleSettings() throws Exception { - executeShellCommand("settings delete global device_idle_constants"); + executeShellCommand(String.format("settings delete global %s", + mDeviceIdleConstantsSetting)); } protected void startForegroundService() throws Exception { From f705bf695e8e6511940ab1a2fa42ef3ef010213f Mon Sep 17 00:00:00 2001 From: Julien Desprez Date: Fri, 11 Nov 2016 12:11:33 +0000 Subject: [PATCH 0292/1415] Build CTS out of TF source Test: make cts dist, run unit tests Bug: 32819381 Change-Id: I202c2a35e3745a372df8bec4903162d933ae04fb --- tests/cts/hostside/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/hostside/Android.mk b/tests/cts/hostside/Android.mk index ad97ecdc6b..96d735fdca 100644 --- a/tests/cts/hostside/Android.mk +++ b/tests/cts/hostside/Android.mk @@ -21,7 +21,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_MODULE := CtsHostsideNetworkTests -LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt +LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib From 2bc9c349db402768c05190189987620361d2f06f Mon Sep 17 00:00:00 2001 From: Aaron Holden Date: Tue, 22 Nov 2016 18:44:36 -0800 Subject: [PATCH 0293/1415] Nuke CTS Migration Library, extend CompatibilityBuildHelper bug: 21762834 Test: cts-tradefed run cts -m CtsAppSecurityHostTestCases Change-Id: I72296ca84c76e4af2de0249e4cdb57fed3065e07 --- tests/cts/hostside/Android.mk | 2 -- .../src/com/android/cts/net/HostsideNetworkTestCase.java | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/cts/hostside/Android.mk b/tests/cts/hostside/Android.mk index 96d735fdca..1c3f0536c4 100644 --- a/tests/cts/hostside/Android.mk +++ b/tests/cts/hostside/Android.mk @@ -23,8 +23,6 @@ LOCAL_MODULE := CtsHostsideNetworkTests LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed -LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib - LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork # Tag this module as a cts test artifact diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 6642512758..f3d7dbd4ff 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -16,7 +16,7 @@ package com.android.cts.net; -import com.android.cts.migration.MigrationHelper; +import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; import com.android.ddmlib.Log; import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; import com.android.ddmlib.testrunner.TestIdentifier; @@ -80,7 +80,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void installPackage(String apk) throws FileNotFoundException, DeviceNotAvailableException { - assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, apk), false)); + CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); + assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false)); } protected void uninstallPackage(String packageName, boolean shouldSucceed) From 68ec71d95415d03d289d2655ba3f66eb1610bd4b Mon Sep 17 00:00:00 2001 From: Bjoern Johansson Date: Wed, 7 Dec 2016 14:42:38 -0800 Subject: [PATCH 0294/1415] Don't require WiFi in CtsHostsideNetworkTests WiFi is not a CDD requirement so these tests should not fail when the device under test does not have WiFi. The behavior is changed so that if there is WiFi then both metered and unmetered tests will run. If there is no WiFi and the current connection is metered then only metered tests will run. If there is no WiFi and the current connection is not metered then only unmetered tests will run. Test: Successfully ran CTS test on both emulator and shamu. BUG: 31648368 Change-Id: Ic643d2490e0a7e69b57a44599f1a4c57c67da873 --- .../net/hostside/AbstractAppIdleTestCase.java | 9 -- .../AbstractBatterySaverModeTestCase.java | 1 - .../hostside/AbstractDozeModeTestCase.java | 1 - ...ractRestrictBackgroundNetworkTestCase.java | 82 ++++++++++++++----- .../cts/net/hostside/AppIdleMeteredTest.java | 4 +- .../net/hostside/AppIdleNonMeteredTest.java | 5 +- .../hostside/BatterySaverModeMeteredTest.java | 4 +- .../BatterySaverModeNonMeteredTest.java | 4 +- .../cts/net/hostside/DataSaverModeTest.java | 6 +- .../cts/net/hostside/DozeModeMeteredTest.java | 4 +- .../net/hostside/DozeModeNonMeteredTest.java | 4 +- .../cts/net/hostside/MixedModesTest.java | 8 +- .../cts/net/HostsideNetworkTestCase.java | 2 - 13 files changed, 84 insertions(+), 50 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index ba56665fbc..fb773cbef2 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -30,7 +30,6 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork if (!isSupported()) return; // Set initial state. - setUpMeteredNetwork(); removePowerSaveModeWhitelist(TEST_APP2_PKG); setAppIdle(false); turnBatteryOff(); @@ -62,14 +61,6 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork return supported; } - /** - * Sets the initial (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - /** * Resets the (non) metered network state. * diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index c1c91dac80..ed738a6af8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -30,7 +30,6 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou if (!isSupported()) return; // Set initial state. - setUpMeteredNetwork(); removePowerSaveModeWhitelist(TEST_APP2_PKG); setBatterySaverMode(false); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index b89cf93b99..cc05b045ae 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -31,7 +31,6 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor if (!isSupported()) return; // Set initial state. - setUpMeteredNetwork(); removePowerSaveModeWhitelist(TEST_APP2_PKG); setDozeMode(false); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 70fc51acfc..46d243ee77 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -85,6 +85,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private String mMeteredWifi; + private boolean mSupported; @Override protected void setUp() throws Exception { @@ -96,6 +97,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); final int myUid = getUid(mContext.getPackageName()); + mSupported = setUpActiveNetworkMeteringState(); Log.i(TAG, "Apps status on " + getName() + ":\n" + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" @@ -191,7 +193,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation /** * Whether this device suport this type of test. * - *

    Should be overridden when necessary, and explicitly used before each test. Example: + *

    Should be overridden when necessary (but always calling + * {@code super.isSupported()} first), and explicitly used before each test + * Example: * *

    
          * public void testSomething() {
    @@ -201,7 +205,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
          * @return {@code true} by default.
          */
         protected boolean isSupported() throws Exception {
    -        return true;
    +        return mSupported;
         }
     
         /**
    @@ -399,15 +403,61 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
         }
     
         /**
    -     * Puts the device in a state where the active network is metered, or fail if it can't achieve
    -     * that state.
    +     * Sets the initial metering state for the active network.
    +     *
    +     * 

    It's called on setup and by default does nothing - it's up to the + * subclasses to override. + * + * @return whether the tests in the subclass are supported on this device. */ - protected void setMeteredNetwork() throws Exception { + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return true; + } + + /** + * Makes sure the active network is not metered. + * + *

    If the device does not supoprt un-metered networks (for example if it + * only has cellular data but not wi-fi), it should return {@code false}; + * otherwise, it should return {@code true} (or fail if the un-metered + * network could not be set). + * + * @return {@code true} if the network is now unmetered. + */ + protected boolean setUnmeteredNetwork() throws Exception { + final NetworkInfo info = mCm.getActiveNetworkInfo(); + assertNotNull("Could not get active network", info); + if (!mCm.isActiveNetworkMetered()) { + Log.d(TAG, "Active network is not metered: " + info); + } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { + Log.i(TAG, "Setting active WI-FI network as not metered: " + info ); + setWifiMeteredStatus(false); + } else { + Log.d(TAG, "Active network cannot be set to un-metered: " + info); + return false; + } + assertActiveNetworkMetered(false); // Sanity check. + return true; + } + + /** + * Enables metering on the active network if supported. + * + *

    If the device does not support metered networks it should return + * {@code false}; otherwise, it should return {@code true} (or fail if the + * metered network could not be set). + * + * @return {@code true} if the network is now metered. + */ + protected boolean setMeteredNetwork() throws Exception { final NetworkInfo info = mCm.getActiveNetworkInfo(); final boolean metered = mCm.isActiveNetworkMetered(); if (metered) { Log.d(TAG, "Active network already metered: " + info); - return; + return true; + } else if (info.getType() != ConnectivityManager.TYPE_WIFI) { + Log.w(TAG, "Active network does not support metering: " + info); + return false; } else { Log.w(TAG, "Active network not metered: " + info); } @@ -418,31 +468,21 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // Sanity check. assertWifiMeteredStatus(netId, true); assertActiveNetworkMetered(true); + return true; } /** - * Puts the device in a state where the active network is not metered, or fail if it can't - * achieve that state. - *

    It assumes the device has a valid WI-FI connection. + * Resets the device metering state to what it was before the test started. + * + *

    This reverts any metering changes made by {@code setMeteredNetwork}. */ protected void resetMeteredNetwork() throws Exception { if (mMeteredWifi != null) { Log.i(TAG, "resetMeteredNetwork(): SID '" + mMeteredWifi + "' was set as metered by test case; resetting it"); setWifiMeteredStatus(mMeteredWifi, false); - } else { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - assertNotNull("Could not get active network", info); - if (!mCm.isActiveNetworkMetered()) { - Log.d(TAG, "Active network is not metered: " + info); - } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { - Log.i(TAG, "Setting active WI-FI network as metered: " + info ); - setWifiMeteredStatus(false); - } else { - fail("Active network is not WI-FI hence cannot be set as non-metered: " + info); - } + assertActiveNetworkMetered(false); // Sanity check. } - assertActiveNetworkMetered(false); // Sanity check. } private void assertActiveNetworkMetered(boolean expected) throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java index e008c695bb..622d99361f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java @@ -19,8 +19,8 @@ package com.android.cts.net.hostside; public class AppIdleMeteredTest extends AbstractAppIdleTestCase { @Override - protected void setUpMeteredNetwork() throws Exception { - setMeteredNetwork(); + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setMeteredNetwork(); } @Override diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java index 633dc81c95..bde71f9100 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java @@ -17,9 +17,8 @@ package com.android.cts.net.hostside; public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase { - @Override - protected void setUpMeteredNetwork() throws Exception { - resetMeteredNetwork(); + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setUnmeteredNetwork(); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java index 3a88bbd1ad..3071cfe3f1 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java @@ -19,8 +19,8 @@ package com.android.cts.net.hostside; public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase { @Override - protected void setUpMeteredNetwork() throws Exception { - setMeteredNetwork(); + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setMeteredNetwork(); } @Override diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index 646c4b993a..6d3076fe0e 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -19,7 +19,7 @@ package com.android.cts.net.hostside; public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { @Override - protected void setUpMeteredNetwork() throws Exception { - resetMeteredNetwork(); + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setUnmeteredNetwork(); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 3e6bd3320a..ac35bd44b6 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -33,7 +33,6 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase if (!isSupported()) return; // Set initial state. - setMeteredNetwork(); setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); @@ -55,6 +54,11 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } } + @Override + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setMeteredNetwork(); + } + public void testGetRestrictBackgroundStatus_disabled() throws Exception { if (!isSupported()) return; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java index 656d274c52..e4189af587 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java @@ -19,8 +19,8 @@ package com.android.cts.net.hostside; public class DozeModeMeteredTest extends AbstractDozeModeTestCase { @Override - protected void setUpMeteredNetwork() throws Exception { - setMeteredNetwork(); + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setMeteredNetwork(); } @Override diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java index c76123822f..edbbb9e1ce 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java @@ -19,7 +19,7 @@ package com.android.cts.net.hostside; public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { @Override - protected void setUpMeteredNetwork() throws Exception { - resetMeteredNetwork(); + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setUnmeteredNetwork(); } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index af52eeece4..ec49eee384 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -68,7 +68,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); - setMeteredNetwork(); + if (!setMeteredNetwork()) { + Log.w(TAG, "testDataAndBatterySaverModes_meteredNetwork() skipped because " + + "device cannot use a metered network"); + return; + } try { setRestrictBackground(true); @@ -139,7 +143,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { return; } - if (mCm.isActiveNetworkMetered()) { + if (!setUnmeteredNetwork()) { Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network" + " is metered"); return; diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 6642512758..e96537c308 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -65,8 +65,6 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec assertNotNull(mAbi); assertNotNull(mCtsBuild); - assertTrue("wi-fi not enabled", getDevice().isWifiEnabled()); - uninstallPackage(TEST_PKG, false); installPackage(TEST_APK); } From 37698cb72bb280dd619f71a7312686a8de26081d Mon Sep 17 00:00:00 2001 From: Aaron Holden Date: Wed, 7 Dec 2016 18:52:10 -0800 Subject: [PATCH 0295/1415] Move libs/deviceutil to device-side/util Test: build cts, run unit tests bug:21762834 Change-Id: Ifd164ced7f040e312e3553f27adf59a648f463ab --- tests/cts/hostside/app/Android.mk | 2 +- .../hostside/AbstractRestrictBackgroundNetworkTestCase.java | 2 +- tests/cts/net/Android.mk | 2 +- .../net/src/android/net/http/cts/HttpResponseCacheTest.java | 3 ++- tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index 9519ec5242..1c1a798fab 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -20,7 +20,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current -LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator \ +LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \ CtsHostsideNetworkTestsAidl LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 5eefcb2ef3..014d7ae6e2 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -16,11 +16,11 @@ package com.android.cts.net.hostside; -import static android.cts.util.SystemUtil.runShellCommand; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index c553a9bb2e..4a776409c7 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -34,7 +34,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support ctsdeviceutil \ +LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support compatibility-device-util \ ctstestrunner ctstestserver mockwebserver # uncomment when b/13249961 is fixed diff --git a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java index 7987a50eb9..198f973dfb 100644 --- a/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java +++ b/tests/cts/net/src/android/net/http/cts/HttpResponseCacheTest.java @@ -21,9 +21,10 @@ import com.google.mockwebserver.MockWebServer; import junit.framework.TestCase; -import android.cts.util.FileUtils; import android.net.http.HttpResponseCache; +import com.android.compatibility.common.util.FileUtils; + import java.io.File; import java.io.InputStream; import java.net.CacheRequest; diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 696d215649..5983cb72c2 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -21,7 +21,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.cts.util.PollingCheck; import android.net.wifi.SupplicantState; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -29,6 +28,8 @@ import android.net.wifi.WifiManager.WifiLock; import android.net.wifi.WifiSsid; import android.test.AndroidTestCase; +import com.android.compatibility.common.util.PollingCheck; + import java.util.concurrent.Callable; public class WifiInfoTest extends AndroidTestCase { From d9e98a6688a1f80c61ae0bca3c8bc05150b505c7 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Wed, 4 Jan 2017 10:37:34 +0000 Subject: [PATCH 0296/1415] Add more assertions related to LocalServerSocket.accept() The isConnected() / isBound() behavior is new, the behavior when bind() / connect() is called is not. See related frameworks/base changes. Test: Tests run under vogar. Bug: https://code.google.com/p/android/issues/detail?id=35942 Change-Id: I8577212270f3b3e76ea015914eebddc0fe4a6afa --- .../src/android/net/cts/LocalServerSocketTest.java | 3 +++ .../net/src/android/net/cts/LocalSocketTest.java | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java index 103d1da2d6..7c5a1b353d 100644 --- a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -38,6 +38,9 @@ public class LocalServerSocketTest extends TestCase { clientSocket.connect(new LocalSocketAddress(address)); LocalSocket serverSocket = localServerSocket.accept(); + assertTrue(serverSocket.isConnected()); + assertTrue(serverSocket.isBound()); + // send data from client to server OutputStream clientOutStream = clientSocket.getOutputStream(); clientOutStream.write(12); diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 0ff4a3080b..8029eb4d67 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -50,7 +50,20 @@ public class LocalSocketTest extends TestCase { assertFalse(clientSocket.isConnected()); clientSocket.connect(locSockAddr); assertTrue(clientSocket.isConnected()); + LocalSocket serverSocket = localServerSocket.accept(); + assertTrue(serverSocket.isConnected()); + assertTrue(serverSocket.isBound()); + try { + serverSocket.bind(localServerSocket.getLocalSocketAddress()); + fail("Cannot bind a LocalSocket from accept()"); + } catch (IOException expected) { + } + try { + serverSocket.connect(locSockAddr); + fail("Cannot connect a LocalSocket from accept()"); + } catch (IOException expected) { + } Credentials credent = clientSocket.getPeerCredentials(); assertTrue(0 != credent.getPid()); From a3577f20f2a2efb1fc015bad0145ee935276d305 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Fri, 6 Jan 2017 14:05:49 +0000 Subject: [PATCH 0297/1415] Add test for LocalSockets created from a FileDescriptor Adding a test to catch future regressions with this code path. Bug: 34095140 Test: vogar --mode app_process tests/tests/net/src/android/net/cts/LocalSocketTest.java Change-Id: I648ed87d4b9e7fa25787c150f08351c6faf55496 --- .../src/android/net/cts/LocalSocketTest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java index 8029eb4d67..6e61705b92 100644 --- a/tests/cts/net/src/android/net/cts/LocalSocketTest.java +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -287,6 +287,42 @@ public class LocalSocketTest extends TestCase { } } + // http://b/34095140 + public void testLocalSocketCreatedFromFileDescriptor() throws Exception { + String address = ADDRESS_PREFIX + "_testLocalSocketCreatedFromFileDescriptor"; + + // Establish connection between a local client and server to get a valid client socket file + // descriptor. + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + // Extract the client FileDescriptor we can use. + FileDescriptor fileDescriptor = socketPair.clientSocket.getFileDescriptor(); + assertTrue(fileDescriptor.valid()); + + // Create the LocalSocket we want to test. + LocalSocket clientSocketCreatedFromFileDescriptor = + LocalSocket.createConnectedLocalSocket(fileDescriptor); + assertTrue(clientSocketCreatedFromFileDescriptor.isConnected()); + assertTrue(clientSocketCreatedFromFileDescriptor.isBound()); + + // Test the LocalSocket can be used for communication. + LocalSocket serverSocket = socketPair.serverSocket.accept(); + OutputStream clientOutputStream = + clientSocketCreatedFromFileDescriptor.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + + clientOutputStream.write(12); + assertEquals(12, serverInputStream.read()); + + // Closing clientSocketCreatedFromFileDescriptor does not close the file descriptor. + clientSocketCreatedFromFileDescriptor.close(); + assertTrue(fileDescriptor.valid()); + + // .. while closing the LocalSocket that owned the file descriptor does. + socketPair.clientSocket.close(); + assertFalse(fileDescriptor.valid()); + } + } + public void testFlush() throws Exception { String address = ADDRESS_PREFIX + "_testFlush"; From 55e97317e98829706ff77aaac8a4e4908a8b30e2 Mon Sep 17 00:00:00 2001 From: Glen Kuhne Date: Tue, 10 Jan 2017 14:00:20 -0800 Subject: [PATCH 0298/1415] CTS: WifiManager.addNetwork with HttpProxy Added CTS tests verifying, that adding a WifiConfiguration containing an httpProxy will: -Succeed if caller is DeviceOwner -Fail if caller is not DeviceOwner Test: Added two CTS tests Bug: 14669153 Change-Id: I2c81492dba5052117a03a2aa7b3cc8ffb5d52d5f --- .../android/net/wifi/cts/WifiManagerTest.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 897e5cfe8e..dcedb18605 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.location.LocationManager; import android.net.NetworkInfo; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; @@ -35,6 +34,8 @@ import android.provider.Settings; import android.test.AndroidTestCase; import android.util.Log; +import com.android.compatibility.common.util.WifiConfigCreator; + import java.net.HttpURLConnection; import java.net.URL; import java.util.HashSet; @@ -68,6 +69,8 @@ public class WifiManagerTest extends AndroidTestCase { private static final String TAG = "WifiManagerTest"; private static final String SSID1 = "\"WifiManagerTest\""; private static final String SSID2 = "\"WifiManagerTestModified\""; + private static final String PROXY_TEST_SSID = "SomeProxyAp"; + private static final String ADD_NETWORK_EXCEPTION_SUBSTR = "addNetwork"; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; private static final int DURATION = 10000; @@ -75,6 +78,8 @@ public class WifiManagerTest extends AndroidTestCase { private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; private static final int WIFI_SCAN_TEST_ITERATIONS = 5; + private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; + private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -405,6 +410,31 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Verifies that addNetwork() fails for WifiConfigurations containing a non-null http proxy when + * the caller doesn't have OVERRIDE_WIFI_CONFIG permission, DeviceOwner or ProfileOwner device + * management policies + */ + public void testSetHttpProxy_PermissionFail() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + WifiConfigCreator configCreator = new WifiConfigCreator(getContext()); + boolean exceptionThrown = false; + try { + configCreator.addHttpProxyNetworkVerifyAndRemove( + PROXY_TEST_SSID, TEST_PAC_URL); + } catch (IllegalStateException e) { + // addHttpProxyNetworkVerifyAndRemove throws three IllegalStateException, + // expect it to throw for the addNetwork operation + if (e.getMessage().contains(ADD_NETWORK_EXCEPTION_SUBSTR)) { + exceptionThrown = true; + } + } + assertTrue(exceptionThrown); + } + private Set getEnabledNetworks(List configuredNetworks) { Set ssids = new HashSet(); for (WifiConfiguration wifiConfig : configuredNetworks) { From 1b93dea624b8f6067a4216646853826162719fe2 Mon Sep 17 00:00:00 2001 From: Glen Kuhne Date: Tue, 10 Jan 2017 14:00:20 -0800 Subject: [PATCH 0299/1415] CTS: WifiManager.addNetwork with HttpProxy Added CTS tests verifying, that adding a WifiConfiguration containing an httpProxy will: -Succeed if caller is DeviceOwner -Fail if caller is not DeviceOwner Test: Added two CTS tests Bug: 14669153 Change-Id: I2c81492dba5052117a03a2aa7b3cc8ffb5d52d5f Merged-In: I2c81492dba5052117a03a2aa7b3cc8ffb5d52d5f --- .../android/net/wifi/cts/WifiManagerTest.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 897e5cfe8e..dcedb18605 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.location.LocationManager; import android.net.NetworkInfo; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; @@ -35,6 +34,8 @@ import android.provider.Settings; import android.test.AndroidTestCase; import android.util.Log; +import com.android.compatibility.common.util.WifiConfigCreator; + import java.net.HttpURLConnection; import java.net.URL; import java.util.HashSet; @@ -68,6 +69,8 @@ public class WifiManagerTest extends AndroidTestCase { private static final String TAG = "WifiManagerTest"; private static final String SSID1 = "\"WifiManagerTest\""; private static final String SSID2 = "\"WifiManagerTestModified\""; + private static final String PROXY_TEST_SSID = "SomeProxyAp"; + private static final String ADD_NETWORK_EXCEPTION_SUBSTR = "addNetwork"; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; private static final int DURATION = 10000; @@ -75,6 +78,8 @@ public class WifiManagerTest extends AndroidTestCase { private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; private static final int WIFI_SCAN_TEST_ITERATIONS = 5; + private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; + private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -405,6 +410,31 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Verifies that addNetwork() fails for WifiConfigurations containing a non-null http proxy when + * the caller doesn't have OVERRIDE_WIFI_CONFIG permission, DeviceOwner or ProfileOwner device + * management policies + */ + public void testSetHttpProxy_PermissionFail() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + WifiConfigCreator configCreator = new WifiConfigCreator(getContext()); + boolean exceptionThrown = false; + try { + configCreator.addHttpProxyNetworkVerifyAndRemove( + PROXY_TEST_SSID, TEST_PAC_URL); + } catch (IllegalStateException e) { + // addHttpProxyNetworkVerifyAndRemove throws three IllegalStateException, + // expect it to throw for the addNetwork operation + if (e.getMessage().contains(ADD_NETWORK_EXCEPTION_SUBSTR)) { + exceptionThrown = true; + } + } + assertTrue(exceptionThrown); + } + private Set getEnabledNetworks(List configuredNetworks) { Set ssids = new HashSet(); for (WifiConfiguration wifiConfig : configuredNetworks) { From 2fa6e7ce432764b477683b78f8a949509a975527 Mon Sep 17 00:00:00 2001 From: bohu Date: Wed, 16 Nov 2016 17:22:47 -0800 Subject: [PATCH 0300/1415] CTS: skip wifi related net test if no such feature When a device does not have wifi feature, we should skip wifi related net tests. BUG: 31806034 Change-Id: I9867342c47499efc855a50a67a04177fa94e83e5 --- .../src/android/net/cts/ConnectivityManagerTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index b8478d246b..185ebfa0fc 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -387,6 +387,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { * Tests reporting of connectivity changed. */ public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() { + if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { + Log.i(TAG, "testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent cannot execute unless device supports WiFi"); + return; + } ConnectivityReceiver.prepare(); toggleWifi(); @@ -400,6 +404,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { } public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() { + if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { + Log.i(TAG, "testConnectivityChanged_whenRegistered_shouldReceiveIntent cannot execute unless device supports WiFi"); + return; + } ConnectivityReceiver.prepare(); ConnectivityReceiver receiver = new ConnectivityReceiver(); IntentFilter filter = new IntentFilter(); @@ -416,6 +424,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent() throws InterruptedException { + if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { + Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot execute unless device supports WiFi"); + return; + } Intent startIntent = new Intent(); startIntent.setComponent(new ComponentName("android.net.cts.appForApi23", "android.net.cts.appForApi23.ConnectivityListeningActivity")); From 038b6a4374f6db8bd99ba3be1d38a67a95d9eabc Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Tue, 10 Jan 2017 12:08:43 +0000 Subject: [PATCH 0301/1415] Prepare for removal of legacy-test from default targets In preparation for removing junit classes from the Android API the legacy-test target will be removed from the TARGET_DEFAULT_JAVA_LIBRARIES. This change adds explicit dependencies on junit and/or legacy-android-test to ensure that modules will compile properly once it is removed. Bug: 30188076 Test: make checkbuild Change-Id: I0f34fe97154240e8f8eef6816df1c794da60351e --- tests/cts/net/Android.mk | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 4a776409c7..98cde9b874 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -34,8 +34,14 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support compatibility-device-util \ - ctstestrunner ctstestserver mockwebserver +LOCAL_STATIC_JAVA_LIBRARIES := \ + core-tests-support \ + compatibility-device-util \ + ctstestrunner \ + ctstestserver \ + mockwebserver \ + junit \ + legacy-android-test # uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current From d872302cdb008868800798908151e0ae26c67574 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Tue, 10 Jan 2017 12:08:43 +0000 Subject: [PATCH 0302/1415] Prepare for removal of legacy-test from default targets In preparation for removing junit classes from the Android API the legacy-test target will be removed from the TARGET_DEFAULT_JAVA_LIBRARIES. This change adds explicit dependencies on junit and/or legacy-android-test to ensure that modules will compile properly once it is removed. Bug: 30188076 Test: make checkbuild Merged-In: I0f34fe97154240e8f8eef6816df1c794da60351e Change-Id: I7e3b028321c42b7427d79365eb3f51ddf896f930 --- tests/cts/net/Android.mk | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index c553a9bb2e..7d2b0bac99 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -34,8 +34,14 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support ctsdeviceutil \ - ctstestrunner ctstestserver mockwebserver +LOCAL_STATIC_JAVA_LIBRARIES := \ + core-tests-support \ + ctsdeviceutil \ + ctstestrunner \ + ctstestserver \ + mockwebserver \ + junit \ + legacy-android-test # uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current From 32599fd50c32c1c0dbc44625725304cf3e5ab634 Mon Sep 17 00:00:00 2001 From: George Burgess IV Date: Wed, 25 Jan 2017 11:15:52 -0800 Subject: [PATCH 0303/1415] Replace strlen("foo") with sizeof("foo") - 1. We have an upcoming change to Bionic that no longer allows us to treat strlen("foo") as a constant expression, which causes this bit of code to no longer compile. So, we need to either use __builtin_strlen("foo") or sizeof("foo") - 1 instead. (Note that the *optimizer* can still turn it into a constant, but optimization happens after we figure out if something is actually a constant expression or not.) sizeof("foo") is used elsewhere in this file, so I just went with that. Bug: 32073964 Test: Now builds. Change-Id: I2797ee75fd114e237de8e97c50549763c88f73f4 --- tests/cts/net/jni/NativeMultinetworkJni.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index 6990efa452..91565043ec 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -88,7 +88,9 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetsocknetwork( return rval == 0 ? 0 : -saved_errno; } -static const int kSockaddrStrLen = INET6_ADDRSTRLEN + strlen("[]:65535"); +// Use sizeof("x") - 1 because we need a compile-time constant, and strlen("x") +// isn't guaranteed to fold to a constant. +static const int kSockaddrStrLen = INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; void sockaddr_ntop(const struct sockaddr *sa, socklen_t salen, char *dst, const size_t size) { char addrstr[INET6_ADDRSTRLEN]; From 446ca6fd2a6ec2872221491b6f02de09bdaa0096 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Fri, 27 Jan 2017 10:15:23 -0800 Subject: [PATCH 0304/1415] WifiManagerTest: |disableOthers| flag change Change the CTS test to reflect the change in behaviour of the |disableOthers| flag in WifiManager.enableNetwork(). This will now just be used as an indication to trigger connection to the specified network instead of disabling all other configured networks. Bug: 34765254 Test: Compiles Change-Id: I97a5a84bb861e289d966552cea7f36d7dd4fd090 --- .../net/src/android/net/wifi/cts/WifiManagerTest.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index dcedb18605..4185189f50 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -218,16 +218,6 @@ public class WifiManagerTest extends AndroidTestCase { return -1; } - private void assertDisableOthers(WifiConfiguration wifiConfiguration, boolean disableOthers) { - for (WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { - if ((!w.SSID.equals(wifiConfiguration.SSID)) && w.status != Status.CURRENT) { - if (disableOthers) { - assertEquals(Status.DISABLED, w.status); - } - } - } - } - /** * test point of wifiManager actions: * 1.reconnect @@ -383,7 +373,6 @@ public class WifiManagerTest extends AndroidTestCase { boolean disableOthers = true; assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertDisableOthers(wifiConfiguration, disableOthers); assertEquals(Status.ENABLED, wifiConfiguration.status); assertTrue(mWifiManager.disableNetwork(netId)); From 9f295aaa43114cc5ea4e18cde4200363806f30e4 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Fri, 27 Jan 2017 11:48:29 -0800 Subject: [PATCH 0305/1415] Add CTS test for client certificate chains Add tests to excercise new WifiEnterpriseConfig methods, including setClientKeyEntryWithCertificateChain, and the new getters related to it. Bug: 34688653 Test: This is a test Change-Id: I183166f5864c5ec77eb8590e2e0f521bbc7a39e7 --- .../wifi/cts/WifiEnterpriseConfigTest.java | 268 ++++++++++++++++++ 1 file changed, 268 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java index a074f14c8d..d3235da369 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java @@ -26,8 +26,11 @@ import android.net.wifi.WifiManager; import android.test.AndroidTestCase; import java.io.ByteArrayInputStream; +import java.security.KeyFactory; +import java.security.PrivateKey; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; public class WifiEnterpriseConfigTest extends AndroidTestCase { private WifiManager mWifiManager; @@ -432,6 +435,246 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { (byte) 0x9e, (byte) 0x34, (byte) 0x73 }; + /** + * Client certificate generated from above and converted with: + * + * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] FAKE_EC_3 = { + (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xdf, (byte) 0x30, (byte) 0x82, + (byte) 0x01, (byte) 0xc7, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, + (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05, + (byte) 0x00, (byte) 0x30, (byte) 0x64, (byte) 0x31, (byte) 0x0b, (byte) 0x30, + (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, + (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x08, (byte) 0x0c, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31, + (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x07, (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f, + (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, + (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, + (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06, (byte) 0x47, (byte) 0x6f, + (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x31, (byte) 0x10, + (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, + (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x0d, + (byte) 0x30, (byte) 0x0b, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x03, (byte) 0x0c, (byte) 0x04, (byte) 0x54, (byte) 0x45, (byte) 0x53, + (byte) 0x54, (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, + (byte) 0x37, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x37, (byte) 0x31, + (byte) 0x37, (byte) 0x35, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x5a, + (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x37, (byte) 0x30, (byte) 0x31, + (byte) 0x32, (byte) 0x35, (byte) 0x31, (byte) 0x37, (byte) 0x35, (byte) 0x38, + (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x50, (byte) 0x31, + (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, + (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x02, (byte) 0x43, + (byte) 0x41, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06, + (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, + (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, + (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, + (byte) 0x31, (byte) 0x11, (byte) 0x30, (byte) 0x0f, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x08, (byte) 0x54, + (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2d, (byte) 0x55, (byte) 0x53, + (byte) 0x52, (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, + (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, + (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, + (byte) 0x03, (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0x4a, (byte) 0xb8, + (byte) 0x60, (byte) 0x17, (byte) 0x40, (byte) 0x91, (byte) 0x30, (byte) 0xf7, + (byte) 0xdf, (byte) 0x36, (byte) 0x83, (byte) 0x31, (byte) 0xb5, (byte) 0x3a, + (byte) 0xf4, (byte) 0xd4, (byte) 0xa1, (byte) 0xce, (byte) 0xd5, (byte) 0x54, + (byte) 0x97, (byte) 0x93, (byte) 0x7e, (byte) 0x7b, (byte) 0x08, (byte) 0x63, + (byte) 0x37, (byte) 0x62, (byte) 0xf1, (byte) 0x4e, (byte) 0x6a, (byte) 0x2e, + (byte) 0x35, (byte) 0x4e, (byte) 0x9f, (byte) 0x48, (byte) 0xcd, (byte) 0x09, + (byte) 0x17, (byte) 0xb3, (byte) 0xc1, (byte) 0x58, (byte) 0x02, (byte) 0x49, + (byte) 0x7b, (byte) 0x4c, (byte) 0xf7, (byte) 0x9b, (byte) 0xbb, (byte) 0x1b, + (byte) 0x2b, (byte) 0x9c, (byte) 0xe9, (byte) 0x36, (byte) 0xc4, (byte) 0x00, + (byte) 0x81, (byte) 0x2c, (byte) 0x28, (byte) 0xd9, (byte) 0x6b, (byte) 0xad, + (byte) 0xe3, (byte) 0xe8, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, + (byte) 0x13, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, + (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, + (byte) 0x01, (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, + (byte) 0x04, (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, + (byte) 0x65, (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, + (byte) 0x47, (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, + (byte) 0x74, (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, + (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, + (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, + (byte) 0x04, (byte) 0x14, (byte) 0xef, (byte) 0xf0, (byte) 0x15, (byte) 0xd7, + (byte) 0xc9, (byte) 0x3e, (byte) 0x9a, (byte) 0x73, (byte) 0xfa, (byte) 0x38, + (byte) 0xc5, (byte) 0x81, (byte) 0x84, (byte) 0x74, (byte) 0xd3, (byte) 0x83, + (byte) 0x74, (byte) 0x26, (byte) 0xf1, (byte) 0x0b, (byte) 0x30, (byte) 0x1f, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, + (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x38, + (byte) 0x6a, (byte) 0x9b, (byte) 0xf8, (byte) 0x3c, (byte) 0x0d, (byte) 0x54, + (byte) 0x9f, (byte) 0xdf, (byte) 0xf8, (byte) 0x53, (byte) 0x32, (byte) 0xa8, + (byte) 0xf7, (byte) 0x09, (byte) 0x15, (byte) 0x08, (byte) 0x76, (byte) 0xab, + (byte) 0x8d, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, + (byte) 0x01, (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, + (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0xa6, (byte) 0x6c, (byte) 0x18, + (byte) 0xa9, (byte) 0x67, (byte) 0x16, (byte) 0x6a, (byte) 0x9e, (byte) 0x23, + (byte) 0xb3, (byte) 0x2a, (byte) 0xb8, (byte) 0x16, (byte) 0x7b, (byte) 0xb4, + (byte) 0xc8, (byte) 0xbc, (byte) 0x51, (byte) 0xe0, (byte) 0x6f, (byte) 0x05, + (byte) 0x66, (byte) 0xa1, (byte) 0x6f, (byte) 0x96, (byte) 0xde, (byte) 0x5b, + (byte) 0x41, (byte) 0x60, (byte) 0xe5, (byte) 0x29, (byte) 0x99, (byte) 0x12, + (byte) 0xfc, (byte) 0xa9, (byte) 0x91, (byte) 0x23, (byte) 0xb7, (byte) 0x9e, + (byte) 0x00, (byte) 0x5f, (byte) 0x93, (byte) 0xd4, (byte) 0xf7, (byte) 0x27, + (byte) 0x29, (byte) 0x77, (byte) 0xfb, (byte) 0x53, (byte) 0x09, (byte) 0xdc, + (byte) 0xe9, (byte) 0xd0, (byte) 0x5c, (byte) 0x92, (byte) 0x6d, (byte) 0xb7, + (byte) 0xcf, (byte) 0x04, (byte) 0xab, (byte) 0xf1, (byte) 0x39, (byte) 0xb9, + (byte) 0x49, (byte) 0x23, (byte) 0x7c, (byte) 0x0f, (byte) 0x15, (byte) 0x27, + (byte) 0xcd, (byte) 0x65, (byte) 0x3c, (byte) 0x6b, (byte) 0x91, (byte) 0x42, + (byte) 0x5a, (byte) 0xfe, (byte) 0xbe, (byte) 0xb8, (byte) 0xa2, (byte) 0xfd, + (byte) 0x67, (byte) 0x43, (byte) 0x4b, (byte) 0xc9, (byte) 0x28, (byte) 0x65, + (byte) 0x1b, (byte) 0x82, (byte) 0x5b, (byte) 0x25, (byte) 0x20, (byte) 0x9b, + (byte) 0xea, (byte) 0x99, (byte) 0xbb, (byte) 0x66, (byte) 0xc1, (byte) 0x8e, + (byte) 0x46, (byte) 0x0b, (byte) 0x4e, (byte) 0x06, (byte) 0xdd, (byte) 0x50, + (byte) 0x51, (byte) 0x64, (byte) 0xe8, (byte) 0x83, (byte) 0x99, (byte) 0x8e, + (byte) 0x53, (byte) 0xe9, (byte) 0x48, (byte) 0x47, (byte) 0x0e, (byte) 0x08, + (byte) 0x5e, (byte) 0x0d, (byte) 0x4a, (byte) 0x54, (byte) 0x17, (byte) 0xc1, + (byte) 0xf8, (byte) 0xcf, (byte) 0xba, (byte) 0x5c, (byte) 0x38, (byte) 0x70, + (byte) 0x33, (byte) 0x31, (byte) 0x22, (byte) 0x03, (byte) 0x6f, (byte) 0x54, + (byte) 0x3c, (byte) 0x41, (byte) 0xf0, (byte) 0x89, (byte) 0x85, (byte) 0xbc, + (byte) 0x77, (byte) 0x3c, (byte) 0xe8, (byte) 0xec, (byte) 0xb4, (byte) 0x35, + (byte) 0x7a, (byte) 0xcc, (byte) 0x8c, (byte) 0x5f, (byte) 0xa1, (byte) 0xed, + (byte) 0xa6, (byte) 0x28, (byte) 0x14, (byte) 0xc7, (byte) 0x8a, (byte) 0xef, + (byte) 0x56, (byte) 0x26, (byte) 0x35, (byte) 0x46, (byte) 0xab, (byte) 0xb0, + (byte) 0x97, (byte) 0xd2, (byte) 0xbd, (byte) 0xa9, (byte) 0x6a, (byte) 0xe4, + (byte) 0x3e, (byte) 0x87, (byte) 0xfb, (byte) 0xe1, (byte) 0x09, (byte) 0x8d, + (byte) 0x33, (byte) 0x12, (byte) 0xcf, (byte) 0xf0, (byte) 0xc0, (byte) 0xb8, + (byte) 0x9b, (byte) 0x9f, (byte) 0xb1, (byte) 0xcb, (byte) 0xac, (byte) 0x76, + (byte) 0xa8, (byte) 0x05, (byte) 0x6b, (byte) 0xcc, (byte) 0x41, (byte) 0xd2, + (byte) 0x26, (byte) 0x73, (byte) 0xfa, (byte) 0x69, (byte) 0xd3, (byte) 0x1f, + (byte) 0xa9, (byte) 0x0c, (byte) 0x6a, (byte) 0xd6, (byte) 0xc9, (byte) 0x35, + (byte) 0xc5, (byte) 0xad, (byte) 0xa1, (byte) 0x98, (byte) 0xc9, (byte) 0x78, + (byte) 0xa0, (byte) 0xe8, (byte) 0x02, (byte) 0x69, (byte) 0x80, (byte) 0x44, + (byte) 0xd9, (byte) 0xe6, (byte) 0xe5, (byte) 0x26, (byte) 0x4f, (byte) 0xcf, + (byte) 0x38, (byte) 0xcb, (byte) 0x55, (byte) 0x8c, (byte) 0x7d, (byte) 0x3c, + (byte) 0xa8, (byte) 0x82, (byte) 0x69, (byte) 0xa3, (byte) 0xdf, (byte) 0x0a, + (byte) 0x79, (byte) 0x7b, (byte) 0xdd, (byte) 0x24, (byte) 0x6a, (byte) 0x21, + (byte) 0x7b, (byte) 0x20, (byte) 0x94, (byte) 0xcd, (byte) 0x15, (byte) 0x92, + (byte) 0xad, (byte) 0x4a, (byte) 0x72, (byte) 0x0b, (byte) 0x0e, (byte) 0xb2, + (byte) 0xc9 + }; + + private static final byte[] FAKE_KEY_3 = { + (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01, + (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, + (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82, + (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e, + (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, + (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b, + (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66, + (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a, + (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02, + (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3, + (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d, + (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67, + (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb, + (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2, + (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79, + (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce, + (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08, + (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b, + (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4, + (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d, + (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23, + (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08, + (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1, + (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4, + (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16, + (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e, + (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01, + (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16, + (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98, + (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf, + (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a, + (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2, + (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc, + (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5, + (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a, + (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b, + (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9, + (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12, + (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e, + (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d, + (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2, + (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d, + (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc, + (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98, + (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96, + (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30, + (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e, + (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad, + (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f, + (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89, + (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13, + (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a, + (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e, + (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa, + (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47, + (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44, + (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22, + (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10, + (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45, + (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4, + (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda, + (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1, + (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab, + (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7, + (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc, + (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d, + (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82, + (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3, + (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a, + (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9, + (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6, + (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00, + (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd, + (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb, + (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4, + (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0, + (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2, + (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce, + (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a, + (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21, + (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d, + (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1, + (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41, + (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce, + (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0, + (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40, + (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a, + (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c, + (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90, + (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf, + (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb, + (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14, + (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab, + (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02, + (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67, + (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d, + (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d, + (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b, + (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2, + (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28, + (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd, + (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d, + (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b, + (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1, + (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51 + }; private boolean hasWifi() { return getContext().getPackageManager().hasSystemFeature( @@ -492,7 +735,32 @@ public class WifiEnterpriseConfigTest extends AndroidTestCase { X509Certificate[] certs = config.getCaCertificates(); assertTrue(cert1.getSerialNumber().equals(certs[0].getSerialNumber())); assertTrue(cert2.getSerialNumber().equals(certs[1].getSerialNumber())); + + X509Certificate clientCert = (X509Certificate) factory.generateCertificate( + new ByteArrayInputStream(FAKE_EC_3)); + KeyFactory kf = KeyFactory.getInstance("RSA"); + PrivateKey clientKey = kf.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_3)); + + config.setClientKeyEntry(clientKey, clientCert); + X509Certificate testClientCert = config.getClientCertificate(); + X509Certificate[] testClientCertChain = config.getClientCertificateChain(); + assertTrue(clientCert.getSerialNumber().equals(testClientCert.getSerialNumber())); + assertTrue(testClientCertChain.length == 1); + assertTrue(testClientCertChain[0] == testClientCert); + config.setClientKeyEntry(null, null); + assertTrue(config.getClientCertificate() == null); + assertTrue(config.getClientCertificateChain() == null); + + config.setClientKeyEntryWithCertificateChain(clientKey, + new X509Certificate[]{clientCert, cert1}); + testClientCert = config.getClientCertificate(); + testClientCertChain = config.getClientCertificateChain(); + assertTrue(clientCert.getSerialNumber().equals(testClientCert.getSerialNumber())); + assertTrue(testClientCertChain.length == 2); + assertTrue(testClientCertChain[0] == testClientCert); + assertTrue(testClientCertChain[1] == cert1); + config.setSubjectMatch(SUBJECT_MATCH); assertTrue(config.getSubjectMatch().equals(SUBJECT_MATCH)); // Hotspot 2.0 related attributes From 1ac3a1f3fcd0dd4acd18122d054c3123a10c0ae9 Mon Sep 17 00:00:00 2001 From: Chris Manton Date: Fri, 14 Oct 2016 17:30:15 -0700 Subject: [PATCH 0306/1415] Include Wear device idle settings Certain tests interacting with device idle must set correctly both the normal and wear device idle setting space. Bug: 32183373 Test: Run on wear device and Nexus6P run cts --skip-device-info -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testDozeModeMetered_enabledButWhitelistedOnNotificationAction run cts --skip-device-info -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testDozeModeNonMetered_enabledButWhitelistedOnNotificationAction Change-Id: I6a53d29021a7d4a257b102a4d3bd5d2cc845c16f --- ...ractRestrictBackgroundNetworkTestCase.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index b4d7d9db78..cbd8feaa72 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -29,6 +29,7 @@ import android.app.Instrumentation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -99,6 +100,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private String mMeteredWifi; + private boolean mHasWatch; + private String mDeviceIdleConstantsSetting; @Override protected void setUp() throws Exception { @@ -110,7 +113,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); final int myUid = getUid(mContext.getPackageName()); - + mHasWatch = mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WATCH); + if (mHasWatch) { + mDeviceIdleConstantsSetting = "device_idle_constants_watch"; + } else { + mDeviceIdleConstantsSetting = "device_idle_constants"; + } Log.i(TAG, "Apps status on " + getName() + ":\n" + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -726,14 +735,14 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } protected void setPendingIntentWhitelistDuration(int durationMs) throws Exception { - final String command = String.format( - "settings put global device_idle_constants %s=%d", - "notification_whitelist_duration", durationMs); - executeSilentShellCommand(command); + executeSilentShellCommand(String.format( + "settings put global %s %s=%d", mDeviceIdleConstantsSetting, + "notification_whitelist_duration", durationMs)); } protected void resetDeviceIdleSettings() throws Exception { - executeShellCommand("settings delete global device_idle_constants"); + executeShellCommand(String.format("settings delete global %s", + mDeviceIdleConstantsSetting)); } protected void startForegroundService() throws Exception { From d5eadafa77a74d3792083a52b0659c46542d42e1 Mon Sep 17 00:00:00 2001 From: Geoffrey Pitsch Date: Mon, 30 Jan 2017 13:32:15 -0500 Subject: [PATCH 0307/1415] All cts uses notification channels and new Builder constructor Test: ran cts for all *Test.java files in CL Change-Id: I62f6eae53b539a1cfc79a05a2aa4070bf30fbfc0 --- .../net/hostside/app2/MyBroadcastReceiver.java | 5 +++-- .../net/hostside/app2/MyForegroundService.java | 10 ++++++++-- .../cts/net/hostside/app2/MyService.java | 18 ++++++++++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java index f59cba1252..aa54075783 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -196,7 +196,8 @@ public class MyBroadcastReceiver extends BroadcastReceiver { * Sends a system notification containing actions with pending intents to launch the app's * main activitiy or service. */ - static void sendNotification(Context context, int notificationId, String notificationType ) { + static void sendNotification(Context context, String channelId, int notificationId, + String notificationType ) { Log.d(TAG, "sendNotification: id=" + notificationId + ", type=" + notificationType); final Intent serviceIntent = new Intent(context, MyService.class); final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, @@ -204,7 +205,7 @@ public class MyBroadcastReceiver extends BroadcastReceiver { final Bundle bundle = new Bundle(); bundle.putCharSequence("parcelable", "I am not"); - final Notification.Builder builder = new Notification.Builder(context) + final Notification.Builder builder = new Notification.Builder(context, channelId) .setSmallIcon(R.drawable.ic_notification); Action action = null; diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java index b88c45dbb4..fa3fdd148c 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java @@ -18,6 +18,8 @@ package com.android.cts.net.hostside.app2; import static com.android.cts.net.hostside.app2.Common.TAG; import android.R; import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.os.IBinder; @@ -27,7 +29,7 @@ import android.util.Log; * Service used to change app state to FOREGROUND_SERVICE. */ public class MyForegroundService extends Service { - + private static final String NOTIFICATION_CHANNEL_ID = "cts/MyForegroundService"; private static final int FLAG_START_FOREGROUND = 1; private static final int FLAG_STOP_FOREGROUND = 2; @@ -39,10 +41,14 @@ public class MyForegroundService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.v(TAG, "MyForegroundService.onStartCommand(): " + intent); + NotificationManager notificationManager = getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(new NotificationChannel( + NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, + NotificationManager.IMPORTANCE_DEFAULT)); switch (intent.getFlags()) { case FLAG_START_FOREGROUND: Log.d(TAG, "Starting foreground"); - startForeground(42, new Notification.Builder(this) + startForeground(42, new Notification.Builder(this, NOTIFICATION_CHANNEL_ID) .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine .build()); break; diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java index 9c19e50238..2496c4ac7d 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java @@ -20,6 +20,8 @@ import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER; import static com.android.cts.net.hostside.app2.Common.TAG; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.Service; import android.content.Context; import android.content.Intent; @@ -36,6 +38,7 @@ import com.android.cts.net.hostside.IMyService; * Service used to dynamically register a broadcast receiver. */ public class MyService extends Service { + private static final String NOTIFICATION_CHANNEL_ID = "MyService"; private MyBroadcastReceiver mReceiver; @@ -75,8 +78,8 @@ public class MyService extends Service { @Override public void sendNotification(int notificationId, String notificationType) { - MyBroadcastReceiver - .sendNotification(getApplicationContext(), notificationId, notificationType); + MyBroadcastReceiver .sendNotification(getApplicationContext(), NOTIFICATION_CHANNEL_ID, + notificationId, notificationType); } }; @@ -85,8 +88,19 @@ public class MyService extends Service { return mBinder; } + @Override + public void onCreate() { + final Context context = getApplicationContext(); + ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) + .createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID, + NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT)); + } + @Override public void onDestroy() { + final Context context = getApplicationContext(); + ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) + .deleteNotificationChannel(NOTIFICATION_CHANNEL_ID); if (mReceiver != null) { Log.d(TAG, "onDestroy(): unregistering " + mReceiver); getApplicationContext().unregisterReceiver(mReceiver); From e098c1804d4894a3a83b77f2992fa7e80dea09fe Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Tue, 10 Jan 2017 12:08:43 +0000 Subject: [PATCH 0308/1415] Prepare for removal of legacy-test from default targets In preparation for removing junit classes from the Android API the legacy-test target will be removed from the TARGET_DEFAULT_JAVA_LIBRARIES. This change adds explicit dependencies on junit and/or legacy-android-test to ensure that modules will compile properly once it is removed. Bug: 30188076 Test: make checkbuild Change-Id: I2bbe603b1344d3eef4b48c498311f91b756b85e3 Merged-In: I0f34fe97154240e8f8eef6816df1c794da60351e --- tests/cts/net/Android.mk | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index c553a9bb2e..7d2b0bac99 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -34,8 +34,14 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases -LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support ctsdeviceutil \ - ctstestrunner ctstestserver mockwebserver +LOCAL_STATIC_JAVA_LIBRARIES := \ + core-tests-support \ + ctsdeviceutil \ + ctstestrunner \ + ctstestserver \ + mockwebserver \ + junit \ + legacy-android-test # uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current From e66cee48611b7876a8c263cf403b5aac4fdcc078 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Mon, 9 Jan 2017 16:02:02 -0800 Subject: [PATCH 0309/1415] Update network tests to make sure app has connectivity on start. In the tests, we check the ouput from "am get-uid-state" command to see if the app is coming to foreground and check for network access. But the command gives internal uid state info in AMS and it's possible that the activity/service is not started yet. Update this behavior so that we check for network access only after the activity/service is started. Bug: 27803922 Test: cts-tradefed run singleCommand cts-dev --module CtsHostsideNetworkTests Change-Id: Ic0d94a585439c1d8629a897a8b56bcbf178a4371 --- tests/cts/hostside/aidl/Android.mk | 1 + .../net/hostside/INetworkStateObserver.aidl | 21 ++++ .../net/hostside/AbstractAppIdleTestCase.java | 8 +- .../AbstractBatterySaverModeTestCase.java | 6 +- .../hostside/AbstractDozeModeTestCase.java | 6 +- ...ractRestrictBackgroundNetworkTestCase.java | 100 ++++++++++++------ .../cts/net/hostside/DataSaverModeTest.java | 6 +- .../android/cts/net/hostside/app2/Common.java | 32 ++++++ .../cts/net/hostside/app2/MyActivity.java | 23 +++- .../hostside/app2/MyForegroundService.java | 8 ++ 10 files changed, 160 insertions(+), 51 deletions(-) create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl diff --git a/tests/cts/hostside/aidl/Android.mk b/tests/cts/hostside/aidl/Android.mk index 58be21f608..85f71c3726 100644 --- a/tests/cts/hostside/aidl/Android.mk +++ b/tests/cts/hostside/aidl/Android.mk @@ -19,6 +19,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current LOCAL_SRC_FILES := \ com/android/cts/net/hostside/IMyService.aidl \ + com/android/cts/net/hostside/INetworkStateObserver.aidl \ com/android/cts/net/hostside/IRemoteSocketFactory.aidl LOCAL_MODULE := CtsHostsideNetworkTestsAidl include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl new file mode 100644 index 0000000000..09f3120ba9 --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +oneway interface INetworkStateObserver { + void onNetworkStateChecked(String resultData); +} \ No newline at end of file diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 78ba4b9514..0e35b1b8ed 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -91,9 +91,7 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork // Make sure foreground app doesn't lose access upon enabling it. setAppIdle(true); - launchActivity(); - assertAppIdle(false); // Sanity check - not idle anymore, since activity was launched... - assertForegroundNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); finishActivity(); assertAppIdle(false); // Sanity check - not idle anymore, since activity was launched... assertBackgroundNetworkAccess(true); @@ -102,9 +100,7 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork // Same for foreground service. setAppIdle(true); - startForegroundService(); - assertAppIdle(true); // Sanity check - still idle - assertForegroundServiceNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); stopForegroundService(); assertAppIdle(true); assertBackgroundNetworkAccess(false); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index 50bcc6058e..546a550d5c 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -87,8 +87,7 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou // Make sure foreground app doesn't lose access upon Battery Saver. setBatterySaverMode(false); - launchActivity(); - assertForegroundNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); setBatterySaverMode(true); assertForegroundNetworkAccess(); @@ -104,8 +103,7 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou // Make sure foreground service doesn't lose access upon enabling Battery Saver. setBatterySaverMode(false); - startForegroundService(); - assertForegroundNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); setBatterySaverMode(true); assertForegroundNetworkAccess(); stopForegroundService(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index 6669af5edd..68f6e7439d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -88,8 +88,7 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor // Make sure foreground service doesn't lose network access upon enabling doze. setDozeMode(false); - startForegroundService(); - assertForegroundNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); setDozeMode(true); assertForegroundNetworkAccess(); stopForegroundService(); @@ -159,8 +158,7 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor // leaves Doze Mode. @Override protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception { - startForegroundService(); - assertForegroundServiceNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); stopForegroundService(); assertBackgroundState(); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 014d7ae6e2..3374378605 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -22,11 +22,13 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import android.app.Instrumentation; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -35,11 +37,15 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; +import android.os.Binder; +import android.os.Bundle; import android.os.SystemClock; import android.service.notification.NotificationListenerService; import android.test.InstrumentationTestCase; import android.util.Log; +import com.android.cts.net.hostside.INetworkStateObserver; + /** * Superclass for tests related to background network restrictions. */ @@ -49,6 +55,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected static final String TEST_PKG = "com.android.cts.net.hostside"; protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; + private static final String TEST_APP2_ACTIVITY_CLASS = TEST_APP2_PKG + ".MyActivity"; + private static final String TEST_APP2_SERVICE_CLASS = TEST_APP2_PKG + ".MyForegroundService"; + private static final int SLEEP_TIME_SEC = 1; private static final boolean DEBUG = true; @@ -76,6 +85,12 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation private static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; private static final int PROCESS_STATE_TOP = 2; + private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; + + protected static final int TYPE_COMPONENT_ACTIVTIY = 0; + protected static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1; + + private static final int FOREGROUND_PROC_NETWORK_TIMEOUT_MS = 6000; // Must be higher than NETWORK_TIMEOUT_MS private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4; @@ -225,13 +240,11 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation */ protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception{ // Checks foreground first. - launchActivity(); - assertForegroundNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); finishActivity(); // Then foreground service - startForegroundService(); - assertForegroundServiceNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); stopForegroundService(); } @@ -329,14 +342,19 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation */ private String checkNetworkAccess(boolean expectAvailable) throws Exception { final String resultData = mServiceClient.checkNetworkStatus(); + return checkForAvailabilityInResultData(resultData, expectAvailable); + } + + private String checkForAvailabilityInResultData(String resultData, boolean expectAvailable) { if (resultData == null) { - return "did not get network status from app2"; + assertNotNull("Network status from app2 is null", resultData); } // Network status format is described on MyBroadcastReceiver.checkNetworkStatus() final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR); assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check final State state = parts[0].equals("null") ? null : State.valueOf(parts[0]); - final DetailedState detailedState = parts[1].equals("null") ? null : DetailedState.valueOf(parts[1]); + final DetailedState detailedState = parts[1].equals("null") + ? null : DetailedState.valueOf(parts[1]); final boolean connected = Boolean.valueOf(parts[2]); final String connectionCheckDetails = parts[3]; final String networkInfo = parts[4]; @@ -641,7 +659,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation Log.i(TAG, "Setting Battery Saver Mode to " + enabled); if (enabled) { turnBatteryOff(); - executeSilentShellCommand("cmd battery unplug"); executeSilentShellCommand("settings put global low_power 1"); } else { executeSilentShellCommand("settings put global low_power 0"); @@ -742,35 +759,58 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mDeviceIdleConstantsSetting)); } - protected void startForegroundService() throws Exception { - executeShellCommand( - "am startservice -f 1 com.android.cts.net.hostside.app2/.MyForegroundService"); - assertForegroundServiceState(); + protected void launchComponentAndAssertNetworkAccess(int type) throws Exception { + if (type == TYPE_COMPONENT_ACTIVTIY) { + turnScreenOn(); + } + final CountDownLatch latch = new CountDownLatch(1); + final Intent launchIntent = getIntentForComponent(type); + final Bundle extras = new Bundle(); + final String[] errors = new String[] {null}; + extras.putBinder(KEY_NETWORK_STATE_OBSERVER, getNewNetworkStateObserver(latch, errors)); + launchIntent.putExtras(extras); + if (type == TYPE_COMPONENT_ACTIVTIY) { + mContext.startActivity(launchIntent); + } else if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) { + mContext.startService(launchIntent); + } + if (latch.await(FOREGROUND_PROC_NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + if (!errors[0].isEmpty()) { + fail("Network is not available for app2 (" + mUid + "): " + errors[0]); + } + } else { + fail("Timed out waiting for network availability status from app2 (" + mUid + ")"); + } + } + + private Intent getIntentForComponent(int type) { + final Intent intent = new Intent(); + if (type == TYPE_COMPONENT_ACTIVTIY) { + intent.setComponent(new ComponentName(TEST_APP2_PKG, TEST_APP2_ACTIVITY_CLASS)); + } else if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) { + intent.setComponent(new ComponentName(TEST_APP2_PKG, TEST_APP2_SERVICE_CLASS)) + .setFlags(1); + } else { + fail("Unknown type: " + type); + } + return intent; } protected void stopForegroundService() throws Exception { - executeShellCommand( - "am startservice -f 2 com.android.cts.net.hostside.app2/.MyForegroundService"); + executeShellCommand(String.format("am startservice -f 2 %s/%s", + TEST_APP2_PKG, TEST_APP2_SERVICE_CLASS)); // NOTE: cannot assert state because it depends on whether activity was on top before. } - /** - * Launches an activity on app2 so its process is elevated to foreground status. - */ - protected void launchActivity() throws Exception { - turnScreenOn(); - executeShellCommand("am start com.android.cts.net.hostside.app2/.MyActivity"); - final int maxTries = 30; - ProcessState state = null; - for (int i = 1; i <= maxTries; i++) { - state = getProcessStateByUid(mUid); - if (state.state == PROCESS_STATE_TOP) return; - Log.w(TAG, "launchActivity(): uid " + mUid + " not on TOP state on attempt #" + i - + "; turning screen on and sleeping 1s before checking again"); - turnScreenOn(); - SystemClock.sleep(SECOND_IN_MS); - } - fail("App2 is not on foreground state after " + maxTries + " attempts: " + state); + private Binder getNewNetworkStateObserver(final CountDownLatch latch, + final String[] errors) { + return new INetworkStateObserver.Stub() { + @Override + public void onNetworkStateChecked(String resultData) { + errors[0] = checkForAvailabilityInResultData(resultData, true); + latch.countDown(); + } + }; } /** diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 7ca302f52a..4c907fff55 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -100,8 +100,7 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase // Make sure foreground app doesn't lose access upon enabling Data Saver. setRestrictBackground(false); - launchActivity(); - assertForegroundNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); setRestrictBackground(true); assertForegroundNetworkAccess(); @@ -117,8 +116,7 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase // Make sure foreground service doesn't lose access upon enabling Data Saver. setRestrictBackground(false); - startForegroundService(); - assertForegroundNetworkAccess(); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); setRestrictBackground(true); assertForegroundNetworkAccess(); stopForegroundService(); diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index dc9a63036a..20bbd5a75c 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -16,7 +16,14 @@ package com.android.cts.net.hostside.app2; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; + +import com.android.cts.net.hostside.INetworkStateObserver; public final class Common { @@ -42,6 +49,9 @@ public final class Common { static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE"; static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT"; + static final String TEST_PKG = "com.android.cts.net.hostside"; + static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; + static int getUid(Context context) { final String packageName = context.getPackageName(); try { @@ -50,4 +60,26 @@ public final class Common { throw new IllegalStateException("Could not get UID for " + packageName, e); } } + + static void notifyNetworkStateObserver(Context context, Intent intent) { + if (intent == null) { + return; + } + final Bundle extras = intent.getExtras(); + if (extras == null) { + return; + } + final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface( + extras.getBinder(KEY_NETWORK_STATE_OBSERVER)); + if (observer != null) { + AsyncTask.execute(() -> { + try { + observer.onNetworkStateChecked( + MyBroadcastReceiver.checkNetworkStatus(context)); + } catch (RemoteException e) { + Log.e(TAG, "Error occured while notifying the observer: " + e); + } + }); + } + } } diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java index 444b696962..da7e704e8b 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java @@ -17,30 +17,47 @@ package com.android.cts.net.hostside.app2; import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_ACTIVITY; import static com.android.cts.net.hostside.app2.Common.TAG; +import static com.android.cts.net.hostside.app2.Common.TEST_PKG; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.AsyncTask; import android.os.Bundle; +import android.os.RemoteException; import android.util.Log; +import com.android.cts.net.hostside.INetworkStateObserver; + /** * Activity used to bring process to foreground. */ public class MyActivity extends Activity { + private BroadcastReceiver finishCommandReceiver = null; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - registerReceiver(new BroadcastReceiver() { - + Common.notifyNetworkStateObserver(this, getIntent()); + finishCommandReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "Finishing MyActivity"); MyActivity.this.finish(); - }}, new IntentFilter(ACTION_FINISH_ACTIVITY)); + } + }; + registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY)); + } + + @Override + public void finish() { + if (finishCommandReceiver != null) { + unregisterReceiver(finishCommandReceiver); + } + super.finish(); } @Override diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java index fa3fdd148c..ff4ba656b1 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java @@ -16,15 +16,22 @@ package com.android.cts.net.hostside.app2; import static com.android.cts.net.hostside.app2.Common.TAG; +import static com.android.cts.net.hostside.app2.Common.TEST_PKG; + import android.R; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; import android.os.IBinder; +import android.os.RemoteException; import android.util.Log; +import com.android.cts.net.hostside.INetworkStateObserver; + /** * Service used to change app state to FOREGROUND_SERVICE. */ @@ -51,6 +58,7 @@ public class MyForegroundService extends Service { startForeground(42, new Notification.Builder(this, NOTIFICATION_CHANNEL_ID) .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine .build()); + Common.notifyNetworkStateObserver(this, intent); break; case FLAG_STOP_FOREGROUND: Log.d(TAG, "Stopping foreground"); From 863ec4b9cb4ee9a8f428bcc76469011bebb0e7ae Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 21 Feb 2017 13:57:43 -0800 Subject: [PATCH 0310/1415] Relax the check of network availability in CtsHostsideNetworkTests. Bug: 35523062 Test: cts-tradefed run singleCommand cts-dev --module CtsHostsideNetworkTests -t \ com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: I6c2df38fd7282a0cb9861afbb624018297d400fd --- .../hostside/AbstractRestrictBackgroundNetworkTestCase.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index f5b5dd187d..15daed971b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -817,7 +817,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } if (latch.await(FOREGROUND_PROC_NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { if (!errors[0].isEmpty()) { - fail("Network is not available for app2 (" + mUid + "): " + errors[0]); + // TODO: revert this change once b/35523062 is fixed. +// fail("Network is not available for app2 (" + mUid + "): " + errors[0]); + assertForegroundNetworkAccess(); } } else { fail("Timed out waiting for network availability status from app2 (" + mUid + ")"); From 485adf65b6c9334a72892a9507d87bfd25c1f61f Mon Sep 17 00:00:00 2001 From: Peter Qiu Date: Mon, 27 Feb 2017 13:40:17 -0800 Subject: [PATCH 0311/1415] WifiManagerTest: add tests for verifying Passpoint configuration management APIs Bug: 35756298 Test: run WifiManagerTest Change-Id: I3d106ca9dd4ea74de91c6553eb285534a7856363 --- .../src/android/net/wifi/cts/FakeKeys.java | 237 ++++++++++++++++++ .../android/net/wifi/cts/WifiManagerTest.java | 131 ++++++++++ 2 files changed, 368 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/FakeKeys.java diff --git a/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java b/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java new file mode 100644 index 0000000000..f422c2f0fa --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2016 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.wifi.cts; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; + +/** + * A class containing test certificates and private keys. + */ +public class FakeKeys { + private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" + + "MIIDKDCCAhCgAwIBAgIJAILlFdwzLVurMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" + + "BAMTB0VBUCBDQTEwHhcNMTYwMTEyMTE1MDE1WhcNMjYwMTA5MTE1MDE1WjASMRAw\n" + + "DgYDVQQDEwdFQVAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" + + "znAPUz26Msae4ws43czR41/J2QtrSIZUKmVUsVumDbYHrPNvTXKSMXAcewORDQYX\n" + + "RqvHvpn8CscB1+oGXZvHwxj4zV0WKoK2zeXkau3vcyl3HIKupJfq2TEACefVjj0t\n" + + "JW+X35PGWp9/H5zIUNVNVjS7Ums84IvKhRB8512PB9UyHagXYVX5GWpAcVpyfrlR\n" + + "FI9Qdhh+Pbk0uyktdbf/CdfgHOoebrTtwRljM0oDtX+2Cv6j0wBK7hD8pPvf1+uy\n" + + "GzczigAU/4Kw7eZqydf9B+5RupR+IZipX41xEiIrKRwqi517WWzXcjaG2cNbf451\n" + + "xpH5PnV3i1tq04jMGQUzFwIDAQABo4GAMH4wHQYDVR0OBBYEFIwX4vs8BiBcScod\n" + + "5noZHRM8E4+iMEIGA1UdIwQ7MDmAFIwX4vs8BiBcScod5noZHRM8E4+ioRakFDAS\n" + + "MRAwDgYDVQQDEwdFQVAgQ0ExggkAguUV3DMtW6swDAYDVR0TBAUwAwEB/zALBgNV\n" + + "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFfQqOTA7Rv7K+luQ7pnas4BYwHE\n" + + "9GEP/uohv6KOy0TGQFbrRTjFoLVNB9BZ1ymMDZ0/TIwIUc7wi7a8t5mEqYH153wW\n" + + "aWooiSjyLLhuI4sNrNCOtisdBq2r2MFXt6h0mAQYOPv8R8K7/fgSxGFqzhyNmmVL\n" + + "1qBJldx34SpwsTALQVPb4hGwJzZfr1PcpEQx6xMnTl8xEWZE3Ms99uaUxbQqIwRu\n" + + "LgAOkNCmY2m89VhzaHJ1uV85AdM/tD+Ysmlnnjt9LRCejbBipjIGjOXrg1JP+lxV\n" + + "muM4vH+P/mlmxsPPz0d65b+EGmJZpoLkO/tdNNvCYzjJpTEWpEsO6NMhKYo=\n" + + "-----END CERTIFICATE-----\n"; + public static final X509Certificate CA_CERT0 = loadCertificate(CA_CERT0_STRING); + + private static final String CA_CERT1_STRING = "-----BEGIN CERTIFICATE-----\n" + + "MIIDKDCCAhCgAwIBAgIJAOM5SzKO2pzCMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" + + "BAMTB0VBUCBDQTAwHhcNMTYwMTEyMDAxMDQ3WhcNMjYwMTA5MDAxMDQ3WjASMRAw\n" + + "DgYDVQQDEwdFQVAgQ0EwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" + + "89ug+IEKVQXnJGKg5g4uVHg6J/8iRUxR5k2eH5o03hrJNMfN2D+cBe/wCiZcnWbI\n" + + "GbGZACWm2nQth2wy9Zgm2LOd3b4ocrHYls3XLq6Qb5Dd7a0JKU7pdGufiNVEkrmF\n" + + "EB+N64wgwH4COTvCiN4erp5kyJwkfqAl2xLkZo0C464c9XoyQOXbmYD9A8v10wZu\n" + + "jyNsEo7Nr2USyw+qhjWSbFbEirP77Tvx+7pJQJwdtk1V9Tn73T2dGF2WHYejei9S\n" + + "mcWpdIUqsu9etYH+zDmtu7I1xlkwiaVsNr2+D+qaCJyOYqrDTKVNK5nmbBPXDWZc\n" + + "NoDbTOoqquX7xONpq9M6jQIDAQABo4GAMH4wHQYDVR0OBBYEFAZ3A2S4qJZZwuNY\n" + + "wkJ6mAdc0gVdMEIGA1UdIwQ7MDmAFAZ3A2S4qJZZwuNYwkJ6mAdc0gVdoRakFDAS\n" + + "MRAwDgYDVQQDEwdFQVAgQ0EwggkA4zlLMo7anMIwDAYDVR0TBAUwAwEB/zALBgNV\n" + + "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHmdMwEhtys4d0E+t7owBmoVR+lU\n" + + "hMCcRtWs8YKX5WIM2kTweT0h/O1xwE1mWmRv/IbDAEb8od4BjAQLhIcolStr2JaO\n" + + "9ZzyxjOnNzqeErh/1DHDbb/moPpqfeJ8YiEz7nH/YU56Q8iCPO7TsgS0sNNE7PfN\n" + + "IUsBW0yHRgpQ4OxWmiZG2YZWiECRzAC0ecPzo59N5iH4vLQIMTMYquiDeMPQnn1e\n" + + "NDGxG8gCtDKIaS6tMg3a28MvWB094pr2ETou8O1C8Ji0Y4hE8QJmSdT7I4+GZjgW\n" + + "g94DZ5RiL7sdp3vC48CXOmeT61YBIvhGUsE1rPhXqkpqQ3Z3C4TFF0jXZZc=\n" + + "-----END CERTIFICATE-----\n"; + public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING); + + private static final String CLIENT_CERT_STR = "-----BEGIN CERTIFICATE-----\n" + + "MIIE/DCCAuQCAQEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxCzAJBgNV\n" + + "BAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdUZXN0aW5n\n" + + "MB4XDTE2MDkzMDIwNTQyOFoXDTE3MDkzMDIwNTQyOFowRDELMAkGA1UEBhMCVVMx\n" + + "CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdU\n" + + "ZXN0aW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnpmcbuaeHfnJ\n" + + "k+2QNvxmdVFTawyFMNk0USCq5sexscwmxbewG/Rb8YnixwJWS44v2XkSujB67z5C\n" + + "s2qudFEhRXKdEuC6idbAuA97KjipHh0AAniWMsyv61fvbgsUC0b0canx3LiDq81p\n" + + "y28NNGmAvoazLZUZ4AhBRiwYZY6FKk723gmZoGbEIeG7J1dlXPusc1662rIjz4eU\n" + + "zlmmlvqyHfNqnNk8L14Vug6Xh+lOEGN85xhu1YHAEKGrS89kZxs5rum/cZU8KH2V\n" + + "v6eKnY03kxjiVLQtnLpm/7VUEoCMGHyruRj+p3my4+DgqMsmsH52RZCBsjyGlpbU\n" + + "NOwOTIX6xh+Rqloduz4AnrMYYIiIw2s8g+2zJM7VbcVKx0fGS26BKdrxgrXWfmNE\n" + + "nR0/REQ5AxDGw0jfTUvtdTkXAf+K4MDjcNLEZ+MA4rHfAfQWZtUR5BkHCQYxNpJk\n" + + "pA0gyk+BpKdC4WdzI14NSWsu5sRCmBCFqH6BTOSEq/V1cNorBxNwLSSTwFFqUDqx\n" + + "Y5nQLXygkJf9WHZWtSKeSjtOYgilz7UKzC2s3CsjmIyGFe+SwpuHJnuE4Uc8Z5Cb\n" + + "bjNGHPzqL6XnmzZHJp7RF8kBdKdjGC7dCUltzOfICZeKlzOOq+Kw42T/nXjuXvpb\n" + + "nkXNxg741Nwd6RecykXJbseFwm3EYxkCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEA\n" + + "Ga1mGwI9aXkL2fTPXO9YkAPzoGeX8aeuVYSQaSkNq+5vnogYCyAt3YDHjRG+ewTT\n" + + "WbnPA991xRAPac+biJeXWmwvgGj0YuT7e79phAiGkTTnbAjFHGfYnBy/tI/v7btO\n" + + "hRNElA5yTJ1m2fVbBEKXzMR83jrT9iyI+YLRN86zUZIaC86xxSbqnrdWN2jOK6MX\n" + + "dS8Arp9tPQjC/4gW+2Ilxv68jiYh+5auWHQZVjppWVY//iu4mAbkq1pTwQEhZ8F8\n" + + "Zrmh9DHh60hLFcfSuhIAwf/NMzppwdkjy1ruKVrpijhGKGp4OWu8nvOUgHSzxc7F\n" + + "PwpVZ5N2Ku4L8MLO6BG2VasRJK7l17TzDXlfLZHJjkuryOFxVaQKt8ZNFgTOaCXS\n" + + "E+gpTLksKU7riYckoiP4+H1sn9qcis0e8s4o/uf1UVc8GSdDw61ReGM5oZEDm1u8\n" + + "H9x20QU6igLqzyBpqvCKv7JNgU1uB2PAODHH78zJiUfnKd1y+o+J1iWzaGj3EFji\n" + + "T8AXksbTP733FeFXfggXju2dyBH+Z1S5BBTEOd1brWgXlHSAZGm97MKZ94r6/tkX\n" + + "qfv3fCos0DKz0oV7qBxYS8wiYhzrRVxG6ITAoH8uuUVVQaZF+G4nJ2jEqNbfuKyX\n" + + "ATQsVNjNNlDA0J33GobPMjT326wa4YAWMx8PI5PJZ3g=\n" + + "-----END CERTIFICATE-----\n"; + public static final X509Certificate CLIENT_CERT = loadCertificate(CLIENT_CERT_STR); + + private static final byte[] FAKE_RSA_KEY_1 = new byte[] { + (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01, + (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, + (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82, + (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e, + (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, + (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b, + (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66, + (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a, + (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02, + (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3, + (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d, + (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67, + (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb, + (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2, + (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79, + (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce, + (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08, + (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b, + (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4, + (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d, + (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23, + (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08, + (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1, + (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4, + (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16, + (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e, + (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01, + (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16, + (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98, + (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf, + (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a, + (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2, + (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc, + (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5, + (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a, + (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b, + (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9, + (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12, + (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e, + (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d, + (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2, + (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d, + (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc, + (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98, + (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96, + (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30, + (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e, + (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad, + (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f, + (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89, + (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13, + (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a, + (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e, + (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa, + (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47, + (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44, + (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22, + (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10, + (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45, + (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4, + (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda, + (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1, + (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab, + (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7, + (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc, + (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d, + (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82, + (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3, + (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a, + (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9, + (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6, + (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00, + (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd, + (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb, + (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4, + (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0, + (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2, + (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce, + (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a, + (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21, + (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d, + (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1, + (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41, + (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce, + (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0, + (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40, + (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a, + (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c, + (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90, + (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf, + (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb, + (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14, + (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab, + (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02, + (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67, + (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d, + (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d, + (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b, + (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2, + (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28, + (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd, + (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d, + (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b, + (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1, + (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51 + }; + public static final PrivateKey RSA_KEY1 = loadPrivateRSAKey(FAKE_RSA_KEY_1); + + private static X509Certificate loadCertificate(String blob) { + try { + final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + InputStream stream = new ByteArrayInputStream(blob.getBytes(StandardCharsets.UTF_8)); + + return (X509Certificate) certFactory.generateCertificate(stream); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static PrivateKey loadPrivateRSAKey(byte[] fakeKey) { + try { + KeyFactory kf = KeyFactory.getInstance("RSA"); + return kf.generatePrivate(new PKCS8EncodedKeySpec(fakeKey)); + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + return null; + } + } +} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 4185189f50..d3dc8faadd 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -29,6 +29,9 @@ import android.net.wifi.WifiConfiguration.Status; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.TxPacketCountListener; import android.net.wifi.WifiManager.WifiLock; +import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.hotspot2.pps.Credential; +import android.net.wifi.hotspot2.pps.HomeSp; import android.os.SystemClock; import android.provider.Settings; import android.test.AndroidTestCase; @@ -38,6 +41,8 @@ import com.android.compatibility.common.util.WifiConfigCreator; import java.net.HttpURLConnection; import java.net.URL; +import java.security.MessageDigest; +import java.security.cert.X509Certificate; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -543,4 +548,130 @@ public class WifiManagerTest extends AndroidTestCase { } assertTrue(i < 15); } + + /** + * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint + * configuration with an user credential. + * + * @throws Exception + */ + public void testAddPasspointConfigWithUserCredential() throws Exception { + testAddPasspointConfig(generatePasspointConfig(generateUserCredential())); + } + + /** + * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint + * configuration with a certificate credential. + * + * @throws Exception + */ + public void testAddPasspointConfigWithCertCredential() throws Exception { + testAddPasspointConfig(generatePasspointConfig(generateCertCredential())); + } + + /** + * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint + * configuration with a SIm credential. + * + * @throws Exception + */ + public void testAddPasspointConfigWithSimCredential() throws Exception { + testAddPasspointConfig(generatePasspointConfig(generateSimCredential())); + } + + /** + * Helper function for generating a {@link PasspointConfiguration} for testing. + * + * @return {@link PasspointConfiguration} + */ + private PasspointConfiguration generatePasspointConfig(Credential credential) { + PasspointConfiguration config = new PasspointConfiguration(); + config.setCredential(credential); + + // Setup HomeSp. + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("Test.com"); + homeSp.setFriendlyName("Test Provider"); + config.setHomeSp(homeSp); + + return config; + } + + /** + * Helper function for generating an user credential for testing. + * + * @return {@link Credential} + */ + private Credential generateUserCredential() { + Credential credential = new Credential(); + credential.setRealm("test.net"); + Credential.UserCredential userCred = new Credential.UserCredential(); + userCred.setEapType(21 /* EAP_TTLS */); + userCred.setUsername("username"); + userCred.setPassword("password"); + userCred.setNonEapInnerMethod("PAP"); + credential.setUserCredential(userCred); + credential.setCaCertificate(FakeKeys.CA_CERT0); + return credential; + } + + /** + * Helper function for generating a certificate credential for testing. + * + * @return {@link Credential} + */ + private Credential generateCertCredential() throws Exception { + Credential credential = new Credential(); + credential.setRealm("test.net"); + Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); + certCredential.setCertType("x509v3"); + certCredential.setCertSha256Fingerprint( + MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded())); + credential.setCertCredential(certCredential); + credential.setCaCertificate(FakeKeys.CA_CERT0); + credential.setClientCertificateChain(new X509Certificate[] {FakeKeys.CLIENT_CERT}); + credential.setClientPrivateKey(FakeKeys.RSA_KEY1); + return credential; + } + + /** + * Helper function for generating a SIM credential for testing. + * + * @return {@link Credential} + */ + private Credential generateSimCredential() throws Exception { + Credential credential = new Credential(); + credential.setRealm("test.net"); + Credential.SimCredential simCredential = new Credential.SimCredential(); + simCredential.setImsi("1234*"); + simCredential.setEapType(18 /* EAP_SIM */); + credential.setSimCredential(simCredential); + return credential; + } + + /** + * Helper function verifying Passpoint configuration management APIs (add, remove, get) for + * a given configuration. + * + * @param config The configuration to test with + */ + private void testAddPasspointConfig(PasspointConfiguration config) throws Exception { + assertTrue(mWifiManager.addOrUpdatePasspointConfiguration(config)); + + // Certificates and keys will be set to null after it is installed to the KeyStore by + // WifiManager. Reset them in the expected config so that it can be used to compare + // against the retrieved config. + config.getCredential().setCaCertificate(null); + config.getCredential().setClientCertificateChain(null); + config.getCredential().setClientPrivateKey(null); + + // Retrieve the configuration and verify it. + List configList = mWifiManager.getPasspointConfigurations(); + assertEquals(1, configList.size()); + assertEquals(config, configList.get(0)); + + // Remove the configuration and verify no installed configuration. + assertTrue(mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn())); + assertTrue(mWifiManager.getPasspointConfigurations().isEmpty()); + } } From 24a0a8e64347b1d254e61c89a9be5e10169a4f76 Mon Sep 17 00:00:00 2001 From: Peter Qiu Date: Mon, 27 Feb 2017 15:23:06 -0800 Subject: [PATCH 0312/1415] wifi: add CTS tests for Passpoint parsing APIs Added a test for PPS MO (PerProviderSubscription Management Object) tree parsing API and a test for Release 1 installation file parsing API. Bug: 35756298 Test: run the newly added PpsMoParserTest and ConfigParserTest Change-Id: I6da40bef9609830afb80d8562e5bfb051920b541 --- .../net/assets/HSR1ProfileWithCACert.base64 | 85 ++++ .../net/assets/PerProviderSubscription.xml | 399 ++++++++++++++++++ .../net/wifi/cts/ConfigParserTest.java | 114 +++++ .../android/net/wifi/cts/PpsMoParserTest.java | 194 +++++++++ 4 files changed, 792 insertions(+) create mode 100644 tests/cts/net/assets/HSR1ProfileWithCACert.base64 create mode 100644 tests/cts/net/assets/PerProviderSubscription.xml create mode 100644 tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java create mode 100644 tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java diff --git a/tests/cts/net/assets/HSR1ProfileWithCACert.base64 b/tests/cts/net/assets/HSR1ProfileWithCACert.base64 new file mode 100644 index 0000000000..995963d2b4 --- /dev/null +++ b/tests/cts/net/assets/HSR1ProfileWithCACert.base64 @@ -0,0 +1,85 @@ +Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu +dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh +cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6 +IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n +SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo +YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn +UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi +V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ +M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM +MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth +VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt +RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD +QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD +QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD +QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx +bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1 +MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv +Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2 +ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo +YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4 +VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo +YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi +RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj +bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i +MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM +MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy +UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX +eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD +QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD +OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3 +dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0 +S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV +K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G +dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur +TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn +SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2 +WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0 +VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM +MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ +Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi +V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ +a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX +eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD +QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q +VTJSbWx1WjJWeWNISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV +KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG +bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB +OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB +Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4 +VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs +UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn +SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2 +WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk +V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU +bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ +QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94 +LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD +UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR +VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U +bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU +azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V +VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw +TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY +TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T +dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV +RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo +U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK +ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz +M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh +CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX +TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH +U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF +YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk +MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV +akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ +MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD +amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY +ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew +OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX +MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF +MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw +aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG +S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS +a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts +RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo= diff --git a/tests/cts/net/assets/PerProviderSubscription.xml b/tests/cts/net/assets/PerProviderSubscription.xml new file mode 100644 index 0000000000..7f2d95de95 --- /dev/null +++ b/tests/cts/net/assets/PerProviderSubscription.xml @@ -0,0 +1,399 @@ + + 1.2 + + PerProviderSubscription + + + urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0 + + + + UpdateIdentifier + 12 + + + i001 + + HomeSP + + FriendlyName + Century House + + + FQDN + mi6.co.uk + + + RoamingConsortiumOI + 112233,445566 + + + IconURL + icon.test.com + + + NetworkID + + n001 + + SSID + TestSSID + + + HESSID + 12345678 + + + + n002 + + SSID + NullHESSID + + + + + HomeOIList + + h001 + + HomeOI + 11223344 + + + HomeOIRequired + true + + + + h002 + + HomeOI + 55667788 + + + HomeOIRequired + false + + + + + OtherHomePartners + + o001 + + FQDN + other.fqdn.com + + + + + + Credential + + CreationDate + 2016-01-01T10:00:00Z + + + ExpirationDate + 2016-02-01T10:00:00Z + + + Realm + shaken.stirred.com + + + CheckAAAServerCertStatus + true + + + UsernamePassword + + Username + james + + + Password + Ym9uZDAwNw== + + + MachineManaged + true + + + SoftTokenApp + TestApp + + + AbleToShare + true + + + EAPMethod + + EAPType + 21 + + + InnerMethod + MS-CHAP-V2 + + + + + DigitalCertificate + + CertificateType + x509v3 + + + CertSHA256Fingerprint + 1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f + + + + SIM + + IMSI + imsi + + + EAPType + 24 + + + + + Policy + + PreferredRoamingPartnerList + + p001 + + FQDN_Match + test1.fqdn.com,exactMatch + + + Priority + 127 + + + Country + us,fr + + + + p002 + + FQDN_Match + test2.fqdn.com,includeSubdomains + + + Priority + 200 + + + Country + * + + + + + MinBackhaulThreshold + + m001 + + NetworkType + home + + + DLBandwidth + 23412 + + + ULBandwidth + 9823 + + + + m002 + + NetworkType + roaming + + + DLBandwidth + 9271 + + + ULBandwidth + 2315 + + + + + PolicyUpdate + + UpdateInterval + 120 + + + UpdateMethod + OMA-DM-ClientInitiated + + + Restriction + HomeSP + + + URI + policy.update.com + + + UsernamePassword + + Username + updateUser + + + Password + updatePass + + + + TrustRoot + + CertURL + update.cert.com + + + CertSHA256Fingerprint + 1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f + + + + + SPExclusionList + + s001 + + SSID + excludeSSID + + + + + RequiredProtoPortTuple + + r001 + + IPProtocol + 12 + + + PortNumber + 34,92,234 + + + + + MaximumBSSLoadValue + 23 + + + + CredentialPriority + 99 + + + AAAServerTrustRoot + + a001 + + CertURL + server1.trust.root.com + + + CertSHA256Fingerprint + 1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f + + + + + SubscriptionUpdate + + UpdateInterval + 120 + + + UpdateMethod + SSP-ClientInitiated + + + Restriction + RoamingPartner + + + URI + subscription.update.com + + + UsernamePassword + + Username + subscriptionUser + + + Password + subscriptionPass + + + + TrustRoot + + CertURL + subscription.update.cert.com + + + CertSHA256Fingerprint + 1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f + + + + + SubscriptionParameter + + CreationDate + 2016-02-01T10:00:00Z + + + ExpirationDate + 2016-03-01T10:00:00Z + + + TypeOfSubscription + Gold + + + UsageLimits + + DataLimit + 921890 + + + StartDate + 2016-12-01T10:00:00Z + + + TimeLimit + 120 + + + UsageTimePeriod + 99910 + + + + + + diff --git a/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java b/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java new file mode 100644 index 0000000000..52ed2a6d73 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 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.wifi.cts; + +import android.net.wifi.hotspot2.ConfigParser; +import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.hotspot2.pps.Credential; +import android.net.wifi.hotspot2.pps.HomeSp; +import android.test.AndroidTestCase; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; + +/** + * CTS tests for Hotspot 2.0 Release 1 installation file parsing API. + */ +public class ConfigParserTest extends AndroidTestCase { + /** + * Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a + * CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}. + */ + private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT = + "assets/HSR1ProfileWithCACert.base64"; + + /** + * Read the content of the given resource file into a String. + * + * @param filename String name of the file + * @return String + * @throws IOException + */ + private String loadResourceFile(String filename) throws IOException { + InputStream in = getClass().getClassLoader().getResourceAsStream(filename); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line).append("\n"); + } + + return builder.toString(); + } + + /** + * Generate a {@link PasspointConfiguration} that matches the configuration specified in the + * XML file {@link #PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT}. + * + * @return {@link PasspointConfiguration} + */ + private PasspointConfiguration generateConfigurationFromProfile() { + PasspointConfiguration config = new PasspointConfiguration(); + + // HomeSP configuration. + HomeSp homeSp = new HomeSp(); + homeSp.setFriendlyName("Century House"); + homeSp.setFqdn("mi6.co.uk"); + homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L}); + config.setHomeSp(homeSp); + + // Credential configuration. + Credential credential = new Credential(); + credential.setRealm("shaken.stirred.com"); + Credential.UserCredential userCredential = new Credential.UserCredential(); + userCredential.setUsername("james"); + userCredential.setPassword("Ym9uZDAwNw=="); + userCredential.setEapType(21); + userCredential.setNonEapInnerMethod("MS-CHAP-V2"); + credential.setUserCredential(userCredential); + Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); + certCredential.setCertType("x509v3"); + byte[] certSha256Fingerprint = new byte[32]; + Arrays.fill(certSha256Fingerprint, (byte)0x1f); + certCredential.setCertSha256Fingerprint(certSha256Fingerprint); + credential.setCertCredential(certCredential); + Credential.SimCredential simCredential = new Credential.SimCredential(); + simCredential.setImsi("imsi"); + simCredential.setEapType(24); + credential.setSimCredential(simCredential); + credential.setCaCertificate(FakeKeys.CA_CERT0); + config.setCredential(credential); + return config; + } + + /** + * Verify a valid installation file is parsed successfully with the matching contents. + * + * @throws Exception + */ + public void testParseConfigFile() throws Exception { + String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT); + PasspointConfiguration expectedConfig = generateConfigurationFromProfile(); + PasspointConfiguration actualConfig = + ConfigParser.parsePasspointConfig( + "application/x-wifi-config", configStr.getBytes()); + assertTrue(actualConfig.equals(expectedConfig)); + } +} \ No newline at end of file diff --git a/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java b/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java new file mode 100644 index 0000000000..5eccc0d0bb --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2017 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.wifi.cts; + +import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.hotspot2.omadm.PpsMoParser; +import android.net.wifi.hotspot2.pps.Credential; +import android.net.wifi.hotspot2.pps.HomeSp; +import android.net.wifi.hotspot2.pps.Policy; +import android.net.wifi.hotspot2.pps.UpdateParameter; +import android.test.AndroidTestCase; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * CTS tests for PPS MO (PerProviderSubscription Management Object) XML string parsing API. + */ +public class PpsMoParserTest extends AndroidTestCase { + private static final String PPS_MO_XML_FILE = "assets/PerProviderSubscription.xml"; + + /** + * Read the content of the given resource file into a String. + * + * @param filename String name of the file + * @return String + * @throws IOException + */ + private String loadResourceFile(String filename) throws IOException { + InputStream in = getClass().getClassLoader().getResourceAsStream(filename); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line).append("\n"); + } + return builder.toString(); + } + + /** + * Generate a {@link PasspointConfiguration} that matches the configuration specified in the + * XML file {@link #PPS_MO_XML_FILE}. + * + * @return {@link PasspointConfiguration} + */ + private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception { + DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + byte[] certFingerprint = new byte[32]; + Arrays.fill(certFingerprint, (byte) 0x1f); + + PasspointConfiguration config = new PasspointConfiguration(); + config.setUpdateIdentifier(12); + config.setCredentialPriority(99); + + // AAA Server trust root. + Map trustRootCertList = new HashMap<>(); + trustRootCertList.put("server1.trust.root.com", certFingerprint); + config.setTrustRootCertList(trustRootCertList); + + // Subscription update. + UpdateParameter subscriptionUpdate = new UpdateParameter(); + subscriptionUpdate.setUpdateIntervalInMinutes(120); + subscriptionUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP); + subscriptionUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER); + subscriptionUpdate.setServerUri("subscription.update.com"); + subscriptionUpdate.setUsername("subscriptionUser"); + subscriptionUpdate.setBase64EncodedPassword("subscriptionPass"); + subscriptionUpdate.setTrustRootCertUrl("subscription.update.cert.com"); + subscriptionUpdate.setTrustRootCertSha256Fingerprint(certFingerprint); + config.setSubscriptionUpdate(subscriptionUpdate); + + // Subscription parameters. + config.setSubscriptionCreationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime()); + config.setSubscriptionExpirationTimeInMs(format.parse("2016-03-01T10:00:00Z").getTime()); + config.setSubscriptionType("Gold"); + config.setUsageLimitDataLimit(921890); + config.setUsageLimitStartTimeInMs(format.parse("2016-12-01T10:00:00Z").getTime()); + config.setUsageLimitTimeLimitInMinutes(120); + config.setUsageLimitUsageTimePeriodInMinutes(99910); + + // HomeSP configuration. + HomeSp homeSp = new HomeSp(); + homeSp.setFriendlyName("Century House"); + homeSp.setFqdn("mi6.co.uk"); + homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L}); + homeSp.setIconUrl("icon.test.com"); + Map homeNetworkIds = new HashMap<>(); + homeNetworkIds.put("TestSSID", 0x12345678L); + homeNetworkIds.put("NullHESSID", null); + homeSp.setHomeNetworkIds(homeNetworkIds); + homeSp.setMatchAllOis(new long[] {0x11223344}); + homeSp.setMatchAnyOis(new long[] {0x55667788}); + homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"}); + config.setHomeSp(homeSp); + + // Credential configuration. + Credential credential = new Credential(); + credential.setCreationTimeInMs(format.parse("2016-01-01T10:00:00Z").getTime()); + credential.setExpirationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime()); + credential.setRealm("shaken.stirred.com"); + credential.setCheckAaaServerCertStatus(true); + Credential.UserCredential userCredential = new Credential.UserCredential(); + userCredential.setUsername("james"); + userCredential.setPassword("Ym9uZDAwNw=="); + userCredential.setMachineManaged(true); + userCredential.setSoftTokenApp("TestApp"); + userCredential.setAbleToShare(true); + userCredential.setEapType(21); + userCredential.setNonEapInnerMethod("MS-CHAP-V2"); + credential.setUserCredential(userCredential); + Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); + certCredential.setCertType("x509v3"); + certCredential.setCertSha256Fingerprint(certFingerprint); + credential.setCertCredential(certCredential); + Credential.SimCredential simCredential = new Credential.SimCredential(); + simCredential.setImsi("imsi"); + simCredential.setEapType(24); + credential.setSimCredential(simCredential); + config.setCredential(credential); + + // Policy configuration. + Policy policy = new Policy(); + List preferredRoamingPartnerList = new ArrayList<>(); + Policy.RoamingPartner partner1 = new Policy.RoamingPartner(); + partner1.setFqdn("test1.fqdn.com"); + partner1.setFqdnExactMatch(true); + partner1.setPriority(127); + partner1.setCountries("us,fr"); + Policy.RoamingPartner partner2 = new Policy.RoamingPartner(); + partner2.setFqdn("test2.fqdn.com"); + partner2.setFqdnExactMatch(false); + partner2.setPriority(200); + partner2.setCountries("*"); + preferredRoamingPartnerList.add(partner1); + preferredRoamingPartnerList.add(partner2); + policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList); + policy.setMinHomeDownlinkBandwidth(23412); + policy.setMinHomeUplinkBandwidth(9823); + policy.setMinRoamingDownlinkBandwidth(9271); + policy.setMinRoamingUplinkBandwidth(2315); + policy.setExcludedSsidList(new String[] {"excludeSSID"}); + Map requiredProtoPortMap = new HashMap<>(); + requiredProtoPortMap.put(12, "34,92,234"); + policy.setRequiredProtoPortMap(requiredProtoPortMap); + policy.setMaximumBssLoadValue(23); + UpdateParameter policyUpdate = new UpdateParameter(); + policyUpdate.setUpdateIntervalInMinutes(120); + policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM); + policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP); + policyUpdate.setServerUri("policy.update.com"); + policyUpdate.setUsername("updateUser"); + policyUpdate.setBase64EncodedPassword("updatePass"); + policyUpdate.setTrustRootCertUrl("update.cert.com"); + policyUpdate.setTrustRootCertSha256Fingerprint(certFingerprint); + policy.setPolicyUpdate(policyUpdate); + config.setPolicy(policy); + return config; + } + + /** + * Parse and verify all supported fields under PPS MO tree. + * + * @throws Exception + */ + public void testParsePPSMOTree() throws Exception { + String ppsMoTree = loadResourceFile(PPS_MO_XML_FILE); + PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree(); + PasspointConfiguration actualConfig = PpsMoParser.parseMoText(ppsMoTree); + assertTrue(actualConfig.equals(expectedConfig)); + } +} From 5dc4e9b091bbd1c5a7dc830cbf3a26136a8e65f6 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Mon, 27 Feb 2017 13:19:22 -0800 Subject: [PATCH 0313/1415] [AWARE] Initial CTS: availability API + broadcast Initial CTS tests for Wi-Fi Aware: - Add CTS test class for Wi-Fi Aware - Setup/initialize - Test the availablity API + broadcast Bug: 30556108 Test: builds, CTS runs (test fails as expected) Change-Id: Ibbc58c3ed7a9ad7312864d038fd34c7202222e82 --- .../net/wifi/aware/cts/SingleDeviceTest.java | 152 ++++++++++++++++++ .../android/net/wifi/aware/cts/TestUtils.java | 36 +++++ 2 files changed, 188 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java create mode 100644 tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java new file mode 100644 index 0000000000..536e885c3a --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2017 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.wifi.aware.cts; + +import static android.net.wifi.aware.cts.TestUtils.shouldTestWifiAware; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.WifiManager; +import android.net.wifi.aware.Characteristics; +import android.net.wifi.aware.WifiAwareManager; +import android.test.AndroidTestCase; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Wi-Fi Aware CTS test suite: single device testing. Performs tests on a single + * device to validate Wi-Fi Aware. + */ +public class SingleDeviceTest extends AndroidTestCase { + static private final String TAG = "WifiAwareCtsTests"; + + // wait for Wi-Fi Aware to become available + static private final int WAIT_FOR_AWARE_CHANGE_SECS = 10; + + private WifiAwareManager mWifiAwareManager; + private WifiManager mWifiManager; + private WifiManager.WifiLock mWifiLock; + + private class WifiAwareBroadcastReceiver extends BroadcastReceiver { + private CountDownLatch mBlocker = new CountDownLatch(1); + + @Override + public void onReceive(Context context, Intent intent) { + if (WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED.equals(intent.getAction())) { + mBlocker.countDown(); + } + } + + boolean waitForStateChange() throws InterruptedException { + return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + if (!shouldTestWifiAware(getContext())) { + return; + } + + mWifiAwareManager = (WifiAwareManager) getContext().getSystemService( + Context.WIFI_AWARE_SERVICE); + assertNotNull("Wi-Fi Aware Manager", mWifiAwareManager); + + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + assertNotNull("Wi-Fi Manager", mWifiManager); + mWifiLock = mWifiManager.createWifiLock(TAG); + mWifiLock.acquire(); + if (!mWifiManager.isWifiEnabled()) { + mWifiManager.setWifiEnabled(true); + } + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); + WifiAwareBroadcastReceiver receiver = new WifiAwareBroadcastReceiver(); + mContext.registerReceiver(receiver, intentFilter); + if (!mWifiAwareManager.isAvailable()) { + assertTrue("Timeout waiting for Wi-Fi Aware to change status", + receiver.waitForStateChange()); + assertTrue("Wi-Fi Aware is not available (should be)", mWifiAwareManager.isAvailable()); + } + } + + @Override + protected void tearDown() throws Exception { + if (!shouldTestWifiAware(getContext())) { + super.tearDown(); + return; + } + + super.tearDown(); + } + + /** + * Validate: + * - Characteristics are available + * - Characteristics values are legitimate. Not in the CDD. However, the tested values are + * based on the Wi-Fi Aware protocol. + */ + public void testCharacteristics() { + if (!shouldTestWifiAware(getContext())) { + return; + } + + Characteristics characteristics = mWifiAwareManager.getCharacteristics(); + assertNotNull("Wi-Fi Aware characteristics are null", characteristics); + assertEquals("Service Name Length", characteristics.getMaxServiceNameLength(), 255); + assertEquals("Service Specific Information Length", + characteristics.getMaxServiceSpecificInfoLength(), 255); + assertEquals("Match Filter Length", characteristics.getMaxMatchFilterLength(), 255); + } + + /** + * Validate that on Wi-Fi Aware availability change we get a broadcast + the API returns + * correct status. + */ + public void testAvailabilityStatusChange() throws Exception { + if (!shouldTestWifiAware(getContext())) { + return; + } + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); + + // 1. Disable Wi-Fi + WifiAwareBroadcastReceiver receiver1 = new WifiAwareBroadcastReceiver(); + mContext.registerReceiver(receiver1, intentFilter); + mWifiManager.setWifiEnabled(false); + + assertTrue("Timeout waiting for Wi-Fi Aware to change status", + receiver1.waitForStateChange()); + assertFalse("Wi-Fi Aware is available (should not be)", mWifiAwareManager.isAvailable()); + + // 2. Enable Wi-Fi + WifiAwareBroadcastReceiver receiver2 = new WifiAwareBroadcastReceiver(); + mContext.registerReceiver(receiver2, intentFilter); + mWifiManager.setWifiEnabled(true); + + assertTrue("Timeout waiting for Wi-Fi Aware to change status", + receiver2.waitForStateChange()); + assertTrue("Wi-Fi Aware is not available (should be)", mWifiAwareManager.isAvailable()); + } +} diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java b/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java new file mode 100644 index 0000000000..ff9a5d2118 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 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.wifi.aware.cts; + +import android.content.Context; +import android.content.pm.PackageManager; + +/** + * Test utilities for Wi-Fi Aware CTS test suite. + */ +public class TestUtils { + static final String TAG = "WifiAwareCtsTests"; + + /** + * Returns a flag indicating whether or not Wi-Fi Aware should be tested. Wi-Fi Aware + * should be tested if the feature is supported on the current device. + */ + public static boolean shouldTestWifiAware(Context context) { + final PackageManager pm = context.getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE); + } +} From 08a2758524274446fc45631aef1026af423589d8 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Tue, 28 Feb 2017 18:00:47 -0800 Subject: [PATCH 0314/1415] [AWARE] CTS for attaching to session + MAC address Add CTS to verify initial session attach: - Basic attach - Attach with identity callback: use to verify MAC address change on subsequent attach. Bug: 30556108 Test: CTS tests pass/fail per expectations Change-Id: I8c2d29be81bef600a2c9eac99868326473d72b6e --- .../net/wifi/aware/cts/SingleDeviceTest.java | 170 +++++++++++++++++- .../android/net/wifi/aware/cts/TestUtils.java | 37 +++- 2 files changed, 198 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java index 536e885c3a..bea4500855 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -16,17 +16,22 @@ package android.net.wifi.aware.cts; -import static android.net.wifi.aware.cts.TestUtils.shouldTestWifiAware; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.WifiManager; +import android.net.wifi.aware.AttachCallback; import android.net.wifi.aware.Characteristics; +import android.net.wifi.aware.IdentityChangedListener; import android.net.wifi.aware.WifiAwareManager; +import android.net.wifi.aware.WifiAwareSession; import android.test.AndroidTestCase; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -35,15 +40,20 @@ import java.util.concurrent.TimeUnit; * device to validate Wi-Fi Aware. */ public class SingleDeviceTest extends AndroidTestCase { - static private final String TAG = "WifiAwareCtsTests"; + private static final String TAG = "WifiAwareCtsTests"; // wait for Wi-Fi Aware to become available static private final int WAIT_FOR_AWARE_CHANGE_SECS = 10; + private final Object mLock = new Object(); + private WifiAwareManager mWifiAwareManager; private WifiManager mWifiManager; private WifiManager.WifiLock mWifiLock; + // used to store any WifiAwareSession allocated during tests - will clean-up after tests + private List mSessions = new ArrayList<>(); + private class WifiAwareBroadcastReceiver extends BroadcastReceiver { private CountDownLatch mBlocker = new CountDownLatch(1); @@ -59,11 +69,92 @@ public class SingleDeviceTest extends AndroidTestCase { } }; + private class AttachCallbackTest extends AttachCallback { + static final int ATTACHED = 0; + static final int ATTACH_FAILED = 1; + static final int ERROR = 2; // no callback: timeout, interruption + + private CountDownLatch mBlocker = new CountDownLatch(1); + private int mCallbackCalled = ERROR; // garbage init + private WifiAwareSession mSession = null; + + @Override + public void onAttached(WifiAwareSession session) { + mCallbackCalled = ATTACHED; + mSession = session; + synchronized (mLock) { + mSessions.add(session); + } + mBlocker.countDown(); + } + + @Override + public void onAttachFailed() { + mCallbackCalled = ATTACH_FAILED; + mBlocker.countDown(); + } + + /** + * Waits for any of the callbacks to be called - or an error (timeout, interruption). + * Returns one of the ATTACHED, ATTACH_FAILED, or ERROR values. + */ + int waitForAnyCallback() { + try { + boolean noTimeout = mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); + if (noTimeout) { + return mCallbackCalled; + } else { + return ERROR; + } + } catch (InterruptedException e) { + return ERROR; + } + } + + /** + * Access the session created by a callback. Only useful to be called after calling + * waitForAnyCallback() and getting the ATTACHED code back. + */ + WifiAwareSession getSession() { + return mSession; + } + } + + private class IdentityChangedListenerTest extends IdentityChangedListener { + private CountDownLatch mBlocker = new CountDownLatch(1); + private byte[] mMac = null; + + @Override + public void onIdentityChanged(byte[] mac) { + mMac = mac; + mBlocker.countDown(); + } + + /** + * Waits for the listener callback to be called - or an error (timeout, interruption). + * Returns true on callback called, false on error (timeout, interruption). + */ + boolean waitForListener() { + try { + return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + return false; + } + } + + /** + * Returns the MAC address of the discovery interface supplied to the triggered callback. + */ + byte[] getMac() { + return mMac; + } + } + @Override protected void setUp() throws Exception { super.setUp(); - if (!shouldTestWifiAware(getContext())) { + if (!TestUtils.shouldTestWifiAware(getContext())) { return; } @@ -92,11 +183,19 @@ public class SingleDeviceTest extends AndroidTestCase { @Override protected void tearDown() throws Exception { - if (!shouldTestWifiAware(getContext())) { + if (!TestUtils.shouldTestWifiAware(getContext())) { super.tearDown(); return; } + synchronized (mLock) { + for (WifiAwareSession session : mSessions) { + // no damage from destroying twice (i.e. ok if test cleaned up after itself already) + session.destroy(); + } + mSessions.clear(); + } + super.tearDown(); } @@ -107,7 +206,7 @@ public class SingleDeviceTest extends AndroidTestCase { * based on the Wi-Fi Aware protocol. */ public void testCharacteristics() { - if (!shouldTestWifiAware(getContext())) { + if (!TestUtils.shouldTestWifiAware(getContext())) { return; } @@ -124,7 +223,7 @@ public class SingleDeviceTest extends AndroidTestCase { * correct status. */ public void testAvailabilityStatusChange() throws Exception { - if (!shouldTestWifiAware(getContext())) { + if (!TestUtils.shouldTestWifiAware(getContext())) { return; } @@ -149,4 +248,61 @@ public class SingleDeviceTest extends AndroidTestCase { receiver2.waitForStateChange()); assertTrue("Wi-Fi Aware is not available (should be)", mWifiAwareManager.isAvailable()); } + + /** + * Validate that can attach to Wi-Fi Aware. + */ + public void testAttachNoIdentity() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + AttachCallbackTest attachCb = new AttachCallbackTest(); + mWifiAwareManager.attach(attachCb, null); + int cbCalled = attachCb.waitForAnyCallback(); + assertEquals("Wi-Fi Aware attach", AttachCallbackTest.ATTACHED, cbCalled); + + WifiAwareSession session = attachCb.getSession(); + assertNotNull("Wi-Fi Aware session", session); + + session.destroy(); + } + + /** + * Validate that can attach to Wi-Fi Aware and get identity information. Use the identity + * information to validate that MAC address changes on every attach. + * + * Note: relies on no other entity using Wi-Fi Aware during the CTS test. Since if it is used + * then the attach/destroy will not correspond to enable/disable and will not result in a new + * MAC address being generated. + */ + public void testAttachDiscoveryAddressChanges() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + final int numIterations = 10; + Set macs = new HashSet<>(); + + for (int i = 0; i < numIterations; ++i) { + AttachCallbackTest attachCb = new AttachCallbackTest(); + IdentityChangedListenerTest identityL = new IdentityChangedListenerTest(); + mWifiAwareManager.attach(attachCb, identityL, null); + assertEquals("Wi-Fi Aware attach: iteration " + i, AttachCallbackTest.ATTACHED, + attachCb.waitForAnyCallback()); + assertTrue("Wi-Fi Aware attach: iteration " + i, identityL.waitForListener()); + + WifiAwareSession session = attachCb.getSession(); + assertNotNull("Wi-Fi Aware session: iteration " + i, session); + + byte[] mac = identityL.getMac(); + assertNotNull("Wi-Fi Aware discovery MAC: iteration " + i, mac); + + session.destroy(); + + macs.add(new TestUtils.MacWrapper(mac)); + } + + assertEquals("", numIterations, macs.size()); + } } diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java b/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java index ff9a5d2118..a12c8bb0d2 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java @@ -19,18 +19,51 @@ package android.net.wifi.aware.cts; import android.content.Context; import android.content.pm.PackageManager; +import java.util.Arrays; + /** * Test utilities for Wi-Fi Aware CTS test suite. */ -public class TestUtils { +class TestUtils { static final String TAG = "WifiAwareCtsTests"; /** * Returns a flag indicating whether or not Wi-Fi Aware should be tested. Wi-Fi Aware * should be tested if the feature is supported on the current device. */ - public static boolean shouldTestWifiAware(Context context) { + static boolean shouldTestWifiAware(Context context) { final PackageManager pm = context.getPackageManager(); return pm.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE); } + + /** + * Wraps a byte[] (MAC address representation). Intended to provide hash and equality operators + * so that the MAC address can be used in containers. + */ + static class MacWrapper { + private byte[] mMac; + + MacWrapper(byte[] mac) { + mMac = mac; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof MacWrapper)) { + return false; + } + + MacWrapper lhs = (MacWrapper) o; + return Arrays.equals(mMac, lhs.mMac); + } + + @Override + public int hashCode() { + return Arrays.hashCode(mMac); + } + } } From 87b18c3df13e50e30e9faf6df95009d3b7b667cf Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Tue, 6 Dec 2016 09:57:59 -0800 Subject: [PATCH 0315/1415] [CM] CTS tests for requestNetwork APIs Add CTS tests for: - requestNetwork API: test onAvailable - requestNetwork with timeout API: test onUnavailable (failure) Bug: 31399536 Test: CTS tests passing Change-Id: I3565ef375ec90f90b2c76aabee14bf993251eeef --- .../net/cts/ConnectivityManagerTest.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 185ebfa0fc..24871ca156 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -18,6 +18,7 @@ package android.net.cts; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -383,6 +384,57 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + /** + * Exercises the requestNetwork with NetworkCallback API. This checks to + * see if we get a callback for an INTERNET request. + */ + public void testRequestNetworkCallback() { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.requestNetwork(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), callback); + + try { + // Wait to get callback for availability of internet + Network internetNetwork = callback.waitForAvailable(); + assertNotNull("Did not receive NetworkCallback#onAvailable for INTERNET", + internetNetwork); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + } + } + + /** + * Exercises the requestNetwork with NetworkCallback API with timeout - expected to + * fail. Use WIFI and switch Wi-Fi off. + */ + public void testRequestNetworkCallback_onUnavailable() { + final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); + if (previousWifiEnabledState) { + disconnectFromWifi(null); + } + + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.requestNetwork(new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .build(), 100, callback); + + try { + // Wait to get callback for unavailability of requested network + assertTrue("Did not receive NetworkCallback#onUnavailable", + callback.waitForUnavailable()); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + if (previousWifiEnabledState) { + connectToWifi(); + } + } + } + /** * Tests reporting of connectivity changed. */ @@ -639,6 +691,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { private final CountDownLatch mAvailableLatch = new CountDownLatch(1); private final CountDownLatch mLostLatch = new CountDownLatch(1); + private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); public Network currentNetwork; public Network lastLostNetwork; @@ -651,6 +704,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; } + public boolean waitForUnavailable() throws InterruptedException { + return mUnavailableLatch.await(2, TimeUnit.SECONDS); + } + + @Override public void onAvailable(Network network) { currentNetwork = network; @@ -665,6 +723,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { } mLostLatch.countDown(); } + + @Override + public void onUnavailable() { + mUnavailableLatch.countDown(); + } } private Network getWifiNetwork() { From a9f33d578d764d6bb0a4e86d8fa31e1c799181b4 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 2 Mar 2017 12:35:34 -0800 Subject: [PATCH 0316/1415] [AWARE] CTS tests for publish/subscribe discovery Validate the SUCCESS case of publish and subscribe discovery sessions. Bug: 30556108 Test: CTS tests pass Change-Id: Ib88606cdf662560258890e2f274c85c3a8818206 --- .../net/wifi/aware/cts/SingleDeviceTest.java | 252 +++++++++++++++++- 1 file changed, 244 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java index bea4500855..37c0ac5892 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -23,13 +23,21 @@ import android.content.IntentFilter; import android.net.wifi.WifiManager; import android.net.wifi.aware.AttachCallback; import android.net.wifi.aware.Characteristics; +import android.net.wifi.aware.DiscoverySessionCallback; import android.net.wifi.aware.IdentityChangedListener; +import android.net.wifi.aware.PeerHandle; +import android.net.wifi.aware.PublishConfig; +import android.net.wifi.aware.PublishDiscoverySession; +import android.net.wifi.aware.SubscribeConfig; +import android.net.wifi.aware.SubscribeDiscoverySession; import android.net.wifi.aware.WifiAwareManager; import android.net.wifi.aware.WifiAwareSession; import android.test.AndroidTestCase; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -150,6 +158,140 @@ public class SingleDeviceTest extends AndroidTestCase { } } + private class DiscoverySessionCallbackTest extends DiscoverySessionCallback { + static final int ON_PUBLISH_STARTED = 0; + static final int ON_SUBSCRIBE_STARTED = 1; + static final int ON_SESSION_CONFIG_UPDATED = 2; + static final int ON_SESSION_CONFIG_FAILED = 3; + static final int ON_SESSION_TERMINATED = 4; + static final int ON_SERVICE_DISCOVERED = 5; + static final int ON_MESSAGE_SEND_SUCCEEDED = 6; + static final int ON_MESSAGE_SEND_FAILED = 7; + static final int ON_MESSAGE_RECEIVED = 8; + + private final Object mLocalLock = new Object(); + + private CountDownLatch mBlocker; + private int mCurrentWaitForCallback; + private ArrayDeque mCallbackQueue = new ArrayDeque<>(); + + private PublishDiscoverySession mPublishDiscoverySession; + private SubscribeDiscoverySession mSubscribeDiscoverySession; + + private void processCallback(int callback) { + synchronized (mLocalLock) { + if (mBlocker != null && mCurrentWaitForCallback == callback) { + mBlocker.countDown(); + } else { + mCallbackQueue.addLast(callback); + } + } + } + + @Override + public void onPublishStarted(PublishDiscoverySession session) { + mPublishDiscoverySession = session; + processCallback(ON_PUBLISH_STARTED); + } + + @Override + public void onSubscribeStarted(SubscribeDiscoverySession session) { + mSubscribeDiscoverySession = session; + processCallback(ON_SUBSCRIBE_STARTED); + } + + @Override + public void onSessionConfigUpdated() { + processCallback(ON_SESSION_CONFIG_UPDATED); + } + + @Override + public void onSessionConfigFailed() { + processCallback(ON_SESSION_CONFIG_FAILED); + } + + @Override + public void onSessionTerminated() { + processCallback(ON_SESSION_TERMINATED); + } + + @Override + public void onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo, + List matchFilter) { + processCallback(ON_SERVICE_DISCOVERED); + } + + @Override + public void onMessageSendSucceeded(int messageId) { + processCallback(ON_MESSAGE_SEND_SUCCEEDED); + } + + @Override + public void onMessageSendFailed(int messageId) { + processCallback(ON_MESSAGE_SEND_FAILED); + } + + @Override + public void onMessageReceived(PeerHandle peerHandle, byte[] message) { + processCallback(ON_MESSAGE_RECEIVED); + } + + /** + * Wait for the specified callback - any of the ON_* constants. Returns a true + * on success (specified callback triggered) or false on failure (timed-out or + * interrupted while waiting for the requested callback). + * + * Note: other callbacks happening while while waiting for the specified callback will + * be queued. + */ + boolean waitForCallback(int callback) { + synchronized (mLocalLock) { + boolean found = mCallbackQueue.remove(callback); + if (found) { + return true; + } + + mCurrentWaitForCallback = callback; + mBlocker = new CountDownLatch(1); + } + + try { + return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + return false; + } + } + + /** + * Indicates whether the specified callback (any of the ON_* constants) has already + * happened and in the queue. Useful when the order of events is important. + */ + boolean hasCallbackAlreadyHappened(int callback) { + synchronized (mLocalLock) { + return mCallbackQueue.contains(callback); + } + } + + /** + * Returns the last created publish discovery session. + */ + PublishDiscoverySession getPublishDiscoverySession() { + PublishDiscoverySession session = mPublishDiscoverySession; + mPublishDiscoverySession = null; + return session; + } + + /** + * Returns the last created subscribe discovery session. + */ + SubscribeDiscoverySession getSubscribeDiscoverySession() { + SubscribeDiscoverySession session = mSubscribeDiscoverySession; + mSubscribeDiscoverySession = null; + return session; + } + + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -257,14 +399,7 @@ public class SingleDeviceTest extends AndroidTestCase { return; } - AttachCallbackTest attachCb = new AttachCallbackTest(); - mWifiAwareManager.attach(attachCb, null); - int cbCalled = attachCb.waitForAnyCallback(); - assertEquals("Wi-Fi Aware attach", AttachCallbackTest.ATTACHED, cbCalled); - - WifiAwareSession session = attachCb.getSession(); - assertNotNull("Wi-Fi Aware session", session); - + WifiAwareSession session = attachAndGetSession(); session.destroy(); } @@ -305,4 +440,105 @@ public class SingleDeviceTest extends AndroidTestCase { assertEquals("", numIterations, macs.size()); } + + /** + * Validate a successful publish discovery session lifetime: publish, update publish, destroy. + */ + public void testPublishDiscoverySuccess() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + final String serviceName = "ValidName"; + + WifiAwareSession session = attachAndGetSession(); + + PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( + serviceName).build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + + // 1. publish + session.publish(publishConfig, discoveryCb, null); + assertTrue("Publish started", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); + PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); + assertNotNull("Publish session", discoverySession); + + // 2. update-publish + publishConfig = new PublishConfig.Builder().setServiceName( + serviceName).setServiceSpecificInfo("extras".getBytes()).build(); + discoverySession.updatePublish(publishConfig); + assertTrue("Publish update", discoveryCb.waitForCallback( + DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); + + // 3. destroy + assertFalse("Publish not terminated", discoveryCb.hasCallbackAlreadyHappened( + DiscoverySessionCallbackTest.ON_SESSION_TERMINATED)); + discoverySession.destroy(); + + // 4. try update post-destroy: should time-out waiting for cb + discoverySession.updatePublish(publishConfig); + assertFalse("Publish update post destroy", discoveryCb.waitForCallback( + DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); + + session.destroy(); + } + + /** + * Validate a successful subscribe discovery session lifetime: subscribe, update subscribe, + * destroy. + */ + public void testSubscribeDiscoverySuccess() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + final String serviceName = "ValidName"; + + WifiAwareSession session = attachAndGetSession(); + + SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName( + serviceName).build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + + // 1. subscribe + session.subscribe(subscribeConfig, discoveryCb, null); + assertTrue("Subscribe started", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SUBSCRIBE_STARTED)); + SubscribeDiscoverySession discoverySession = discoveryCb.getSubscribeDiscoverySession(); + assertNotNull("Subscribe session", discoverySession); + + // 2. update-subscribe + subscribeConfig = new SubscribeConfig.Builder().setServiceName( + serviceName).setServiceSpecificInfo("extras".getBytes()).build(); + discoverySession.updateSubscribe(subscribeConfig); + assertTrue("Subscribe update", discoveryCb.waitForCallback( + DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); + + // 3. destroy + assertFalse("Subscribe not terminated", discoveryCb.hasCallbackAlreadyHappened( + DiscoverySessionCallbackTest.ON_SESSION_TERMINATED)); + discoverySession.destroy(); + + // 4. try update post-destroy: should time-out waiting for cb + discoverySession.updateSubscribe(subscribeConfig); + assertFalse("Subscribe update post destroy", discoveryCb.waitForCallback( + DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); + + session.destroy(); + } + + // local utilities + + WifiAwareSession attachAndGetSession() { + AttachCallbackTest attachCb = new AttachCallbackTest(); + mWifiAwareManager.attach(attachCb, null); + int cbCalled = attachCb.waitForAnyCallback(); + assertEquals("Wi-Fi Aware attach", AttachCallbackTest.ATTACHED, cbCalled); + + WifiAwareSession session = attachCb.getSession(); + assertNotNull("Wi-Fi Aware session", session); + + return session; + } } From ab5186e4f64233d72c1ea75716f7581d4b0f5ed9 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 2 Mar 2017 13:54:14 -0800 Subject: [PATCH 0317/1415] [AWARE] CTS for failure mode of send message API Test that sending a message with invalid peer handle (null) fails as expected. Note: limited testing - Single device testing doesn't have a peer - Cannot create an invalid peer handle since opaque object Bug: 30556108 Test: CTS tests pass Change-Id: I72f4b67ea3c3dfc00aa48f6601d064b406dabde7 --- .../net/wifi/aware/cts/SingleDeviceTest.java | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java index 37c0ac5892..ab87815399 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -75,7 +75,7 @@ public class SingleDeviceTest extends AndroidTestCase { boolean waitForStateChange() throws InterruptedException { return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); } - }; + } private class AttachCallbackTest extends AttachCallback { static final int ATTACHED = 0; @@ -289,7 +289,6 @@ public class SingleDeviceTest extends AndroidTestCase { mSubscribeDiscoverySession = null; return session; } - } @Override @@ -528,9 +527,43 @@ public class SingleDeviceTest extends AndroidTestCase { session.destroy(); } + /** + * Test the send message flow. Since testing single device cannot send to a real peer - + * validate that sending to a bogus peer fails. + */ + public void testSendMessageFail() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + WifiAwareSession session = attachAndGetSession(); + + PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( + "ValidName").build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + + // 1. publish + session.publish(publishConfig, discoveryCb, null); + assertTrue("Publish started", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); + PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); + assertNotNull("Publish session", discoverySession); + + // 2. send a message with a null peer-handle - expect exception + try { + discoverySession.sendMessage(null, -1290, "some message".getBytes()); + fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // empty + } + + discoverySession.destroy(); + session.destroy(); + } + // local utilities - WifiAwareSession attachAndGetSession() { + private WifiAwareSession attachAndGetSession() { AttachCallbackTest attachCb = new AttachCallbackTest(); mWifiAwareManager.attach(attachCb, null); int cbCalled = attachCb.waitForAnyCallback(); From 12be803ccee1fa111615a9a9fade01f3e47807d8 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 2 Mar 2017 15:52:14 -0800 Subject: [PATCH 0318/1415] [AWARE] CTS for Aware data-path creation Test Aware data-path creation API flow - failure. Note: testing limited to failure since single device testing doesn't have a peer Bug: 30556108 Test: CTS tests pass Change-Id: Ie15ad57d7331b21fbb6706091691bd5f87e1264e --- .../net/wifi/aware/cts/SingleDeviceTest.java | 108 +++++++++++++++++- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java index ab87815399..fcd04541b4 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -20,6 +20,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.net.wifi.aware.AttachCallback; import android.net.wifi.aware.Characteristics; @@ -32,6 +35,8 @@ import android.net.wifi.aware.SubscribeConfig; import android.net.wifi.aware.SubscribeDiscoverySession; import android.net.wifi.aware.WifiAwareManager; import android.net.wifi.aware.WifiAwareSession; +import android.os.Handler; +import android.os.HandlerThread; import android.test.AndroidTestCase; import java.util.ArrayDeque; @@ -54,10 +59,17 @@ public class SingleDeviceTest extends AndroidTestCase { static private final int WAIT_FOR_AWARE_CHANGE_SECS = 10; private final Object mLock = new Object(); + private final HandlerThread mHandlerThread = new HandlerThread("SingleDeviceTest"); + private final Handler mHandler; + { + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + } private WifiAwareManager mWifiAwareManager; private WifiManager mWifiManager; private WifiManager.WifiLock mWifiLock; + private ConnectivityManager mConnectivityManager; // used to store any WifiAwareSession allocated during tests - will clean-up after tests private List mSessions = new ArrayList<>(); @@ -291,6 +303,27 @@ public class SingleDeviceTest extends AndroidTestCase { } } + private class NetworkCallbackTest extends ConnectivityManager.NetworkCallback { + private CountDownLatch mBlocker = new CountDownLatch(1); + + @Override + public void onUnavailable() { + mBlocker.countDown(); + } + + /** + * Wait for the onUnavailable() callback to be triggered. Returns true if triggered, + * otherwise (timed-out, interrupted) returns false. + */ + boolean waitForOnUnavailable() { + try { + return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + return false; + } + } + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -311,6 +344,10 @@ public class SingleDeviceTest extends AndroidTestCase { mWifiManager.setWifiEnabled(true); } + mConnectivityManager = (ConnectivityManager) getContext().getSystemService( + Context.CONNECTIVITY_SERVICE); + assertNotNull("Connectivity Manager", mConnectivityManager); + IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); WifiAwareBroadcastReceiver receiver = new WifiAwareBroadcastReceiver(); @@ -421,7 +458,7 @@ public class SingleDeviceTest extends AndroidTestCase { for (int i = 0; i < numIterations; ++i) { AttachCallbackTest attachCb = new AttachCallbackTest(); IdentityChangedListenerTest identityL = new IdentityChangedListenerTest(); - mWifiAwareManager.attach(attachCb, identityL, null); + mWifiAwareManager.attach(attachCb, identityL, mHandler); assertEquals("Wi-Fi Aware attach: iteration " + i, AttachCallbackTest.ATTACHED, attachCb.waitForAnyCallback()); assertTrue("Wi-Fi Aware attach: iteration " + i, identityL.waitForListener()); @@ -457,7 +494,7 @@ public class SingleDeviceTest extends AndroidTestCase { DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); // 1. publish - session.publish(publishConfig, discoveryCb, null); + session.publish(publishConfig, discoveryCb, mHandler); assertTrue("Publish started", discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); @@ -501,7 +538,7 @@ public class SingleDeviceTest extends AndroidTestCase { DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); // 1. subscribe - session.subscribe(subscribeConfig, discoveryCb, null); + session.subscribe(subscribeConfig, discoveryCb, mHandler); assertTrue("Subscribe started", discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SUBSCRIBE_STARTED)); SubscribeDiscoverySession discoverySession = discoveryCb.getSubscribeDiscoverySession(); @@ -543,7 +580,7 @@ public class SingleDeviceTest extends AndroidTestCase { DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); // 1. publish - session.publish(publishConfig, discoveryCb, null); + session.publish(publishConfig, discoveryCb, mHandler); assertTrue("Publish started", discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); @@ -561,11 +598,72 @@ public class SingleDeviceTest extends AndroidTestCase { session.destroy(); } + /** + * Request an Aware data-path on a Publish discovery session (which can be done with a null + * peer - to accept all requests). Validate that times-out. + */ + public void testDataPathInContextOfDiscoveryFail() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + WifiAwareSession session = attachAndGetSession(); + + PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( + "ValidName").build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + NetworkCallbackTest networkCb = new NetworkCallbackTest(); + + // 1. publish + session.publish(publishConfig, discoveryCb, mHandler); + assertTrue("Publish started", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); + PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); + assertNotNull("Publish session", discoverySession); + + // 2. request an AWARE network + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( + discoverySession.createNetworkSpecifier(null, null)).build(); + mConnectivityManager.requestNetwork(nr, networkCb, 2000); + assertTrue("OnUnavailable received", networkCb.waitForOnUnavailable()); + + discoverySession.destroy(); + session.destroy(); + } + + /** + * Request an Aware data-path as a Responder with no peer MAC address (i.e. accept any peer + * request). Validate that times-out. + */ + public void testDataPathOutOfBandFail() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + WifiAwareSession session = attachAndGetSession(); + + PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( + "ValidName").build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + NetworkCallbackTest networkCb = new NetworkCallbackTest(); + + // 1. request an AWARE network + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( + session.createNetworkSpecifier( + WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, null, null)).build(); + mConnectivityManager.requestNetwork(nr, networkCb, 2000); + assertTrue("OnUnavailable received", networkCb.waitForOnUnavailable()); + + session.destroy(); + } + // local utilities private WifiAwareSession attachAndGetSession() { AttachCallbackTest attachCb = new AttachCallbackTest(); - mWifiAwareManager.attach(attachCb, null); + mWifiAwareManager.attach(attachCb, mHandler); int cbCalled = attachCb.waitForAnyCallback(); assertEquals("Wi-Fi Aware attach", AttachCallbackTest.ATTACHED, cbCalled); From 9602110a367d6c6e448d02ae68f95159f961aecb Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Wed, 8 Mar 2017 09:08:00 -0800 Subject: [PATCH 0319/1415] [AWARE] Update network creation tests open/encrypted API Updated/add CTS tests to validate createNetworkSpecifierXxx API for open and passphrase modules. As these are (still) single-ended CTS tests - they validate failure. Bug: 26564544 Test: CTS passing Change-Id: I07b76bee5a9b73780d341ac8511a2738ded751ca --- .../net/wifi/aware/cts/SingleDeviceTest.java | 81 ++++++++++++++++--- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java index fcd04541b4..1f7b31b078 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -599,10 +599,10 @@ public class SingleDeviceTest extends AndroidTestCase { } /** - * Request an Aware data-path on a Publish discovery session (which can be done with a null - * peer - to accept all requests). Validate that times-out. + * Request an Aware data-path (open) on a Publish discovery session (which can be done with a + * null peer - to accept all requests). Validate that times-out. */ - public void testDataPathInContextOfDiscoveryFail() { + public void testDataPathOpenInContextOfDiscoveryFail() { if (!TestUtils.shouldTestWifiAware(getContext())) { return; } @@ -624,7 +624,7 @@ public class SingleDeviceTest extends AndroidTestCase { // 2. request an AWARE network NetworkRequest nr = new NetworkRequest.Builder().addTransportType( NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( - discoverySession.createNetworkSpecifier(null, null)).build(); + discoverySession.createNetworkSpecifierOpen(null)).build(); mConnectivityManager.requestNetwork(nr, networkCb, 2000); assertTrue("OnUnavailable received", networkCb.waitForOnUnavailable()); @@ -633,10 +633,45 @@ public class SingleDeviceTest extends AndroidTestCase { } /** - * Request an Aware data-path as a Responder with no peer MAC address (i.e. accept any peer - * request). Validate that times-out. + * Request an Aware data-path (encrypted) on a Publish discovery session (which can be done + * with a null peer - to accept all requests). Validate that times-out. */ - public void testDataPathOutOfBandFail() { + public void testDataPathPassphraseInContextOfDiscoveryFail() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + WifiAwareSession session = attachAndGetSession(); + + PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( + "ValidName").build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + NetworkCallbackTest networkCb = new NetworkCallbackTest(); + + // 1. publish + session.publish(publishConfig, discoveryCb, mHandler); + assertTrue("Publish started", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); + PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); + assertNotNull("Publish session", discoverySession); + + // 2. request an AWARE network + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( + discoverySession.createNetworkSpecifierPassphrase(null, + "Some very long but not very good passphrase")).build(); + mConnectivityManager.requestNetwork(nr, networkCb, 2000); + assertTrue("OnUnavailable received", networkCb.waitForOnUnavailable()); + + discoverySession.destroy(); + session.destroy(); + } + + /** + * Request an Aware data-path (open) as a Responder with no peer MAC address (i.e. accept any + * peer request). Validate that times-out. + */ + public void testDataPathOpenOutOfBandFail() { if (!TestUtils.shouldTestWifiAware(getContext())) { return; } @@ -651,8 +686,36 @@ public class SingleDeviceTest extends AndroidTestCase { // 1. request an AWARE network NetworkRequest nr = new NetworkRequest.Builder().addTransportType( NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( - session.createNetworkSpecifier( - WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, null, null)).build(); + session.createNetworkSpecifierOpen( + WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, null)).build(); + mConnectivityManager.requestNetwork(nr, networkCb, 2000); + assertTrue("OnUnavailable received", networkCb.waitForOnUnavailable()); + + session.destroy(); + } + + /** + * Request an Aware data-path (encrypted) as a Responder with no peer MAC address (i.e. + * accept any peer request). Validate that times-out. + */ + public void testDataPathPassphraseOutOfBandFail() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + WifiAwareSession session = attachAndGetSession(); + + PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( + "ValidName").build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + NetworkCallbackTest networkCb = new NetworkCallbackTest(); + + // 1. request an AWARE network + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( + session.createNetworkSpecifierPassphrase( + WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, null, + "abcdefghihk")).build(); mConnectivityManager.requestNetwork(nr, networkCb, 2000); assertTrue("OnUnavailable received", networkCb.waitForOnUnavailable()); From 6bf853a9e158576ac0c11328877fa659313d0657 Mon Sep 17 00:00:00 2001 From: Peter Qiu Date: Thu, 9 Mar 2017 13:18:32 -0800 Subject: [PATCH 0320/1415] wifi: update callsite for Passpoint configuration management APIs The APIs are updated to not return a boolean status based on the API Councils comment. So update the callsite accordingly. Bug: 35858311 Test: make -j32 Change-Id: Ie9106ecddb2b15178ad37ec6f014d5cc7ce77c43 --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index d3dc8faadd..f05ff82f04 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -656,7 +656,7 @@ public class WifiManagerTest extends AndroidTestCase { * @param config The configuration to test with */ private void testAddPasspointConfig(PasspointConfiguration config) throws Exception { - assertTrue(mWifiManager.addOrUpdatePasspointConfiguration(config)); + mWifiManager.addOrUpdatePasspointConfiguration(config); // Certificates and keys will be set to null after it is installed to the KeyStore by // WifiManager. Reset them in the expected config so that it can be used to compare @@ -671,7 +671,7 @@ public class WifiManagerTest extends AndroidTestCase { assertEquals(config, configList.get(0)); // Remove the configuration and verify no installed configuration. - assertTrue(mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn())); + mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn()); assertTrue(mWifiManager.getPasspointConfigurations().isEmpty()); } } From d5fc89275d70e0ef600da80dbc1c1eba953de9aa Mon Sep 17 00:00:00 2001 From: Peter Qiu Date: Fri, 10 Mar 2017 12:35:59 -0800 Subject: [PATCH 0321/1415] wifi: hotspot2: verify getter methods Bug: 35756298 Test: run PpsMoParserTest Change-Id: Ib70bf59f76815e89ba0fc5d67a26502788e19c86 --- .../android/net/wifi/cts/PpsMoParserTest.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java b/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java index 5eccc0d0bb..b5e2f772d1 100644 --- a/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java @@ -73,110 +73,193 @@ public class PpsMoParserTest extends AndroidTestCase { PasspointConfiguration config = new PasspointConfiguration(); config.setUpdateIdentifier(12); + assertEquals(12, config.getUpdateIdentifier()); config.setCredentialPriority(99); + assertEquals(99, config.getCredentialPriority()); // AAA Server trust root. Map trustRootCertList = new HashMap<>(); trustRootCertList.put("server1.trust.root.com", certFingerprint); config.setTrustRootCertList(trustRootCertList); + assertEquals(trustRootCertList, config.getTrustRootCertList()); // Subscription update. UpdateParameter subscriptionUpdate = new UpdateParameter(); subscriptionUpdate.setUpdateIntervalInMinutes(120); + assertEquals(120, subscriptionUpdate.getUpdateIntervalInMinutes()); subscriptionUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP); + assertEquals(UpdateParameter.UPDATE_METHOD_SSP, subscriptionUpdate.getUpdateMethod()); subscriptionUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER); + assertEquals(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER, + subscriptionUpdate.getRestriction()); subscriptionUpdate.setServerUri("subscription.update.com"); + assertEquals("subscription.update.com", subscriptionUpdate.getServerUri()); subscriptionUpdate.setUsername("subscriptionUser"); + assertEquals("subscriptionUser", subscriptionUpdate.getUsername()); subscriptionUpdate.setBase64EncodedPassword("subscriptionPass"); + assertEquals("subscriptionPass", subscriptionUpdate.getBase64EncodedPassword()); subscriptionUpdate.setTrustRootCertUrl("subscription.update.cert.com"); + assertEquals("subscription.update.cert.com", subscriptionUpdate.getTrustRootCertUrl()); subscriptionUpdate.setTrustRootCertSha256Fingerprint(certFingerprint); + assertTrue(Arrays.equals(certFingerprint, + subscriptionUpdate.getTrustRootCertSha256Fingerprint())); config.setSubscriptionUpdate(subscriptionUpdate); + assertEquals(subscriptionUpdate, config.getSubscriptionUpdate()); // Subscription parameters. config.setSubscriptionCreationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime()); + assertEquals(format.parse("2016-02-01T10:00:00Z").getTime(), + config.getSubscriptionCreationTimeInMs()); config.setSubscriptionExpirationTimeInMs(format.parse("2016-03-01T10:00:00Z").getTime()); + assertEquals(format.parse("2016-03-01T10:00:00Z").getTime(), + config.getSubscriptionExpirationTimeInMs()); config.setSubscriptionType("Gold"); + assertEquals("Gold", config.getSubscriptionType()); config.setUsageLimitDataLimit(921890); + assertEquals(921890, config.getUsageLimitDataLimit()); config.setUsageLimitStartTimeInMs(format.parse("2016-12-01T10:00:00Z").getTime()); + assertEquals(format.parse("2016-12-01T10:00:00Z").getTime(), + config.getUsageLimitStartTimeInMs()); config.setUsageLimitTimeLimitInMinutes(120); + assertEquals(120, config.getUsageLimitTimeLimitInMinutes()); config.setUsageLimitUsageTimePeriodInMinutes(99910); + assertEquals(99910, config.getUsageLimitUsageTimePeriodInMinutes()); // HomeSP configuration. HomeSp homeSp = new HomeSp(); homeSp.setFriendlyName("Century House"); + assertEquals("Century House", homeSp.getFriendlyName()); homeSp.setFqdn("mi6.co.uk"); + assertEquals("mi6.co.uk", homeSp.getFqdn()); homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L}); + assertTrue(Arrays.equals(new long[] {0x112233L, 0x445566L}, + homeSp.getRoamingConsortiumOis())); homeSp.setIconUrl("icon.test.com"); + assertEquals("icon.test.com", homeSp.getIconUrl()); Map homeNetworkIds = new HashMap<>(); homeNetworkIds.put("TestSSID", 0x12345678L); homeNetworkIds.put("NullHESSID", null); homeSp.setHomeNetworkIds(homeNetworkIds); + assertEquals(homeNetworkIds, homeSp.getHomeNetworkIds()); homeSp.setMatchAllOis(new long[] {0x11223344}); + assertTrue(Arrays.equals(new long[] {0x11223344}, homeSp.getMatchAllOis())); homeSp.setMatchAnyOis(new long[] {0x55667788}); + assertTrue(Arrays.equals(new long[] {0x55667788}, homeSp.getMatchAnyOis())); homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"}); + assertTrue(Arrays.equals(new String[] {"other.fqdn.com"}, + homeSp.getOtherHomePartners())); config.setHomeSp(homeSp); + assertEquals(homeSp, config.getHomeSp()); // Credential configuration. Credential credential = new Credential(); credential.setCreationTimeInMs(format.parse("2016-01-01T10:00:00Z").getTime()); + assertEquals(format.parse("2016-01-01T10:00:00Z").getTime(), + credential.getCreationTimeInMs()); credential.setExpirationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime()); + assertEquals(format.parse("2016-02-01T10:00:00Z").getTime(), + credential.getExpirationTimeInMs()); credential.setRealm("shaken.stirred.com"); + assertEquals("shaken.stirred.com", credential.getRealm()); credential.setCheckAaaServerCertStatus(true); + assertTrue(credential.getCheckAaaServerCertStatus()); Credential.UserCredential userCredential = new Credential.UserCredential(); userCredential.setUsername("james"); + assertEquals("james", userCredential.getUsername()); userCredential.setPassword("Ym9uZDAwNw=="); + assertEquals("Ym9uZDAwNw==", userCredential.getPassword()); userCredential.setMachineManaged(true); + assertTrue(userCredential.getMachineManaged()); userCredential.setSoftTokenApp("TestApp"); + assertEquals("TestApp", userCredential.getSoftTokenApp()); userCredential.setAbleToShare(true); + assertTrue(userCredential.getAbleToShare()); userCredential.setEapType(21); + assertEquals(21, userCredential.getEapType()); userCredential.setNonEapInnerMethod("MS-CHAP-V2"); + assertEquals("MS-CHAP-V2", userCredential.getNonEapInnerMethod()); credential.setUserCredential(userCredential); + assertEquals(userCredential, credential.getUserCredential()); Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); certCredential.setCertType("x509v3"); + assertEquals("x509v3", certCredential.getCertType()); certCredential.setCertSha256Fingerprint(certFingerprint); + assertTrue(Arrays.equals(certFingerprint, certCredential.getCertSha256Fingerprint())); credential.setCertCredential(certCredential); + assertEquals(certCredential, credential.getCertCredential()); Credential.SimCredential simCredential = new Credential.SimCredential(); simCredential.setImsi("imsi"); + assertEquals("imsi", simCredential.getImsi()); simCredential.setEapType(24); + assertEquals(24, simCredential.getEapType()); credential.setSimCredential(simCredential); + assertEquals(simCredential, credential.getSimCredential()); config.setCredential(credential); + assertEquals(credential, config.getCredential()); // Policy configuration. Policy policy = new Policy(); List preferredRoamingPartnerList = new ArrayList<>(); Policy.RoamingPartner partner1 = new Policy.RoamingPartner(); partner1.setFqdn("test1.fqdn.com"); + assertEquals("test1.fqdn.com", partner1.getFqdn()); partner1.setFqdnExactMatch(true); + assertTrue(partner1.getFqdnExactMatch()); partner1.setPriority(127); + assertEquals(127, partner1.getPriority()); partner1.setCountries("us,fr"); + assertEquals("us,fr", partner1.getCountries()); Policy.RoamingPartner partner2 = new Policy.RoamingPartner(); partner2.setFqdn("test2.fqdn.com"); + assertEquals("test2.fqdn.com", partner2.getFqdn()); partner2.setFqdnExactMatch(false); + assertFalse(partner2.getFqdnExactMatch()); partner2.setPriority(200); + assertEquals(200, partner2.getPriority()); partner2.setCountries("*"); + assertEquals("*", partner2.getCountries()); preferredRoamingPartnerList.add(partner1); preferredRoamingPartnerList.add(partner2); policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList); + assertEquals(preferredRoamingPartnerList, policy.getPreferredRoamingPartnerList()); policy.setMinHomeDownlinkBandwidth(23412); + assertEquals(23412, policy.getMinHomeDownlinkBandwidth()); policy.setMinHomeUplinkBandwidth(9823); + assertEquals(9823, policy.getMinHomeUplinkBandwidth()); policy.setMinRoamingDownlinkBandwidth(9271); + assertEquals(9271, policy.getMinRoamingDownlinkBandwidth()); policy.setMinRoamingUplinkBandwidth(2315); + assertEquals(2315, policy.getMinRoamingUplinkBandwidth()); policy.setExcludedSsidList(new String[] {"excludeSSID"}); + assertTrue(Arrays.equals(new String[] {"excludeSSID"}, policy.getExcludedSsidList())); Map requiredProtoPortMap = new HashMap<>(); requiredProtoPortMap.put(12, "34,92,234"); policy.setRequiredProtoPortMap(requiredProtoPortMap); + assertEquals(requiredProtoPortMap, policy.getRequiredProtoPortMap()); policy.setMaximumBssLoadValue(23); + assertEquals(23, policy.getMaximumBssLoadValue()); UpdateParameter policyUpdate = new UpdateParameter(); policyUpdate.setUpdateIntervalInMinutes(120); + assertEquals(120, policyUpdate.getUpdateIntervalInMinutes()); policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM); + assertEquals(UpdateParameter.UPDATE_METHOD_OMADM, policyUpdate.getUpdateMethod()); policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP); + assertEquals(UpdateParameter.UPDATE_RESTRICTION_HOMESP, policyUpdate.getRestriction()); policyUpdate.setServerUri("policy.update.com"); + assertEquals("policy.update.com", policyUpdate.getServerUri()); policyUpdate.setUsername("updateUser"); + assertEquals("updateUser", policyUpdate.getUsername()); policyUpdate.setBase64EncodedPassword("updatePass"); + assertEquals("updatePass", policyUpdate.getBase64EncodedPassword()); policyUpdate.setTrustRootCertUrl("update.cert.com"); + assertEquals("update.cert.com", policyUpdate.getTrustRootCertUrl()); policyUpdate.setTrustRootCertSha256Fingerprint(certFingerprint); + assertTrue(Arrays.equals(certFingerprint, + policyUpdate.getTrustRootCertSha256Fingerprint())); policy.setPolicyUpdate(policyUpdate); + assertEquals(policyUpdate, policy.getPolicyUpdate()); config.setPolicy(policy); + assertEquals(policy, config.getPolicy()); return config; } From 154dea6b603c6545f960ed2bd74a81824611176b Mon Sep 17 00:00:00 2001 From: Peter Qiu Date: Thu, 9 Mar 2017 13:18:32 -0800 Subject: [PATCH 0322/1415] wifi: update callsite for Passpoint configuration management APIs The APIs are updated to not return a boolean status based on the API Councils comment. So update the callsite accordingly. Bug: 35858311 Test: make -j32 Change-Id: Ie9106ecddb2b15178ad37ec6f014d5cc7ce77c43 Merged-In: Ie9106ecddb2b15178ad37ec6f014d5cc7ce77c43 --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index d3dc8faadd..f05ff82f04 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -656,7 +656,7 @@ public class WifiManagerTest extends AndroidTestCase { * @param config The configuration to test with */ private void testAddPasspointConfig(PasspointConfiguration config) throws Exception { - assertTrue(mWifiManager.addOrUpdatePasspointConfiguration(config)); + mWifiManager.addOrUpdatePasspointConfiguration(config); // Certificates and keys will be set to null after it is installed to the KeyStore by // WifiManager. Reset them in the expected config so that it can be used to compare @@ -671,7 +671,7 @@ public class WifiManagerTest extends AndroidTestCase { assertEquals(config, configList.get(0)); // Remove the configuration and verify no installed configuration. - assertTrue(mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn())); + mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn()); assertTrue(mWifiManager.getPasspointConfigurations().isEmpty()); } } From a7ec8300d98e92c1363303f7f103bf0787d13a27 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 7 Mar 2017 00:22:33 +0900 Subject: [PATCH 0323/1415] Dup fds to stop finalizers from invalidating them. The hostside VPN tests were failing because finalizers were closing the ParcelFileDescriptors that we use to get socekt fds. The close operations were causing the fds to be marked as invalid (i.e., -1), causing the tests' system calls on them to fail with EBADF. Fix this by dup(2)ing the fds and closing the original objects. Also, add some asserts to debug this sort of failure. Fix: 35927643 Test: HostsideVpnTests passed 20/20 times on bullhead Change-Id: If88530b5bd32622bd4726cd6f0907f731209bb43 --- .../net/hostside/RemoteSocketFactoryClient.java | 15 ++++++++++++--- .../src/com/android/cts/net/hostside/VpnTest.java | 10 +++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java index 799fe50ebe..80f99b6605 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java @@ -22,11 +22,15 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.ConditionVariable; import android.os.IBinder; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.system.ErrnoException; +import android.system.Os; import com.android.cts.net.hostside.IRemoteSocketFactory; import java.io.FileDescriptor; +import java.io.IOException; public class RemoteSocketFactoryClient { private static final int TIMEOUT_MS = 5000; @@ -76,9 +80,14 @@ public class RemoteSocketFactoryClient { } } - public FileDescriptor openSocketFd( - String host, int port, int timeoutMs) throws RemoteException { - return mService.openSocketFd(host, port, timeoutMs).getFileDescriptor(); + public FileDescriptor openSocketFd(String host, int port, int timeoutMs) + throws RemoteException, ErrnoException, IOException { + // Dup the filedescriptor so ParcelFileDescriptor's finalizer doesn't garbage collect it + // and cause our fd to become invalid. http://b/35927643 . + ParcelFileDescriptor pfd = mService.openSocketFd(host, port, timeoutMs); + FileDescriptor fd = Os.dup(pfd.getFileDescriptor()); + pfd.close(); + return fd; } public String getPackageName() throws RemoteException { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index a8ad2b868e..2bd3c39d2c 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -481,7 +481,11 @@ public class VpnTest extends InstrumentationTestCase { private FileDescriptor openSocketFd(String host, int port, int timeoutMs) throws Exception { Socket s = new Socket(host, port); s.setSoTimeout(timeoutMs); - return ParcelFileDescriptor.fromSocket(s).getFileDescriptor(); + // Dup the filedescriptor so ParcelFileDescriptor's finalizer doesn't garbage collect it + // and cause our fd to become invalid. http://b/35927643 . + FileDescriptor fd = Os.dup(ParcelFileDescriptor.fromSocket(s).getFileDescriptor()); + s.close(); + return fd; } private FileDescriptor openSocketFdInOtherApp( @@ -511,7 +515,9 @@ public class VpnTest extends InstrumentationTestCase { private void assertSocketStillOpen(FileDescriptor fd, String host) throws Exception { try { + assertTrue(fd.valid()); sendRequest(fd, host); + assertTrue(fd.valid()); } finally { Os.close(fd); } @@ -519,10 +525,12 @@ public class VpnTest extends InstrumentationTestCase { private void assertSocketClosed(FileDescriptor fd, String host) throws Exception { try { + assertTrue(fd.valid()); sendRequest(fd, host); fail("Socket opened before VPN connects should be closed when VPN connects"); } catch (ErrnoException expected) { assertEquals(ECONNABORTED, expected.errno); + assertTrue(fd.valid()); } finally { Os.close(fd); } From e5ad8b0bb1607426c99c95e8a85c958ebebc8628 Mon Sep 17 00:00:00 2001 From: peter_li Date: Tue, 21 Mar 2017 20:03:18 +0800 Subject: [PATCH 0324/1415] [CTS]It should be more reasonable to use setBatterySaverMode API to leave power-save mode instead of plugging in charger for "CtsHostsideNetworkTests" test case. Symptom: It should be more reasonable to use setBatterySaverMode API to leave power-save mode instead of plugging in charger for "CtsHostsideNetworkTests" test case. Root Cause: It uses setBatterySaverMode API to enter power-save mode and uses plugging in charger to leave power save mode.It should be more reasonable to use setBatterySaverMode API to leave power-save mode instead of plugging in charger. Solution: To use setBatterySaverMode API to leave power-save mode instead of plugging in charger. Project: N70 Note: NA Test done by RD: Futher testing need Q team's support: Change-Id: I491c5d0675f340e1c9911b84e41f034663b1454d --- .../com/android/cts/net/hostside/AbstractAppIdleTestCase.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 79435f1712..831b387b4d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -147,6 +147,8 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork assertBackgroundNetworkAccess(true); setBatterySaverMode(true); assertBackgroundNetworkAccess(false); + // Use setBatterySaverMode API to leave power-save mode instead of plugging in charger + setBatterySaverMode(false); turnBatteryOn(); assertBackgroundNetworkAccess(true); From d3e27e4bf0b309559207e22354bb696422096b86 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 23 Mar 2017 15:19:52 +0900 Subject: [PATCH 0325/1415] Require that the VPN tests pass on TVs. The tests were skipped for historical reasons that are no longer valid, and creates a hole in testing because there are now several VPN apps that work on TVs. Test: HostsideVpnTests passes on fugu with UID routing kernel bug fixed Bug: 36465489 Change-Id: Ib0d6a5cec085e1fc09cf0609b08ca897629afe0c --- .../hostside/app/src/com/android/cts/net/hostside/VpnTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index 2bd3c39d2c..bc982cec78 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -110,8 +110,7 @@ public class VpnTest extends InstrumentationTestCase { private boolean supportedHardware() { final PackageManager pm = getInstrumentation().getContext().getPackageManager(); - return !pm.hasSystemFeature("android.hardware.type.television") && - !pm.hasSystemFeature("android.hardware.type.watch"); + return !pm.hasSystemFeature("android.hardware.type.watch"); } @Override From c9819a49a5d39431254899be678eafa469dfb784 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Mon, 20 Mar 2017 10:53:23 -0700 Subject: [PATCH 0326/1415] [AWARE] Add CTS tests for publish/subscribe TTL Add time-to-live (TTL) testing on publish/subscribe. Can be verified with single device testing. Bug: 30556108 Test: CTS tests pass Change-Id: Ic0fc6b7bd2bc12a5e615b3334a5373da73ccfbf6 --- .../net/wifi/aware/cts/SingleDeviceTest.java | 99 ++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java index 1f7b31b078..e134b46848 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -257,6 +257,23 @@ public class SingleDeviceTest extends AndroidTestCase { * be queued. */ boolean waitForCallback(int callback) { + return waitForCallback(callback, WAIT_FOR_AWARE_CHANGE_SECS); + } + + /** + * Wait for the specified callback - any of the ON_* constants. Returns a true + * on success (specified callback triggered) or false on failure (timed-out or + * interrupted while waiting for the requested callback). + * + * Same as waitForCallback(int callback) execpt that allows specifying a custom timeout. + * The default timeout is a short value expected to be sufficient for all behaviors which + * should happen relatively quickly. Specifying a custom timeout should only be done for + * those cases which are known to take a specific longer period of time. + * + * Note: other callbacks happening while while waiting for the specified callback will + * be queued. + */ + boolean waitForCallback(int callback, int timeoutSec) { synchronized (mLocalLock) { boolean found = mCallbackQueue.remove(callback); if (found) { @@ -268,7 +285,7 @@ public class SingleDeviceTest extends AndroidTestCase { } try { - return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); + return mBlocker.await(timeoutSec, TimeUnit.SECONDS); } catch (InterruptedException e) { return false; } @@ -520,6 +537,46 @@ public class SingleDeviceTest extends AndroidTestCase { session.destroy(); } + /** + * Validate that publish with a Time To Live (TTL) setting expires within the specified + * time (and validates that the terminate callback is triggered). + */ + public void testPublishLimitedTtlSuccess() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + final String serviceName = "ValidName"; + final int ttlSec = 5; + + WifiAwareSession session = attachAndGetSession(); + + PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( + serviceName).setTtlSec(ttlSec).setTerminateNotificationEnabled(true).build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + + // 1. publish + session.publish(publishConfig, discoveryCb, mHandler); + assertTrue("Publish started", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); + PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); + assertNotNull("Publish session", discoverySession); + + // 2. wait for terminate within 'ttlSec'. + assertTrue("Publish terminated", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SESSION_TERMINATED, + ttlSec + 5)); + + // 3. try update post-termination: should time-out waiting for cb + publishConfig = new PublishConfig.Builder().setServiceName( + serviceName).setServiceSpecificInfo("extras".getBytes()).build(); + discoverySession.updatePublish(publishConfig); + assertFalse("Publish update post terminate", discoveryCb.waitForCallback( + DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); + + session.destroy(); + } + /** * Validate a successful subscribe discovery session lifetime: subscribe, update subscribe, * destroy. @@ -564,6 +621,46 @@ public class SingleDeviceTest extends AndroidTestCase { session.destroy(); } + /** + * Validate that subscribe with a Time To Live (TTL) setting expires within the specified + * time (and validates that the terminate callback is triggered). + */ + public void testSubscribeLimitedTtlSuccess() { + if (!TestUtils.shouldTestWifiAware(getContext())) { + return; + } + + final String serviceName = "ValidName"; + final int ttlSec = 5; + + WifiAwareSession session = attachAndGetSession(); + + SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName( + serviceName).setTtlSec(ttlSec).setTerminateNotificationEnabled(true).build(); + DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); + + // 1. subscribe + session.subscribe(subscribeConfig, discoveryCb, mHandler); + assertTrue("Subscribe started", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SUBSCRIBE_STARTED)); + SubscribeDiscoverySession discoverySession = discoveryCb.getSubscribeDiscoverySession(); + assertNotNull("Subscribe session", discoverySession); + + // 2. wait for terminate within 'ttlSec'. + assertTrue("Subscribe terminated", + discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SESSION_TERMINATED, + ttlSec + 5)); + + // 3. try update post-termination: should time-out waiting for cb + subscribeConfig = new SubscribeConfig.Builder().setServiceName( + serviceName).setServiceSpecificInfo("extras".getBytes()).build(); + discoverySession.updateSubscribe(subscribeConfig); + assertFalse("Subscribe update post terminate", discoveryCb.waitForCallback( + DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); + + session.destroy(); + } + /** * Test the send message flow. Since testing single device cannot send to a real peer - * validate that sending to a bogus peer fails. From 894c917c9bac50616b68e402953679db1507a52d Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Mon, 27 Mar 2017 14:23:10 -0700 Subject: [PATCH 0327/1415] Skip data saver related tests if the device doesn't support it. Bug: 36007771 Test: manual Change-Id: I817d2cc23e5c8d460367ede749ff35e799f48ee0 --- ...ractRestrictBackgroundNetworkTestCase.java | 20 ++++++++++-- .../cts/net/hostside/DataSaverModeTest.java | 31 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 15daed971b..42eb321cbc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -100,6 +100,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected ConnectivityManager mCm; protected WifiManager mWfm; protected int mUid; + private int mMyUid; private String mMeteredWifi; private MyServiceClient mServiceClient; private boolean mHasWatch; @@ -115,7 +116,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); - final int myUid = getUid(mContext.getPackageName()); + mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); mServiceClient.bind(); mHasWatch = mContext.getPackageManager().hasSystemFeature( @@ -128,7 +129,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mSupported = setUpActiveNetworkMeteringState(); Log.i(TAG, "Apps status on " + getName() + ":\n" - + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" + + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); } @@ -204,6 +205,21 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertEquals("wrong status", toString(expectedStatus), actualStatus); } + protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); + } + + protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "Expected: " + toString(expectedStatus) + + " but actual: " + toString(actualStatus)); + return false; + } + return true; + } + protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { assertBackgroundState(); // Sanity check. assertNetworkAccess(expectAllowed); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index c3537c89f4..599a31ce1c 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,16 +20,21 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import android.util.Log; + public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { "com.android.providers.downloads" }; + private boolean mIsDataSaverSupported; + @Override public void setUp() throws Exception { super.setUp(); + mIsDataSaverSupported = isDataSaverSupported(); if (!isSupported()) return; // Set initial state. @@ -59,6 +64,32 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase return setMeteredNetwork(); } + @Override + protected boolean isSupported() throws Exception { + if (!mIsDataSaverSupported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Data Saver Mode"); + } + return mIsDataSaverSupported && super.isSupported(); + } + + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + private boolean isDataSaverSupported() throws Exception { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + public void testGetRestrictBackgroundStatus_disabled() throws Exception { if (!isSupported()) return; From 41914d36f308c87bc567245f67e1594131a9ebe6 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Mon, 27 Mar 2017 14:23:10 -0700 Subject: [PATCH 0328/1415] DO NOT MERGE: Skip data saver related tests if the device doesn't support it. Bug: 36007771 Test: manual Change-Id: I817d2cc23e5c8d460367ede749ff35e799f48ee0 --- ...ractRestrictBackgroundNetworkTestCase.java | 20 ++++++++++-- .../cts/net/hostside/DataSaverModeTest.java | 31 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index a50034819a..d2720d631a 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -99,6 +99,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected ConnectivityManager mCm; protected WifiManager mWfm; protected int mUid; + private int mMyUid; private String mMeteredWifi; private boolean mHasWatch; private String mDeviceIdleConstantsSetting; @@ -113,7 +114,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); - final int myUid = getUid(mContext.getPackageName()); + mMyUid = getUid(mContext.getPackageName()); mHasWatch = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_WATCH); if (mHasWatch) { @@ -124,7 +125,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mSupported = setUpActiveNetworkMeteringState(); Log.i(TAG, "Apps status on " + getName() + ":\n" - + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" + + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); } @@ -199,6 +200,21 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertEquals("wrong status", toString(expectedStatus), actualStatus); } + protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); + } + + protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "Expected: " + toString(expectedStatus) + + " but actual: " + toString(actualStatus)); + return false; + } + return true; + } + protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { assertBackgroundState(); // Sanity check. assertNetworkAccess(expectAllowed); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 9e4b0c13de..72d0be9d0c 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,16 +20,21 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import android.util.Log; + public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { "com.android.providers.downloads" }; + private boolean mIsDataSaverSupported; + @Override public void setUp() throws Exception { super.setUp(); + mIsDataSaverSupported = isDataSaverSupported(); if (!isSupported()) return; // Set initial state. @@ -59,6 +64,32 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase return setMeteredNetwork(); } + @Override + protected boolean isSupported() throws Exception { + if (!mIsDataSaverSupported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Data Saver Mode"); + } + return mIsDataSaverSupported && super.isSupported(); + } + + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + private boolean isDataSaverSupported() throws Exception { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + public void testGetRestrictBackgroundStatus_disabled() throws Exception { if (!isSupported()) return; From d69455289f21d7645ba0a7bc1cb959ae5f82f74f Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Mon, 27 Mar 2017 14:23:10 -0700 Subject: [PATCH 0329/1415] DO NOT MERGE: Skip data saver related tests if the device doesn't support it. Bug: 36007771 Test: manual Change-Id: I817d2cc23e5c8d460367ede749ff35e799f48ee0 --- ...ractRestrictBackgroundNetworkTestCase.java | 20 ++++++++++-- .../cts/net/hostside/DataSaverModeTest.java | 31 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 46d243ee77..793938a1ac 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -84,6 +84,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected ConnectivityManager mCm; protected WifiManager mWfm; protected int mUid; + private int mMyUid; private String mMeteredWifi; private boolean mSupported; @@ -96,11 +97,11 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); - final int myUid = getUid(mContext.getPackageName()); + mMyUid = getUid(mContext.getPackageName()); mSupported = setUpActiveNetworkMeteringState(); Log.i(TAG, "Apps status on " + getName() + ":\n" - + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n" + + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); } @@ -175,6 +176,21 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertEquals("wrong status", toString(expectedStatus), actualStatus); } + protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); + } + + protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "Expected: " + toString(expectedStatus) + + " but actual: " + toString(actualStatus)); + return false; + } + return true; + } + protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { assertBackgroundState(); // Sanity check. assertNetworkAccess(expectAllowed); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index ac35bd44b6..d5e236f0b8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,16 +20,21 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import android.util.Log; + public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { "com.android.providers.downloads" }; + private boolean mIsDataSaverSupported; + @Override public void setUp() throws Exception { super.setUp(); + mIsDataSaverSupported = isDataSaverSupported(); if (!isSupported()) return; // Set initial state. @@ -59,6 +64,32 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase return setMeteredNetwork(); } + @Override + protected boolean isSupported() throws Exception { + if (!mIsDataSaverSupported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Data Saver Mode"); + } + return mIsDataSaverSupported && super.isSupported(); + } + + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + private boolean isDataSaverSupported() throws Exception { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + public void testGetRestrictBackgroundStatus_disabled() throws Exception { if (!isSupported()) return; From d44cfd7014dd51077496c29bfeec41dee3d6763c Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 6 Mar 2017 10:34:27 -0800 Subject: [PATCH 0330/1415] Initial CTS Tests for IpSec Classes -Test SPI creation, duplication and deletion -Test IpSecTransform creation, apply to socket, and delete Bug: 34811227 Test: Verified on Bullhead with UDP on IPv6 (default) Change-Id: I1ffc84e549c7666996472ed323eb44810c3b9843 --- .../src/android/net/cts/IpSecManagerTest.java | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/IpSecManagerTest.java diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java new file mode 100644 index 0000000000..93b5c44918 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2017 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 android.content.Context; +import android.net.ConnectivityManager; +import android.net.IpSecAlgorithm; +import android.net.IpSecManager; +import android.net.IpSecTransform; +import android.test.AndroidTestCase; +import android.util.Log; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; + +public class IpSecManagerTest extends AndroidTestCase { + + private static final String TAG = IpSecManagerTest.class.getSimpleName(); + + private IpSecManager mISM; + + private ConnectivityManager mCM; + + private static final InetAddress GOOGLE_DNS_4; + private static final InetAddress GOOGLE_DNS_6; + + static { + try { + // Google Public DNS Addresses; + GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8"); + GOOGLE_DNS_6 = InetAddress.getByName("2001:4860:4860::8888"); + } catch (UnknownHostException e) { + throw new RuntimeException("Could not resolve DNS Addresses", e); + } + } + + private static final InetAddress[] GOOGLE_DNS_LIST = + new InetAddress[] {GOOGLE_DNS_4, GOOGLE_DNS_6}; + + private static final int DROID_SPI = 0xD1201D; + + private static final byte[] CRYPT_KEY = + new byte[] { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F + }; + private static final byte[] AUTH_KEY = + new byte[] { + 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7F + }; + + protected void setUp() throws Exception { + super.setUp(); + mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE); + } + + /* + * Allocate a random SPI + * Allocate a specific SPI using previous randomly created SPI value + * Realloc the same SPI that was specifically created (expect SpiUnavailable) + * Close SPIs + */ + public void testAllocSpi() throws Exception { + for (InetAddress addr : GOOGLE_DNS_LIST) { + IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null; + randomSpi = + mISM.reserveSecurityParameterIndex( + IpSecTransform.DIRECTION_OUT, + addr, + IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + assertTrue(randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + + droidSpi = + mISM.reserveSecurityParameterIndex( + IpSecTransform.DIRECTION_IN, addr, DROID_SPI); + assertTrue(droidSpi.getSpi() == DROID_SPI); + + try { + mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_IN, addr, DROID_SPI); + fail("Duplicate SPI was allowed to be created"); + } catch (IpSecManager.SpiUnavailableException expected) { + // This is a success case because we expect a dupe SPI to throw + } + + randomSpi.close(); + droidSpi.close(); + } + } + + /* + * Alloc outbound SPI + * Alloc inbound SPI + * Create transport mode transform + * open socket + * apply transform to socket + * send data on socket + * release transform + * send data (expect exception) + */ + public void testCreateTransform() throws Exception { + InetAddress local = InetAddress.getLoopbackAddress(); + IpSecManager.SecurityParameterIndex outSpi = + mISM.reserveSecurityParameterIndex( + IpSecTransform.DIRECTION_OUT, + local, + IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + + IpSecManager.SecurityParameterIndex inSpi = + mISM.reserveSecurityParameterIndex( + IpSecTransform.DIRECTION_IN, local, outSpi.getSpi()); + + IpSecTransform transform = + new IpSecTransform.Builder(mContext) + .setSpi(IpSecTransform.DIRECTION_OUT, outSpi) + .setEncryption( + IpSecTransform.DIRECTION_OUT, + new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + IpSecTransform.DIRECTION_OUT, + new IpSecAlgorithm( + IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 8)) + .setSpi(IpSecTransform.DIRECTION_IN, inSpi) + .setEncryption( + IpSecTransform.DIRECTION_IN, + new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + IpSecTransform.DIRECTION_IN, + new IpSecAlgorithm( + IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256, + AUTH_KEY, + CRYPT_KEY.length * 8)) + .buildTransportModeTransform(local); + + DatagramSocket localSocket; + localSocket = new DatagramSocket(8888); + + localSocket.setSoTimeout(500); + mISM.applyTransportModeTransform(localSocket, transform); + byte[] data = new String("Best test data ever!").getBytes("UTF-8"); + + DatagramPacket out = new DatagramPacket(data, data.length, local, 8888); + localSocket.send(out); + DatagramPacket in = new DatagramPacket(new byte[data.length], data.length); + + localSocket.receive(in); + Log.d(TAG, Arrays.toString(data)); + Log.d(TAG, Arrays.toString(in.getData())); + assertTrue(Arrays.equals(data, in.getData())); + transform.close(); + try { + localSocket.send(out); + } catch (IOException e) { + } + + mISM.removeTransportModeTransform(localSocket, transform); + } +} From ea6bd5400afa4119786396707e76e9d6e6ca4b94 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 6 Mar 2017 10:34:27 -0800 Subject: [PATCH 0331/1415] Initial CTS Tests for IpSec Classes -Test SPI creation, duplication and deletion -Test IpSecTransform creation, apply to socket, and delete Bug: 30984788, 34811227 Test: Verified on Bullhead with UDP on IPv6 (default) Change-Id: I1ffc84e549c7666996472ed323eb44810c3b9843 (cherry picked from commit 4eddc41200c1912b40218d0ee7b0f0cc05c1a960) --- .../src/android/net/cts/IpSecManagerTest.java | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/IpSecManagerTest.java diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java new file mode 100644 index 0000000000..93b5c44918 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2017 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 android.content.Context; +import android.net.ConnectivityManager; +import android.net.IpSecAlgorithm; +import android.net.IpSecManager; +import android.net.IpSecTransform; +import android.test.AndroidTestCase; +import android.util.Log; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; + +public class IpSecManagerTest extends AndroidTestCase { + + private static final String TAG = IpSecManagerTest.class.getSimpleName(); + + private IpSecManager mISM; + + private ConnectivityManager mCM; + + private static final InetAddress GOOGLE_DNS_4; + private static final InetAddress GOOGLE_DNS_6; + + static { + try { + // Google Public DNS Addresses; + GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8"); + GOOGLE_DNS_6 = InetAddress.getByName("2001:4860:4860::8888"); + } catch (UnknownHostException e) { + throw new RuntimeException("Could not resolve DNS Addresses", e); + } + } + + private static final InetAddress[] GOOGLE_DNS_LIST = + new InetAddress[] {GOOGLE_DNS_4, GOOGLE_DNS_6}; + + private static final int DROID_SPI = 0xD1201D; + + private static final byte[] CRYPT_KEY = + new byte[] { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F + }; + private static final byte[] AUTH_KEY = + new byte[] { + 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7F + }; + + protected void setUp() throws Exception { + super.setUp(); + mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE); + } + + /* + * Allocate a random SPI + * Allocate a specific SPI using previous randomly created SPI value + * Realloc the same SPI that was specifically created (expect SpiUnavailable) + * Close SPIs + */ + public void testAllocSpi() throws Exception { + for (InetAddress addr : GOOGLE_DNS_LIST) { + IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null; + randomSpi = + mISM.reserveSecurityParameterIndex( + IpSecTransform.DIRECTION_OUT, + addr, + IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + assertTrue(randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + + droidSpi = + mISM.reserveSecurityParameterIndex( + IpSecTransform.DIRECTION_IN, addr, DROID_SPI); + assertTrue(droidSpi.getSpi() == DROID_SPI); + + try { + mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_IN, addr, DROID_SPI); + fail("Duplicate SPI was allowed to be created"); + } catch (IpSecManager.SpiUnavailableException expected) { + // This is a success case because we expect a dupe SPI to throw + } + + randomSpi.close(); + droidSpi.close(); + } + } + + /* + * Alloc outbound SPI + * Alloc inbound SPI + * Create transport mode transform + * open socket + * apply transform to socket + * send data on socket + * release transform + * send data (expect exception) + */ + public void testCreateTransform() throws Exception { + InetAddress local = InetAddress.getLoopbackAddress(); + IpSecManager.SecurityParameterIndex outSpi = + mISM.reserveSecurityParameterIndex( + IpSecTransform.DIRECTION_OUT, + local, + IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + + IpSecManager.SecurityParameterIndex inSpi = + mISM.reserveSecurityParameterIndex( + IpSecTransform.DIRECTION_IN, local, outSpi.getSpi()); + + IpSecTransform transform = + new IpSecTransform.Builder(mContext) + .setSpi(IpSecTransform.DIRECTION_OUT, outSpi) + .setEncryption( + IpSecTransform.DIRECTION_OUT, + new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + IpSecTransform.DIRECTION_OUT, + new IpSecAlgorithm( + IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 8)) + .setSpi(IpSecTransform.DIRECTION_IN, inSpi) + .setEncryption( + IpSecTransform.DIRECTION_IN, + new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + IpSecTransform.DIRECTION_IN, + new IpSecAlgorithm( + IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256, + AUTH_KEY, + CRYPT_KEY.length * 8)) + .buildTransportModeTransform(local); + + DatagramSocket localSocket; + localSocket = new DatagramSocket(8888); + + localSocket.setSoTimeout(500); + mISM.applyTransportModeTransform(localSocket, transform); + byte[] data = new String("Best test data ever!").getBytes("UTF-8"); + + DatagramPacket out = new DatagramPacket(data, data.length, local, 8888); + localSocket.send(out); + DatagramPacket in = new DatagramPacket(new byte[data.length], data.length); + + localSocket.receive(in); + Log.d(TAG, Arrays.toString(data)); + Log.d(TAG, Arrays.toString(in.getData())); + assertTrue(Arrays.equals(data, in.getData())); + transform.close(); + try { + localSocket.send(out); + } catch (IOException e) { + } + + mISM.removeTransportModeTransform(localSocket, transform); + } +} From b45c3dc6f1118c732d516c7a4756700b7daf5b39 Mon Sep 17 00:00:00 2001 From: Peter Qiu Date: Mon, 3 Apr 2017 14:20:12 -0700 Subject: [PATCH 0332/1415] wifi: catch UnsupportedOperationException for devices with Passpoint disabled For devices with build config |config_wifi_hotspot2_enabled| set to false (Passpoint disabled), an UnsupportedOperationException will be thrown when Passpoint related WifiManager APIs are invoked. For these devices, the testing of Passpoint APIs are not relevant. So just catch and ignore this type of exceptions to avoid any test failures. While there, set the UpdateIdentifier for Passpoint configurations, to avoid the CA certificate verification when adding the config, since we're using a fake CA certificate for testing. Bug: 36863137 Test: cts-tradefed run cts-dev -m CtsNetTestCases -t android.net.wifi.cts.WifiManagerTest Change-Id: I8ebdc58349c33f13b510c3d9e2a5fc8ce4ef09c4 --- .../android/net/wifi/cts/WifiManagerTest.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index f05ff82f04..14ae1b450a 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -587,6 +587,10 @@ public class WifiManagerTest extends AndroidTestCase { private PasspointConfiguration generatePasspointConfig(Credential credential) { PasspointConfiguration config = new PasspointConfiguration(); config.setCredential(credential); + // Setting update identifier to indicate R2 configuration, to avoid CA + // certificate being verified, since we're using a fake CA certificate + // for testing. + config.setUpdateIdentifier(1); // Setup HomeSp. HomeSp homeSp = new HomeSp(); @@ -656,22 +660,26 @@ public class WifiManagerTest extends AndroidTestCase { * @param config The configuration to test with */ private void testAddPasspointConfig(PasspointConfiguration config) throws Exception { - mWifiManager.addOrUpdatePasspointConfiguration(config); + try { + mWifiManager.addOrUpdatePasspointConfiguration(config); - // Certificates and keys will be set to null after it is installed to the KeyStore by - // WifiManager. Reset them in the expected config so that it can be used to compare - // against the retrieved config. - config.getCredential().setCaCertificate(null); - config.getCredential().setClientCertificateChain(null); - config.getCredential().setClientPrivateKey(null); + // Certificates and keys will be set to null after it is installed to the KeyStore by + // WifiManager. Reset them in the expected config so that it can be used to compare + // against the retrieved config. + config.getCredential().setCaCertificate(null); + config.getCredential().setClientCertificateChain(null); + config.getCredential().setClientPrivateKey(null); - // Retrieve the configuration and verify it. - List configList = mWifiManager.getPasspointConfigurations(); - assertEquals(1, configList.size()); - assertEquals(config, configList.get(0)); + // Retrieve the configuration and verify it. + List configList = mWifiManager.getPasspointConfigurations(); + assertEquals(1, configList.size()); + assertEquals(config, configList.get(0)); - // Remove the configuration and verify no installed configuration. - mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn()); - assertTrue(mWifiManager.getPasspointConfigurations().isEmpty()); + // Remove the configuration and verify no installed configuration. + mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn()); + assertTrue(mWifiManager.getPasspointConfigurations().isEmpty()); + } catch (UnsupportedOperationException e) { + // Passpoint build config |config_wifi_hotspot2_enabled| is disabled, so noop. + } } } From 3c0a0400722c6e47aaab841f5160b024fb2fa1b7 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 6 Apr 2017 18:20:41 -0700 Subject: [PATCH 0333/1415] Update IpSecAlgorithm CTS for API compliance changes Bug: 36073210, b/34811227 Test: verified on Bullhead Change-Id: I8f37016cc9aadafd3e58f6af535bd7bc1d0f4a96 --- .../net/src/android/net/cts/IpSecManagerTest.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 93b5c44918..39d683d136 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -85,8 +85,7 @@ public class IpSecManagerTest extends AndroidTestCase { randomSpi = mISM.reserveSecurityParameterIndex( IpSecTransform.DIRECTION_OUT, - addr, - IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + addr); assertTrue(randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); droidSpi = @@ -121,8 +120,7 @@ public class IpSecManagerTest extends AndroidTestCase { IpSecManager.SecurityParameterIndex outSpi = mISM.reserveSecurityParameterIndex( IpSecTransform.DIRECTION_OUT, - local, - IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + local); IpSecManager.SecurityParameterIndex inSpi = mISM.reserveSecurityParameterIndex( @@ -133,21 +131,21 @@ public class IpSecManagerTest extends AndroidTestCase { .setSpi(IpSecTransform.DIRECTION_OUT, outSpi) .setEncryption( IpSecTransform.DIRECTION_OUT, - new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY)) + new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) .setAuthentication( IpSecTransform.DIRECTION_OUT, new IpSecAlgorithm( - IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256, + IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 8)) .setSpi(IpSecTransform.DIRECTION_IN, inSpi) .setEncryption( IpSecTransform.DIRECTION_IN, - new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY)) + new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) .setAuthentication( IpSecTransform.DIRECTION_IN, new IpSecAlgorithm( - IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256, + IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, CRYPT_KEY.length * 8)) .buildTransportModeTransform(local); From 7b9e244aaa462aff37fd57c6a1025d750f139196 Mon Sep 17 00:00:00 2001 From: jdesprez Date: Tue, 11 Apr 2017 15:43:44 -0700 Subject: [PATCH 0334/1415] Update configurations to avoid using ApkInstaller - use the new tradefed version of it. - add a tests to check configs. Test: build, run collect-tests-only dry-run Bug: 37213493 Change-Id: Ia212b707befe3ffc70ef43cbc292e97be3f364f1 --- tests/cts/net/AndroidTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml index 389b926f83..fbad7391c8 100644 --- a/tests/cts/net/AndroidTest.xml +++ b/tests/cts/net/AndroidTest.xml @@ -13,7 +13,7 @@ limitations under the License. --> - +

    + * No apps should ever attempt to acquire this permission, since it would give those + * apps extremely broad access to connectivity functionality. + */ + public void testNetworkStackPermission() { + final PackageManager pm = getContext().getPackageManager(); + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_STACK + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + for (PackageInfo pi : holding) { + fail("The NETWORK_STACK permission must not be held by " + pi.packageName + + " and must be revoked for security reasons"); + } + } + + /** + * Verify that the {@link android.Manifest.permission#NETWORK_SETTINGS} permission is + * never held by any package. + *

    + * Only Settings, SysUi and shell apps should ever attempt to acquire this + * permission, since it would give those apps extremely broad access to connectivity + * functionality. The permission is intended to be granted to only those apps with direct user + * access and no others. + */ + public void testNetworkSettingsPermission() { + final PackageManager pm = getContext().getPackageManager(); + + final ArraySet allowedPackages = new ArraySet(); + final ArraySet allowedUIDs = new ArraySet(); + // explicitly add allowed UIDs + allowedUIDs.add(Process.SYSTEM_UID); + allowedUIDs.add(Process.SHELL_UID); + allowedUIDs.add(Process.PHONE_UID); + + // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using + // this fact to determined allowed package name for sysui + String validPkg = ""; + final List sysuiPackage = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.BIND_QUICK_SETTINGS_TILE + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + + if (sysuiPackage.size() > 1) { + fail("The BIND_QUICK_SETTINGS_TILE permission must only be held by one package"); + } + + if (sysuiPackage.size() == 1) { + validPkg = sysuiPackage.get(0).packageName; + allowedPackages.add(validPkg); + } + + // the captive portal flow also currently holds the NETWORK_SETTINGS permission + final Intent intent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); + final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); + if (ri != null) { + allowedPackages.add(ri.activityInfo.packageName); + } + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_SETTINGS + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + for (PackageInfo pi : holding) { + String packageName = pi.packageName; + if (allowedPackages.contains(packageName)) { + // this is an explicitly allowed package + } else { + // now check if the packages are from allowed UIDs + boolean allowed = false; + try { + if (allowedUIDs.contains(pm.getPackageUid(packageName, 0))) { + allowed = true; + Log.d(TAG, packageName + " is on an allowed UID"); + } + } catch (PackageManager.NameNotFoundException e) { } + if (!allowed) { + fail("The NETWORK_SETTINGS permission must not be held by " + + packageName + " and must be revoked for security reasons"); + } + } + } + } + + /** + * Verify that the {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} permission is + * only held by the device setup wizard application. + *

    + * Only the SetupWizard app should ever attempt to acquire this + * permission, since it would give those apps extremely broad access to connectivity + * functionality. The permission is intended to be granted to only the device setup wizard. + */ + public void testNetworkSetupWizardPermission() { + final PackageManager pm = getContext().getPackageManager(); + + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_SETUP_WIZARD); + final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); + String validPkg = ""; + if (ri != null) { + validPkg = ri.activityInfo.packageName; + } + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_SETUP_WIZARD + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + for (PackageInfo pi : holding) { + if (!Objects.equals(pi.packageName, validPkg)) { + fail("The NETWORK_SETUP_WIZARD permission must not be held by " + pi.packageName + + " and must be revoked for security reasons [" + validPkg +"]"); + } + } + } } From d8eb370a89689cc349a6168f773ec4fa36203b7f Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Fri, 13 Jul 2018 20:04:45 +0100 Subject: [PATCH 0502/1415] Extend Uri tests The internal UriCodec class is being removed from libcore/ and the associated CTS tests are being removed. This change adds equivalent URI decoding tests to the UriTest CTS test class. Test: make droid && make cts Test: run cts-dev -m CtsNetTestCases -t android.net.cts.UriTest Bug: 111055375 Change-Id: Ided15d5abf8478064d193034e84c4dbe0689c6f0 --- .../cts/net/src/android/net/cts/UriTest.java | 61 +++++++++++++++---- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 05e826a2c4..611eae2590 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -158,22 +158,61 @@ public class UriTest extends AndroidTestCase { String encoded = Uri.encode("Bob:/", "/"); assertEquals(-1, encoded.indexOf(':')); assertTrue(encoded.indexOf('/') > -1); - assertDecode(null); - assertDecode(""); - assertDecode("Bob"); - assertDecode(":Bob"); - assertDecode("::Bob"); - assertDecode("Bob::Lee"); - assertDecode("Bob:Lee"); - assertDecode("Bob::"); - assertDecode("Bob:"); - assertDecode("::Bob::"); + assertEncodeDecodeRoundtripExact(null); + assertEncodeDecodeRoundtripExact(""); + assertEncodeDecodeRoundtripExact("Bob"); + assertEncodeDecodeRoundtripExact(":Bob"); + assertEncodeDecodeRoundtripExact("::Bob"); + assertEncodeDecodeRoundtripExact("Bob::Lee"); + assertEncodeDecodeRoundtripExact("Bob:Lee"); + assertEncodeDecodeRoundtripExact("Bob::"); + assertEncodeDecodeRoundtripExact("Bob:"); + assertEncodeDecodeRoundtripExact("::Bob::"); } - private void assertDecode(String s) { + private static void assertEncodeDecodeRoundtripExact(String s) { assertEquals(s, Uri.decode(Uri.encode(s, null))); } + public void testDecode_emptyString_returnsEmptyString() { + assertEquals("", Uri.decode("")); + } + + public void testDecode_null_returnsNull() { + assertNull(Uri.decode(null)); + } + + public void testDecode_wrongHexDigit() { + // %p in the end. + assertEquals("ab/$\u0102%\u0840\uFFFD\u0000", Uri.decode("ab%2f$%C4%82%25%e0%a1%80%p")); + } + + public void testDecode_secondHexDigitWrong() { + // %1p in the end. + assertEquals("ab/$\u0102%\u0840\uFFFD\u0001", Uri.decode("ab%2f$%c4%82%25%e0%a1%80%1p")); + } + + public void testDecode_endsWithPercent_appendsUnknownCharacter() { + // % in the end. + assertEquals("ab/$\u0102%\u0840\uFFFD", Uri.decode("ab%2f$%c4%82%25%e0%a1%80%")); + } + + public void testDecode_plusNotConverted() { + assertEquals("ab/$\u0102%+\u0840", Uri.decode("ab%2f$%c4%82%25+%e0%a1%80")); + } + + // Last character needs decoding (make sure we are flushing the buffer with chars to decode). + public void testDecode_lastCharacter() { + assertEquals("ab/$\u0102%\u0840", Uri.decode("ab%2f$%c4%82%25%e0%a1%80")); + } + + // Check that a second row of encoded characters is decoded properly (internal buffers are + // reset properly). + public void testDecode_secondRowOfEncoded() { + assertEquals("ab/$\u0102%\u0840aa\u0840", + Uri.decode("ab%2f$%c4%82%25%e0%a1%80aa%e0%a1%80")); + } + public void testFromFile() { File f = new File("/tmp/bob"); Uri uri = Uri.fromFile(f); From cc7747d2de2d28c520e53f135c1f8236d051709e Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Tue, 24 Jul 2018 12:36:37 -0700 Subject: [PATCH 0503/1415] Skip the test if cannot open ctrl file The shell access to the proc/xt_qtaguid/ctrl file is blocked in next android release since no apps or users should directly read/write to those proc files anymore. This CTS test is checking some critical kernel behavior to make sure the xt_qtaguid module have specific kernel fixes. So if the ctrl file is not accessible, there is no way to verify those critical fixes, we can only skipped the test. These testcases are also added in VTS qtaguid test so we can still check the devices have those kernel fixes. Bug: 110906349 Test: atest CtsNativeNetTestCases Change-Id: Iae0512bb37f8b93577a134f15affb4f2a448be18 --- .../native/qtaguid/src/NativeQtaguidTest.cpp | 61 +++++++------------ 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/tests/cts/net/native/qtaguid/src/NativeQtaguidTest.cpp b/tests/cts/net/native/qtaguid/src/NativeQtaguidTest.cpp index 1892a44ebd..7dc6240667 100644 --- a/tests/cts/net/native/qtaguid/src/NativeQtaguidTest.cpp +++ b/tests/cts/net/native/qtaguid/src/NativeQtaguidTest.cpp @@ -18,36 +18,29 @@ #include #include #include +#include #include #include -#include #include #include -int hasQtaguidKernelSupport() { - struct utsname buf; - int kernel_version_major; - int kernel_version_minor; - - int ret = uname(&buf); - if (ret) { - ret = -errno; - return ret; - } - char dummy; - ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major, &kernel_version_minor, &dummy); - if (ret < 3) - return -EINVAL; - - if ((kernel_version_major == 4 && kernel_version_minor < 9) || - (kernel_version_major < 4)) { - return 1; - } else { - return access("/proc/net/xt_qtaguid/ctrl", F_OK) != -1; - } +int canAccessQtaguidFile() { + int fd = open("/proc/net/xt_qtaguid/ctrl", O_RDONLY | O_CLOEXEC); + close(fd); + return fd != -1; } +#define SKIP_IF_QTAGUID_NOT_SUPPORTED() \ + do { \ + int res = canAccessQtaguidFile(); \ + ASSERT_LE(0, res); \ + if (!res) { \ + GTEST_LOG_(INFO) << "This test is skipped since kernel may not have the module\n"; \ + return; \ + } \ + } while (0) + int getCtrlSkInfo(int tag, uid_t uid, uint64_t* sk_addr, int* ref_cnt) { FILE *fp; fp = fopen("/proc/net/xt_qtaguid/ctrl", "r"); @@ -95,12 +88,8 @@ void checkNoSocketPointerLeaks(int family) { } TEST (NativeQtaguidTest, close_socket_without_untag) { - int res = hasQtaguidKernelSupport(); - ASSERT_LE(0, res); - if (!res) { - GTEST_LOG_(INFO) << "This test is skipped since kernel may not have the module\n"; - return; - } + SKIP_IF_QTAGUID_NOT_SUPPORTED(); + int sockfd = socket(AF_INET, SOCK_STREAM, 0); uid_t uid = getuid(); int tag = arc4random(); @@ -114,12 +103,8 @@ TEST (NativeQtaguidTest, close_socket_without_untag) { } TEST (NativeQtaguidTest, close_socket_without_untag_ipv6) { - int res = hasQtaguidKernelSupport(); - ASSERT_LE(0, res); - if (!res) { - GTEST_LOG_(INFO) << "This test is skipped since kernel may not have the module\n"; - return; - } + SKIP_IF_QTAGUID_NOT_SUPPORTED(); + int sockfd = socket(AF_INET6, SOCK_STREAM, 0); uid_t uid = getuid(); int tag = arc4random(); @@ -133,12 +118,8 @@ TEST (NativeQtaguidTest, close_socket_without_untag_ipv6) { } TEST (NativeQtaguidTest, no_socket_addr_leak) { - int res = hasQtaguidKernelSupport(); - ASSERT_LE(0, res); - if (!res) { - GTEST_LOG_(INFO) << "This test is skipped since kernel may not have the module\n"; - return; - } + SKIP_IF_QTAGUID_NOT_SUPPORTED(); + checkNoSocketPointerLeaks(AF_INET); checkNoSocketPointerLeaks(AF_INET6); } From 679ee7cbe7f5b2d08b7035580dd57084a41fe77f Mon Sep 17 00:00:00 2001 From: Adam Vartanian Date: Fri, 27 Jul 2018 11:44:06 +0100 Subject: [PATCH 0504/1415] CTS test for SslCertificate.getX509Certificate Bug: 111696337 Bug: 36984840 Test: cts -m CtsNetTestCases -t android.net.http Change-Id: I778a18fd3636efc1e60d61e6d2b78685635c07f8 --- .../android/net/http/cts/SslCertificateTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java index 70ae496356..95f415c58c 100644 --- a/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslCertificateTest.java @@ -230,6 +230,19 @@ public class SslCertificateTest extends TestCase { final String EXPECTED = "Issued to: c=ccc,o=testOName,ou=testUName,cn=testCName;\n" + "Issued by: e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName;\n"; assertEquals(EXPECTED, ssl.toString()); + assertNull(ssl.getX509Certificate()); } + public void testGetX509Certificate() { + final String TO = "c=ccc,o=testOName,ou=testUName,cn=testCName"; + final String BY = "e=aeei,c=adb,o=testOName,ou=testUName,cn=testCName"; + Date validNotBefore = new Date(System.currentTimeMillis() - 1000); + Date validNotAfter = new Date(System.currentTimeMillis()); + SslCertificate ssl = new SslCertificate(TO, BY, validNotBefore, validNotAfter); + assertNull(ssl.getX509Certificate()); + + X509Certificate cert = new MockX509Certificate(); + ssl = new SslCertificate(cert); + assertSame(cert, ssl.getX509Certificate()); + } } From 497a93647cd9cb5fdce0e0b25c1e566107e8f7cd Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 19 Jun 2018 19:30:31 -0700 Subject: [PATCH 0505/1415] Use a different key for signing networkpolicy test app. One of the preparation steps for running cts involves loading up the sim card with the key used to sign CtsCarrierApiTestCases.apk. It means if the same key is used for signing networkpolicy test app too, then the app is considered as carrier privileged by the system and can't be forced into app standby state. Fixes: 77861812 Test: cts-tradefed run singleCommand cts-dev -m CtsHostsideNetworkTests -t \ com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testDataSaverMode_disabled Change-Id: Iaa9f4fabe83430fa42b6f67c1025db41a5e1d938 Merged-In: Iaa9f4fabe83430fa42b6f67c1025db41a5e1d938 --- tests/cts/hostside/app2/Android.mk | 2 ++ tests/cts/hostside/certs/README | 2 ++ tests/cts/hostside/certs/cts-net-app.pk8 | Bin 0 -> 1219 bytes tests/cts/hostside/certs/cts-net-app.x509.pem | 19 ++++++++++++++++++ 4 files changed, 23 insertions(+) create mode 100644 tests/cts/hostside/certs/README create mode 100644 tests/cts/hostside/certs/cts-net-app.pk8 create mode 100644 tests/cts/hostside/certs/cts-net-app.x509.pem diff --git a/tests/cts/hostside/app2/Android.mk b/tests/cts/hostside/app2/Android.mk index 9a4a30fbff..5c0bae194b 100644 --- a/tests/cts/hostside/app2/Android.mk +++ b/tests/cts/hostside/app2/Android.mk @@ -32,4 +32,6 @@ LOCAL_DEX_PREOPT := false # Tag this module as a cts test artifact LOCAL_COMPATIBILITY_SUITE := cts vts general-tests +LOCAL_CERTIFICATE := cts/hostsidetests/net/certs/cts-net-app + include $(BUILD_CTS_SUPPORT_PACKAGE) diff --git a/tests/cts/hostside/certs/README b/tests/cts/hostside/certs/README new file mode 100644 index 0000000000..b660a82dc8 --- /dev/null +++ b/tests/cts/hostside/certs/README @@ -0,0 +1,2 @@ +# Generated with: +development/tools/make_key cts-net-app '/CN=cts-net-app' diff --git a/tests/cts/hostside/certs/cts-net-app.pk8 b/tests/cts/hostside/certs/cts-net-app.pk8 new file mode 100644 index 0000000000000000000000000000000000000000..1703e4ee340b7c7ab818097cefbbf95fb86f3747 GIT binary patch literal 1219 zcmV;!1U&mNf&{+;0RS)!1_>&LNQUrsW5^Br2+u}0)hbn0N#A&vRMl( z)K7&#gN-YqA(ePu&=E2o$Vjep&N^#?J+IQe_UD^8vWC4%PBxI-ME{s%p~72w0ZU@; zaXKTG43uCz5lGMl@ha*FIBFHPR{XV|cKf1`B_%f8?!Ujr zt-{>0C4_u?`%vIYq{z#o&|wc%#UbbC#EF~*3eXtI#Pu@b#2AEmesXH!;BA|+2B81W z!Zu8OMUNETxR$5$c?)i;hZYR4J*6YT$pCc&@}h3pQGsU#%?m@^a{>ba009Dm0RaHk zc>v0s8?m!kl+%O!>N@ze<-9;f(^2U#XFDru6^Rdi7GW7mTF+$(jvu=f&c6qwe0xQc z-YV8)osrJ&&LK`cr5XVSk|=+5h9S}kmdcGs++ig(JtFrKB&6at^XSEN7gbjf(l>>Q zW5q!7d>b5VnALd8DRw?XvqUfpAAaDQ)mpy#BAh*U&nzY5KA?dt?&F!_gTW_hO&aG? zFz!^L2yHTF#V@X&LqF|!Q4`{WkX^!rOP6AzE3-+ExKAD|AnK7^^w$v-bH;VQMuXQG z^wqpIj+;*3h|p36xkZ4_k2@ee;ehD~XA7iWt0O?}W4hlp!7008eHpZ&=5xtRJbcFmSVJik5H=O_+OcDr64K?)M2Tx(p#1Bj!W}szK*F#xG5_9njbtuN zvAj31ay#p;XUyF~^2T$(v1bpJYKX(0Hjh1=a0St$<@BH?5pD>(7CE0M%ug3w#-4iu zfq)5bl2l+u5>xWKztT8zHPHfrfdIA^X{1GXSD$}V6aG5WdD+aZ)3UOU)PA-Q{> z3qB8AR`51~p;B8g;f0T+gwBF{nn#RZ*xS3do08bdRK^ktwT+BuQ7nn@r4GbJz7x8u zX+HvifdH9pz)+xQ>TMce;8KGy?O90aj>ISS3b7$HM<}?=R_^2Dov>KX=fW4gZ0oL# z4TlXtL8u4+=w-H(!dkS=iZ?}Kj79RMiGFcJL@(@4Kz{D4>0IF9=(5M)>0ajZaHD0q hCv|>6qS`CJYwg-kjl|iF9l$*x Date: Thu, 23 Aug 2018 13:00:15 -0700 Subject: [PATCH 0506/1415] DO NOT MERGE: CDD Annotations for Section: 7.4.2 C-1-1: MUST implement the WifiAwareManager APIs as described in the SDK documentation. --> SingleDeviceTest C-1-4:MUST randomize the Wi-Fi Aware management interface address at intervals no longer then 30 minutes and whenever Wi-Fi Aware is enabled -->SingleDeviceTest#testAttachDiscoveryAddressChanges() CDD SECTION:7.4.1.1/C-1-1,C-1-3: Wifi Direct C-1-1: MUST implement the corresponding Android API as described in the SDK documentation. C-1-3: MUST support regular Wi-Fi operation. --> ConcurrencyTest 7.4.2.4/C-1-1,C-2-1: C-1-1: MUST implement the Passpoint related WifiManager APIs as described in the SDK documentation. C-1-2: MUST support IEEE 802.11u standard, specifically related to Network Discovery and Selection, such as Generic Advertisement Service (GAS) and Access Network Query Protocol (ANQP). --> Passpoint configuration tests Added C-0-3 to ConnectivityBackgroundTestActivity as well CDD VERSION: 8.1: https://source.android.com/compatibility/8.1/android-8.1-cdd Bug: 112612833 Test: make cts Change-Id: Ief11b3ae7899bfdca12a7cce63daca600b1f0cdf --- .../net/src/android/net/wifi/aware/cts/SingleDeviceTest.java | 4 ++++ tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java | 3 +++ .../net/src/android/net/wifi/cts/WifiConfigurationTest.java | 3 +++ tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java | 2 ++ tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 5 +++++ .../src/android/net/wifi/cts/WifiManager_WifiLockTest.java | 3 +++ 6 files changed, 20 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java index 87e22d82b7..5dce5ab39d 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -41,6 +41,8 @@ import android.provider.Settings; import android.test.AndroidTestCase; import android.util.Log; +import com.android.compatibility.common.util.CddTest; + import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashSet; @@ -54,6 +56,7 @@ import java.util.concurrent.TimeUnit; * Wi-Fi Aware CTS test suite: single device testing. Performs tests on a single * device to validate Wi-Fi Aware. */ +@CddTest(requirement="7.4.2.3/C-1-1") public class SingleDeviceTest extends AndroidTestCase { private static final String TAG = "WifiAwareCtsTests"; @@ -485,6 +488,7 @@ public class SingleDeviceTest extends AndroidTestCase { * then the attach/destroy will not correspond to enable/disable and will not result in a new * MAC address being generated. */ + @CddTest(requirement="7.4.2.3/C-1-4") public void testAttachDiscoveryAddressChanges() { if (!TestUtils.shouldTestWifiAware(getContext())) { return; diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java index a066ba80de..418788322e 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java @@ -31,9 +31,12 @@ import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_DISABLED; import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_ENABLED; import android.test.AndroidTestCase; +import com.android.compatibility.common.util.CddTest; + import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +@CddTest(requirement="7.4.2.1/C-1-1,C-1-3") public class ConcurrencyTest extends AndroidTestCase { private class MySync { int expectedWifiState; diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java index 4480a24a9a..8b17a57425 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java @@ -23,6 +23,9 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.test.AndroidTestCase; +import com.android.compatibility.common.util.CddTest; + +@CddTest(requirement="7.4.2/C-1-1") public class WifiConfigurationTest extends AndroidTestCase { private WifiManager mWifiManager; @Override diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 5983cb72c2..c97f010556 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -29,9 +29,11 @@ import android.net.wifi.WifiSsid; import android.test.AndroidTestCase; import com.android.compatibility.common.util.PollingCheck; +import com.android.compatibility.common.util.CddTest; import java.util.concurrent.Callable; +@CddTest(requirement="7.4.2/C-1-1") public class WifiInfoTest extends AndroidTestCase { private static class MySync { int expectedState = STATE_NULL; diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 89daca21da..87239b4ca5 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -37,6 +37,7 @@ import android.provider.Settings; import android.test.AndroidTestCase; import android.util.Log; +import com.android.compatibility.common.util.CddTest; import com.android.compatibility.common.util.WifiConfigCreator; import java.net.HttpURLConnection; @@ -49,6 +50,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +@CddTest(requirement="7.4.2/C-1-1") public class WifiManagerTest extends AndroidTestCase { private static class MySync { int expectedState = STATE_NULL; @@ -586,6 +588,7 @@ public class WifiManagerTest extends AndroidTestCase { * * @throws Exception */ + @CddTest(requirement="7.4.2.4/C-1-1,C-1-2,C-2-1") public void testAddPasspointConfigWithUserCredential() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported @@ -600,6 +603,7 @@ public class WifiManagerTest extends AndroidTestCase { * * @throws Exception */ + @CddTest(requirement="7.4.2.4/C-1-1,C-1-2,C-2-1") public void testAddPasspointConfigWithCertCredential() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported @@ -614,6 +618,7 @@ public class WifiManagerTest extends AndroidTestCase { * * @throws Exception */ + @CddTest(requirement="7.4.2.4/C-1-1,C-1-2,C-2-1") public void testAddPasspointConfigWithSimCredential() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java index 3cdd56af89..aeb1234dd3 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java @@ -21,6 +21,9 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; +import com.android.compatibility.common.util.CddTest; + +@CddTest(requirement="7.4.2/C-1-1") public class WifiManager_WifiLockTest extends AndroidTestCase { private static final String WIFI_TAG = "WifiManager_WifiLockTest"; From 6943e15b8cc826a0ea0ae6fa153fe3c511fd53d5 Mon Sep 17 00:00:00 2001 From: saurav subedi Date: Wed, 5 Sep 2018 17:32:32 -0700 Subject: [PATCH 0507/1415] DO NOT MERGE: CDD Annotations for Section: 7.4.7 Bug: 112612833 Test: make cts Change-Id: I7443794296f9364bc0e88e5ba3b717d6c01511a7 --- .../src/com/android/cts/net/hostside/DataSaverModeTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 599a31ce1c..c24ca89e2f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -22,6 +22,9 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELI import android.util.Log; +import com.android.compatibility.common.util.CddTest; + +@CddTest(requirement="7.4.7/C-1-1,H-1-1") public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { From 340047b18cd716c5aa3e26cbb697aad80e6637f6 Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Fri, 27 Apr 2018 08:50:14 -0700 Subject: [PATCH 0508/1415] WifiManagerTest: allow for multiple modes Now that WifiService can/will support dual simultaneous mode operation, make sure the tests allow for it as well. Bug: 31346104 Bug: 115567184 Test: atest android.net.wifi.cts Change-Id: Id3aaacb3651568c18850a0fdf3832c0f52218cf2 Merged-In: Id3aaacb3651568c18850a0fdf3832c0f52218cf2 --- .../android/net/wifi/cts/WifiManagerTest.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 87239b4ca5..90540f4696 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -838,10 +838,9 @@ public class WifiManagerTest extends AndroidTestCase { TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - // at this point, wifi should be off - assertFalse(mWifiManager.isWifiEnabled()); - stopLocalOnlyHotspot(callback, wifiEnabled); + + // wifi should either stay on, or come back on assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } @@ -853,7 +852,7 @@ public class WifiManagerTest extends AndroidTestCase { * tethering is started. * Note: Location mode must be enabled for this test. */ - public void testSetWifiEnabledByAppDoesNotStopHotspot() { + public void testSetWifiEnabledByAppDoesNotStopHotspot() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported return; @@ -865,15 +864,18 @@ public class WifiManagerTest extends AndroidTestCase { boolean wifiEnabled = mWifiManager.isWifiEnabled(); + if (wifiEnabled) { + // disable wifi so we have something to turn on (some devices may be able to run + // simultaneous modes) + setWifiEnabled(false); + } + TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - // at this point, wifi should be off - assertFalse(mWifiManager.isWifiEnabled()); // now we should fail to turn on wifi assertFalse(mWifiManager.setWifiEnabled(true)); stopLocalOnlyHotspot(callback, wifiEnabled); - assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } /** @@ -897,9 +899,6 @@ public class WifiManagerTest extends AndroidTestCase { TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - // at this point, wifi should be off - assertFalse(mWifiManager.isWifiEnabled()); - // now make a second request - this should fail. TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLOHSLock); try { @@ -908,9 +907,12 @@ public class WifiManagerTest extends AndroidTestCase { Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice"); caughtException = true; } + if (!caughtException) { + // second start did not fail, should clean up the hotspot. + stopLocalOnlyHotspot(callback2, wifiEnabled); + } assertTrue(caughtException); stopLocalOnlyHotspot(callback, wifiEnabled); - assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } } From ab53484d7b7337ac6897facd74488411745041eb Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Wed, 11 Jul 2018 15:46:21 -0700 Subject: [PATCH 0509/1415] VpnTest: test getConnectionOwnerUid API Test connection->UID resolution for both UDP and TCP connections. Bug: 9496886 Bug: 109758967 Test: atest HostsideVpnTests Change-Id: Ic17c64df74f65d788fd3d95a25af3c5b44946881 --- .../com/android/cts/net/hostside/VpnTest.java | 49 +++++++++++++++++-- .../com/android/cts/net/HostsideVpnTests.java | 4 ++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index bc982cec78..1ba701de29 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -16,6 +16,7 @@ package com.android.cts.net.hostside; +import static android.os.Process.INVALID_UID; import static android.system.OsConstants.*; import android.content.Intent; @@ -36,6 +37,7 @@ import android.support.test.uiautomator.UiScrollable; import android.support.test.uiautomator.UiSelector; import android.system.ErrnoException; import android.system.Os; +import android.system.OsConstants; import android.system.StructPollfd; import android.test.InstrumentationTestCase; import android.test.MoreAsserts; @@ -353,7 +355,7 @@ public class VpnTest extends InstrumentationTestCase { MoreAsserts.assertEquals(data, read); } - private static void checkTcpReflection(String to, String expectedFrom) throws IOException { + private void checkTcpReflection(String to, String expectedFrom) throws IOException { // Exercise TCP over the VPN by "connecting to ourselves". We open a server socket and a // client socket, and connect the client socket to a remote host, with the port of the // server socket. The PacketReflector reflects the packets, changing the source addresses @@ -391,7 +393,8 @@ public class VpnTest extends InstrumentationTestCase { // Accept the connection on the server side. listen.setSoTimeout(SOCKET_TIMEOUT_MS); server = listen.accept(); - + checkConnectionOwnerUidTcp(client); + checkConnectionOwnerUidTcp(server); // Check that the source and peer addresses are as expected. assertEquals(expectedFrom, client.getLocalAddress().getHostAddress()); assertEquals(expectedFrom, server.getLocalAddress().getHostAddress()); @@ -424,7 +427,23 @@ public class VpnTest extends InstrumentationTestCase { } } - private static void checkUdpEcho(String to, String expectedFrom) throws IOException { + private void checkConnectionOwnerUidUdp(DatagramSocket s, boolean expectSuccess) { + final int expectedUid = expectSuccess ? Process.myUid() : INVALID_UID; + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_UDP, loc, rem); + assertEquals(expectedUid, uid); + } + + private void checkConnectionOwnerUidTcp(Socket s) { + final int expectedUid = Process.myUid(); + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem); + assertEquals(expectedUid, uid); + } + + private void checkUdpEcho(String to, String expectedFrom) throws IOException { DatagramSocket s; InetAddress address = InetAddress.getByName(to); if (address instanceof Inet6Address) { // http://b/18094870 @@ -448,6 +467,7 @@ public class VpnTest extends InstrumentationTestCase { try { if (expectedFrom != null) { s.send(p); + checkConnectionOwnerUidUdp(s, true); s.receive(p); MoreAsserts.assertEquals(data, p.getData()); } else { @@ -455,7 +475,9 @@ public class VpnTest extends InstrumentationTestCase { s.send(p); s.receive(p); fail("Received unexpected reply"); - } catch(IOException expected) {} + } catch (IOException expected) { + checkConnectionOwnerUidUdp(s, false); + } } } finally { s.close(); @@ -580,4 +602,23 @@ public class VpnTest extends InstrumentationTestCase { checkNoTrafficOnVpn(); } + + public void testGetConnectionOwnerUidSecurity() throws Exception { + + if (!supportedHardware()) return; + + DatagramSocket s; + InetAddress address = InetAddress.getByName("localhost"); + s = new DatagramSocket(); + s.setSoTimeout(SOCKET_TIMEOUT_MS); + s.connect(address, 7); + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + try { + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem); + fail("Only an active VPN app may call this API."); + } catch (SecurityException expected) { + return; + } + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java index 69b07af193..853668c719 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -44,4 +44,8 @@ public class HostsideVpnTests extends HostsideNetworkTestCase { public void testAppDisallowed() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppDisallowed"); } + + public void testGetConnectionOwnerUidSecurity() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testGetConnectionOwnerUidSecurity"); + } } From cd79fb2af625ba62241652f91f13794b0316dc27 Mon Sep 17 00:00:00 2001 From: saurav subedi Date: Fri, 7 Sep 2018 10:57:01 -0700 Subject: [PATCH 0510/1415] DO NOT MERGE:CDD Annotation for 7.4.7/C-2-1 Devices that don't provide data saver mode must return RESTRICT_BACKGROUND_STATUS_DISABLED for the ConnectivityManager#getRestrictBackgroundStatus() Bug: 116495679 Test: make cts Change-Id: I81b52c9d26afcf51a7e416d20589c9c7cfb878f6 --- .../app/src/com/android/cts/net/hostside/DataSaverModeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index c24ca89e2f..c3962fbbc3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -24,7 +24,7 @@ import android.util.Log; import com.android.compatibility.common.util.CddTest; -@CddTest(requirement="7.4.7/C-1-1,H-1-1") +@CddTest(requirement="7.4.7/C-1-1,H-1-1,C-2-1") public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { From ff39f3fa71bbb38ea0ca37f67f6e0557e6a2d962 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Thu, 20 Sep 2018 14:38:52 -0700 Subject: [PATCH 0511/1415] Move tests requiring /proc/sys/net access to hostside This access is going away for apps. Move these tests to hostside tests to be executed by the shell domain. Test: atest cts/hostsidetests/net/src/com/android/cts/net/ProcNetTest.java Test: atest android.net.cts.ConnectivityManagerTest Test: atest android.net.cts.IpSecSysctlTest Test: atest android.net.cts.MultinetworkSysctlTest Bug: 116053204 Change-Id: Id7e867184dd344a2d877515956e76019d627788b --- .../src/com/android/cts/net/ProcNetTest.java | 183 ++++++++++++++++++ .../net/cts/ConnectivityManagerTest.java | 65 ------- .../src/android/net/cts/IpSecSysctlTest.java | 45 ----- .../net/cts/MultinetworkSysctlTest.java | 73 ------- .../src/android/net/cts/SysctlBaseTest.java | 70 ------- 5 files changed, 183 insertions(+), 253 deletions(-) create mode 100644 tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java delete mode 100644 tests/cts/net/src/android/net/cts/IpSecSysctlTest.java delete mode 100644 tests/cts/net/src/android/net/cts/MultinetworkSysctlTest.java delete mode 100644 tests/cts/net/src/android/net/cts/SysctlBaseTest.java diff --git a/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java b/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java new file mode 100644 index 0000000000..1335eb8011 --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2018 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.security.cts; + +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceTestCase; +import com.android.tradefed.testtype.IBuildReceiver; +import com.android.tradefed.testtype.IDeviceTest; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.lang.Integer; +import java.lang.String; +import java.util.stream.Collectors; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.zip.GZIPInputStream; + +/** + * Host-side tests for values in /proc/net. + * + * These tests analyze /proc/net to verify that certain networking properties are correct. + */ +public class ProcNetTest extends DeviceTestCase implements IBuildReceiver, IDeviceTest { + private static final String SPI_TIMEOUT_SYSCTL = "/proc/sys/net/core/xfrm_acq_expires"; + private static final int MIN_ACQ_EXPIRES = 3600; + // Global sysctls. Must be present and set to 1. + private static final String[] GLOBAL_SYSCTLS = { + "/proc/sys/net/ipv4/fwmark_reflect", + "/proc/sys/net/ipv6/fwmark_reflect", + "/proc/sys/net/ipv4/tcp_fwmark_accept", + }; + + // Per-interface IPv6 autoconf sysctls. + private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf"; + private static final String AUTOCONF_SYSCTL = "accept_ra_rt_table"; + + // Expected values for MIN|MAX_PLEN. + private static final String ACCEPT_RA_RT_INFO_MIN_PLEN_STRING = "accept_ra_rt_info_min_plen"; + private static final int ACCEPT_RA_RT_INFO_MIN_PLEN_VALUE = 48; + private static final String ACCEPT_RA_RT_INFO_MAX_PLEN_STRING = "accept_ra_rt_info_max_plen"; + private static final int ACCEPT_RA_RT_INFO_MAX_PLEN_VALUE = 64; + // Expected values for RFC 7559 router soliciations. + // Maximum number of router solicitations to send. -1 means no limit. + private static final int IPV6_WIFI_ROUTER_SOLICITATIONS = -1; + private ITestDevice mDevice; + private IBuildInfo mBuild; + + /** + * {@inheritDoc} + */ + @Override + public void setBuild(IBuildInfo build) { + mBuild = build; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDevice(ITestDevice device) { + super.setDevice(device); + mDevice = device; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + protected void assertLess(String sysctl, int a, int b) { + assertTrue("value of " + sysctl + ": expected < " + b + " but was: " + a, a < b); + } + + protected void assertAtLeast(String sysctl, int a, int b) { + assertTrue("value of " + sysctl + ": expected >= " + b + " but was: " + a, a >= b); + } + + public int readIntFromPath(String path) throws Exception { + String mode = mDevice.executeAdbCommand("shell", "stat", "-c", "%a", path).trim(); + String user = mDevice.executeAdbCommand("shell", "stat", "-c", "%u", path).trim(); + String group = mDevice.executeAdbCommand("shell", "stat", "-c", "%g", path).trim(); + assertEquals(mode, "644"); + assertEquals(user, "0"); + assertEquals(group, "0"); + return Integer.parseInt(mDevice.executeAdbCommand("shell", "cat", path).trim()); + } + + /** + * Checks that SPI default timeouts are overridden, and set to a reasonable length of time + */ + public void testMinAcqExpires() throws Exception { + int value = readIntFromPath(SPI_TIMEOUT_SYSCTL); + assertAtLeast(SPI_TIMEOUT_SYSCTL, value, MIN_ACQ_EXPIRES); + } + + /** + * Checks that the sysctls for multinetwork kernel features are present and + * enabled. The necessary kernel commits are: + * + * Mainline Linux: + * e110861 net: add a sysctl to reflect the fwmark on replies + * 1b3c61d net: Use fwmark reflection in PMTU discovery. + * 84f39b0 net: support marking accepting TCP sockets + * + * Common Android tree (e.g., 3.10): + * a03f539 net: ipv6: autoconf routes into per-device tables + */ + public void testProcSysctls() throws Exception { + for (String sysctl : GLOBAL_SYSCTLS) { + int value = readIntFromPath(sysctl); + assertEquals(sysctl, 1, value); + } + + String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1", + IPV6_SYSCTL_DIR).split("\n"); + for (String interfaceDir : interfaceDirs) { + if (interfaceDir.equals("all") || interfaceDir.equals("lo")) { + continue; + } + String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + AUTOCONF_SYSCTL; + int value = readIntFromPath(path); + assertLess(path, value, 0); + } + } + + /** Verify that accept_ra_rt_info_{min,max}_plen exists and is set to the expected value */ + public void testAcceptRaRtInfoMinMaxPlen() throws Exception { + String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1", + IPV6_SYSCTL_DIR).split("\n"); + for (String interfaceDir : interfaceDirs) { + if (interfaceDir.equals("all") || interfaceDir.equals("lo")) { + continue; + } + String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "accept_ra_rt_info_min_plen"; + int value = readIntFromPath(path); + assertEquals(path, value, ACCEPT_RA_RT_INFO_MIN_PLEN_VALUE); + path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "accept_ra_rt_info_max_plen"; + value = readIntFromPath(path); + assertEquals(path, value, ACCEPT_RA_RT_INFO_MAX_PLEN_VALUE); + } + } + + /** + * Verify that router_solicitations exists and is set to the expected value + * and verify that router_solicitation_max_interval exists and is in an acceptable interval. + */ + public void testRouterSolicitations() throws Exception { + String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1", + IPV6_SYSCTL_DIR).split("\n"); + for (String interfaceDir : interfaceDirs) { + if (interfaceDir.equals("all") || interfaceDir.equals("lo")) { + continue; + } + String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "router_solicitations"; + int value = readIntFromPath(path); + assertEquals(IPV6_WIFI_ROUTER_SOLICITATIONS, value); + path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "router_solicitation_max_interval"; + int interval = readIntFromPath(path); + final int lowerBoundSec = 15 * 60; + final int upperBoundSec = 60 * 60; + assertTrue(lowerBoundSec <= interval); + assertTrue(interval <= upperBoundSec); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 441bee3e5c..6e4f34ecf7 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -107,17 +107,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { "Host: " + TEST_HOST + "\r\n" + "Connection: keep-alive\r\n\r\n"; - // Base path for IPv6 sysctls - private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf"; - - // Expected values for MIN|MAX_PLEN. - private static final int IPV6_WIFI_ACCEPT_RA_RT_INFO_MIN_PLEN = 48; - private static final int IPV6_WIFI_ACCEPT_RA_RT_INFO_MAX_PLEN = 64; - - // Expected values for RFC 7559 router soliciations. - // Maximum number of router solicitations to send. -1 means no limit. - private static final int IPV6_WIFI_ROUTER_SOLICITATIONS = -1; - // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. private static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; @@ -908,60 +897,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (SecurityException expected) {} } - private Scanner makeWifiSysctlScanner(String key) throws FileNotFoundException { - Network network = ensureWifiConnected(); - String iface = mCm.getLinkProperties(network).getInterfaceName(); - String path = IPV6_SYSCTL_DIR + "/" + iface + "/" + key; - return new Scanner(new File(path)); - } - - /** Verify that accept_ra_rt_info_min_plen exists and is set to the expected value */ - public void testAcceptRaRtInfoMinPlen() throws Exception { - if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { - Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot execute unless device supports WiFi"); - return; - } - Scanner s = makeWifiSysctlScanner("accept_ra_rt_info_min_plen"); - assertEquals(IPV6_WIFI_ACCEPT_RA_RT_INFO_MIN_PLEN, s.nextInt()); - } - - /** Verify that accept_ra_rt_info_max_plen exists and is set to the expected value */ - public void testAcceptRaRtInfoMaxPlen() throws Exception { - if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { - Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot execute unless device supports WiFi"); - return; - } - Scanner s = makeWifiSysctlScanner("accept_ra_rt_info_max_plen"); - assertEquals(IPV6_WIFI_ACCEPT_RA_RT_INFO_MAX_PLEN, s.nextInt()); - } - - /** Verify that router_solicitations exists and is set to the expected value */ - public void testRouterSolicitations() throws Exception { - if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { - Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot execute unless device supports WiFi"); - return; - } - Scanner s = makeWifiSysctlScanner("router_solicitations"); - assertEquals(IPV6_WIFI_ROUTER_SOLICITATIONS, s.nextInt()); - } - - /** Verify that router_solicitation_max_interval exists and is in an acceptable interval */ - public void testRouterSolicitationMaxInterval() throws Exception { - if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { - Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot execute unless device supports WiFi"); - return; - } - Scanner s = makeWifiSysctlScanner("router_solicitation_max_interval"); - int interval = s.nextInt(); - // Verify we're in the interval [15 minutes, 60 minutes]. Lower values may adversely - // impact battery life and higher values can decrease the probability of detecting - // network changes. - final int lowerBoundSec = 15 * 60; - final int upperBoundSec = 60 * 60; - assertTrue(lowerBoundSec <= interval); - assertTrue(interval <= upperBoundSec); - } - // Returns "true", "false" or "none" private String getWifiMeteredStatus(String ssid) throws Exception { // Interestingly giving the SSID as an argument to list wifi-networks diff --git a/tests/cts/net/src/android/net/cts/IpSecSysctlTest.java b/tests/cts/net/src/android/net/cts/IpSecSysctlTest.java deleted file mode 100644 index b362282c89..0000000000 --- a/tests/cts/net/src/android/net/cts/IpSecSysctlTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2018 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 android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.system.StructStat; -import android.test.AndroidTestCase; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.IOException; - -/** - * Tests for multinetwork sysctl functionality. - */ -public class IpSecSysctlTest extends SysctlBaseTest { - - // SPI expiration sysctls. Must be present and set greater than 1h. - private static final String SPI_TIMEOUT_SYSCTL = "/proc/sys/net/core/xfrm_acq_expires"; - private static final int MIN_ACQ_EXPIRES = 3600; - - /** - * Checks that SPI default timeouts are overridden, and set to a reasonable length of time - */ - public void testProcFiles() throws ErrnoException, IOException, NumberFormatException { - int value = getIntValue(SPI_TIMEOUT_SYSCTL); - assertAtLeast(SPI_TIMEOUT_SYSCTL, value, MIN_ACQ_EXPIRES); - } -} diff --git a/tests/cts/net/src/android/net/cts/MultinetworkSysctlTest.java b/tests/cts/net/src/android/net/cts/MultinetworkSysctlTest.java deleted file mode 100644 index 1d0c111fd6..0000000000 --- a/tests/cts/net/src/android/net/cts/MultinetworkSysctlTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2014 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 android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.system.StructStat; -import android.test.AndroidTestCase; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.IOException; - -/** - * Tests for multinetwork sysctl functionality. - */ -public class MultinetworkSysctlTest extends SysctlBaseTest { - - // Global sysctls. Must be present and set to 1. - private static final String[] GLOBAL_SYSCTLS = { - "/proc/sys/net/ipv4/fwmark_reflect", - "/proc/sys/net/ipv6/fwmark_reflect", - "/proc/sys/net/ipv4/tcp_fwmark_accept", - }; - - // Per-interface IPv6 autoconf sysctls. - private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf"; - private static final String AUTOCONF_SYSCTL = "accept_ra_rt_table"; - - /** - * Checks that the sysctls for multinetwork kernel features are present and - * enabled. The necessary kernel commits are: - * - * Mainline Linux: - * e110861 net: add a sysctl to reflect the fwmark on replies - * 1b3c61d net: Use fwmark reflection in PMTU discovery. - * 84f39b0 net: support marking accepting TCP sockets - * - * Common Android tree (e.g., 3.10): - * a03f539 net: ipv6: autoconf routes into per-device tables - */ - public void testProcFiles() throws ErrnoException, IOException, NumberFormatException { - for (String sysctl : GLOBAL_SYSCTLS) { - int value = getIntValue(sysctl); - assertEquals(sysctl, 1, value); - } - - File[] interfaceDirs = new File(IPV6_SYSCTL_DIR).listFiles(); - for (File interfaceDir : interfaceDirs) { - if (interfaceDir.getName().equals("all") || interfaceDir.getName().equals("lo")) { - continue; - } - String sysctl = new File(interfaceDir, AUTOCONF_SYSCTL).getAbsolutePath(); - int value = getIntValue(sysctl); - assertLess(sysctl, value, 0); - } - } -} diff --git a/tests/cts/net/src/android/net/cts/SysctlBaseTest.java b/tests/cts/net/src/android/net/cts/SysctlBaseTest.java deleted file mode 100644 index a5966d48d3..0000000000 --- a/tests/cts/net/src/android/net/cts/SysctlBaseTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2018 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 android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.system.StructStat; -import android.test.AndroidTestCase; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.IOException; - -/** - * Tests for multinetwork sysctl functionality. - */ -public class SysctlBaseTest extends AndroidTestCase { - - // Expected mode, UID, and GID of sysctl files. - private static final int SYSCTL_MODE = 0100644; - private static final int SYSCTL_UID = 0; - private static final int SYSCTL_GID = 0; - - private void checkSysctlPermissions(String fileName) throws ErrnoException { - StructStat stat = Os.stat(fileName); - assertEquals("mode of " + fileName + ":", SYSCTL_MODE, stat.st_mode); - assertEquals("UID of " + fileName + ":", SYSCTL_UID, stat.st_uid); - assertEquals("GID of " + fileName + ":", SYSCTL_GID, stat.st_gid); - } - - protected void assertLess(String sysctl, int a, int b) { - assertTrue("value of " + sysctl + ": expected < " + b + " but was: " + a, a < b); - } - - protected void assertAtLeast(String sysctl, int a, int b) { - assertTrue("value of " + sysctl + ": expected >= " + b + " but was: " + a, a >= b); - } - - private String readFile(String fileName) throws ErrnoException, IOException { - byte[] buf = new byte[1024]; - FileDescriptor fd = Os.open(fileName, 0, OsConstants.O_RDONLY); - int bytesRead = Os.read(fd, buf, 0, buf.length); - assertLess("length of " + fileName + ":", bytesRead, buf.length); - return new String(buf); - } - - /* - * Checks permissions and retrieves the sysctl's value. Retrieval of value should always use - * this method - */ - protected int getIntValue(String filename) throws ErrnoException, IOException { - checkSysctlPermissions(filename); - return Integer.parseInt(readFile(filename).trim()); - } -} From d502c991233b62f6fb12c96b6d79f1aef4cb9353 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Fri, 28 Sep 2018 10:36:12 -0700 Subject: [PATCH 0512/1415] Refactor duplicate code into single function Address comments in aosp/763607 Bug: 116053204 Test: atest ProcNetTest Change-Id: Iec8b58b6499a7764b3757d4dd820e1f45a65e814 --- .../src/com/android/cts/net/ProcNetTest.java | 58 +++++++------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java b/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java index 1335eb8011..19e61c62a0 100644 --- a/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java +++ b/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java @@ -22,16 +22,11 @@ import com.android.tradefed.testtype.DeviceTestCase; import com.android.tradefed.testtype.IBuildReceiver; import com.android.tradefed.testtype.IDeviceTest; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStreamReader; import java.lang.Integer; import java.lang.String; -import java.util.stream.Collectors; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.zip.GZIPInputStream; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; /** * Host-side tests for values in /proc/net. @@ -62,6 +57,7 @@ public class ProcNetTest extends DeviceTestCase implements IBuildReceiver, IDevi private static final int IPV6_WIFI_ROUTER_SOLICITATIONS = -1; private ITestDevice mDevice; private IBuildInfo mBuild; + private String[] mSysctlDirs; /** * {@inheritDoc} @@ -83,8 +79,19 @@ public class ProcNetTest extends DeviceTestCase implements IBuildReceiver, IDevi @Override protected void setUp() throws Exception { super.setUp(); + mSysctlDirs = getSysctlDirs(); } + private String[] getSysctlDirs() throws Exception { + String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1", + IPV6_SYSCTL_DIR).split("\n"); + List interfaceDirsList = new ArrayList(Arrays.asList(interfaceDirs)); + interfaceDirsList.remove("all"); + interfaceDirsList.remove("lo"); + return interfaceDirsList.toArray(new String[interfaceDirsList.size()]); + } + + protected void assertLess(String sysctl, int a, int b) { assertTrue("value of " + sysctl + ": expected < " + b + " but was: " + a, a < b); } @@ -113,15 +120,7 @@ public class ProcNetTest extends DeviceTestCase implements IBuildReceiver, IDevi /** * Checks that the sysctls for multinetwork kernel features are present and - * enabled. The necessary kernel commits are: - * - * Mainline Linux: - * e110861 net: add a sysctl to reflect the fwmark on replies - * 1b3c61d net: Use fwmark reflection in PMTU discovery. - * 84f39b0 net: support marking accepting TCP sockets - * - * Common Android tree (e.g., 3.10): - * a03f539 net: ipv6: autoconf routes into per-device tables + * enabled. */ public void testProcSysctls() throws Exception { for (String sysctl : GLOBAL_SYSCTLS) { @@ -129,26 +128,18 @@ public class ProcNetTest extends DeviceTestCase implements IBuildReceiver, IDevi assertEquals(sysctl, 1, value); } - String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1", - IPV6_SYSCTL_DIR).split("\n"); - for (String interfaceDir : interfaceDirs) { - if (interfaceDir.equals("all") || interfaceDir.equals("lo")) { - continue; - } + for (String interfaceDir : mSysctlDirs) { String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + AUTOCONF_SYSCTL; int value = readIntFromPath(path); assertLess(path, value, 0); } } - /** Verify that accept_ra_rt_info_{min,max}_plen exists and is set to the expected value */ + /** + * Verify that accept_ra_rt_info_{min,max}_plen exists and is set to the expected value + */ public void testAcceptRaRtInfoMinMaxPlen() throws Exception { - String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1", - IPV6_SYSCTL_DIR).split("\n"); - for (String interfaceDir : interfaceDirs) { - if (interfaceDir.equals("all") || interfaceDir.equals("lo")) { - continue; - } + for (String interfaceDir : mSysctlDirs) { String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "accept_ra_rt_info_min_plen"; int value = readIntFromPath(path); assertEquals(path, value, ACCEPT_RA_RT_INFO_MIN_PLEN_VALUE); @@ -163,12 +154,7 @@ public class ProcNetTest extends DeviceTestCase implements IBuildReceiver, IDevi * and verify that router_solicitation_max_interval exists and is in an acceptable interval. */ public void testRouterSolicitations() throws Exception { - String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1", - IPV6_SYSCTL_DIR).split("\n"); - for (String interfaceDir : interfaceDirs) { - if (interfaceDir.equals("all") || interfaceDir.equals("lo")) { - continue; - } + for (String interfaceDir : mSysctlDirs) { String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "router_solicitations"; int value = readIntFromPath(path); assertEquals(IPV6_WIFI_ROUTER_SOLICITATIONS, value); From 7f494f69183ac09fc94573e62f6eaa7dbc0ed054 Mon Sep 17 00:00:00 2001 From: xshu Date: Fri, 7 Sep 2018 11:30:10 -0700 Subject: [PATCH 0513/1415] CTS: Location scan is not disabled at screen off Location Wi-Fi scanning should not be turned off when the screen turns off. Bug: 113876483 Test: Run CTS, manually toggle location Wi-Fi scanning off right after the screen turns on and observe failure. Test: Run CTS with location Wi-Fi scanning initially turned off and observe failure. Test: Run CTS with location Wi-Fi scanning initially turned on and observe success. Change-Id: I092a3854b6365de72c2cfe38a55a0e1cedfcabd9 --- .../android/net/wifi/cts/WifiManagerTest.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index ea31fdffd6..3b8ad6ca65 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -38,6 +38,8 @@ import android.net.wifi.hotspot2.pps.HomeSp; import android.os.Process; import android.os.SystemClock; import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.uiautomator.UiDevice; import android.test.AndroidTestCase; import android.util.ArraySet; import android.util.Log; @@ -66,6 +68,7 @@ public class WifiManagerTest extends AndroidTestCase { private List mScanResults = null; private NetworkInfo mNetworkInfo; private Object mLOHSLock = new Object(); + private UiDevice mUiDevice; // Please refer to WifiManager private static final int MIN_RSSI = -100; @@ -90,6 +93,7 @@ public class WifiManagerTest extends AndroidTestCase { private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; private static final int DURATION = 10000; + private static final int DURATION_SCREEN_TOGGLE = 2000; private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000; private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; private static final int WIFI_SCAN_TEST_ITERATIONS = 5; @@ -162,6 +166,8 @@ public class WifiManagerTest extends AndroidTestCase { mWifiLock.acquire(); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); + mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + turnScreenOnNoDelay(); Thread.sleep(DURATION); assertTrue(mWifiManager.isWifiEnabled()); synchronized (mMySync) { @@ -1072,4 +1078,88 @@ public class WifiManagerTest extends AndroidTestCase { } } } + + private void turnScreenOnNoDelay() throws Exception { + mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); + mUiDevice.executeShellCommand("wm dismiss-keyguard"); + } + + private void turnScreenOn() throws Exception { + turnScreenOnNoDelay(); + // Since the screen on/off intent is ordered, they will not be sent right now. + Thread.sleep(DURATION_SCREEN_TOGGLE); + } + + private void turnScreenOff() throws Exception { + mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); + // Since the screen on/off intent is ordered, they will not be sent right now. + Thread.sleep(DURATION_SCREEN_TOGGLE); + } + + /** + * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled + * but location is on. + * @throws Exception + */ + public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + if (!hasLocationFeature()) { + // skip the test if location is not supported + return; + } + if (!isLocationEnabled()) { + fail("Please enable location for this test - since Marshmallow WiFi scan results are" + + " empty when location is disabled!"); + } + if(!mWifiManager.isScanAlwaysAvailable()) { + fail("Please enable Wi-Fi scanning for this test!"); + } + setWifiEnabled(false); + turnScreenOn(); + assertWifiScanningIsOn(); + // Toggle screen and verify Wi-Fi scanning is still on. + turnScreenOff(); + assertWifiScanningIsOn(); + turnScreenOn(); + assertWifiScanningIsOn(); + } + + /** + * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is enabled. + * @throws Exception + */ + public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + if (!hasLocationFeature()) { + // skip the test if location is not supported + return; + } + if (!isLocationEnabled()) { + fail("Please enable location for this test - since Marshmallow WiFi scan results are" + + " empty when location is disabled!"); + } + if(!mWifiManager.isScanAlwaysAvailable()) { + fail("Please enable Wi-Fi scanning for this test!"); + } + setWifiEnabled(true); + turnScreenOn(); + assertWifiScanningIsOn(); + // Toggle screen and verify Wi-Fi scanning is still on. + turnScreenOff(); + assertWifiScanningIsOn(); + turnScreenOn(); + assertWifiScanningIsOn(); + } + + private void assertWifiScanningIsOn() { + if(!mWifiManager.isScanAlwaysAvailable()) { + fail("Wi-Fi scanning should be on."); + } + } } From c7758c460ce66ae130ad7abfa9eb7bae3d495e95 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Mon, 1 Oct 2018 14:02:44 -0700 Subject: [PATCH 0514/1415] [CTS] Clarify CTS assert message for missing RTT AP support Add a much more verbose message for the common failure case in which the CTS is run without an AP which supports IEEE 802.11mc / RTT. That may help speed up issue resolution. Bug: 116849381 Test: atest WifiRttTest Change-Id: I4ea3fbe17563f0087a013cbf48f7f601fec7e363 --- .../cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java index 74a0c3dfbc..20791c068e 100644 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java +++ b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java @@ -16,11 +16,9 @@ package android.net.wifi.rtt.cts; -import android.content.IntentFilter; import android.net.wifi.ScanResult; import android.net.wifi.rtt.RangingRequest; import android.net.wifi.rtt.RangingResult; -import android.net.wifi.rtt.WifiRttManager; import com.android.compatibility.common.util.DeviceReportLog; import com.android.compatibility.common.util.ResultType; @@ -64,7 +62,10 @@ public class WifiRttTest extends TestBase { // Scan for IEEE 802.11mc supporting APs ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); - assertTrue("Cannot find test AP", testAp != null); + assertTrue( + "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " + + "your test setup includes them!", + testAp != null); // Perform RTT operations RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build(); From f99027bf27c683164ff74a325eeb96c8b0624ca3 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Fri, 5 Oct 2018 10:49:48 -0700 Subject: [PATCH 0515/1415] CTS to verify local-only hotspot started at 2Ghz The only exception is automotive builds which may start local-only hotspot at 5Ghz Bug:115666270 Test: run cts -m CtsNetTestCases -t android.net.wifi.cts.WifiManagerTest#testStartLocalOnlyHotspotSuccess Change-Id: Ic3df22dab4ee93b531b92e6ed38adfa2b75880c7 --- .../net/src/android/net/wifi/cts/WifiManagerTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 3b8ad6ca65..b09d4581b9 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -408,6 +408,10 @@ public class WifiManagerTest extends AndroidTestCase { return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); } + private boolean hasAutomotiveFeature() { + return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + /** * test point of wifiManager NetWork: * 1.add NetWork @@ -847,6 +851,11 @@ public class WifiManagerTest extends AndroidTestCase { // check if we got the callback assertTrue(callback.onStartedCalled); assertNotNull(callback.reservation.getWifiConfiguration()); + if (!hasAutomotiveFeature()) { + assertEquals( + WifiConfiguration.AP_BAND_2GHZ, + callback.reservation.getWifiConfiguration().apBand); + } assertFalse(callback.onFailedCalled); assertFalse(callback.onStoppedCalled); } From 0b72fa9cfe8ebe5726057e238a1eaeb948eb5d27 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Thu, 4 Oct 2018 10:52:12 +0100 Subject: [PATCH 0516/1415] Remove explicit dependency on conscrypt The dependency is unnecessary as by default conscrypt is included in the "standard libraries". Test: build Bug: 113148576 Change-Id: I30d68049215c61931bdd7aa5e2a0f125e6d1bf90 --- tests/cts/net/Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 1430071997..6967adb57b 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -26,7 +26,6 @@ LOCAL_MULTILIB := both LOCAL_JAVA_LIBRARIES := \ voip-common \ - conscrypt \ org.apache.http.legacy \ android.test.base.stubs \ From 2a41b1cdda8f5b3647619d10a0c0f859a79cfb74 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 18 Oct 2018 17:20:47 +0900 Subject: [PATCH 0517/1415] Add Uri tests for IPv6 literal adresses Bug: 25540738 Test: this Change-Id: Id63a5dd17293014218df78bcb440993cc5f3beb8 --- .../cts/net/src/android/net/cts/UriTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 080f00bee2..1dfe43dd7f 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -22,6 +22,7 @@ import android.os.Parcel; import android.test.AndroidTestCase; import java.io.File; import java.util.Arrays; +import java.util.ArrayList; public class UriTest extends AndroidTestCase { public void testParcelling() { @@ -73,6 +74,12 @@ public class UriTest extends AndroidTestCase { assertEquals("new", b.getFragment()); assertEquals("bar", b.getSchemeSpecificPart()); assertEquals("foo", b.getScheme()); + + a = Uri.fromParts("scheme", "[2001:db8::dead:e1f]/foo", "bar"); + b = a.buildUpon().fragment("qux").build(); + assertEquals("qux", b.getFragment()); + assertEquals("[2001:db8::dead:e1f]/foo", b.getSchemeSpecificPart()); + assertEquals("scheme", b.getScheme()); } public void testStringUri() { @@ -120,6 +127,38 @@ public class UriTest extends AndroidTestCase { assertEquals("a.foo.com", uri.getHost()); assertEquals(-1, uri.getPort()); assertEquals("\\.example.com/path", uri.getPath()); + + uri = Uri.parse("https://[2001:db8::dead:e1f]/foo"); + assertEquals("[2001:db8::dead:e1f]", uri.getAuthority()); + assertNull(uri.getUserInfo()); + assertEquals("[2001:db8::dead:e1f]", uri.getHost()); + assertEquals(-1, uri.getPort()); + assertEquals("/foo", uri.getPath()); + assertEquals(null, uri.getFragment()); + assertEquals("//[2001:db8::dead:e1f]/foo", uri.getSchemeSpecificPart()); + + uri = Uri.parse("https://[2001:db8::dead:e1f]/#foo"); + assertEquals("[2001:db8::dead:e1f]", uri.getAuthority()); + assertNull(uri.getUserInfo()); + assertEquals("[2001:db8::dead:e1f]", uri.getHost()); + assertEquals(-1, uri.getPort()); + assertEquals("/", uri.getPath()); + assertEquals("foo", uri.getFragment()); + assertEquals("//[2001:db8::dead:e1f]/", uri.getSchemeSpecificPart()); + + uri = Uri.parse( + "https://some:user@[2001:db8::dead:e1f]:1234/foo?corge=thud&corge=garp#bar"); + assertEquals("some:user@[2001:db8::dead:e1f]:1234", uri.getAuthority()); + assertEquals("some:user", uri.getUserInfo()); + assertEquals("[2001:db8::dead:e1f]", uri.getHost()); + assertEquals(1234, uri.getPort()); + assertEquals("/foo", uri.getPath()); + assertEquals("bar", uri.getFragment()); + assertEquals("//some:user@[2001:db8::dead:e1f]:1234/foo?corge=thud&corge=garp", + uri.getSchemeSpecificPart()); + assertEquals("corge=thud&corge=garp", uri.getQuery()); + assertEquals("thud", uri.getQueryParameter("corge")); + assertEquals(Arrays.asList("thud", "garp"), uri.getQueryParameters("corge")); } public void testCompareTo() { @@ -174,6 +213,7 @@ public class UriTest extends AndroidTestCase { assertEncodeDecodeRoundtripExact("Bob::"); assertEncodeDecodeRoundtripExact("Bob:"); assertEncodeDecodeRoundtripExact("::Bob::"); + assertEncodeDecodeRoundtripExact("https:/some:user@[2001:db8::dead:e1f]:1234/foo#bar"); } private static void assertEncodeDecodeRoundtripExact(String s) { From c1ba8dd9acd0e91b19d131e95961279fa6ac2eaa Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Thu, 8 Nov 2018 17:13:07 +0800 Subject: [PATCH 0518/1415] Add test for Uri.toSafeString Due to exposing api of toSafeString, add coresponding testing for it. Bug: 119153962 Test: atest UriTest Change-Id: I156b2b03ee9c1d4a05ac635b4f684c5b4dcfca08 --- .../cts/net/src/android/net/cts/UriTest.java | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 1dfe43dd7f..5344f93df9 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -504,4 +504,78 @@ public class UriTest extends AndroidTestCase { Uri.parse("HTTP://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c") .normalizeScheme()); } + + public void testToSafeString_tel() { + checkToSafeString("tel:xxxxxx", "tel:Google"); + checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890"); + checkToSafeString("tEl:xxx.xxx-xxxx", "tEl:123.456-7890"); + } + + public void testToSafeString_sip() { + checkToSafeString("sip:xxxxxxx@xxxxxxx.xxxxxxxx", "sip:android@android.com:1234"); + checkToSafeString("sIp:xxxxxxx@xxxxxxx.xxx", "sIp:android@android.com"); + } + + public void testToSafeString_sms() { + checkToSafeString("sms:xxxxxx", "sms:123abc"); + checkToSafeString("smS:xxx.xxx-xxxx", "smS:123.456-7890"); + } + + public void testToSafeString_smsto() { + checkToSafeString("smsto:xxxxxx", "smsto:123abc"); + checkToSafeString("SMSTo:xxx.xxx-xxxx", "SMSTo:123.456-7890"); + } + + public void testToSafeString_mailto() { + checkToSafeString("mailto:xxxxxxx@xxxxxxx.xxx", "mailto:android@android.com"); + checkToSafeString("Mailto:xxxxxxx@xxxxxxx.xxxxxxxxxx", + "Mailto:android@android.com/secret"); + } + + public void testToSafeString_nfc() { + checkToSafeString("nfc:xxxxxx", "nfc:123abc"); + checkToSafeString("nfc:xxx.xxx-xxxx", "nfc:123.456-7890"); + checkToSafeString("nfc:xxxxxxx@xxxxxxx.xxx", "nfc:android@android.com"); + } + + public void testToSafeString_http() { + checkToSafeString("http://www.android.com/...", "http://www.android.com"); + checkToSafeString("HTTP://www.android.com/...", "HTTP://www.android.com"); + checkToSafeString("http://www.android.com/...", "http://www.android.com/"); + checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param"); + checkToSafeString("http://www.android.com/...", + "http://user:pwd@www.android.com/secretUrl?param"); + checkToSafeString("http://www.android.com/...", + "http://user@www.android.com/secretUrl?param"); + checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param"); + checkToSafeString("http:///...", "http:///path?param"); + checkToSafeString("http:///...", "http://"); + checkToSafeString("http://:12345/...", "http://:12345/"); + } + + public void testToSafeString_https() { + checkToSafeString("https://www.android.com/...", "https://www.android.com/secretUrl?param"); + checkToSafeString("https://www.android.com:8443/...", + "https://user:pwd@www.android.com:8443/secretUrl?param"); + checkToSafeString("https://www.android.com/...", "https://user:pwd@www.android.com"); + checkToSafeString("Https://www.android.com/...", "Https://user:pwd@www.android.com"); + } + + public void testToSafeString_ftp() { + checkToSafeString("ftp://ftp.android.com/...", "ftp://ftp.android.com/"); + checkToSafeString("ftP://ftp.android.com/...", "ftP://anonymous@ftp.android.com/"); + checkToSafeString("ftp://ftp.android.com:2121/...", + "ftp://root:love@ftp.android.com:2121/"); + } + + public void testToSafeString_notSupport() { + checkToSafeString("unsupported://ajkakjah/askdha/secret?secret", + "unsupported://ajkakjah/askdha/secret?secret"); + checkToSafeString("unsupported:ajkakjah/askdha/secret?secret", + "unsupported:ajkakjah/askdha/secret?secret"); + } + + private void checkToSafeString(String expectedSafeString, String original) { + assertEquals(expectedSafeString, Uri.parse(original).toSafeString()); + } } From 9d7688dd9e7d0d4007fee8693c65ef0beb56748d Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 1 Nov 2018 15:14:44 -0700 Subject: [PATCH 0519/1415] WifiManagerTest: Remove tests for deprecated API's Remove/Modify tests that are invoking the deprecated API's. Use the shell automator to toggle wifi state. CTS tests for the replacement API surface (i.e NetworkRequest & NetworkSuggestion) will be added later. Bug: 115504728 Test: `atest android.net.wifi.cts.WifiManagerTest` Change-Id: I04b3e1572ddfd31b28639185e5cf54dd70a1ae42 --- .../android/net/wifi/cts/WifiManagerTest.java | 187 +++--------------- 1 file changed, 30 insertions(+), 157 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index b09d4581b9..bfb9970bd3 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -41,9 +41,11 @@ import android.provider.Settings; import android.support.test.InstrumentationRegistry; import android.support.test.uiautomator.UiDevice; import android.test.AndroidTestCase; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import com.android.compatibility.common.util.SystemUtil; import com.android.compatibility.common.util.WifiConfigCreator; import java.net.HttpURLConnection; @@ -83,9 +85,6 @@ public class WifiManagerTest extends AndroidTestCase { private static final String TAG = "WifiManagerTest"; private static final String SSID1 = "\"WifiManagerTest\""; - private static final String SSID2 = "\"WifiManagerTestModified\""; - private static final String PROXY_TEST_SSID = "SomeProxyAp"; - private static final String ADD_NETWORK_EXCEPTION_SUBSTR = "addNetwork"; // A full single scan duration is about 6-7 seconds if country code is set // to US. If country code is set to world mode (00), we would expect a scan // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here. @@ -198,8 +197,8 @@ public class WifiManagerTest extends AndroidTestCase { } else { mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); } - // now trigger the change - assertTrue(mWifiManager.setWifiEnabled(enable)); + // now trigger the change using shell commands. + SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable")); waitForExpectedWifiState(enable); } } @@ -274,20 +273,13 @@ public class WifiManagerTest extends AndroidTestCase { } /** - * test point of wifiManager actions: - * 1.reconnect - * 2.reassociate - * 3.disconnect - * 4.createWifiLock + * Test creation of WifiManager Lock. */ - public void testWifiManagerActions() throws Exception { + public void testWifiManagerLock() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported return; } - assertTrue(mWifiManager.reconnect()); - assertTrue(mWifiManager.reassociate()); - assertTrue(mWifiManager.disconnect()); final String TAG = "Test"; assertNotNull(mWifiManager.createWifiLock(TAG)); assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); @@ -412,125 +404,6 @@ public class WifiManagerTest extends AndroidTestCase { return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); } - /** - * test point of wifiManager NetWork: - * 1.add NetWork - * 2.update NetWork - * 3.remove NetWork - * 4.enable NetWork - * 5.disable NetWork - * 6.configured Networks - * 7.save configure; - */ - public void testWifiManagerNetWork() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // store the list of enabled networks, so they can be re-enabled after test completes - Set enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); - try { - WifiConfiguration wifiConfiguration; - // add a WifiConfig - final int notExist = -1; - List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - if (notExist != pos) { - wifiConfiguration = wifiConfiguredNetworks.get(pos); - mWifiManager.removeNetwork(wifiConfiguration.networkId); - } - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertEquals(notExist, pos); - final int size = wifiConfiguredNetworks.size(); - - wifiConfiguration = new WifiConfiguration(); - wifiConfiguration.SSID = SSID1; - wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - int netId = mWifiManager.addNetwork(wifiConfiguration); - assertTrue(existSSID(SSID1)); - - wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - assertEquals(size + 1, wifiConfiguredNetworks.size()); - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertTrue(notExist != pos); - - // Enable & disable network - boolean disableOthers = true; - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertEquals(Status.ENABLED, wifiConfiguration.status); - - assertTrue(mWifiManager.disableNetwork(netId)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertEquals(Status.DISABLED, wifiConfiguration.status); - - // Update a WifiConfig - wifiConfiguration = wifiConfiguredNetworks.get(pos); - wifiConfiguration.SSID = SSID2; - netId = mWifiManager.updateNetwork(wifiConfiguration); - assertFalse(existSSID(SSID1)); - assertTrue(existSSID(SSID2)); - - // Remove a WifiConfig - assertTrue(mWifiManager.removeNetwork(netId)); - assertFalse(mWifiManager.removeNetwork(notExist)); - assertFalse(existSSID(SSID1)); - assertFalse(existSSID(SSID2)); - - assertTrue(mWifiManager.saveConfiguration()); - } finally { - reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks()); - mWifiManager.saveConfiguration(); - } - } - - /** - * Verifies that addNetwork() fails for WifiConfigurations containing a non-null http proxy when - * the caller doesn't have OVERRIDE_WIFI_CONFIG permission, DeviceOwner or ProfileOwner device - * management policies - */ - public void testSetHttpProxy_PermissionFail() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiConfigCreator configCreator = new WifiConfigCreator(getContext()); - boolean exceptionThrown = false; - try { - configCreator.addHttpProxyNetworkVerifyAndRemove( - PROXY_TEST_SSID, TEST_PAC_URL); - } catch (IllegalStateException e) { - // addHttpProxyNetworkVerifyAndRemove throws three IllegalStateException, - // expect it to throw for the addNetwork operation - if (e.getMessage().contains(ADD_NETWORK_EXCEPTION_SUBSTR)) { - exceptionThrown = true; - } - } - assertTrue(exceptionThrown); - } - - private Set getEnabledNetworks(List configuredNetworks) { - Set ssids = new HashSet(); - for (WifiConfiguration wifiConfig : configuredNetworks) { - if (Status.ENABLED == wifiConfig.status || Status.CURRENT == wifiConfig.status) { - ssids.add(wifiConfig.SSID); - Log.i(TAG, String.format("remembering enabled network %s", wifiConfig.SSID)); - } - } - return ssids; - } - - private void reEnableNetworks(Set enabledSsids, - List configuredNetworks) { - for (WifiConfiguration wifiConfig : configuredNetworks) { - if (enabledSsids.contains(wifiConfig.SSID)) { - mWifiManager.enableNetwork(wifiConfig.networkId, false); - Log.i(TAG, String.format("re-enabling network %s", wifiConfig.SSID)); - } - } - } - public void testSignal() { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported @@ -902,37 +775,37 @@ public class WifiManagerTest extends AndroidTestCase { } /** - * Verify calls to setWifiEnabled from a non-settings app while softap mode is active do not - * exit softap mode. - * - * This test uses the LocalOnlyHotspot API to enter softap mode. This should also be true when - * tethering is started. - * Note: Location mode must be enabled for this test. + * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK. */ - public void testSetWifiEnabledByAppDoesNotStopHotspot() throws Exception { + public void testDeprecatedApis() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported return; } - // check that softap mode is supported by the device - if (!mWifiManager.isPortableHotspotSupported()) { - return; - } + setWifiEnabled(true); + connectWifi(); // ensures that there is at-least 1 saved network on the device. + + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = SSID1; + wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + + assertEquals(WifiConfiguration.INVALID_NETWORK_ID, + mWifiManager.addNetwork(wifiConfiguration)); + assertEquals(WifiConfiguration.INVALID_NETWORK_ID, + mWifiManager.updateNetwork(wifiConfiguration)); + assertFalse(mWifiManager.enableNetwork(0, true)); + assertFalse(mWifiManager.disableNetwork(0)); + assertFalse(mWifiManager.removeNetwork(0)); + assertFalse(mWifiManager.disconnect()); + assertFalse(mWifiManager.reconnect()); + assertFalse(mWifiManager.reassociate()); + assertTrue(mWifiManager.getConfiguredNetworks().isEmpty()); boolean wifiEnabled = mWifiManager.isWifiEnabled(); - - if (wifiEnabled) { - // disable wifi so we have something to turn on (some devices may be able to run - // simultaneous modes) - setWifiEnabled(false); - } - - TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - - // now we should fail to turn on wifi - assertFalse(mWifiManager.setWifiEnabled(true)); - - stopLocalOnlyHotspot(callback, wifiEnabled); + // now we should fail to toggle wifi state. + assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled)); + Thread.sleep(DURATION); + assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } /** From d0a2b9d50a5b438e0e293a5f10176e5b57ed71dd Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 14 Nov 2018 14:58:07 -0800 Subject: [PATCH 0520/1415] WifiManagerTest: Test for new privileged permission Add a new test to ensure that the NETWORK_MANAGED_PROVISIONING is only granted to the correct app. Bug: 115980767 Test: atest WifiManagerTest Change-Id: Ifca1fcd81e201134bbb4173c3f142cca91ed49f9 --- .../android/net/wifi/cts/WifiManagerTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index b09d4581b9..40e25ad66c 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -99,6 +99,8 @@ public class WifiManagerTest extends AndroidTestCase { private static final int WIFI_SCAN_TEST_ITERATIONS = 5; private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; + private static final String MANAGED_PROVISIONING_PACKAGE_NAME + = "com.android.managedprovisioning"; private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @@ -1088,6 +1090,41 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Verify that the {@link android.Manifest.permission#NETWORK_MANAGED_PROVISIONING} permission + * is only held by the device managed provisioning application. + *

    + * Only the ManagedProvisioning app should ever attempt to acquire this + * permission, since it would give those apps extremely broad access to connectivity + * functionality. The permission is intended to be granted to only the device managed + * provisioning. + */ + public void testNetworkManagedProvisioningPermission() { + final PackageManager pm = getContext().getPackageManager(); + + // TODO(b/115980767): Using hardcoded package name. Need a better mechanism to find the + // managed provisioning app. + // Ensure that the package exists. + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setPackage(MANAGED_PROVISIONING_PACKAGE_NAME); + final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); + String validPkg = ""; + if (ri != null) { + validPkg = ri.activityInfo.packageName; + } + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_MANAGED_PROVISIONING + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + for (PackageInfo pi : holding) { + if (!Objects.equals(pi.packageName, validPkg)) { + fail("The NETWORK_MANAGED_PROVISIONING permission must not be held by " + + pi.packageName + " and must be revoked for security reasons [" + + validPkg +"]"); + } + } + } + private void turnScreenOnNoDelay() throws Exception { mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); mUiDevice.executeShellCommand("wm dismiss-keyguard"); From de0f268f789222dd17d3c28c0f07656f2c168d81 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 21 Nov 2018 22:56:31 +0800 Subject: [PATCH 0521/1415] Exempt adb socket for hostside VpnTest Vpn test would destroy socket. If adb run over network, adb socket would be killed during Vpn test. Then, test stop due to adb disconnect. Bug: 119382723 Test: - build pass - run cts -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideVpnTests Change-Id: I91b4ab018a9e7fc73dcb7969e4a6520d6b27d629 --- tests/cts/hostside/app/Android.mk | 3 ++- .../com/android/cts/net/hostside/VpnTest.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index c03e70bcb0..62e0172817 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -19,7 +19,8 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SDK_VERSION := current +#LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \ CtsHostsideNetworkTestsAidl diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index 1ba701de29..48f0afb61e 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -30,6 +30,7 @@ import android.net.NetworkRequest; import android.net.VpnService; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.SystemProperties; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; @@ -559,6 +560,14 @@ public class VpnTest extends InstrumentationTestCase { public void testDefault() throws Exception { if (!supportedHardware()) return; + // If adb TCP port opened, this test may running by adb over network. + // All of socket would be destroyed in this test. So this test don't + // support adb over network, see b/119382723. + if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 + || SystemProperties.getInt("service.adb.tcp.port", -1) > -1) { + Log.i(TAG, "adb is running over the network, so skip this test"); + return; + } FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); @@ -576,6 +585,7 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + // Shell app must not be put in here or it would kill the ADB-over-network use case String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, @@ -593,6 +603,12 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); String disallowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + // If adb TCP port opened, this test may running by adb over TCP. + // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test, + // see b/119382723. + // Note: The test don't support running adb over network for root device + disallowedApps = disallowedApps + ",com.android.shell"; + Log.i(TAG, "Append shell app to disallowedApps: " + disallowedApps); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, "", disallowedApps); From 30897c29ef24b47a6a227d0716c811ee81e7bc59 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Mon, 19 Nov 2018 14:53:32 -0800 Subject: [PATCH 0522/1415] Tests for app idle whitelisting. Ensuring that app idle network whitelisting works as expected and does not override other power saving restrictions. Bug: 117846754 Bug: 111423978 Test: atest CtsHostsideNetworkTests and atest NetworkPolicyManagerServiceTest Change-Id: I09172184e2fe543d6723639e5e62ae6afd5a6087 --- .../net/hostside/AbstractAppIdleTestCase.java | 19 +++++ ...ractRestrictBackgroundNetworkTestCase.java | 22 ++++- .../cts/net/hostside/MixedModesTest.java | 80 +++++++++++++++++++ ...ostsideRestrictBackgroundNetworkTests.java | 25 ++++++ 4 files changed, 142 insertions(+), 4 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 0e141c05ad..7bf7bd44f4 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -175,6 +175,25 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork assertBackgroundNetworkAccess(true); } + public void testAppIdleNetworkAccess_idleWhitelisted() throws Exception { + if (!isSupported()) return; + + setAppIdle(true); + assertAppIdle(true); + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(true); + + removeAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + // Make sure whitelisting a random app doesn't affect the tested app. + addAppIdleWhitelist(mUid + 1); + assertBackgroundNetworkAccess(false); + removeAppIdleWhitelist(mUid + 1); + } + public void testAppIdle_toast() throws Exception { if (!isSupported()) return; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 5232372047..ec5a877757 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -26,10 +26,6 @@ import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - import android.app.ActivityManager; import android.app.Instrumentation; import android.app.NotificationManager; @@ -53,6 +49,10 @@ import android.test.InstrumentationTestCase; import android.text.TextUtils; import android.util.Log; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + /** * Superclass for tests related to background network restrictions. */ @@ -744,6 +744,20 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertRestrictBackground("restrict-background-blacklist", uid, expected); } + protected void addAppIdleWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy add app-idle-whitelist " + uid); + assertAppIdleWhitelist(uid, true); + } + + protected void removeAppIdleWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy remove app-idle-whitelist " + uid); + assertAppIdleWhitelist(uid, false); + } + + protected void assertAppIdleWhitelist(int uid, boolean expected) throws Exception { + assertRestrictBackground("app-idle-whitelist", uid, expected); + } + private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception { final int maxTries = 5; boolean actual = false; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index 87f9d7738d..74875cd2c9 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -306,4 +306,84 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { setBatterySaverMode(false); } } + + /** + * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled. + */ + public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { + if (!isSupported()) { + return; + } + + setDozeMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + // UID still shouldn't have access because of Doze. + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + removeAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setDozeMode(false); + } + } + + public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { + if (!isSupported()) { + return; + } + + setDozeMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setDozeMode(false); + removeAppIdleWhitelist(mUid); + } + } + + public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + if (!isSupported()) { + return; + } + + setBatterySaverMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setBatterySaverMode(false); + removeAppIdleWhitelist(mUid); + } + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index fe9d36ce1d..5f5ea43d67 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -156,6 +156,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + public void testAppIdleMetered_idleWhitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testAppIdleNetworkAccess_idleWhitelisted"); + } + // TODO: currently power-save mode and idle uses the same whitelist, so this test would be // redundant (as it would be testing the same as testBatterySaverMode_reinstall()) // public void testAppIdle_reinstall() throws Exception { @@ -181,6 +186,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + public void testAppIdleNonMetered_idleWhitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testAppIdleNetworkAccess_idleWhitelisted"); + } + public void testAppIdleNonMetered_whenCharging() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", "testAppIdleNetworkAccess_whenCharging"); @@ -281,6 +291,21 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testAppIdleAndBatterySaver_tempPowerSaveWhitelists"); } + public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDozeAndAppIdle_appIdleWhitelist"); + } + + public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists"); + } + + public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists"); + } + /******************* * Helper methods. * *******************/ From af95fad957196933570b974635d7499370e5b2fa Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Fri, 27 Apr 2018 08:50:14 -0700 Subject: [PATCH 0523/1415] WifiManagerTest: allow for multiple modes Now that WifiService can/will support dual simultaneous mode operation, make sure the tests allow for it as well. Bug: 31346104 Bug: 115567184 Test: atest android.net.wifi.cts Change-Id: Id3aaacb3651568c18850a0fdf3832c0f52218cf2 Merged-In: Id3aaacb3651568c18850a0fdf3832c0f52218cf2 --- .../android/net/wifi/cts/WifiManagerTest.java | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index b2d912e56c..44b49c0274 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -825,10 +825,9 @@ public class WifiManagerTest extends AndroidTestCase { TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - // at this point, wifi should be off - assertFalse(mWifiManager.isWifiEnabled()); - stopLocalOnlyHotspot(callback, wifiEnabled); + + // wifi should either stay on, or come back on assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } @@ -840,23 +839,31 @@ public class WifiManagerTest extends AndroidTestCase { * tethering is started. * Note: Location mode must be enabled for this test. */ - public void testSetWifiEnabledByAppDoesNotStopHotspot() { - // first check that softap mode is supported by the device + + public void testSetWifiEnabledByAppDoesNotStopHotspot() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + // check that softap mode is supported by the device if (!mWifiManager.isPortableHotspotSupported()) { return; } boolean wifiEnabled = mWifiManager.isWifiEnabled(); + if (wifiEnabled) { + // disable wifi so we have something to turn on (some devices may be able to run + // simultaneous modes) + setWifiEnabled(false); + } + TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - // at this point, wifi should be off - assertFalse(mWifiManager.isWifiEnabled()); // now we should fail to turn on wifi assertFalse(mWifiManager.setWifiEnabled(true)); stopLocalOnlyHotspot(callback, wifiEnabled); - assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } /** @@ -876,9 +883,6 @@ public class WifiManagerTest extends AndroidTestCase { TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - // at this point, wifi should be off - assertFalse(mWifiManager.isWifiEnabled()); - // now make a second request - this should fail. TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLOHSLock); try { @@ -887,9 +891,12 @@ public class WifiManagerTest extends AndroidTestCase { Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice"); caughtException = true; } + if (!caughtException) { + // second start did not fail, should clean up the hotspot. + stopLocalOnlyHotspot(callback2, wifiEnabled); + } assertTrue(caughtException); stopLocalOnlyHotspot(callback, wifiEnabled); - assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } } From 4b1386285a7444fbb1d853228a2cac8ea88865f6 Mon Sep 17 00:00:00 2001 From: David Su Date: Wed, 28 Nov 2018 09:25:43 -0800 Subject: [PATCH 0524/1415] Scan Optimization: Check set device mobility permission is granted to <= 1 app Add a new CTS test to ensure that set device mobility permission is granted to at most 1 app. Bug: 120097108 Test: "atest WifiManagerTest" after installing app with new permission granted Change-Id: Ifda2163da6da9e9365c440d47031d25f92c6c375 --- .../android/net/wifi/cts/WifiManagerTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index deaa64421c..8ea72e00e9 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -58,6 +58,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; public class WifiManagerTest extends AndroidTestCase { private static class MySync { @@ -998,6 +999,30 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Verify that the {@link android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE} permission + * is held by at most one application. + */ + public void testWifiSetDeviceMobilityStatePermission() { + final PackageManager pm = getContext().getPackageManager(); + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + + List uniquePackageNames = holding + .stream() + .map(pi -> pi.packageName) + .distinct() + .collect(Collectors.toList()); + + if (uniquePackageNames.size() > 1) { + fail("The WIFI_SET_DEVICE_MOBILITY_STATE permission must not be held by more than one " + + "application, but is held by " + uniquePackageNames.size() + " applications: " + + String.join(", ", uniquePackageNames)); + } + } + private void turnScreenOnNoDelay() throws Exception { mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); mUiDevice.executeShellCommand("wm dismiss-keyguard"); From 3c5f35a38ea554c942309440a2d12ad1da4e3f78 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 21 Nov 2018 14:38:40 +0800 Subject: [PATCH 0525/1415] Test for asynchronous DNS query API Add basic test for asynchronous DNS query API Test: build atest CtsNativeNetDnsTestCases Change-Id: Ib757ba8f0128d3efe7dfbcbfb45d36e4350834f9 --- tests/cts/net/native/dns_async/Android.bp | 36 +++++ .../cts/net/native/dns_async/AndroidTest.xml | 29 ++++ .../dns_async/src/NativeDnsAsyncTest.cpp | 148 ++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 tests/cts/net/native/dns_async/Android.bp create mode 100644 tests/cts/net/native/dns_async/AndroidTest.xml create mode 100644 tests/cts/net/native/dns_async/src/NativeDnsAsyncTest.cpp diff --git a/tests/cts/net/native/dns_async/Android.bp b/tests/cts/net/native/dns_async/Android.bp new file mode 100644 index 0000000000..2b9346fc0b --- /dev/null +++ b/tests/cts/net/native/dns_async/Android.bp @@ -0,0 +1,36 @@ +cc_defaults { + name: "dns_async_defaults", + + cflags: [ + "-fstack-protector-all", + "-g", + "-Wall", + "-Wextra", + "-Werror", + "-fno-builtin", + ], + srcs: [ + "src/NativeDnsAsyncTest.cpp", + ], + shared_libs: [ + "liblog", + "libutils", + "libandroid", + ], +} + +cc_test { + name: "CtsNativeNetDnsTestCases", + defaults: ["dns_async_defaults"], + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + test_suites: [ + "cts", + ], +} \ No newline at end of file diff --git a/tests/cts/net/native/dns_async/AndroidTest.xml b/tests/cts/net/native/dns_async/AndroidTest.xml new file mode 100644 index 0000000000..e092b36186 --- /dev/null +++ b/tests/cts/net/native/dns_async/AndroidTest.xml @@ -0,0 +1,29 @@ + + + + diff --git a/tests/cts/net/native/dns_async/src/NativeDnsAsyncTest.cpp b/tests/cts/net/native/dns_async/src/NativeDnsAsyncTest.cpp new file mode 100644 index 0000000000..087eb5ed5a --- /dev/null +++ b/tests/cts/net/native/dns_async/src/NativeDnsAsyncTest.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2018 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* poll */ +#include +#include + +#include +#include + +namespace { +constexpr int MAXPACKET = 8 * 1024; +constexpr int PTON_MAX = 16; + +int getAsyncResponse(int fd, int timeoutMs, int* rcode, u_char* buf, int bufLen) { + struct pollfd wait_fd[1]; + wait_fd[0].fd = fd; + wait_fd[0].events = POLLIN; + short revents; + int ret; + ret = poll(wait_fd, 1, timeoutMs); + revents = wait_fd[0].revents; + if (revents & POLLIN) { + int n = android_res_nresult(fd, rcode, buf, bufLen); + return n; + } + + return -1; +} + +std::vector extractIpAddressAnswers(u_char* buf, int bufLen, int ipType) { + ns_msg handle; + if (ns_initparse((const uint8_t*) buf, bufLen, &handle) < 0) { + return {}; + } + int ancount = ns_msg_count(handle, ns_s_an); + ns_rr rr; + std::vector answers; + for (int i = 0; i < ancount; i++) { + if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) { + continue; + } + const u_char* rdata = ns_rr_rdata(rr); + char buffer[INET6_ADDRSTRLEN]; + if (inet_ntop(ipType, (const char*) rdata, buffer, sizeof(buffer))) { + answers.push_back(buffer); + } + } + return answers; +} + +void expectAnswersValid(int fd, int ipType, int expectedRcode) { + int rcode = -1; + u_char buf[MAXPACKET] = {}; + int res = getAsyncResponse(fd, 10000, &rcode, buf, MAXPACKET); + EXPECT_GT(res, 0); + EXPECT_EQ(rcode, expectedRcode); + + + if (expectedRcode == NOERROR) { + auto answers = extractIpAddressAnswers(buf, res, ipType); + EXPECT_GT(answers.size(), 0U); + for (auto &answer : answers) { + char pton[PTON_MAX]; + EXPECT_EQ(1, inet_pton(ipType, answer.c_str(), pton)); + } + } +} + +} // namespace + +TEST (NativeDnsAsyncTest, Async_Query) { + // V4 + int fd = android_res_nquery(NETWORK_UNSPECIFIED ,"www.google.com", ns_c_in, ns_t_a); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET, NOERROR); + + // V6 + fd = android_res_nquery(NETWORK_UNSPECIFIED ,"www.google.com", ns_c_in, ns_t_aaaa); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET6, NOERROR); +} + +TEST (NativeDnsAsyncTest, Async_Send) { + // V4 + u_char buf[MAXPACKET] = {}; + int len = res_mkquery(QUERY, "www.youtube.com", + ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf)); + EXPECT_GT(len, 0); + int fd = android_res_nsend(NETWORK_UNSPECIFIED , buf, len); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET, NOERROR); + + // V6 + memset(buf, 0, MAXPACKET); + len = res_mkquery(QUERY, "www.youtube.com", + ns_c_in, ns_t_aaaa, nullptr, 0, nullptr, buf, sizeof(buf)); + EXPECT_GT(len, 0); + fd = android_res_nsend(NETWORK_UNSPECIFIED , buf, len); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET6, NOERROR); +} + +TEST (NativeDnsAsyncTest, Async_NXDOMAIN) { + u_char buf[MAXPACKET] = {}; + int len = res_mkquery(QUERY, "test-nx.metric.gstatic.com", + ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf)); + EXPECT_GT(len, 0); + int fd = android_res_nsend(NETWORK_UNSPECIFIED , buf, len); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET, NXDOMAIN); +} + +TEST (NativeDnsAsyncTest, Async_Cancel) { + int fd = android_res_nquery(NETWORK_UNSPECIFIED ,"www.google.com", ns_c_in, ns_t_a); + int rcode = -1; + u_char buf[MAXPACKET] = {}; + android_res_cancel(fd); + + int res = android_res_nresult(fd, &rcode, buf, MAXPACKET); + EXPECT_EQ(res, -EBADF); +} + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 7131af6b93596886333b22511f836e34bdc46e9c Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Fri, 12 Oct 2018 13:17:47 +0100 Subject: [PATCH 0526/1415] Add tests for InetAddresses.parseNumericAddress() Test: run cts -m CtsNetTestCases Bug: 78686891 Change-Id: I1e121ab3fd619964625c4b51e0b7280eef001775 --- tests/cts/net/Android.mk | 4 +- .../android/net/cts/InetAddressesTest.java | 134 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tests/cts/net/src/android/net/cts/InetAddressesTest.java diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 6967adb57b..bb1f4c73c4 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -45,7 +45,9 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ ctstestserver \ mockwebserver \ junit \ - truth-prebuilt + junit-params \ + truth-prebuilt \ + # uncomment when b/13249961 is fixed #LOCAL_SDK_VERSION := current diff --git a/tests/cts/net/src/android/net/cts/InetAddressesTest.java b/tests/cts/net/src/android/net/cts/InetAddressesTest.java new file mode 100644 index 0000000000..7837ce9ed5 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/InetAddressesTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 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 android.net.InetAddresses; +import java.net.InetAddress; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +@RunWith(JUnitParamsRunner.class) +public class InetAddressesTest { + + public static String[][] validNumericAddressesAndStringRepresentation() { + return new String[][] { + // Regular IPv4. + { "1.2.3.4", "1.2.3.4" }, + + // Regular IPv6. + { "2001:4860:800d::68", "2001:4860:800d::68" }, + { "1234:5678::9ABC:DEF0", "1234:5678::9abc:def0" }, + { "2001:cdba:9abc:5678::", "2001:cdba:9abc:5678::" }, + { "::2001:cdba:9abc:5678", "::2001:cdba:9abc:5678" }, + { "64:ff9b::1.2.3.4", "64:ff9b::102:304" }, + + { "::9abc:5678", "::154.188.86.120" }, + + // Mapped IPv4 + { "::ffff:127.0.0.1", "127.0.0.1" }, + + // Android does not recognize Octal (leading 0) cases: they are treated as decimal. + { "0177.00.00.01", "177.0.0.1" }, + + // Verify that examples from JavaDoc work correctly. + { "192.0.2.1", "192.0.2.1" }, + { "2001:db8::1:2", "2001:db8::1:2" }, + }; + } + + public static String[] invalidNumericAddresses() { + return new String[] { + "", + " ", + "\t", + "\n", + "1.2.3.4.", + "1.2.3", + "1.2", + "1", + "1234", + "0", + "0x1.0x2.0x3.0x4", + "0x7f.0x00.0x00.0x01", + "0256.00.00.01", + "fred", + "www.google.com", + // IPv6 encoded for use in URL as defined in RFC 2732 + "[fe80::6:2222]", + }; + } + + @Parameters(method = "validNumericAddressesAndStringRepresentation") + @Test + public void parseNumericAddress(String address, String expectedString) { + InetAddress inetAddress = InetAddresses.parseNumericAddress(address); + assertEquals(expectedString, inetAddress.getHostAddress()); + } + + @Parameters(method = "invalidNumericAddresses") + @Test + public void test_parseNonNumericAddress(String address) { + try { + InetAddress inetAddress = InetAddresses.parseNumericAddress(address); + fail(String.format( + "Address %s is not numeric but was parsed as %s", address, inetAddress)); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains(address); + } + } + + @Test + public void test_parseNumericAddress_null() { + try { + InetAddress inetAddress = InetAddresses.parseNumericAddress(null); + fail(String.format("null is not numeric but was parsed as %s", inetAddress)); + } catch (NullPointerException e) { + // expected + } + } + + @Parameters(method = "validNumericAddressesAndStringRepresentation") + @Test + public void test_isNumericAddress(String address, String unused) { + assertTrue("expected '" + address + "' to be treated as numeric", + InetAddresses.isNumericAddress(address)); + } + + @Parameters(method = "invalidNumericAddresses") + @Test + public void test_isNotNumericAddress(String address) { + assertFalse("expected '" + address + "' to be treated as non-numeric", + InetAddresses.isNumericAddress(address)); + } + + @Test + public void test_isNumericAddress_null() { + try { + InetAddresses.isNumericAddress(null); + fail("expected null to throw a NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } +} From c2b211f450420c80418b6b0f0cddefc57a765864 Mon Sep 17 00:00:00 2001 From: Julien Desprez Date: Mon, 17 Dec 2018 12:45:11 -0800 Subject: [PATCH 0527/1415] Tag modules for their sim card required Test: tf/cts unit tests ./cts-tradefed run cts-dev -m CtsNetTestCases --shard-count 2 (with and without sim card) ./cts-tradefed run cts-dev -m CtsCarrierApiTestCases --shard-count 2 (with and without uicc sim card) Bug: 69367250 Change-Id: Idcd35b9345be32658a1fd44027b03e5a47ff7e88 --- tests/cts/net/AndroidTest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml index 1326970462..76ff1674f6 100644 --- a/tests/cts/net/AndroidTest.xml +++ b/tests/cts/net/AndroidTest.xml @@ -15,6 +15,8 @@

    - * Only Settings, SysUi and shell apps should ever attempt to acquire this - * permission, since it would give those apps extremely broad access to connectivity + * Only Settings, SysUi, NetworkStack and shell apps should ever attempt to acquire + * this permission, since it would give those apps extremely broad access to connectivity * functionality. The permission is intended to be granted to only those apps with direct user * access and no others. */ @@ -886,6 +886,7 @@ public class WifiManagerTest extends AndroidTestCase { allowedUIDs.add(Process.SYSTEM_UID); allowedUIDs.add(Process.SHELL_UID); allowedUIDs.add(Process.PHONE_UID); + allowedUIDs.add(Process.NETWORK_STACK_UID); // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using // this fact to determined allowed package name for sysui From 823149f58f674bb653b0ff00fecf89d46fde572d Mon Sep 17 00:00:00 2001 From: David Su Date: Wed, 6 Feb 2019 11:42:55 -0800 Subject: [PATCH 0545/1415] Grant CTS test APK ACCESS_BACKGROUND_LOCATION permission Fixed broken CTS tests due to missing permissions. Bug: 123622071 Test: cts-tradefed, run cts -m CtsNetTestCases Change-Id: I6ddd2afbae6f685c018fd53d988e543ddbcfec04 --- tests/cts/net/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 0bfb650882..2a57c101b2 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -22,6 +22,7 @@ + From ccef9c809333f890641409dc0a3cb077e85a7943 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Tue, 22 Jan 2019 17:36:16 -0800 Subject: [PATCH 0546/1415] Add checks for detailed uid stats Get the detailed network stats for the test uid and check if the detail stats is consistent with the per uid stats. This test is necessary since the new devices may get detailed network stats and per uid total stats from different eBPF maps. Test: atest TrafficStatsTest Bug: 79171384 Change-Id: I04533e9fa146e052bdc3787ec6b1f8dad9c19fb7 --- .../src/android/net/cts/TrafficStatsTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index a8743fad7f..af096da089 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -16,6 +16,7 @@ package android.net.cts; +import android.net.NetworkStats; import android.net.TrafficStats; import android.os.Process; import android.test.AndroidTestCase; @@ -99,6 +100,7 @@ public class TrafficStatsTest extends AndroidTestCase { final int byteCount = 1024; final int packetCount = 1024; + TrafficStats.startDataProfiling(null); final ServerSocket server = new ServerSocket(0); new Thread("TrafficStatsTest.testTrafficStatsForLocalhost") { @Override @@ -153,6 +155,7 @@ public class TrafficStatsTest extends AndroidTestCase { Thread.sleep(1000); } catch (InterruptedException e) { } + NetworkStats testStats = TrafficStats.stopDataProfiling(null); long mobileTxPacketsAfter = TrafficStats.getMobileTxPackets(); long mobileRxPacketsAfter = TrafficStats.getMobileRxPackets(); @@ -194,6 +197,24 @@ public class TrafficStatsTest extends AndroidTestCase { Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); } + // Check the per uid stats read from data profiling have the stats expected. The data + // profiling snapshot is generated from readNetworkStatsDetail() method in + // networkStatsService and in this way we can verify the detail networkStats of a given uid + // is correct. + NetworkStats.Entry entry = testStats.getTotal(null, Process.myUid()); + assertTrue("txPackets detail: " + entry.txPackets + " uidTxPackets: " + uidTxDeltaPackets, + entry.txPackets >= packetCount + minExpectedExtraPackets + && entry.txPackets <= uidTxDeltaPackets); + assertTrue("rxPackets detail: " + entry.rxPackets + " uidRxPackets: " + uidRxDeltaPackets, + entry.rxPackets >= packetCount + minExpectedExtraPackets + && entry.rxPackets <= uidRxDeltaPackets); + assertTrue("txBytes detail: " + entry.txBytes + " uidTxDeltaBytes: " + uidTxDeltaBytes, + entry.txBytes >= tcpPacketToIpBytes(packetCount, byteCount) + + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && entry.txBytes <= uidTxDeltaBytes); + assertTrue("rxBytes detail: " + entry.rxBytes + " uidRxDeltaBytes: " + uidRxDeltaBytes, + entry.rxBytes >= tcpPacketToIpBytes(packetCount, byteCount) + + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && entry.rxBytes <= uidRxDeltaBytes); + assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets + "+" + deltaTxOtherPackets, From 17ef99be740500c9755ac31718ecaca7631fb93b Mon Sep 17 00:00:00 2001 From: "jungyee.yoo" Date: Tue, 22 Jan 2019 15:43:24 +0900 Subject: [PATCH 0547/1415] Add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. Bug: 123205589 Test: run cts-on-gsi -m -m CtsNetTestCases -t android.net.wifi.cts.WifiManagerTest#testStartLocalOnlyHotspotSingleRequestByApps Bug: 123379970 Test: run cts-on-gsi -m -m CtsNetTestCases -t ndroid.net.wifi.cts.WifiManagerTest#testStartLocalOnlyHotspotSuccess Change-Id: I7506c3037dc5368d69330acc47c97c765185870f --- .../android/net/wifi/cts/WifiManagerTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index af91fbfb15..2ed012491e 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -874,6 +874,15 @@ public class WifiManagerTest extends AndroidTestCase { TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); + // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. + // TODO: remove this sleep as soon as b/124330089 is fixed. + try { + Log.d(TAG, "Sleep for 2 seconds"); + Thread.sleep(2000); + } catch (InterruptedException e) { + Log.d(TAG, "Thread InterruptedException!"); + } + stopLocalOnlyHotspot(callback, wifiEnabled); // wifi should either stay on, or come back on @@ -949,6 +958,15 @@ public class WifiManagerTest extends AndroidTestCase { } assertTrue(caughtException); + // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. + // TODO: remove this sleep as soon as b/124330089 is fixed. + try { + Log.d(TAG, "Sleep for 2 seconds"); + Thread.sleep(2000); + } catch (InterruptedException e) { + Log.d(TAG, "Thread InterruptedException!"); + } + stopLocalOnlyHotspot(callback, wifiEnabled); } } From 2186a943d32a9c4433d19d5d97d702b6531ff73d Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Fri, 15 Feb 2019 17:58:15 -0800 Subject: [PATCH 0548/1415] Add permissions needed for WifiManager.getConnectionInfo().getSSID(). Fixes: 124383293 Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: I3145e4ba1e768b7bb3c89867e36b506a90b87506 --- tests/cts/hostside/app/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index 2553f475aa..b91f39d36e 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -23,6 +23,8 @@ + + From 54c6488a76a552af10d23790929f8f9be32f5458 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 14 Feb 2019 17:43:43 +0800 Subject: [PATCH 0549/1415] p2p: add cts coverage for WifiP2pConfig.Builder Bug: 123780303 Test: cts - atest CtsNetTestCases:android.net.wifi.cts.WifiP2pConfigTest Change-Id: I8529bf725c648e499acd6017ee57fe3db7422fef --- tests/cts/net/src/android/net/wifi/OWNERS | 5 ++ .../cts/net/src/android/net/wifi/aware/OWNERS | 1 - .../net/wifi/p2p/cts/WifiP2pConfigTest.java | 62 +++++++++++++++++++ tests/cts/net/src/android/net/wifi/rtt/OWNERS | 1 - 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/src/android/net/wifi/OWNERS delete mode 100644 tests/cts/net/src/android/net/wifi/aware/OWNERS create mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/rtt/OWNERS diff --git a/tests/cts/net/src/android/net/wifi/OWNERS b/tests/cts/net/src/android/net/wifi/OWNERS new file mode 100644 index 0000000000..4a6001bcfe --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/OWNERS @@ -0,0 +1,5 @@ +etancohen@google.com +lorenzo@google.com +mplass@google.com +rpius@google.com +satk@google.com diff --git a/tests/cts/net/src/android/net/wifi/aware/OWNERS b/tests/cts/net/src/android/net/wifi/aware/OWNERS deleted file mode 100644 index cf116f89dd..0000000000 --- a/tests/cts/net/src/android/net/wifi/aware/OWNERS +++ /dev/null @@ -1 +0,0 @@ -etancohen@google.com diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java new file mode 100644 index 0000000000..639db8a7c3 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 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.wifi.p2p.cts; + +import android.net.MacAddress; +import android.net.wifi.p2p.WifiP2pConfig; +import android.net.wifi.p2p.WifiP2pGroup; +import android.test.AndroidTestCase; + +public class WifiP2pConfigTest extends AndroidTestCase { + static final String TEST_NETWORK_NAME = "DIRECT-xy-Hello"; + static final String TEST_PASSPHRASE = "8etterW0r1d"; + static final int TEST_OWNER_BAND = WifiP2pConfig.GROUP_OWNER_BAND_5GHZ; + static final int TEST_OWNER_FREQ = 2447; + static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff"; + + public void testWifiP2pConfigBuilderForPersist() { + WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder(); + builder.setNetworkName(TEST_NETWORK_NAME) + .setPassphrase(TEST_PASSPHRASE) + .setGroupOperatingBand(TEST_OWNER_BAND) + .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) + .enablePersistentMode(true); + WifiP2pConfig config = builder.build(); + + assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS)); + assertTrue(config.networkName.equals(TEST_NETWORK_NAME)); + assertTrue(config.passphrase.equals(TEST_PASSPHRASE)); + assertEquals(config.groupOwnerBand, TEST_OWNER_BAND); + assertEquals(config.netId, WifiP2pGroup.PERSISTENT_NET_ID); + } + + public void testWifiP2pConfigBuilderForNonPersist() { + WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder(); + builder.setNetworkName(TEST_NETWORK_NAME) + .setPassphrase(TEST_PASSPHRASE) + .setGroupOperatingFrequency(TEST_OWNER_FREQ) + .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) + .enablePersistentMode(false); + WifiP2pConfig config = builder.build(); + + assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS)); + assertTrue(config.networkName.equals(TEST_NETWORK_NAME)); + assertTrue(config.passphrase.equals(TEST_PASSPHRASE)); + assertEquals(config.groupOwnerBand, TEST_OWNER_FREQ); + assertEquals(config.netId, WifiP2pGroup.TEMPORARY_NET_ID); + } +} diff --git a/tests/cts/net/src/android/net/wifi/rtt/OWNERS b/tests/cts/net/src/android/net/wifi/rtt/OWNERS deleted file mode 100644 index cf116f89dd..0000000000 --- a/tests/cts/net/src/android/net/wifi/rtt/OWNERS +++ /dev/null @@ -1 +0,0 @@ -etancohen@google.com From db6c9fd35a0eaf441273a1ff937de323dbd6286a Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 14 Feb 2019 14:27:13 +0800 Subject: [PATCH 0550/1415] p2p: add cts coverage for new WifiP2pManager API Bug: 123781797 Test: cts - atest CtsNetTestCases:android.net.wifi.cts.ConcurrencyTest Change-Id: Id37429c48e6e784bfe1cc6de0378f5213991c241 --- .../android/net/wifi/cts/ConcurrencyTest.java | 320 +++++++++++++++++- 1 file changed, 304 insertions(+), 16 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java index 5e91366a9d..c80e3720c5 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java @@ -16,36 +16,66 @@ package android.net.wifi.cts; +import static org.junit.Assert.assertNotEquals; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.net.wifi.p2p.WifiP2pManager; -import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_DISABLED; -import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_ENABLED; +import android.provider.Settings; import android.test.AndroidTestCase; +import android.util.Log; import com.android.compatibility.common.util.SystemUtil; +import java.util.Arrays; +import java.util.BitSet; +import java.util.LinkedList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class ConcurrencyTest extends AndroidTestCase { private class MySync { - int expectedWifiState; - int expectedP2pState; + static final int WIFI_STATE = 0; + static final int P2P_STATE = 1; + static final int DISCOVERY_STATE = 2; + static final int NETWORK_INFO = 3; + + public BitSet pendingSync = new BitSet(); + + public int expectedWifiState; + public int expectedP2pState; + public int expectedDiscoveryState; + public NetworkInfo expectedNetworkInfo; + } + + private class MyResponse { + public boolean valid = false; + + public boolean success; + public int p2pState; + public int discoveryState; + public NetworkInfo networkInfo; } private WifiManager mWifiManager; + private WifiP2pManager mWifiP2pManager; + private WifiP2pManager.Channel mWifiP2pChannel; private MySync mMySync = new MySync(); + private MyResponse mMyResponse = new MyResponse(); - private static final String TAG = "WifiInfoTest"; + private static final String TAG = "ConcurrencyTest"; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; private static final int DURATION = 10000; @@ -56,16 +86,33 @@ public class ConcurrencyTest extends AndroidTestCase { final String action = intent.getAction(); if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { synchronized (mMySync) { + mMySync.pendingSync.set(MySync.WIFI_STATE); mMySync.expectedWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED); mMySync.notify(); } } else if(action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { synchronized (mMySync) { + mMySync.pendingSync.set(MySync.P2P_STATE); mMySync.expectedP2pState = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, WifiP2pManager.WIFI_P2P_STATE_DISABLED); mMySync.notify(); } + } else if (action.equals(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.pendingSync.set(MySync.DISCOVERY_STATE); + mMySync.expectedDiscoveryState = intent.getIntExtra( + WifiP2pManager.EXTRA_DISCOVERY_STATE, + WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); + mMySync.notify(); + } + } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.pendingSync.set(MySync.NETWORK_INFO); + mMySync.expectedNetworkInfo = (NetworkInfo) intent.getExtra( + WifiP2pManager.EXTRA_NETWORK_INFO, null); + mMySync.notify(); + } } } }; @@ -81,6 +128,8 @@ public class ConcurrencyTest extends AndroidTestCase { mIntentFilter = new IntentFilter(); mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); + mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); mContext.registerReceiver(mReceiver, mIntentFilter); mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); @@ -92,6 +141,8 @@ public class ConcurrencyTest extends AndroidTestCase { assertTrue(!mWifiManager.isWifiEnabled()); mMySync.expectedWifiState = WifiManager.WIFI_STATE_DISABLED; mMySync.expectedP2pState = WifiP2pManager.WIFI_P2P_STATE_DISABLED; + mMySync.expectedDiscoveryState = WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED; + mMySync.expectedNetworkInfo = null; } @Override @@ -108,16 +159,66 @@ public class ConcurrencyTest extends AndroidTestCase { super.tearDown(); } - private void waitForBroadcasts() { + private boolean waitForBroadcasts(List waitSyncList) { synchronized (mMySync) { long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && (mMySync.expectedWifiState != WifiManager.WIFI_STATE_ENABLED || - mMySync.expectedP2pState != WifiP2pManager.WIFI_P2P_STATE_ENABLED)) { + while (System.currentTimeMillis() < timeout) { + List handledSyncList = waitSyncList.stream() + .filter(w -> mMySync.pendingSync.get(w)) + .collect(Collectors.toList()); + handledSyncList.forEach(w -> mMySync.pendingSync.clear(w)); + waitSyncList.removeAll(handledSyncList); + if (waitSyncList.isEmpty()) { + break; + } try { mMySync.wait(WAIT_MSEC); } catch (InterruptedException e) { } } + if (!waitSyncList.isEmpty()) { + Log.i(TAG, "Missing broadcast: " + waitSyncList); + } + return waitSyncList.isEmpty(); + } + } + + private boolean waitForBroadcasts(int waitSingleSync) { + return waitForBroadcasts( + new LinkedList(Arrays.asList(waitSingleSync))); + } + + private boolean waitForServiceResponse(MyResponse waitResponse) { + synchronized (waitResponse) { + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout) { + try { + waitResponse.wait(WAIT_MSEC); + } catch (InterruptedException e) { } + + if (waitResponse.valid) { + return true; + } + } + return false; + } + } + + // Return true if location is enabled. + private boolean isLocationEnabled() { + return Settings.Secure.getInt(getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) + != Settings.Secure.LOCATION_MODE_OFF; + } + + // Returns true if the device has location feature. + private boolean hasLocationFeature() { + return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); + } + + private void resetResponse(MyResponse responseObj) { + synchronized (responseObj) { + responseObj.valid = false; + responseObj.networkInfo = null; } } @@ -148,25 +249,212 @@ public class ConcurrencyTest extends AndroidTestCase { cm.unregisterNetworkCallback(networkCallback); } - public void testConcurrency() { + private boolean setupWifiP2p() { // Cannot support p2p alone if (!WifiFeature.isWifiSupported(getContext())) { assertTrue(!WifiFeature.isP2pSupported(getContext())); - return; + return false; } if (!WifiFeature.isP2pSupported(getContext())) { // skip the test if p2p is not supported + return false; + } + + if (!hasLocationFeature()) { + Log.d(TAG, "Skipping test as location is not supported"); + return false; + } + if (!isLocationEnabled()) { + fail("Please enable location for this test - since P-release WiFi Direct" + + " needs Location enabled."); + } + + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (!mWifiManager.isWifiEnabled() && System.currentTimeMillis() < timeout) { + try { + enableWifi(); + } catch (InterruptedException e) { } + } + + assertTrue(mWifiManager.isWifiEnabled()); + + assertTrue(waitForBroadcasts( + new LinkedList( + Arrays.asList(MySync.WIFI_STATE, MySync.P2P_STATE)))); + + assertEquals(WifiManager.WIFI_STATE_ENABLED, mMySync.expectedWifiState); + assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMySync.expectedP2pState); + + mWifiP2pManager = + (WifiP2pManager) getContext().getSystemService(Context.WIFI_P2P_SERVICE); + mWifiP2pChannel = mWifiP2pManager.initialize( + getContext(), getContext().getMainLooper(), null); + + assertNotNull(mWifiP2pManager); + assertNotNull(mWifiP2pChannel); + + assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); + // wait for changing to EnabledState + assertNotNull(mMySync.expectedNetworkInfo); + assertTrue(mMySync.expectedNetworkInfo.isAvailable()); + + return true; + } + + public void testConcurrency() { + if (!setupWifiP2p()) { return; } - // Enable wifi - SystemUtil.runShellCommand("svc wifi enable"); + resetResponse(mMyResponse); + mWifiP2pManager.requestP2pState(mWifiP2pChannel, new WifiP2pManager.P2pStateListener() { + @Override + public void onP2pStateAvailable(int state) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.p2pState = state; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMyResponse.p2pState); + } - waitForBroadcasts(); + public void testRequestDiscoveryState() { + if (!setupWifiP2p()) { + return; + } - assertTrue(mMySync.expectedWifiState == WifiManager.WIFI_STATE_ENABLED); - assertTrue(mMySync.expectedP2pState == WifiP2pManager.WIFI_P2P_STATE_ENABLED); + resetResponse(mMyResponse); + mWifiP2pManager.requestDiscoveryState( + mWifiP2pChannel, new WifiP2pManager.DiscoveryStateListener() { + @Override + public void onDiscoveryStateAvailable(int state) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.discoveryState = state; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED, mMyResponse.discoveryState); + + resetResponse(mMyResponse); + mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() { + @Override + public void onSuccess() { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.success = true; + mMyResponse.notify(); + } + } + + @Override + public void onFailure(int reason) { + synchronized (mMyResponse) { + Log.d(TAG, "discoveryPeers failure reason: " + reason); + mMyResponse.valid = true; + mMyResponse.success = false; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + assertTrue(waitForBroadcasts(MySync.DISCOVERY_STATE)); + + resetResponse(mMyResponse); + mWifiP2pManager.requestDiscoveryState(mWifiP2pChannel, + new WifiP2pManager.DiscoveryStateListener() { + @Override + public void onDiscoveryStateAvailable(int state) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.discoveryState = state; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED, mMyResponse.discoveryState); + + mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, null); + } + + public void testRequestNetworkInfo() { + if (!setupWifiP2p()) { + return; + } + + resetResponse(mMyResponse); + mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel, + new WifiP2pManager.NetworkInfoListener() { + @Override + public void onNetworkInfoAvailable(NetworkInfo info) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.networkInfo = info; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertNotNull(mMyResponse.networkInfo); + // The state might be IDLE, DISCONNECTED, FAILED before a connection establishment. + // Just ensure the state is NOT CONNECTED. + assertNotEquals(NetworkInfo.DetailedState.CONNECTED, + mMySync.expectedNetworkInfo.getDetailedState()); + + resetResponse(mMyResponse); + mWifiP2pManager.createGroup(mWifiP2pChannel, new WifiP2pManager.ActionListener() { + @Override + public void onSuccess() { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.success = true; + mMyResponse.notify(); + } + } + + @Override + public void onFailure(int reason) { + synchronized (mMyResponse) { + Log.d(TAG, "createGroup failure reason: " + reason); + mMyResponse.valid = true; + mMyResponse.success = false; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); + assertNotNull(mMySync.expectedNetworkInfo); + assertEquals(NetworkInfo.DetailedState.CONNECTED, + mMySync.expectedNetworkInfo.getDetailedState()); + + resetResponse(mMyResponse); + mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel, + new WifiP2pManager.NetworkInfoListener() { + @Override + public void onNetworkInfoAvailable(NetworkInfo info) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.networkInfo = info; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertNotNull(mMyResponse.networkInfo); + assertEquals(NetworkInfo.DetailedState.CONNECTED, + mMyResponse.networkInfo.getDetailedState()); + + mWifiP2pManager.removeGroup(mWifiP2pChannel, null); } } From 328a891956b7c0729cb652f79ce1504648da03e0 Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Wed, 20 Feb 2019 15:46:43 +0000 Subject: [PATCH 0551/1415] Make net cts not using isolated storage Disabling isolated storage so existing tests can still write files to /sdcard and shell can read it successfully. Bug: 124651276 Test: atest android.net.cts.NetworkWatchlistTest#testGetWatchlistConfigHash Change-Id: I6c40d1ae12fc2cff76c976c11650423df5ce044f --- tests/cts/net/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml index 76ff1674f6..ff93afc375 100644 --- a/tests/cts/net/AndroidTest.xml +++ b/tests/cts/net/AndroidTest.xml @@ -26,5 +26,6 @@ diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 7c9ce8f833..a2443b391a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -128,7 +128,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void runDeviceTests(String packageName, String testClassName, String methodName) throws DeviceNotAvailableException { RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, - "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + "androidx.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); if (testClassName != null) { if (methodName != null) { From e1a851f029730532fef7f315b4787131c899075d Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 27 Feb 2019 18:15:17 +0800 Subject: [PATCH 0557/1415] Minor change for jni cts test of asynchronous DNS query API Test: build atest MultinetworkApiTest Change-Id: I644adb74b841d70bb3396104fb483793a25cd36a --- tests/cts/net/jni/NativeMultinetworkJni.cpp | 42 +++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index 332148bf39..d1a92a47a1 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -42,7 +42,7 @@ if (actual < expected) { \ jniThrowExceptionFmt(env, "java/lang/AssertionError", \ "%s:%d: %s EXPECT_GE: expected %d, got %d", \ - __FILE__, __LINE__, expected, actual); \ + __FILE__, __LINE__, msg, expected, actual); \ } \ } while (0) @@ -65,7 +65,7 @@ } while (0) static const int MAXPACKET = 8 * 1024; -static const int TIMEOUT_MS = 2000; +static const int TIMEOUT_MS = 15000; static const char kHostname[] = "connectivitycheck.android.com"; static const char kNxDomainName[] = "test1-nx.metric.gstatic.com"; static const char kGoogleName[] = "www.google.com"; @@ -82,23 +82,29 @@ int getAsyncResponse(JNIEnv* env, int fd, int timeoutMs, int* rcode, uint8_t* bu int n = android_res_nresult(fd, rcode, buf, bufLen); // Verify that android_res_nresult() closed the fd char dummy; - EXPECT_EQ(env, -1, read(fd, &dummy, sizeof dummy), "res_nresult check for closing fd"); + EXPECT_EQ(env, -1, read(fd, &dummy, sizeof(dummy)), "res_nresult check for closing fd"); EXPECT_EQ(env, EBADF, errno, "res_nresult check for errno"); return n; } - return -EREMOTEIO; + return -ETIMEDOUT; } int extractIpAddressAnswers(uint8_t* buf, size_t bufLen, int family) { ns_msg handle; if (ns_initparse((const uint8_t*) buf, bufLen, &handle) < 0) { - return -EREMOTEIO; + return -errno; } const int ancount = ns_msg_count(handle, ns_s_an); + // Answer count = 0 is valid(e.g. response of query with root) + if (!ancount) { + return 0; + } ns_rr rr; + bool hasValidAns = false; for (int i = 0; i < ancount; i++) { if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) { + // If there is no valid answer, test will fail. continue; } const uint8_t* rdata = ns_rr_rdata(rr); @@ -106,8 +112,9 @@ int extractIpAddressAnswers(uint8_t* buf, size_t bufLen, int family) { if (inet_ntop(family, (const char*) rdata, buffer, sizeof(buffer)) == NULL) { return -errno; } + hasValidAns = true; } - return 0; + return hasValidAns ? 0 : -EBADMSG; } int expectAnswersValid(JNIEnv* env, int fd, int family, int expectedRcode) { @@ -117,10 +124,8 @@ int expectAnswersValid(JNIEnv* env, int fd, int family, int expectedRcode) { if (res < 0) { return res; } - if(rcode != expectedRcode) { - ALOGD("rcode:%d, expectedRcode = %d", rcode, expectedRcode); - return -EREMOTEIO; - } + + EXPECT_EQ(env, expectedRcode, rcode, "rcode is not expected"); if (expectedRcode == ns_r_noerror && res > 0) { return extractIpAddressAnswers(buf, res, family); @@ -151,8 +156,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck( "v4 res_nquery check answers"); // V4 NXDOMAIN - fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, - ANDROID_RESOLV_NO_CACHE_LOOKUP); + fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0); EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN"); EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain), "v4 res_nquery NXDOMAIN check answers"); @@ -164,8 +168,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck( "v6 res_nquery check answers"); // V6 NXDOMAIN - fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, - ANDROID_RESOLV_NO_CACHE_LOOKUP); + fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0); EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN"); EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain), "v6 res_nquery NXDOMAIN check answers"); @@ -201,7 +204,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNsendCheck( memset(buf1, 0, sizeof(buf1)); len1 = makeQuery(kNxDomainName, ns_t_a, buf1, sizeof(buf1)); EXPECT_GT(env, len1, 0, "v4 res_mkquery NXDOMAIN"); - fd1 = android_res_nsend(handle, buf1, len1, ANDROID_RESOLV_NO_CACHE_LOOKUP); + fd1 = android_res_nsend(handle, buf1, len1, 0); EXPECT_GE(env, fd1, 0, "v4 res_nsend NXDOMAIN"); EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_nxdomain), "v4 res_nsend NXDOMAIN check answers"); @@ -224,11 +227,11 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNsendCheck( EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_noerror), "v6 res_nsend 1st check answers"); - // // V6 NXDOMAIN + // V6 NXDOMAIN memset(buf1, 0, sizeof(buf1)); len1 = makeQuery(kNxDomainName, ns_t_aaaa, buf1, sizeof(buf1)); EXPECT_GT(env, len1, 0, "v6 res_mkquery NXDOMAIN"); - fd1 = android_res_nsend(handle, buf1, len1, ANDROID_RESOLV_NO_CACHE_LOOKUP); + fd1 = android_res_nsend(handle, buf1, len1, 0); EXPECT_GE(env, fd1, 0, "v6 res_nsend NXDOMAIN"); EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_nxdomain), "v6 res_nsend NXDOMAIN check answers"); @@ -245,8 +248,9 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck( int rcode = -1; uint8_t buf[MAXPACKET] = {}; android_res_cancel(fd); - android_res_cancel(fd); + EXPECT_EQ(env, -EBADF, android_res_nresult(fd, &rcode, buf, MAXPACKET), "res_cancel"); + android_res_cancel(fd); EXPECT_EQ(env, -EBADF, android_res_nresult(fd, &rcode, buf, MAXPACKET), "res_cancel"); return 0; } @@ -269,7 +273,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck fd = android_res_nquery(handle, exceedingLabelQuery.c_str(), ns_c_in, ns_t_a, 0); EXPECT_EQ(env, -EMSGSIZE, fd, "res_nquery exceedingLabelQuery"); - fd = android_res_nquery(handle, exceedingDomainQuery.c_str(), ns_c_in, ns_t_a, 0); + fd = android_res_nquery(handle, exceedingDomainQuery.c_str(), ns_c_in, ns_t_aaaa, 0); EXPECT_EQ(env, -EMSGSIZE, fd, "res_nquery exceedingDomainQuery"); uint8_t buf[10] = {}; From 77dbefc0f828e7c00307f4b599291079ed15468d Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Tue, 26 Feb 2019 15:40:02 -0800 Subject: [PATCH 0558/1415] Add rtsp uri test cases for Uri.toSafeString() Test: atest CtsNetTestCases:android.net.cts.UriTest Bug: 123669012 Change-Id: I6dac4028fd9eb6b9240a87d9e41f9dafc34bbabe --- tests/cts/net/src/android/net/cts/UriTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java index 5344f93df9..40b8fb7259 100644 --- a/tests/cts/net/src/android/net/cts/UriTest.java +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -568,6 +568,15 @@ public class UriTest extends AndroidTestCase { "ftp://root:love@ftp.android.com:2121/"); } + public void testToSafeString_rtsp() { + checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/"); + checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/video.mov"); + checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/video.mov?param"); + checkToSafeString("RtsP://rtsp.android.com/...", "RtsP://anonymous@rtsp.android.com/"); + checkToSafeString("rtsp://rtsp.android.com:2121/...", + "rtsp://username:password@rtsp.android.com:2121/"); + } + public void testToSafeString_notSupport() { checkToSafeString("unsupported://ajkakjah/askdha/secret?secret", "unsupported://ajkakjah/askdha/secret?secret"); From 0c6f9ef7c80e318e848c94dbd3dee426fa35666c Mon Sep 17 00:00:00 2001 From: Yichun Li Date: Tue, 26 Feb 2019 18:03:52 -0800 Subject: [PATCH 0559/1415] Backfill OWNERS for CTS module CtsHostsideNetworkTests You're receiving this CL because you're the owner of CtsHostsideNetworkTests as per http://go/cts-test-owners. Please refer to the following doc for more details on why we are backfilling OWNERS file: http://go/backfill-cts-owners. Test: Ignored Bug: 126563878 Change-Id: Ib239888264404f6acd265f9923d8c2c4eb988797 --- tests/cts/hostside/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/cts/hostside/OWNERS diff --git a/tests/cts/hostside/OWNERS b/tests/cts/hostside/OWNERS new file mode 100644 index 0000000000..52c8053323 --- /dev/null +++ b/tests/cts/hostside/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 61373 +sudheersai@google.com +lorenzo@google.com +jchalard@google.com From 420804ce3e68183b019b217064af1c417496c3e0 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Thu, 28 Feb 2019 10:01:06 -0800 Subject: [PATCH 0560/1415] Migrate cts/tests/tests/net to androidx.test See go/jetpack-test-android-migration Test: m -j CtsNetTestCases Change-Id: I4a76e9b9410f94e297bca4287f450fe3b72fb409 Merged-In: If102677e4cdc4361b5d93283c4d6140dc477a94a --- tests/cts/net/Android.mk | 4 ++-- tests/cts/net/AndroidManifest.xml | 2 +- .../android/net/cts/ConnectivityManagerTest.java | 15 +++++++-------- .../net/src/android/net/cts/MacAddressTest.java | 6 ++++-- .../src/android/net/cts/NetworkWatchlistTest.java | 8 ++++---- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index bb1f4c73c4..2084dbc357 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -40,8 +40,8 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ core-tests-support \ - compatibility-device-util \ - ctstestrunner \ + compatibility-device-util-axt \ + ctstestrunner-axt \ ctstestserver \ mockwebserver \ junit \ diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 0bfb650882..b261b39885 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -42,7 +42,7 @@ - Date: Wed, 26 Dec 2018 16:08:09 -0800 Subject: [PATCH 0561/1415] [Wifi] Update CTS test for Wifi Locks This commit adds CTS test cases for High-Perf and Low-Latency wifi locks. Bug: 34905427 Bug: 116512430 Test: atest WifiManager_WifiLockTest Change-Id: I94cb7fc0aa7876d6796eca6ca97b744dc009ef3e --- .../wifi/cts/WifiManager_WifiLockTest.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java index 3cdd56af89..e08a972bd0 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java @@ -25,13 +25,27 @@ public class WifiManager_WifiLockTest extends AndroidTestCase { private static final String WIFI_TAG = "WifiManager_WifiLockTest"; - public void testWifiLock() { + /** + * Verify acquire and release of High Performance wifi locks + */ + public void testHiPerfWifiLock() { + testWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF); + } + + /** + * Verify acquire and release of Low latency wifi locks + */ + public void testLowLatencyWifiLock() { + testWifiLock(WifiManager.WIFI_MODE_FULL_LOW_LATENCY); + } + + private void testWifiLock(int lockType) { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported return; } WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - WifiLock wl = wm.createWifiLock(WIFI_TAG); + WifiLock wl = wm.createWifiLock(lockType, WIFI_TAG); wl.setReferenceCounted(true); assertFalse(wl.isHeld()); @@ -55,7 +69,7 @@ public class WifiManager_WifiLockTest extends AndroidTestCase { // expected } - wl = wm.createWifiLock(WIFI_TAG); + wl = wm.createWifiLock(lockType, WIFI_TAG); wl.setReferenceCounted(false); assertFalse(wl.isHeld()); wl.acquire(); From c626be0dc78d8ffa9d30c63455aa48900023ffec Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Tue, 12 Feb 2019 20:46:59 -0800 Subject: [PATCH 0562/1415] Migrate cts/tests/tests/net to androidx.test See go/jetpack-test-android-migration This is the internal version of aosp/915793 Exempt-From-Owner-Approval: already reviewed in aosp Test: m -j CtsNetTestCases Change-Id: If102677e4cdc4361b5d93283c4d6140dc477a94a --- tests/cts/net/Android.mk | 4 ++-- tests/cts/net/AndroidManifest.xml | 2 +- .../android/net/cts/ConnectivityManagerTest.java | 15 +++++++-------- .../net/src/android/net/cts/MacAddressTest.java | 6 ++++-- .../src/android/net/cts/NetworkWatchlistTest.java | 8 ++++---- .../src/android/net/wifi/cts/WifiManagerTest.java | 8 ++------ 6 files changed, 20 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index bb1f4c73c4..2084dbc357 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -40,8 +40,8 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ core-tests-support \ - compatibility-device-util \ - ctstestrunner \ + compatibility-device-util-axt \ + ctstestrunner-axt \ ctstestserver \ mockwebserver \ junit \ diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 2a57c101b2..630de7e08f 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -43,7 +43,7 @@ - Date: Fri, 1 Mar 2019 13:25:23 -0800 Subject: [PATCH 0563/1415] Migrate remaining cts to androidx.test. See go/jetpack-test-android-migration Exempt-From-Owner-Approval: automated package name refactoring; already reviewed+merged internally Test: m cts Change-Id: I6877435bf0436b8ef1dd252b225eac2908e78b71 Merged-In: I092c369229f8cb4c13827cbad4fd162622ac7849 --- tests/cts/hostside/app/Android.mk | 2 +- tests/cts/hostside/app/AndroidManifest.xml | 2 +- .../src/com/android/cts/net/HostsideNetworkTestCase.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index 62e0172817..11f6bb1460 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -21,7 +21,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests #LOCAL_SDK_VERSION := current LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \ +LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt ctstestrunner-axt ub-uiautomator \ CtsHostsideNetworkTestsAidl LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index 2553f475aa..ba0e242ab9 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -45,7 +45,7 @@ diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 7c9ce8f833..a2443b391a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -128,7 +128,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void runDeviceTests(String packageName, String testClassName, String methodName) throws DeviceNotAvailableException { RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, - "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + "androidx.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); if (testClassName != null) { if (methodName != null) { From 7513ebc64fe46b38944e4f97995e0d8a23969e2c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 4 Mar 2019 11:57:19 -0800 Subject: [PATCH 0564/1415] Remove point-to-point assertion in IpSecManagerTunnelTest This change removes the requirement for IPsec interfaces to be point-to-point. The two implementations (VTI vs XFRMI) have different point-to-point values, and as such, this assertion is no longer valid. Bug: 126578549 Test: Ran tests against XFRM-I kernels Change-Id: I0597e0aa86ccea2cd28d7c5e02063c788ddb08b8 --- tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 95ca25ce64..5dc9b63b87 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -127,7 +127,6 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Check interface was created NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertTrue(netIntf.isPointToPoint()); assertNotNull(netIntf); // Add addresses and check From a0629ad8b9680949d4b62a7fd953dd17d5b8f6d2 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 24 Jan 2019 14:21:06 +0800 Subject: [PATCH 0565/1415] Minor changes and more cts tests for DnsResolver Test: built, flashed, booted atest DnsResolverTest Change-Id: I39f24b9751ab507bf7fc6bcd90376fafc60221b8 --- .../src/android/net/cts/DnsResolverTest.java | 215 +++++++++++++----- 1 file changed, 161 insertions(+), 54 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 2e40584ecb..308f1edb0c 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -17,16 +17,16 @@ package android.net.cts; import static android.net.DnsResolver.CLASS_IN; -import static android.net.DnsResolver.TYPE_A; -import static android.net.DnsResolver.TYPE_AAAA; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; +import static android.net.DnsResolver.TYPE_AAAA; +import android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityManager; +import android.net.DnsPacket; import android.net.DnsResolver; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkUtils; import android.os.Handler; import android.os.Looper; import android.system.ErrnoException; @@ -35,14 +35,18 @@ import android.util.Log; import java.net.InetAddress; import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; public class DnsResolverTest extends AndroidTestCase { private static final String TAG = "DnsResolverTest"; private static final char[] HEX_CHARS = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static final int TIMEOUT_MS = 12_000; + private ConnectivityManager mCM; private Handler mHandler; private DnsResolver mDns; @@ -54,7 +58,7 @@ public class DnsResolverTest extends AndroidTestCase { mDns = DnsResolver.getInstance(); } - private static String bytesArrayToHexString(byte[] bytes) { + private static String byteArrayToHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int i = 0; i < bytes.length; ++i) { int b = bytes[i] & 0xFF; @@ -77,85 +81,188 @@ public class DnsResolverTest extends AndroidTestCase { assertTrue( "This test requires that at least one network be connected. " + - "Please ensure that the device is connected to a network.", + "Please ensure that the device is connected to a network.", testableNetworks.size() >= 1); return testableNetworks.toArray(new Network[0]); } public void testInetAddressQuery() throws ErrnoException { + final String dname = "www.google.com"; + final String msg = "InetAddress query " + dname; for (Network network : getTestableNetworks()) { - CountDownLatch latch = new CountDownLatch(1); - final int TIMEOUT_MS = 5_000; - final String dname = "www.google.com"; + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference> answers = new AtomicReference<>(); mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP, mHandler, answerList -> { - if (answerList.size() != 0) { - latch.countDown(); + answers.set(answerList); for (InetAddress addr : answerList) { - Log.e(TAG, "Reported addr:" + addr.toString()); + Log.d(TAG, "Reported addr:" + addr.toString()); } + latch.countDown(); } - } ); - String msg = "InetAddress query " + dname + " but no valid answer after " - + TIMEOUT_MS + "ms."; try { - assertTrue(msg, latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) {} + assertTrue(msg + " but no valid answer after " + TIMEOUT_MS + "ms.", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertGreaterThan(msg + " returned 0 result", answers.get().size(), 0); + } catch (InterruptedException e) { + } + } + } + + static private void assertGreaterThan(String msg, int a, int b) { + assertTrue(msg + ": " + a + " > " + b, a > b); + } + + static private void assertValidAnswer(String msg, @NonNull DnsAnswer ans) { + // Check rcode field.(0, No error condition). + assertTrue(msg + " Response error, rcode: " + ans.getRcode(), ans.getRcode() == 0); + // Check answer counts. + assertTrue(msg + " No answer found", ans.getANCount() > 0); + // Check question counts. + assertTrue(msg + " No question found", ans.getQDCount() > 0); + } + + static private void assertValidEmptyAnswer(String msg, @NonNull DnsAnswer ans) { + // Check rcode field.(0, No error condition). + assertTrue(msg + " Response error, rcode: " + ans.getRcode(), ans.getRcode() == 0); + // Check answer counts. Expect 0 answer. + assertTrue(msg + " Not an empty answer", ans.getANCount() == 0); + // Check question counts. + assertTrue(msg + " No question found", ans.getQDCount() > 0); + } + + private class DnsAnswer extends DnsPacket { + DnsAnswer(@NonNull byte[] data) throws ParseException { + super(data); + // Check QR field.(query (0), or a response (1)). + if ((mHeader.flags & (1 << 15)) == 0) { + throw new ParseException("Not an answer packet"); + } + } + + int getRcode() { + return mHeader.rcode; + } + int getANCount(){ + return mHeader.getRecordCount(ANSECTION); + } + int getQDCount(){ + return mHeader.getRecordCount(QDSECTION); } } public void testRawQuery() throws ErrnoException { + final String dname = "www.google.com"; + final String msg = "Raw query " + dname; for (Network network : getTestableNetworks()) { - CountDownLatch latch = new CountDownLatch(1); - final int TIMEOUT_MS = 5_000; - final String dname = "www.google.com"; - - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mHandler, answer -> { - if (answer != null) { - latch.countDown(); - Log.e(TAG, "Reported blob:" + bytesArrayToHexString(answer)); + final CountDownLatch latch = new CountDownLatch(1); + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mHandler, + answer -> { + if (answer == null) { + fail(msg + " no answer returned"); + } + try { + assertValidAnswer(msg, new DnsAnswer(answer)); + Log.d(TAG, "Reported blob:" + byteArrayToHexString(answer)); + latch.countDown(); + } catch (DnsPacket.ParseException e) { + fail(msg + e.getMessage()); + } } - } ); - String msg = "Raw query " + dname + " but no valid answer after " + TIMEOUT_MS + "ms."; try { - assertTrue(msg, latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) {} + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + } } } public void testRawQueryWithBlob() throws ErrnoException { + final byte[] blob = new byte[]{ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ + }; + final String msg = "Raw query with blob " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { - CountDownLatch latch = new CountDownLatch(1); - final int TIMEOUT_MS = 5_000; - final byte[] blob = new byte[] { - /* Header */ - 0x55, 0x66, /* Transaction ID */ - 0x01, 0x00, /* Flags */ - 0x00, 0x01, /* Questions */ - 0x00, 0x00, /* Answer RRs */ - 0x00, 0x00, /* Authority RRs */ - 0x00, 0x00, /* Additional RRs */ - /* Queries */ - 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, - 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01 /* Class */ - }; - + final CountDownLatch latch = new CountDownLatch(1); mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mHandler, answer -> { - if (answer != null) { - latch.countDown(); - Log.e(TAG, "Reported blob:" + bytesArrayToHexString(answer)); + if (answer == null) { + fail(msg + " no answer returned"); + } + try { + assertValidAnswer(msg, new DnsAnswer(answer)); + Log.d(TAG, "Reported blob:" + byteArrayToHexString(answer)); + latch.countDown(); + } catch (DnsPacket.ParseException e) { + fail(msg + e.getMessage()); + } } - } ); - String msg = "Raw query with blob " + bytesArrayToHexString(blob) + - " but no valid answer after " + TIMEOUT_MS + "ms."; try { - assertTrue(msg, latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) {} + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + } + } + } + + public void testEmptyQuery() throws ErrnoException { + final String dname = ""; + final String msg = "Raw query empty dname(ROOT)"; + for (Network network : getTestableNetworks()) { + final CountDownLatch latch = new CountDownLatch(1); + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mHandler, + answer -> { + if (answer == null) { + fail(msg + " no answer returned"); + } + try { + // Except no answer record because of querying with empty dname(ROOT) + assertValidEmptyAnswer(msg, new DnsAnswer(answer)); + latch.countDown(); + } catch (DnsPacket.ParseException e) { + fail(msg + e.getMessage()); + } + } + ); + try { + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + } + } + } + + public void testNXQuery() throws ErrnoException { + final String dname = "test1-nx.metric.gstatic.com"; + final String msg = "InetAddress query " + dname; + for (Network network : getTestableNetworks()) { + final CountDownLatch latch = new CountDownLatch(1); + mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP, mHandler, answerList -> { + if (answerList.size() == 0) { + latch.countDown(); + return; + } + fail(msg + " but get valid answers"); + } + ); + try { + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + } } } } From c45065bdeae7c4b3104bf76d11b98b2ad7246e6b Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Wed, 6 Mar 2019 15:52:42 -0800 Subject: [PATCH 0566/1415] DO NOT MERGE - Migrate remaining cts to androidx.test. See go/jetpack-test-android-migration Test: m cts Exempt-From-Owner-Approval: automated refactoring, has already been reviewed by owners downstream Bug: 127482512 Change-Id: If72aed95ef9e436bcc6e063abc0478eca365cc9b --- tests/cts/hostside/app/Android.mk | 2 +- tests/cts/hostside/app/AndroidManifest.xml | 2 +- .../com/android/cts/net/HostsideNetworkTestCase.java | 2 +- tests/cts/net/Android.mk | 4 ++-- tests/cts/net/AndroidManifest.xml | 2 +- .../src/android/net/cts/ConnectivityManagerTest.java | 12 +++++++----- .../cts/net/src/android/net/cts/MacAddressTest.java | 6 ++++-- .../src/android/net/cts/NetworkWatchlistTest.java | 8 ++++---- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index c03e70bcb0..6d89e58576 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -20,7 +20,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current -LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \ +LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt ctstestrunner-axt ub-uiautomator \ CtsHostsideNetworkTestsAidl LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index 2553f475aa..ba0e242ab9 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -45,7 +45,7 @@ diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 7c9ce8f833..a2443b391a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -128,7 +128,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void runDeviceTests(String packageName, String testClassName, String methodName) throws DeviceNotAvailableException { RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, - "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + "androidx.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); if (testClassName != null) { if (methodName != null) { diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 1430071997..45941a79e1 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -41,8 +41,8 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ core-tests-support \ - compatibility-device-util \ - ctstestrunner \ + compatibility-device-util-axt \ + ctstestrunner-axt \ ctstestserver \ mockwebserver \ junit \ diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 0bfb650882..b261b39885 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -42,7 +42,7 @@ - Date: Tue, 12 Mar 2019 16:41:39 -0700 Subject: [PATCH 0567/1415] Removed Passpoint tests from WifiManagerTest Passpoint APIs require NETWORK_SETTINGS permission, which the CTS verifier cannot acquire. Bug: 127824266 Test: atest WifiManagerTest Change-Id: I1c69ae748318c0c5431326be77f8b1a942a1f2db --- .../android/net/wifi/cts/WifiManagerTest.java | 158 ------------------ 1 file changed, 158 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index a66fcdb0ba..8e66cb8953 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -509,164 +509,6 @@ public class WifiManagerTest extends AndroidTestCase { assertTrue(i < 15); } - /** - * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint - * configuration with an user credential. - * - * @throws Exception - */ - public void testAddPasspointConfigWithUserCredential() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - testAddPasspointConfig(generatePasspointConfig(generateUserCredential())); - } - - /** - * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint - * configuration with a certificate credential. - * - * @throws Exception - */ - public void testAddPasspointConfigWithCertCredential() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - testAddPasspointConfig(generatePasspointConfig(generateCertCredential())); - } - - /** - * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint - * configuration with a SIm credential. - * - * @throws Exception - */ - public void testAddPasspointConfigWithSimCredential() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - testAddPasspointConfig(generatePasspointConfig(generateSimCredential())); - } - - /** - * Helper function for generating a {@link PasspointConfiguration} for testing. - * - * @return {@link PasspointConfiguration} - */ - private PasspointConfiguration generatePasspointConfig(Credential credential) { - PasspointConfiguration config = new PasspointConfiguration(); - config.setCredential(credential); - - // Setup HomeSp. - HomeSp homeSp = new HomeSp(); - homeSp.setFqdn("Test.com"); - homeSp.setFriendlyName("Test Provider"); - homeSp.setRoamingConsortiumOis(new long[] {0x11223344}); - config.setHomeSp(homeSp); - - return config; - } - - /** - * Helper function for generating an user credential for testing. - * - * @return {@link Credential} - */ - private Credential generateUserCredential() { - Credential credential = new Credential(); - credential.setRealm("test.net"); - Credential.UserCredential userCred = new Credential.UserCredential(); - userCred.setEapType(21 /* EAP_TTLS */); - userCred.setUsername("username"); - userCred.setPassword("password"); - userCred.setNonEapInnerMethod("PAP"); - credential.setUserCredential(userCred); - credential.setCaCertificate(FakeKeys.CA_PUBLIC_CERT); - return credential; - } - - /** - * Helper function for generating a certificate credential for testing. - * - * @return {@link Credential} - */ - private Credential generateCertCredential() throws Exception { - Credential credential = new Credential(); - credential.setRealm("test.net"); - Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); - certCredential.setCertType("x509v3"); - certCredential.setCertSha256Fingerprint( - MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded())); - credential.setCertCredential(certCredential); - credential.setCaCertificate(FakeKeys.CA_PUBLIC_CERT); - credential.setClientCertificateChain(new X509Certificate[] {FakeKeys.CLIENT_CERT}); - credential.setClientPrivateKey(FakeKeys.RSA_KEY1); - return credential; - } - - /** - * Helper function for generating a SIM credential for testing. - * - * @return {@link Credential} - */ - private Credential generateSimCredential() throws Exception { - Credential credential = new Credential(); - credential.setRealm("test.net"); - Credential.SimCredential simCredential = new Credential.SimCredential(); - simCredential.setImsi("1234*"); - simCredential.setEapType(18 /* EAP_SIM */); - credential.setSimCredential(simCredential); - return credential; - } - - /** - * Helper function verifying Passpoint configuration management APIs (add, remove, get) for - * a given configuration. - * - * @param config The configuration to test with - */ - private void testAddPasspointConfig(PasspointConfiguration config) throws Exception { - try { - - // obtain number of passpoint networks already present in device (preloaded) - List preConfigList = mWifiManager.getPasspointConfigurations(); - int numOfNetworks = preConfigList.size(); - - // add new (test) configuration - mWifiManager.addOrUpdatePasspointConfiguration(config); - - // Certificates and keys will be set to null after it is installed to the KeyStore by - // WifiManager. Reset them in the expected config so that it can be used to compare - // against the retrieved config. - config.getCredential().setCaCertificate(null); - config.getCredential().setClientCertificateChain(null); - config.getCredential().setClientPrivateKey(null); - - // retrieve the configuration and verify it. The retrieved list may not be in order - - // check all configs to see if any match - List configList = mWifiManager.getPasspointConfigurations(); - assertEquals(numOfNetworks + 1, configList.size()); - - boolean anyMatch = false; - for (PasspointConfiguration passpointConfiguration : configList) { - if (passpointConfiguration.equals(config)) { - anyMatch = true; - break; - } - } - assertTrue(anyMatch); - - // remove the (test) configuration and verify number of installed configurations - mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn()); - assertEquals(mWifiManager.getPasspointConfigurations().size(), numOfNetworks); - } catch (UnsupportedOperationException e) { - // Passpoint build config |config_wifi_hotspot2_enabled| is disabled, so noop. - } - } - public class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback { Object hotspotLock; WifiManager.LocalOnlyHotspotReservation reservation = null; From 3953e40365470b468db1e95e3a47ed627a5cae39 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 14 Mar 2019 10:30:06 +0800 Subject: [PATCH 0568/1415] Fix API Review issues. Modify the method name in LinkProperties. Bug: 126699682 Test: make cts passed. Change-Id: I3729e8915a8eff36e8de9035b5bf1571f8609e42 --- tests/cts/net/src/android/net/cts/DnsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index 84231c25a8..746dcb0a1c 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -287,7 +287,7 @@ public class DnsTest extends AndroidTestCase { final NetworkCallback callback = new NetworkCallback() { @Override public void onLinkPropertiesChanged(Network network, LinkProperties lp) { - if (lp.hasGlobalIPv6Address()) { + if (lp.hasGlobalIpv6Address()) { latch.countDown(); } } From e451659573add8b4479b4553d1d785b0f825bd5c Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Wed, 13 Mar 2019 23:58:13 -0700 Subject: [PATCH 0569/1415] Wifi: Add CTS test for WifiManager.MulticastLock This commit adds the CTS tests for the class WifiManager.MulticastLock Bug: 124017617 Test: atest android.net.wifi.cts Change-Id: I6e7a6e70f350dcd23fe541ef746770e3561d49e6 --- tests/cts/net/AndroidManifest.xml | 1 + .../net/wifi/cts/MulticastLockTest.java | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 630de7e08f..dbd8fef08e 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -31,6 +31,7 @@ + diff --git a/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java b/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java new file mode 100644 index 0000000000..54fe9c72a9 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 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.wifi.cts; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.MulticastLock; +import android.test.AndroidTestCase; + +public class MulticastLockTest extends AndroidTestCase { + + private static final String WIFI_TAG = "MulticastLockTest"; + + /** + * Verify acquire and release of Multicast locks + */ + public void testMulticastLock() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + MulticastLock mcl = wm.createMulticastLock(WIFI_TAG); + + mcl.setReferenceCounted(true); + assertFalse(mcl.isHeld()); + mcl.acquire(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertFalse(mcl.isHeld()); + mcl.acquire(); + mcl.acquire(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertFalse(mcl.isHeld()); + assertNotNull(mcl.toString()); + try { + mcl.release(); + fail("should throw out exception because release is called" + +" a greater number of times than acquire"); + } catch (RuntimeException e) { + // expected + } + + mcl = wm.createMulticastLock(WIFI_TAG); + mcl.setReferenceCounted(false); + assertFalse(mcl.isHeld()); + mcl.acquire(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertFalse(mcl.isHeld()); + mcl.acquire(); + mcl.acquire(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertFalse(mcl.isHeld()); + assertNotNull(mcl.toString()); + // releasing again after release: but ignored for non-referenced locks + mcl.release(); + } +} From e16d426550b6683e4abf9dc70004d00bad548804 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 14 Mar 2019 14:31:28 -0700 Subject: [PATCH 0570/1415] Wifi: Rename class name WifiManager_WifiLockTest This commit renames both the class name and the file name from WifiManager_WifiLockTest into WifiLockTest since WifiManager is implied from the package and directory hierarchy. Bug: 34905427 Test: atest android.net.wifi.cts Change-Id: Iaade2ba98cb1608384c2527eddb29bb6d020bf78 --- .../{WifiManager_WifiLockTest.java => WifiLockTest.java} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename tests/cts/net/src/android/net/wifi/cts/{WifiManager_WifiLockTest.java => WifiLockTest.java} (93%) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java similarity index 93% rename from tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java rename to tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java index e08a972bd0..0703e6096b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java @@ -21,9 +21,9 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -public class WifiManager_WifiLockTest extends AndroidTestCase { +public class WifiLockTest extends AndroidTestCase { - private static final String WIFI_TAG = "WifiManager_WifiLockTest"; + private static final String WIFI_TAG = "WifiLockTest"; /** * Verify acquire and release of High Performance wifi locks @@ -82,7 +82,7 @@ public class WifiManager_WifiLockTest extends AndroidTestCase { wl.release(); assertFalse(wl.isHeld()); assertNotNull(wl.toString()); - // should be ignored + // releasing again after release: but ignored for non-referenced locks wl.release(); } } From 0d952ca8473b208c71b8c86843c17ac3952eb84a Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Fri, 15 Mar 2019 08:32:54 -0700 Subject: [PATCH 0571/1415] WifiManagerTest: Enforce a min number of suggestions per app The enforced number is set at 50. Also, removed the usage of a deprecated API in WifiManagerTest. Bug: 126536466 Test: atest WifiManagerTest Change-Id: I3a1ab4150cbbecef1157152c51b1148e1e2360ca --- .../android/net/wifi/cts/WifiManagerTest.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 8e66cb8953..93795b2bf0 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -94,6 +94,8 @@ public class WifiManagerTest extends AndroidTestCase { private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; private static final int WIFI_SCAN_TEST_ITERATIONS = 5; + private static final int ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP = 50; + private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; private static final String MANAGED_PROVISIONING_PACKAGE_NAME = "com.android.managedprovisioning"; @@ -246,7 +248,6 @@ public class WifiManagerTest extends AndroidTestCase { private void connectWifi() throws Exception { synchronized (mMySync) { if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) return; - assertTrue(mWifiManager.reconnect()); long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; while (System.currentTimeMillis() < timeout && mNetworkInfo.getState() != NetworkInfo.State.CONNECTED) @@ -982,6 +983,19 @@ public class WifiManagerTest extends AndroidTestCase { assertWifiScanningIsOn(); } + /** + * Verify that the platform supports a reasonable number of suggestions per app. + * @throws Exception + */ + public void testMaxNumberOfNetworkSuggestionsPerApp() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + assertTrue(mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp() + > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP); + } + private void assertWifiScanningIsOn() { if(!mWifiManager.isScanAlwaysAvailable()) { fail("Wi-Fi scanning should be on."); From 26cc1b4a04e57ffefc6291851d3179962e27a2f1 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 6 Mar 2019 16:52:03 +0800 Subject: [PATCH 0572/1415] Improve test for the changing of DnsResolver 1. Done for some code-style nits. 2. Update tests because AnswerCallback of DnsResolver is changed. Bug: 124882626 Test: built, flashed, booted atest DnsResolverTest Change-Id: Ie862c7ea5077f56fd9a4d96baf3f466b65db93d8 --- .../src/android/net/cts/DnsResolverTest.java | 207 +++++++++++------- 1 file changed, 131 insertions(+), 76 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 308f1edb0c..643d54216a 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -18,15 +18,18 @@ package android.net.cts; import static android.net.DnsResolver.CLASS_IN; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; +import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; import android.net.DnsPacket; import android.net.DnsResolver; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.ParseException; import android.os.Handler; import android.os.Looper; import android.system.ErrnoException; @@ -86,41 +89,55 @@ public class DnsResolverTest extends AndroidTestCase { return testableNetworks.toArray(new Network[0]); } - public void testInetAddressQuery() throws ErrnoException { + public void testQueryWithInetAddressCallback() { final String dname = "www.google.com"; - final String msg = "InetAddress query " + dname; + final String msg = "Query with InetAddressAnswerCallback " + dname; for (Network network : getTestableNetworks()) { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference> answers = new AtomicReference<>(); - - mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP, mHandler, answerList -> { - answers.set(answerList); - for (InetAddress addr : answerList) { - Log.d(TAG, "Reported addr:" + addr.toString()); - } - latch.countDown(); + final DnsResolver.InetAddressAnswerCallback callback = + new DnsResolver.InetAddressAnswerCallback() { + @Override + public void onAnswer(@NonNull List answerList) { + answers.set(answerList); + for (InetAddress addr : answerList) { + Log.d(TAG, "Reported addr: " + addr.toString()); } - ); + latch.countDown(); + } + + @Override + public void onParseException(@NonNull ParseException e) { + fail(msg + e.getMessage()); + } + + @Override + public void onQueryException(@NonNull ErrnoException e) { + fail(msg + e.getMessage()); + } + }; + mDns.query(network, dname, CLASS_IN, TYPE_A, FLAG_NO_CACHE_LOOKUP, mHandler, callback); try { assertTrue(msg + " but no valid answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertGreaterThan(msg + " returned 0 result", answers.get().size(), 0); } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); } } } - static private void assertGreaterThan(String msg, int a, int b) { - assertTrue(msg + ": " + a + " > " + b, a > b); + static private void assertGreaterThan(String msg, int first, int second) { + assertTrue(msg + " Excepted " + first + " to be greater than " + second, first > second); } static private void assertValidAnswer(String msg, @NonNull DnsAnswer ans) { // Check rcode field.(0, No error condition). assertTrue(msg + " Response error, rcode: " + ans.getRcode(), ans.getRcode() == 0); // Check answer counts. - assertTrue(msg + " No answer found", ans.getANCount() > 0); + assertGreaterThan(msg + " No answer found", ans.getANCount(), 0); // Check question counts. - assertTrue(msg + " No question found", ans.getQDCount() > 0); + assertGreaterThan(msg + " No question found", ans.getQDCount(), 0); } static private void assertValidEmptyAnswer(String msg, @NonNull DnsAnswer ans) { @@ -129,10 +146,10 @@ public class DnsResolverTest extends AndroidTestCase { // Check answer counts. Expect 0 answer. assertTrue(msg + " Not an empty answer", ans.getANCount() == 0); // Check question counts. - assertTrue(msg + " No question found", ans.getQDCount() > 0); + assertGreaterThan(msg + " No question found", ans.getQDCount(), 0); } - private class DnsAnswer extends DnsPacket { + private static class DnsAnswer extends DnsPacket { DnsAnswer(@NonNull byte[] data) throws ParseException { super(data); // Check QR field.(query (0), or a response (1)). @@ -152,34 +169,56 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQuery() throws ErrnoException { + class RawAnswerCallbackImpl extends DnsResolver.RawAnswerCallback { + private final CountDownLatch mLatch = new CountDownLatch(1); + private final String mMsg; + RawAnswerCallbackImpl(String msg) { + this.mMsg = msg; + } + + public boolean waitForAnswer() throws InterruptedException { + return mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + @Override + public void onAnswer(@NonNull byte[] answer) { + try { + assertValidAnswer(mMsg, new DnsAnswer(answer)); + Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); + mLatch.countDown(); + } catch (ParseException e) { + fail(mMsg + e.getMessage()); + } + } + + @Override + public void onParseException(@NonNull ParseException e) { + fail(mMsg + e.getMessage()); + } + + @Override + public void onQueryException(@NonNull ErrnoException e) { + fail(mMsg + e.getMessage()); + } + } + + public void testQueryWithRawAnswerCallback() { final String dname = "www.google.com"; - final String msg = "Raw query " + dname; + final String msg = "Query with RawAnswerCallback " + dname; for (Network network : getTestableNetworks()) { - final CountDownLatch latch = new CountDownLatch(1); - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mHandler, - answer -> { - if (answer == null) { - fail(msg + " no answer returned"); - } - try { - assertValidAnswer(msg, new DnsAnswer(answer)); - Log.d(TAG, "Reported blob:" + byteArrayToHexString(answer)); - latch.countDown(); - } catch (DnsPacket.ParseException e) { - fail(msg + e.getMessage()); - } - } - ); + final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mHandler, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + callback.waitForAnswer()); } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); } } } - public void testRawQueryWithBlob() throws ErrnoException { + public void testQueryBlobWithRawAnswerCallback() { final byte[] blob = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -194,74 +233,90 @@ public class DnsResolverTest extends AndroidTestCase { 0x00, 0x01, /* Type */ 0x00, 0x01 /* Class */ }; - final String msg = "Raw query with blob " + byteArrayToHexString(blob); + final String msg = "Query with RawAnswerCallback " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { - final CountDownLatch latch = new CountDownLatch(1); - mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mHandler, answer -> { - if (answer == null) { - fail(msg + " no answer returned"); - } - try { - assertValidAnswer(msg, new DnsAnswer(answer)); - Log.d(TAG, "Reported blob:" + byteArrayToHexString(answer)); - latch.countDown(); - } catch (DnsPacket.ParseException e) { - fail(msg + e.getMessage()); - } - } - ); + final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); + mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mHandler, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + callback.waitForAnswer()); } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); } } } - public void testEmptyQuery() throws ErrnoException { + public void testQueryRoot() { final String dname = ""; - final String msg = "Raw query empty dname(ROOT)"; + final String msg = "Query with RawAnswerCallback empty dname(ROOT) "; for (Network network : getTestableNetworks()) { final CountDownLatch latch = new CountDownLatch(1); - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mHandler, - answer -> { - if (answer == null) { - fail(msg + " no answer returned"); - } - try { - // Except no answer record because of querying with empty dname(ROOT) - assertValidEmptyAnswer(msg, new DnsAnswer(answer)); - latch.countDown(); - } catch (DnsPacket.ParseException e) { - fail(msg + e.getMessage()); - } + final DnsResolver.RawAnswerCallback callback = new DnsResolver.RawAnswerCallback() { + @Override + public void onAnswer(@NonNull byte[] answer) { + try { + // Except no answer record because of querying with empty dname(ROOT) + assertValidEmptyAnswer(msg, new DnsAnswer(answer)); + latch.countDown(); + } catch (ParseException e) { + fail(msg + e.getMessage()); } - ); + } + + @Override + public void onParseException(@NonNull ParseException e) { + fail(msg + e.getMessage()); + } + + @Override + public void onQueryException(@NonNull ErrnoException e) { + fail(msg + e.getMessage()); + } + }; + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mHandler, callback); try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + assertTrue(msg + "but no answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { + fail(msg + "Waiting for DNS lookup was interrupted"); } } } - public void testNXQuery() throws ErrnoException { + public void testQueryNXDomain() { final String dname = "test1-nx.metric.gstatic.com"; - final String msg = "InetAddress query " + dname; + final String msg = "Query with InetAddressAnswerCallback " + dname; for (Network network : getTestableNetworks()) { final CountDownLatch latch = new CountDownLatch(1); - mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP, mHandler, answerList -> { - if (answerList.size() == 0) { - latch.countDown(); - return; - } - fail(msg + " but get valid answers"); + final DnsResolver.InetAddressAnswerCallback callback = + new DnsResolver.InetAddressAnswerCallback() { + @Override + public void onAnswer(@NonNull List answerList) { + if (answerList.size() == 0) { + latch.countDown(); + return; } - ); + fail(msg + " but get valid answers"); + } + + @Override + public void onParseException(@NonNull ParseException e) { + fail(msg + e.getMessage()); + } + + @Override + public void onQueryException(@NonNull ErrnoException e) { + fail(msg + e.getMessage()); + } + }; + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mHandler, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); } } } From 24c8d2ab38ae4a78d1223e320ec5597c8d784d76 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 7 Mar 2019 19:04:04 +0800 Subject: [PATCH 0573/1415] Alter CTS tests for change of async DNS API Bug: 124882626 Test: built, flashed, booted atest DnsResolverTest Change-Id: If823a27773cc778fba49db02045b77222c4cd1af --- .../net/src/android/net/cts/DnsResolverTest.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 643d54216a..6fbe586bb4 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -40,6 +40,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -51,14 +52,14 @@ public class DnsResolverTest extends AndroidTestCase { static final int TIMEOUT_MS = 12_000; private ConnectivityManager mCM; - private Handler mHandler; + private Executor mExecutor; private DnsResolver mDns; protected void setUp() throws Exception { super.setUp(); mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); - mHandler = new Handler(Looper.getMainLooper()); mDns = DnsResolver.getInstance(); + mExecutor = new Handler(Looper.getMainLooper())::post; } private static String byteArrayToHexString(byte[] bytes) { @@ -116,7 +117,8 @@ public class DnsResolverTest extends AndroidTestCase { fail(msg + e.getMessage()); } }; - mDns.query(network, dname, CLASS_IN, TYPE_A, FLAG_NO_CACHE_LOOKUP, mHandler, callback); + mDns.query(network, dname, CLASS_IN, TYPE_A, FLAG_NO_CACHE_LOOKUP, + mExecutor, callback); try { assertTrue(msg + " but no valid answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -208,7 +210,7 @@ public class DnsResolverTest extends AndroidTestCase { for (Network network : getTestableNetworks()) { final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mHandler, callback); + mExecutor, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -236,7 +238,7 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "Query with RawAnswerCallback " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); - mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mHandler, callback); + mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -274,7 +276,7 @@ public class DnsResolverTest extends AndroidTestCase { } }; mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mHandler, callback); + mExecutor, callback); try { assertTrue(msg + "but no answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -311,7 +313,7 @@ public class DnsResolverTest extends AndroidTestCase { } }; mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mHandler, callback); + mExecutor, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); From 361584140b7d6c7ab117a4181045c57e551e5dbc Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Fri, 8 Mar 2019 16:41:03 +0800 Subject: [PATCH 0574/1415] Add cancel test cases for async DNS API Bug: 124882626 Test: built, flashed, booted atest DnsResolverTest Change-Id: I9b496821e422f71009319eeefc6f3c6c1e249111 --- .../src/android/net/cts/DnsResolverTest.java | 162 +++++++++++++++++- 1 file changed, 155 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 6fbe586bb4..f6cc76852b 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -17,9 +17,11 @@ package android.net.cts; import static android.net.DnsResolver.CLASS_IN; +import static android.net.DnsResolver.FLAG_EMPTY; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; +import static android.system.OsConstants.EBADF; import android.annotation.NonNull; import android.annotation.Nullable; @@ -30,6 +32,7 @@ import android.net.DnsResolver; import android.net.Network; import android.net.NetworkCapabilities; import android.net.ParseException; +import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; import android.system.ErrnoException; @@ -50,6 +53,7 @@ public class DnsResolverTest extends AndroidTestCase { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static final int TIMEOUT_MS = 12_000; + static final int CANCEL_RETRY_TIMES = 5; private ConnectivityManager mCM; private Executor mExecutor; @@ -118,7 +122,7 @@ public class DnsResolverTest extends AndroidTestCase { } }; mDns.query(network, dname, CLASS_IN, TYPE_A, FLAG_NO_CACHE_LOOKUP, - mExecutor, callback); + mExecutor, null, callback); try { assertTrue(msg + " but no valid answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -174,12 +178,19 @@ public class DnsResolverTest extends AndroidTestCase { class RawAnswerCallbackImpl extends DnsResolver.RawAnswerCallback { private final CountDownLatch mLatch = new CountDownLatch(1); private final String mMsg; - RawAnswerCallbackImpl(String msg) { + private final int mTimeout; + + RawAnswerCallbackImpl(@NonNull String msg, int timeout) { this.mMsg = msg; + this.mTimeout = timeout; + } + + RawAnswerCallbackImpl(@NonNull String msg) { + this(msg, TIMEOUT_MS); } public boolean waitForAnswer() throws InterruptedException { - return mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); + return mLatch.await(mTimeout, TimeUnit.MILLISECONDS); } @Override @@ -210,7 +221,7 @@ public class DnsResolverTest extends AndroidTestCase { for (Network network : getTestableNetworks()) { final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, callback); + mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -238,7 +249,7 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "Query with RawAnswerCallback " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); - mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, callback); + mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -276,7 +287,7 @@ public class DnsResolverTest extends AndroidTestCase { } }; mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, callback); + mExecutor, null, callback); try { assertTrue(msg + "but no answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -313,7 +324,7 @@ public class DnsResolverTest extends AndroidTestCase { } }; mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, callback); + mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -322,4 +333,141 @@ public class DnsResolverTest extends AndroidTestCase { } } } + + /** + * A query callback that ensures that the query is cancelled and that onAnswer is never + * called. If the query succeeds before it is cancelled, needRetry will return true so the + * test can retry. + */ + class VerifyCancelCallback extends DnsResolver.RawAnswerCallback { + private static final int CANCEL_TIMEOUT = 3_000; + + private final CountDownLatch mLatch = new CountDownLatch(1); + private final String mMsg; + private final CancellationSignal mCancelSignal; + + VerifyCancelCallback(@NonNull String msg, @NonNull CancellationSignal cancelSignal) { + this.mMsg = msg; + this.mCancelSignal = cancelSignal; + } + + public boolean needRetry() throws InterruptedException { + return mLatch.await(CANCEL_TIMEOUT, TimeUnit.MILLISECONDS); + } + + @Override + public void onAnswer(@NonNull byte[] answer) { + if (mCancelSignal.isCanceled()) { + fail(mMsg + " should not have returned any answers"); + } + mLatch.countDown(); + } + + @Override + public void onParseException(@NonNull ParseException e) { + fail(mMsg + e.getMessage()); + } + + @Override + public void onQueryException(@NonNull ErrnoException e) { + if (mCancelSignal.isCanceled() && e.errno == EBADF) return; + fail(mMsg + e.getMessage()); + } + } + + public void testQueryCancel() throws ErrnoException { + final String dname = "www.google.com"; + final String msg = "Test cancel query " + dname; + // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect + // that the query is cancelled before it succeeds. If it is not cancelled before it + // succeeds, retry the until it is. + for (Network network : getTestableNetworks()) { + boolean retry = false; + int round = 0; + do { + if (++round > CANCEL_RETRY_TIMES) { + fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times"); + } + final CountDownLatch latch = new CountDownLatch(1); + final CancellationSignal cancelSignal = new CancellationSignal(); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mExecutor, cancelSignal, callback); + mExecutor.execute(() -> { + cancelSignal.cancel(); + latch.countDown(); + }); + try { + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(msg + "Waiting for DNS lookup was interrupted"); + } + } while (retry); + } + } + + public void testQueryBlobCancel() throws ErrnoException { + final byte[] blob = new byte[]{ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ + }; + final String msg = "Test cancel raw Query " + byteArrayToHexString(blob); + // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect + // that the query is cancelled before it succeeds. If it is not cancelled before it + // succeeds, retry the until it is. + for (Network network : getTestableNetworks()) { + boolean retry = false; + int round = 0; + do { + if (++round > CANCEL_RETRY_TIMES) { + fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times"); + } + final CountDownLatch latch = new CountDownLatch(1); + final CancellationSignal cancelSignal = new CancellationSignal(); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); + mDns.query(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mExecutor.execute(() -> { + cancelSignal.cancel(); + latch.countDown(); + }); + try { + retry = callback.needRetry(); + assertTrue(msg + " cancel is not done", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } while (retry); + } + } + + public void testCancelBeforeQuery() throws ErrnoException { + final String dname = "www.google.com"; + final String msg = "Test cancelled query " + dname; + for (Network network : getTestableNetworks()) { + final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg, 3_000); + final CancellationSignal cancelSignal = new CancellationSignal(); + cancelSignal.cancel(); + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mExecutor, cancelSignal, callback); + try { + assertTrue(msg + " should not return any answers", + !callback.waitForAnswer()); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } + } } From d05db41eb7a413339d25f8bd37f44b229980a1a5 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 19 Mar 2019 21:34:38 +0800 Subject: [PATCH 0575/1415] Export API of listening for network change events in app2 Currently, due to foreground app will never get blocked by NetworkPolicyManagerService, so onBlockedStatusChanged cannot be tested under cts net app. Thus, listen for network change events in app2 allows subsequent tests on NetworkCallbacks. Bug: 118862340 Test: m -j cts Change-Id: I26ca370fc6ae4dd3f32ce6cf448bae83f3fbfbcc --- tests/cts/hostside/aidl/Android.mk | 1 + .../android/cts/net/hostside/IMyService.aidl | 3 + .../cts/net/hostside/INetworkCallback.aidl | 25 +++++++ ...ractRestrictBackgroundNetworkTestCase.java | 4 + .../cts/net/hostside/MyServiceClient.java | 6 +- .../cts/net/hostside/app2/MyService.java | 74 ++++++++++++++++++- 6 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl diff --git a/tests/cts/hostside/aidl/Android.mk b/tests/cts/hostside/aidl/Android.mk index 85f71c3726..20dabc15b2 100644 --- a/tests/cts/hostside/aidl/Android.mk +++ b/tests/cts/hostside/aidl/Android.mk @@ -19,6 +19,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current LOCAL_SRC_FILES := \ com/android/cts/net/hostside/IMyService.aidl \ + com/android/cts/net/hostside/INetworkCallback.aidl \ com/android/cts/net/hostside/INetworkStateObserver.aidl \ com/android/cts/net/hostside/IRemoteSocketFactory.aidl LOCAL_MODULE := CtsHostsideNetworkTestsAidl diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl index 72d105990e..a820ae581f 100644 --- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl @@ -16,10 +16,13 @@ package com.android.cts.net.hostside; +import com.android.cts.net.hostside.INetworkCallback; + interface IMyService { void registerBroadcastReceiver(); int getCounters(String receiverName, String action); String checkNetworkStatus(); String getRestrictBackgroundStatus(); void sendNotification(int notificationId, String notificationType); + void registerNetworkCallback(in INetworkCallback cb); } diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl new file mode 100644 index 0000000000..740ec26ee2 --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import android.net.Network; + +interface INetworkCallback { + void onBlockedStatusChanged(in Network network, boolean blocked); + void onAvailable(in Network network); + void onLost(in Network network); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 5232372047..d15913d85c 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -962,6 +962,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("app2 receiver is not ready"); } + protected void registerNetworkCallback(INetworkCallback cb) throws Exception { + mServiceClient.registerNetworkCallback(cb); + } + /** * Registers a {@link NotificationListenerService} implementation that will execute the * notification actions right after the notification is sent. diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java index e2976c2150..3ee7b99c35 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java @@ -26,8 +26,6 @@ import android.os.RemoteException; import com.android.cts.net.hostside.IMyService; -import java.io.FileDescriptor; - public class MyServiceClient { private static final int TIMEOUT_MS = 5000; private static final String PACKAGE = MyServiceClient.class.getPackage().getName(); @@ -98,4 +96,8 @@ public class MyServiceClient { public void sendNotification(int notificationId, String notificationType) throws RemoteException { mService.sendNotification(notificationId, notificationType); } + + public void registerNetworkCallback(INetworkCallback cb) throws RemoteException { + mService.registerNetworkCallback(cb); + } } diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java index 2496c4ac7d..ec536aff68 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java @@ -16,6 +16,7 @@ package com.android.cts.net.hostside.app2; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; + import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER; import static com.android.cts.net.hostside.app2.Common.TAG; @@ -26,13 +27,16 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.os.IBinder; -import android.os.Looper; +import android.os.RemoteException; import android.util.Log; -import android.widget.Toast; import com.android.cts.net.hostside.IMyService; +import com.android.cts.net.hostside.INetworkCallback; /** * Service used to dynamically register a broadcast receiver. @@ -40,7 +44,10 @@ import com.android.cts.net.hostside.IMyService; public class MyService extends Service { private static final String NOTIFICATION_CHANNEL_ID = "MyService"; + ConnectivityManager mCm; + private MyBroadcastReceiver mReceiver; + private ConnectivityManager.NetworkCallback mNetworkCallback; // TODO: move MyBroadcast static functions here - they were kept there to make git diff easier. @@ -81,8 +88,67 @@ public class MyService extends Service { MyBroadcastReceiver .sendNotification(getApplicationContext(), NOTIFICATION_CHANNEL_ID, notificationId, notificationType); } + + @Override + public void registerNetworkCallback(INetworkCallback cb) { + if (mNetworkCallback != null) { + Log.d(TAG, "unregister previous network callback: " + mNetworkCallback); + unregisterNetworkCallback(); + } + Log.d(TAG, "registering network callback"); + + mNetworkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onBlockedStatusChanged(Network network, boolean blocked) { + try { + cb.onBlockedStatusChanged(network, blocked); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onBlockedStatusChanged: " + e); + unregisterNetworkCallback(); + } + } + + @Override + public void onAvailable(Network network) { + try { + cb.onAvailable(network); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onAvailable: " + e); + unregisterNetworkCallback(); + } + } + + @Override + public void onLost(Network network) { + try { + cb.onLost(network); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onLost: " + e); + unregisterNetworkCallback(); + } + } + }; + mCm.registerNetworkCallback(makeWifiNetworkRequest(), mNetworkCallback); + try { + cb.asBinder().linkToDeath(() -> unregisterNetworkCallback(), 0); + } catch (RemoteException e) { + unregisterNetworkCallback(); + } + } }; + private void unregisterNetworkCallback() { + Log.d(TAG, "unregistering network callback"); + mCm.unregisterNetworkCallback(mNetworkCallback); + mNetworkCallback = null; + } + + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + @Override public IBinder onBind(Intent intent) { return mBinder; @@ -94,6 +160,8 @@ public class MyService extends Service { ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) .createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT)); + mCm = (ConnectivityManager) getApplicationContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); } @Override From 27e1316c337fe96920061ebe2ac0120b1de50536 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 20 Mar 2019 14:45:10 +0800 Subject: [PATCH 0576/1415] Add cts test cases for NetworkCallback.onBlockedStatusChanged Bug: 118862340 Test: atest HostsideNetworkCallbackTests Change-Id: Ic19b3b648a94adf4449393beb9b30ad7a7dc2283 --- ...ractRestrictBackgroundNetworkTestCase.java | 17 ++ .../cts/net/hostside/DataSaverModeTest.java | 17 -- .../cts/net/hostside/NetworkCallbackTest.java | 241 ++++++++++++++++++ .../cts/net/HostsideNetworkCallbackTests.java | 42 +++ 4 files changed, 300 insertions(+), 17 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index d15913d85c..bbc0354e2f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -369,6 +369,23 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state ); } + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + protected boolean isDataSaverSupported() throws Exception { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + /** * Returns whether an app state should be considered "background" for restriction purposes. */ diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 599a31ce1c..72563d499e 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -73,23 +73,6 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase return mIsDataSaverSupported && super.isSupported(); } - /** - * As per CDD requirements, if the device doesn't support data saver mode then - * ConnectivityManager.getRestrictBackgroundStatus() will always return - * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if - * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns - * RESTRICT_BACKGROUND_STATUS_DISABLED or not. - */ - private boolean isDataSaverSupported() throws Exception { - assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - try { - setRestrictBackground(true); - return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - } finally { - setRestrictBackground(false); - } - } - public void testGetRestrictBackgroundStatus_disabled() throws Exception { if (!isSupported()) return; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java new file mode 100644 index 0000000000..24dde9d356 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import android.net.Network; + +import java.util.Objects; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase { + + private boolean mIsDataSaverSupported; + private Network mNetwork; + private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback(); + + enum CallbackState { + NONE, + AVAILABLE, + LOST, + BLOCKED_STATUS + } + + private static class CallbackInfo { + public final CallbackState state; + public final Network network; + public final Object arg; + + CallbackInfo(CallbackState s, Network n, Object o) { + state = s; network = n; arg = o; + } + + public String toString() { + return String.format("%s (%s) (%s)", state, network, arg); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof CallbackInfo)) return false; + // Ignore timeMs, since it's unpredictable. + final CallbackInfo other = (CallbackInfo) o; + return (state == other.state) && Objects.equals(network, other.network) + && Objects.equals(arg, other.arg); + } + + @Override + public int hashCode() { + return Objects.hash(state, network, arg); + } + } + + private class TestNetworkCallback extends INetworkCallback.Stub { + private static final int TEST_CALLBACK_TIMEOUT_MS = 200; + + private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + protected void setLastCallback(CallbackState state, Network network, Object o) { + mCallbacks.offer(new CallbackInfo(state, network, o)); + } + + CallbackInfo nextCallback(int timeoutMs) { + CallbackInfo cb = null; + try { + cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + } + if (cb == null) { + fail("Did not receive callback after " + timeoutMs + "ms"); + } + return cb; + } + + CallbackInfo expectCallback(CallbackState state, Network expectedNetwork, Object o) { + final CallbackInfo expected = new CallbackInfo(state, expectedNetwork, o); + final CallbackInfo actual = nextCallback(TEST_CALLBACK_TIMEOUT_MS); + assertEquals("Unexpected callback:", expected, actual); + return actual; + } + + @Override + public void onAvailable(Network network) { + setLastCallback(CallbackState.AVAILABLE, network, null); + } + + @Override + public void onLost(Network network) { + setLastCallback(CallbackState.LOST, network, null); + } + + @Override + public void onBlockedStatusChanged(Network network, boolean blocked) { + setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked); + } + + public void expectLostCallback(Network expectedNetwork) { + expectCallback(CallbackState.LOST, expectedNetwork, null); + } + + public void expectAvailableCallback(Network expectedNetwork) { + expectCallback(CallbackState.AVAILABLE, expectedNetwork, null); + } + + public void expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) { + expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, + expectBlocked); + } + + void assertNoCallback() { + CallbackInfo cb = null; + try { + cb = mCallbacks.poll(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + // Expected. + } + if (cb != null) { + assertNull("Unexpected callback: " + cb, cb); + } + } + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + mIsDataSaverSupported = isDataSaverSupported(); + + mNetwork = mCm.getActiveNetwork(); + + // Set initial state. + setBatterySaverMode(false); + registerBroadcastReceiver(); + + if (!mIsDataSaverSupported) return; + setRestrictBackground(false); + removeRestrictBackgroundWhitelist(mUid); + removeRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(0); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + if (!mIsDataSaverSupported) return; + + try { + resetMeteredNetwork(); + } finally { + setRestrictBackground(false); + } + } + + public void testOnBlockedStatusChanged_data_saver() throws Exception { + if (!mIsDataSaverSupported) return; + + // Prepare metered wifi + if (!setMeteredNetwork()) return; + + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable restrict background + setRestrictBackground(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Add to whitelist + addRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Remove from whitelist + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Set to non-metered network + setUnmeteredNetwork(); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Disable restrict background, should not trigger callback + setRestrictBackground(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.assertNoCallback(); + } + + + public void testOnBlockedStatusChanged_power_saver() throws Exception { + // Prepare metered wifi + if (!setMeteredNetwork()) return; + + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Set to non-metered network + setUnmeteredNetwork(); + mTestNetworkCallback.assertNoCallback(); + + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } + + // TODO: 1. test against VPN lockdown. + // 2. test against multiple networks. +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java new file mode 100644 index 0000000000..8d6c4acd7d --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net; +public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + uninstallPackage(TEST_APP2_PKG, false); + installPackage(TEST_APP2_APK); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + uninstallPackage(TEST_APP2_PKG, true); + } + + public void testOnBlockedStatusChanged_data_saver() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_data_saver"); + } + + public void testOnBlockedStatusChanged_power_saver() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_power_saver"); + } +} + From f011d5f95bf73c8f0a64fe15ddd0ef29ca253863 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 25 Mar 2019 13:40:16 +0900 Subject: [PATCH 0577/1415] Enable instant and ABI XML tags for native networking tests. These tests include native code so mark them as multi_abi. They also pass in instant mode so mark them instant_app. Fix: 123367032 Fix: 123367595 Test: atest CtsNativeNetDnsTestCases CtsNativeNetTestCases Test: cts-tradefed run commandAndExit cts --enable-parameterized-modules --module-parameter instant_app -m CtsNativeNetDnsTestCases Test: cts-tradefed run commandAndExit cts --enable-parameterized-modules --module-parameter instant_app -m CtsNativeNetTestCases Change-Id: Id66705ecb012a07aa34318f41afb1840dd25b9e3 --- tests/cts/net/native/dns/AndroidTest.xml | 2 ++ tests/cts/net/native/qtaguid/AndroidTest.xml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/cts/net/native/dns/AndroidTest.xml b/tests/cts/net/native/dns/AndroidTest.xml index e63c6789a5..fe88cdaffe 100644 --- a/tests/cts/net/native/dns/AndroidTest.xml +++ b/tests/cts/net/native/dns/AndroidTest.xml @@ -16,6 +16,8 @@ diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 7c9ce8f833..a2443b391a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -128,7 +128,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void runDeviceTests(String packageName, String testClassName, String methodName) throws DeviceNotAvailableException { RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, - "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + "androidx.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); if (testClassName != null) { if (methodName != null) { diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 1430071997..45941a79e1 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -41,8 +41,8 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ core-tests-support \ - compatibility-device-util \ - ctstestrunner \ + compatibility-device-util-axt \ + ctstestrunner-axt \ ctstestserver \ mockwebserver \ junit \ diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 0bfb650882..b261b39885 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -42,7 +42,7 @@ - Date: Wed, 19 Dec 2018 23:50:35 -0800 Subject: [PATCH 0579/1415] RESTRICT AUTOMERGE: Port "Exempt adb socket for hostside VpnTest" to Cts 8.1 https://android-review.googlesource.com/c/platform/cts/+/833600 Change-Id: Id6f986aacc3cadf713ebbc8305ca535b861390fc Bug: 119382723 --- tests/cts/hostside/app/Android.mk | 3 ++- .../com/android/cts/net/hostside/VpnTest.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) mode change 100644 => 100755 tests/cts/hostside/app/Android.mk diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk old mode 100644 new mode 100755 index f094f3f4a1..127ef322e6 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -19,7 +19,8 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SDK_VERSION := current +#LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \ CtsHostsideNetworkTestsAidl diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index bc982cec78..b3f61c486d 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -29,6 +29,7 @@ import android.net.NetworkRequest; import android.net.VpnService; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.SystemProperties; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; @@ -537,6 +538,14 @@ public class VpnTest extends InstrumentationTestCase { public void testDefault() throws Exception { if (!supportedHardware()) return; + // If adb TCP port opened, this test may running by adb over network. + // All of socket would be destroyed in this test. So this test don't + // support adb over network, see b/119382723. + if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 + || SystemProperties.getInt("service.adb.tcp.port", -1) > -1) { + Log.i(TAG, "adb is running over the network, so skip this test"); + return; + } FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); @@ -554,6 +563,7 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + // Shell app must not be put in here or it would kill the ADB-over-network use case String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, @@ -571,6 +581,12 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); String disallowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + // If adb TCP port opened, this test may running by adb over TCP. + // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test, + // see b/119382723. + // Note: The test don't support running adb over network for root device + disallowedApps = disallowedApps + ",com.android.shell"; + Log.i(TAG, "Append shell app to disallowedApps: " + disallowedApps); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, "", disallowedApps); From acadb939b5e74d5035099545763cffe1cd20dd79 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 26 Mar 2019 17:43:42 +0800 Subject: [PATCH 0580/1415] Improve test and fix doulbe-close fd problem for async DNS API cts 1. Change test cases for enlarging buffer size of FrameworkListener. 2. Remove test procedure which caused doulbe-close fd. Bug: 129317069 Bug: 126307309 Test: atest CtsNativeNetDnsTestCases MultinetworkApiTest Change-Id: I8d871cebca6fa7e298a874ba430ec0aaa05c0eed --- tests/cts/net/jni/NativeMultinetworkJni.cpp | 31 +++++++++---------- .../cts/net/native/dns/NativeDnsAsyncTest.cpp | 21 ++++++------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index d1a92a47a1..a6b5e90b1d 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -245,13 +245,12 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck( net_handle_t handle = (net_handle_t) nethandle; int fd = android_res_nquery(handle, kGoogleName, ns_c_in, ns_t_a, 0); - int rcode = -1; - uint8_t buf[MAXPACKET] = {}; + errno = 0; android_res_cancel(fd); - EXPECT_EQ(env, -EBADF, android_res_nresult(fd, &rcode, buf, MAXPACKET), "res_cancel"); - - android_res_cancel(fd); - EXPECT_EQ(env, -EBADF, android_res_nresult(fd, &rcode, buf, MAXPACKET), "res_cancel"); + int err = errno; + EXPECT_EQ(env, 0, err, "res_cancel"); + // DO NOT call cancel or result with the same fd more than once, + // otherwise it will hit fdsan double-close fd. return 0; } @@ -288,10 +287,10 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck fd = android_res_nsend(handle, largeBuf, sizeof(largeBuf), 0); EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend buffer larger than 8KB"); - // 1000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of - // commands to 1024 bytes. TODO: b/126307309 - fd = android_res_nsend(handle, largeBuf, 1000, 0); - EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 1000 bytes filled with 0"); + // 5000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of + // commands to 4096 bytes. + fd = android_res_nsend(handle, largeBuf, 5000, 0); + EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 5000 bytes filled with 0"); // 500 bytes filled with 0 fd = android_res_nsend(handle, largeBuf, 500, 0); @@ -299,16 +298,16 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL), "res_nsend 500 bytes filled with 0 check answers"); - // 1000 bytes filled with 0xFF - uint8_t ffBuf[1001] = {}; + // 5000 bytes filled with 0xFF + uint8_t ffBuf[5001] = {}; memset(ffBuf, 0xFF, sizeof(ffBuf)); - ffBuf[1000] = '\0'; + ffBuf[5000] = '\0'; fd = android_res_nsend(handle, ffBuf, sizeof(ffBuf), 0); - EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 1000 bytes filled with 0xFF"); + EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 5000 bytes filled with 0xFF"); // 500 bytes filled with 0xFF - ffBuf[501] = '\0'; - fd = android_res_nsend(handle, ffBuf, 500, 0); + ffBuf[500] = '\0'; + fd = android_res_nsend(handle, ffBuf, 501, 0); EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0xFF"); EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL), "res_nsend 500 bytes filled with 0xFF check answers"); diff --git a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp index 2fc9ff8fd8..e501475996 100644 --- a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp +++ b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp @@ -194,13 +194,12 @@ TEST (NativeDnsAsyncTest, Async_NXDOMAIN) { TEST (NativeDnsAsyncTest, Async_Cancel) { int fd = android_res_nquery( NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0); - int rcode = -1; - uint8_t buf[MAXPACKET] = {}; + errno = 0; android_res_cancel(fd); - android_res_cancel(fd); - - int res = android_res_nresult(fd, &rcode, buf, MAXPACKET); - EXPECT_EQ(-EBADF, res); + int err = errno; + EXPECT_EQ(err, 0); + // DO NOT call cancel or result with the same fd more than once, + // otherwise it will hit fdsan double-close fd. } TEST (NativeDnsAsyncTest, Async_Query_MALFORMED) { @@ -235,9 +234,9 @@ TEST (NativeDnsAsyncTest, Async_Send_MALFORMED) { NETWORK_UNSPECIFIED, largeBuf.data(), largeBuf.size(), 0); EXPECT_EQ(-EMSGSIZE, fd); - // 1000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of - // commands to 1024 bytes. TODO: fix this. - fd = android_res_nsend(NETWORK_UNSPECIFIED, largeBuf.data(), 1000, 0); + // 5000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of + // commands to 4096 bytes. + fd = android_res_nsend(NETWORK_UNSPECIFIED, largeBuf.data(), 5000, 0); EXPECT_EQ(-EMSGSIZE, fd); // 500 bytes filled with 0 @@ -245,8 +244,8 @@ TEST (NativeDnsAsyncTest, Async_Send_MALFORMED) { EXPECT_GE(fd, 0); expectAnswersNotValid(fd, -EINVAL); - // 1000 bytes filled with 0xFF - std::vector ffBuf(1000, 0xFF); + // 5000 bytes filled with 0xFF + std::vector ffBuf(5000, 0xFF); fd = android_res_nsend( NETWORK_UNSPECIFIED, ffBuf.data(), ffBuf.size(), 0); EXPECT_EQ(-EMSGSIZE, fd); From 3852fd92f583e4f05db4d086b168df9f070eae4c Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 28 Mar 2019 17:38:32 +0900 Subject: [PATCH 0581/1415] Fix expected reverse lookup of Google DNS IP addresses DnsTest.testDnsWorks expects that reverse lookup for the Google public DNS servers will return something with google.com in the name. This no longer works because the reverse DNS entries have changed to dns.google. Bug: 129452237 Test: atest android.net.cts.DnsTest.testDnsWorks Change-Id: Iee8bfe418bf6003e5c78df77d75f6f9745249267 --- tests/cts/net/jni/NativeDnsJni.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 352c0c52cc..6d3d1c3250 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -120,8 +120,8 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas gai_strerror(res)); return JNI_FALSE; } - if (strstr(buf, "google.com") == NULL) { - ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com: %s", + if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { + ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", GoogleDNSIpV4Address, buf); return JNI_FALSE; } @@ -133,8 +133,9 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas res, gai_strerror(res)); return JNI_FALSE; } - if (strstr(buf, "google.com") == NULL) { - ALOGD("getnameinfo(%s) didn't return google.com: %s", GoogleDNSIpV6Address2, buf); + if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { + ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + GoogleDNSIpV6Address2, buf); return JNI_FALSE; } From 92f1edd2f0b2d19568c2ee70e86208eb34506d10 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 26 Mar 2019 19:41:38 +0800 Subject: [PATCH 0582/1415] Improve cancellation test for async DNS API After having a lock between callback and cancellationsignal, errno with EBADF should not happen. Bug: 129317069 Test: atest DnsResolverTest Change-Id: I08e800b078d40345eb3f46da1323db251c8dcd47 --- tests/cts/net/src/android/net/cts/DnsResolverTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index f6cc76852b..57a5dc7788 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -370,7 +370,6 @@ public class DnsResolverTest extends AndroidTestCase { @Override public void onQueryException(@NonNull ErrnoException e) { - if (mCancelSignal.isCanceled() && e.errno == EBADF) return; fail(mMsg + e.getMessage()); } } From 8fd050640166eb04cc96c1933cb6a2093155d7dc Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 28 Mar 2019 21:04:11 +0800 Subject: [PATCH 0583/1415] Add more test for async DNS api Bug: 129395490 Test: atest DnsResolverTest Change-Id: I4d2cdc2be577846c08dfe994da60965f983acb97 --- .../src/android/net/cts/DnsResolverTest.java | 108 +++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 57a5dc7788..0ff6cd8bac 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -379,7 +379,7 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "Test cancel query " + dname; // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it - // succeeds, retry the until it is. + // succeeds, retry the test until it is. for (Network network : getTestableNetworks()) { boolean retry = false; int round = 0; @@ -425,7 +425,7 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "Test cancel raw Query " + byteArrayToHexString(blob); // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it - // succeeds, retry the until it is. + // succeeds, retry the test until it is. for (Network network : getTestableNetworks()) { boolean retry = false; int round = 0; @@ -469,4 +469,108 @@ public class DnsResolverTest extends AndroidTestCase { } } } + + /** + * A query callback for InetAddress that ensures that the query is + * cancelled and that onAnswer is never called. If the query succeeds + * before it is cancelled, needRetry will return true so the + * test can retry. + */ + class VerifyCancelInetAddressCallback extends DnsResolver.InetAddressAnswerCallback { + private static final int CANCEL_TIMEOUT = 3_000; + + private final CountDownLatch mLatch = new CountDownLatch(1); + private final String mMsg; + private final List mAnswers; + private final CancellationSignal mCancelSignal; + + VerifyCancelInetAddressCallback(@NonNull String msg, @Nullable CancellationSignal cancel) { + this.mMsg = msg; + this.mCancelSignal = cancel; + mAnswers = new ArrayList<>(); + } + + public boolean waitForAnswer() throws InterruptedException { + return mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public boolean needRetry() throws InterruptedException { + return mLatch.await(CANCEL_TIMEOUT, TimeUnit.MILLISECONDS); + } + + public boolean isAnswerEmpty() { + return mAnswers.isEmpty(); + } + + @Override + public void onAnswer(@NonNull List answerList) { + if (mCancelSignal != null && mCancelSignal.isCanceled()) { + fail(mMsg + " should not have returned any answers"); + } + mAnswers.clear(); + mAnswers.addAll(answerList); + mLatch.countDown(); + } + + @Override + public void onParseException(@NonNull ParseException e) { + fail(mMsg + e.getMessage()); + } + + @Override + public void onQueryException(@NonNull ErrnoException e) { + fail(mMsg + e.getMessage()); + } + } + + public void testQueryForInetAddress() { + final String dname = "www.google.com"; + final String msg = "Test query for InetAddress " + dname; + for (Network network : getTestableNetworks()) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP, + mExecutor, null, callback); + try { + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } + } + + public void testQueryCancelForInetAddress() throws ErrnoException { + final String dname = "www.google.com"; + final String msg = "Test cancel query for InetAddress " + dname; + // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect + // that the query is cancelled before it succeeds. If it is not cancelled before it + // succeeds, retry the test until it is. + for (Network network : getTestableNetworks()) { + boolean retry = false; + int round = 0; + do { + if (++round > CANCEL_RETRY_TIMES) { + fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times"); + } + final CountDownLatch latch = new CountDownLatch(1); + final CancellationSignal cancelSignal = new CancellationSignal(); + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, cancelSignal); + mDns.query(network, dname, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mExecutor.execute(() -> { + cancelSignal.cancel(); + latch.countDown(); + }); + try { + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(msg + "Waiting for DNS lookup was interrupted"); + } + } while (retry); + } + } } From 950e10572b4d999787bd46c6f3758a0e9f89f213 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 29 Mar 2019 22:05:29 +0900 Subject: [PATCH 0584/1415] Add test coverage for ICMP echo constants. Bug: 129251251 Test: atest android.net.ipv6.cts.PingTest com.android.cts.net.HostsideVpnTests Change-Id: Icca18e0870588ca250225ce79cf30dbd8c361e84 --- .../cts/net/hostside/PacketReflector.java | 19 +++++++++++++++---- .../src/android/net/ipv6/cts/PingTest.java | 4 ++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java index a4a2956d3a..124c2c3862 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java @@ -16,6 +16,11 @@ package com.android.cts.net.hostside; +import static android.system.OsConstants.ICMP6_ECHO_REPLY; +import static android.system.OsConstants.ICMP6_ECHO_REQUEST; +import static android.system.OsConstants.ICMP_ECHO; +import static android.system.OsConstants.ICMP_ECHOREPLY; + import android.system.ErrnoException; import android.system.Os; import android.util.Log; @@ -47,8 +52,6 @@ public class PacketReflector extends Thread { private static final byte ICMP_ECHO = 8; private static final byte ICMP_ECHOREPLY = 0; - private static final byte ICMPV6_ECHO_REQUEST = (byte) 128; - private static final byte ICMPV6_ECHO_REPLY = (byte) 129; private static String TAG = "PacketReflector"; @@ -125,7 +128,7 @@ public class PacketReflector extends Thread { byte type = buf[hdrLen]; if (!(version == 4 && type == ICMP_ECHO) && - !(version == 6 && type == ICMPV6_ECHO_REQUEST)) { + !(version == 6 && type == (byte) ICMP6_ECHO_REQUEST)) { return; } @@ -145,10 +148,18 @@ public class PacketReflector extends Thread { return; } + byte replyType = buf[hdrLen]; + if ((type == ICMP_ECHO && replyType != ICMP_ECHOREPLY) + || (type == (byte) ICMP6_ECHO_REQUEST && replyType != (byte) ICMP6_ECHO_REPLY)) { + Log.i(TAG, "Received unexpected ICMP reply: original " + type + + ", reply " + replyType); + return; + } + // Compare the response we got with the original packet. // The only thing that should have changed are addresses, type and checksum. // Overwrite them with the received bytes and see if the packet is otherwise identical. - request[hdrLen] = buf[hdrLen]; // Type. + request[hdrLen] = buf[hdrLen]; // Type request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1. request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2. diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java index c23ad30f05..146fd83978 100644 --- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java +++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java @@ -61,7 +61,7 @@ public class PingTest extends AndroidTestCase { /** The beginning of an ICMPv6 echo request: type, code, and uninitialized checksum. */ private static final byte[] PING_HEADER = new byte[] { - (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00 + (byte) ICMP6_ECHO_REQUEST, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; /** @@ -135,7 +135,7 @@ public class PingTest extends AndroidTestCase { byte[] response = new byte[bytesRead]; responseBuffer.flip(); responseBuffer.get(response, 0, bytesRead); - assertEquals((byte) 0x81, response[0]); + assertEquals((byte) ICMP6_ECHO_REPLY, response[0]); // Find out what ICMP ID was used in the packet that was sent. int id = ((InetSocketAddress) Os.getsockname(s)).getPort(); From 478f45e36db572d9c8d74255f80231911ee9940b Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Fri, 29 Mar 2019 10:34:39 -0700 Subject: [PATCH 0585/1415] WifiManagerTest: Test for new privileged permission Add a new test to ensure that the NETWORK_CARRIER_PROVISIONING is only granted to one app. Bug: 129401919 Test: atest WifiManagerTest Change-Id: Id2e722d63b02d9cee718dd3af49e9ef113bd5ffb --- .../android/net/wifi/cts/WifiManagerTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 93795b2bf0..1d666827fa 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -881,6 +881,30 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission + * is held by at most one application. + */ + public void testNetworkCarrierProvisioningPermission() { + final PackageManager pm = getContext().getPackageManager(); + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_CARRIER_PROVISIONING + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + + List uniquePackageNames = holding + .stream() + .map(pi -> pi.packageName) + .distinct() + .collect(Collectors.toList()); + + if (uniquePackageNames.size() > 1) { + fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than one " + + "application, but is held by " + uniquePackageNames.size() + " applications: " + + String.join(", ", uniquePackageNames)); + } + } + /** * Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE} * permission is held by at most one application. From c1419d913d247c63f1c1e7ba20338d2b9217f8dd Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 27 Mar 2019 14:57:21 +0800 Subject: [PATCH 0586/1415] Fix tests in TrafficStatsTest that are affected by adb over network If the adb TCP port is opened, this test may be run by adb over network. Huge amount of data traffic might go through the network and accounted into total packets stats. The upper bound check would be meaningless. Bug: 126320702 Test: atest android.net.cts.TrafficStatsTest 10 trials for both cases Change-Id: Iaee455826dc01741c6a3a9f5f8096361c69a1e7c --- .../src/android/net/cts/TrafficStatsTest.java | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index af096da089..503ba51727 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -16,15 +16,14 @@ package android.net.cts; +import android.content.pm.PackageManager; import android.net.NetworkStats; import android.net.TrafficStats; import android.os.Process; +import android.os.SystemProperties; import android.test.AndroidTestCase; import android.util.Log; -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -237,19 +236,37 @@ public class TrafficStatsTest extends AndroidTestCase { uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaRxOtherPackets, 0)); // Localhost traffic *does* count against total stats. - // Fudge by 132 packets of 1500 bytes not related to the test. + // Check the total stats increased after test data transfer over localhost has been made. assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, - totalTxPacketsAfter >= totalTxPacketsBefore + uidTxDeltaPackets && - totalTxPacketsAfter <= totalTxPacketsBefore + uidTxDeltaPackets + 132); + totalTxPacketsAfter >= totalTxPacketsBefore + uidTxDeltaPackets); assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, - totalRxPacketsAfter >= totalRxPacketsBefore + uidRxDeltaPackets && - totalRxPacketsAfter <= totalRxPacketsBefore + uidRxDeltaPackets + 132); + totalRxPacketsAfter >= totalRxPacketsBefore + uidRxDeltaPackets); assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, - totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes && - totalTxBytesAfter <= totalTxBytesBefore + uidTxDeltaBytes + 132 * 1500); + totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes); assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, - totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes && - totalRxBytesAfter <= totalRxBytesBefore + uidRxDeltaBytes + 132 * 1500); + totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes); + + // If the adb TCP port is opened, this test may be run by adb over network. + // Huge amount of data traffic might go through the network and accounted into total packets + // stats. The upper bound check would be meaningless. + // TODO: Consider precisely calculate the traffic accounted due to adb over network and + // subtract it when checking upper bound instead of skip checking. + final PackageManager pm = mContext.getPackageManager(); + if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 + || SystemProperties.getInt("service.adb.tcp.port", -1) > -1 + || !pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) { + Log.i(LOG_TAG, "adb is running over the network, skip the upper bound check"); + } else { + // Fudge by 132 packets of 1500 bytes not related to the test. + assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, + totalTxPacketsAfter <= totalTxPacketsBefore + uidTxDeltaPackets + 132); + assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, + totalRxPacketsAfter <= totalRxPacketsBefore + uidRxDeltaPackets + 132); + assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, + totalTxBytesAfter <= totalTxBytesBefore + uidTxDeltaBytes + 132 * 1500); + assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, + totalRxBytesAfter <= totalRxBytesBefore + uidRxDeltaBytes + 132 * 1500); + } // Localhost traffic should *not* count against mobile stats, // There might be some other traffic, but nowhere near 1MB. @@ -265,6 +282,5 @@ public class TrafficStatsTest extends AndroidTestCase { assertTrue("mrxb: " + mobileRxBytesBefore + " -> " + mobileRxBytesAfter, mobileRxBytesAfter >= mobileRxBytesBefore && mobileRxBytesAfter <= mobileRxBytesBefore + 200000); - } } From 5dc16818233197e691ef7f64d767e6a5ac0fdbd0 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 23 Jan 2019 16:18:10 +0800 Subject: [PATCH 0587/1415] [KA09] add cts test for tcp keepalive offload Add a test case to make sure tcp keepalive offload starts correctly. Bug: 114151147 Test: atest ConnectivityManagerTest#testCreateTcpKeepalive Change-Id: Iaf1c2fab755f3df8e866b4988f64c25906e1737a --- .../net/cts/ConnectivityManagerTest.java | 242 +++++++++++++++++- 1 file changed, 241 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 1b7d29001b..4180ea4396 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -23,12 +23,17 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.AF_UNSPEC; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import android.app.Instrumentation; import android.app.PendingIntent; +import android.app.UiAutomation; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -46,8 +51,10 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; +import android.net.SocketKeepalive; import android.net.wifi.WifiManager; import android.os.Looper; +import android.os.MessageQueue; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; @@ -64,11 +71,13 @@ import com.android.internal.telephony.PhoneConstants; import libcore.io.Streams; +import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -79,6 +88,7 @@ import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.HashMap; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -96,7 +106,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 private static final String TEST_HOST = "connectivitycheck.gstatic.com"; private static final int SOCKET_TIMEOUT_MS = 2000; + private static final int CONNECT_TIMEOUT_MS = 2000; + private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000; + private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000; private static final int SEND_BROADCAST_TIMEOUT = 30000; + private static final int MIN_KEEPALIVE_INTERVAL = 10; private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; @@ -126,7 +140,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { new HashMap(); boolean mWifiConnectAttempted; private TestNetworkCallback mCellNetworkCallback; - + private UiAutomation mUiAutomation; + private boolean mShellPermissionIdentityAdopted; @Override protected void setUp() throws Exception { @@ -153,6 +168,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { mNetworks.put(n.type, n); } catch (Exception e) {} } + mUiAutomation = mInstrumentation.getUiAutomation(); + mShellPermissionIdentityAdopted = false; } @Override @@ -164,6 +181,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (cellConnectAttempted()) { disconnectFromCell(); } + dropShellPermissionIdentity(); super.tearDown(); } @@ -1037,4 +1055,226 @@ public class ConnectivityManagerTest extends AndroidTestCase { setWifiMeteredStatus(ssid, oldMeteredSetting); } } + + // TODO: move the following socket keep alive test to dedicated test class. + /** + * Callback used in tcp keepalive offload that allows caller to wait callback fires. + */ + private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback { + public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; + + public static class CallbackValue { + public final CallbackType callbackType; + public final int error; + + private CallbackValue(final CallbackType type, final int error) { + this.callbackType = type; + this.error = error; + } + + public static class OnStartedCallback extends CallbackValue { + OnStartedCallback() { super(CallbackType.ON_STARTED, 0); } + } + + public static class OnStoppedCallback extends CallbackValue { + OnStoppedCallback() { super(CallbackType.ON_STOPPED, 0); } + } + + public static class OnErrorCallback extends CallbackValue { + OnErrorCallback(final int error) { super(CallbackType.ON_ERROR, error); } + } + + @Override + public boolean equals(Object o) { + return o.getClass() == this.getClass() + && this.callbackType == ((CallbackValue) o).callbackType + && this.error == ((CallbackValue) o).error; + } + + @Override + public String toString() { + return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error); + } + } + + private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + @Override + public void onStarted() { + mCallbacks.add(new CallbackValue.OnStartedCallback()); + } + + @Override + public void onStopped() { + mCallbacks.add(new CallbackValue.OnStoppedCallback()); + } + + @Override + public void onError(final int error) { + mCallbacks.add(new CallbackValue.OnErrorCallback(error)); + } + + public CallbackValue pollCallback() { + try { + return mCallbacks.poll(KEEPALIVE_CALLBACK_TIMEOUT_MS, + TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + fail("Callback not seen after " + KEEPALIVE_CALLBACK_TIMEOUT_MS + " ms"); + } + return null; + } + private void expectCallback(CallbackValue expectedCallback) { + final CallbackValue actualCallback = pollCallback(); + assertEquals(expectedCallback, actualCallback); + } + + public void expectStarted() { + expectCallback(new CallbackValue.OnStartedCallback()); + } + + public void expectStopped() { + expectCallback(new CallbackValue.OnStoppedCallback()); + } + + public void expectError(int error) { + expectCallback(new CallbackValue.OnErrorCallback(error)); + } + } + + private InetAddress getAddrByName(final String hostname, final int family) throws Exception { + final InetAddress[] allAddrs = InetAddress.getAllByName(hostname); + for (InetAddress addr : allAddrs) { + if (family == AF_INET && addr instanceof Inet4Address) return addr; + + if (family == AF_INET6 && addr instanceof Inet6Address) return addr; + + if (family == AF_UNSPEC) return addr; + } + return null; + } + + private Socket getConnectedSocket(final Network network, final String host, final int port, + final int socketTimeOut, final int family) throws Exception { + final Socket s = network.getSocketFactory().createSocket(); + try { + final InetAddress addr = getAddrByName(host, family); + if (addr == null) fail("Fail to get destination address for " + family); + + final InetSocketAddress sockAddr = new InetSocketAddress(addr, port); + s.setSoTimeout(socketTimeOut); + s.connect(sockAddr, CONNECT_TIMEOUT_MS); + } catch (Exception e) { + s.close(); + throw e; + } + return s; + } + + private boolean isKeepaliveSupported() throws Exception { + final Network network = ensureWifiConnected(); + final Executor executor = mContext.getMainExecutor(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + try (Socket s = getConnectedSocket(network, TEST_HOST, + HTTP_PORT, KEEPALIVE_SOCKET_TIMEOUT_MS, AF_INET); + SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { + sk.start(MIN_KEEPALIVE_INTERVAL); + final TestSocketKeepaliveCallback.CallbackValue result = callback.pollCallback(); + switch (result.callbackType) { + case ON_STARTED: + sk.stop(); + callback.expectStopped(); + return true; + case ON_ERROR: + if (result.error == SocketKeepalive.ERROR_UNSUPPORTED) return false; + // else fallthrough. + default: + fail("Got unexpected callback: " + result); + return false; + } + } + } + + private void adoptShellPermissionIdentity() { + mUiAutomation.adoptShellPermissionIdentity(); + mShellPermissionIdentityAdopted = true; + } + + private void dropShellPermissionIdentity() { + if (mShellPermissionIdentityAdopted) { + mUiAutomation.dropShellPermissionIdentity(); + mShellPermissionIdentityAdopted = false; + } + } + + public void testCreateTcpKeepalive() throws Exception { + adoptShellPermissionIdentity(); + + if (!isKeepaliveSupported()) return; + + final Network network = ensureWifiConnected(); + final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + // So far only ipv4 tcp keepalive offload is supported. + // TODO: add test case for ipv6 tcp keepalive offload when it is supported. + try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, + KEEPALIVE_SOCKET_TIMEOUT_MS, AF_INET)) { + + // Should able to start keep alive offload when socket is idle. + final Executor executor = mContext.getMainExecutor(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { + sk.start(MIN_KEEPALIVE_INTERVAL); + callback.expectStarted(); + + // App should not able to write during keepalive offload. + final OutputStream out = s.getOutputStream(); + try { + out.write(requestBytes); + fail("Should not able to write"); + } catch (IOException e) { } + // App should not able to read during keepalive offload. + final InputStream in = s.getInputStream(); + byte[] responseBytes = new byte[4096]; + try { + in.read(responseBytes); + fail("Should not able to read"); + } catch (IOException e) { } + + // Stop. + sk.stop(); + callback.expectStopped(); + } + + // Ensure socket is still connected. + assertTrue(s.isConnected()); + assertFalse(s.isClosed()); + + // Let socket be not idle. + try { + final OutputStream out = s.getOutputStream(); + out.write(requestBytes); + } catch (IOException e) { + fail("Failed to write data " + e); + } + // Make sure response data arrives. + final MessageQueue fdHandlerQueue = Looper.getMainLooper().getQueue(); + final FileDescriptor fd = s.getFileDescriptor$(); + final CountDownLatch mOnReceiveLatch = new CountDownLatch(1); + fdHandlerQueue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, (readyFd, events) -> { + mOnReceiveLatch.countDown(); + return 0; // Unregister listener. + }); + if (!mOnReceiveLatch.await(2, TimeUnit.SECONDS)) { + fdHandlerQueue.removeOnFileDescriptorEventListener(fd); + fail("Timeout: no response data"); + } + + // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue + // that has not been read. + try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { + sk.start(MIN_KEEPALIVE_INTERVAL); + callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); + } + + } + } } From 16fc55e30de5922b26c2437d1b5d4831fcd00374 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 3 Apr 2019 18:06:33 +0900 Subject: [PATCH 0588/1415] Add FrameworksNetCommonTests to CTS The common tests include tests that must be both in CTS and unit tests. Bug: 129199908 Test: atest CtsNetTestCases, IpPrefixCommonTest is run and passes. Change-Id: Id16f40247cca9a6c5bba573006b84547727f1bab --- tests/cts/net/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 2084dbc357..04974702a6 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -39,6 +39,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ + FrameworksNetCommonTests \ core-tests-support \ compatibility-device-util-axt \ ctstestrunner-axt \ From ef4ac8c021b8cfe108a5b80d8c2cb1806b6cc51f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Apr 2019 09:39:20 -0700 Subject: [PATCH 0589/1415] Add FrameworksNetCommonTests to CTS The common tests include tests that must be both in CTS and unit tests. Bug: 129199908 Test: atest CtsNetTestCases, IpPrefixCommonTest is run and passes. Change-Id: I872fb80e8a0b21144f0b66b33645a320dcd5dcf2 (cherry picked from commit 855e7889d62839fe6449f97086656e860c4db177) --- tests/cts/net/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 2084dbc357..04974702a6 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -39,6 +39,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ + FrameworksNetCommonTests \ core-tests-support \ compatibility-device-util-axt \ ctstestrunner-axt \ From d11be5bbeb31330a5a304522ea8f96276e895371 Mon Sep 17 00:00:00 2001 From: saurav subedi Date: Fri, 7 Sep 2018 10:57:01 -0700 Subject: [PATCH 0590/1415] DO NOT MERGE:CDD Annotation for 7.4.7/C-2-1 Devices that don't provide data saver mode must return RESTRICT_BACKGROUND_STATUS_DISABLED for the ConnectivityManager#getRestrictBackgroundStatus() Bug:130032710 Test: make cts Change-Id: I81b52c9d26afcf51a7e416d20589c9c7cfb878f6 --- .../src/com/android/cts/net/hostside/DataSaverModeTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index 599a31ce1c..c3962fbbc3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -22,6 +22,9 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELI import android.util.Log; +import com.android.compatibility.common.util.CddTest; + +@CddTest(requirement="7.4.7/C-1-1,H-1-1,C-2-1") public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { From 3a984ca812e0955ce69352ed1dff02eb24e370b1 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 28 Mar 2019 17:38:32 +0900 Subject: [PATCH 0591/1415] Fix expected reverse lookup of Google DNS IP addresses DnsTest.testDnsWorks expects that reverse lookup for the Google public DNS servers will return something with google.com in the name. This no longer works because the reverse DNS entries have changed to dns.google. Bug: 129452237 Test: atest android.net.cts.DnsTest.testDnsWorks Change-Id: Iee8bfe418bf6003e5c78df77d75f6f9745249267 Merged-In: Iee8bfe418bf6003e5c78df77d75f6f9745249267 (cherry picked from commit 3852fd92f583e4f05db4d086b168df9f070eae4c) --- tests/cts/net/jni/NativeDnsJni.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 4eb3c7aebc..1df9169cdc 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -120,8 +120,8 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas gai_strerror(res)); return JNI_FALSE; } - if (strstr(buf, "google.com") == NULL) { - ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com: %s", + if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { + ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", GoogleDNSIpV4Address, buf); return JNI_FALSE; } @@ -133,8 +133,9 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas res, gai_strerror(res)); return JNI_FALSE; } - if (strstr(buf, "google.com") == NULL) { - ALOGD("getnameinfo(%s) didn't return google.com: %s", GoogleDNSIpV6Address2, buf); + if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { + ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + GoogleDNSIpV6Address2, buf); return JNI_FALSE; } From 5227dbe606d73326111c4e2c391bf3097647f3ee Mon Sep 17 00:00:00 2001 From: Adam Vartanian Date: Tue, 9 Apr 2019 15:46:20 +0100 Subject: [PATCH 0592/1415] Add test for SslError.getCertificate() Bug: 129200144 Test: cts -m CtsNetTestCases -t android.net.http.cts Change-Id: I1b23746865a4bffc90847b30384defd2c7d49879 --- tests/cts/net/src/android/net/http/cts/SslErrorTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/cts/net/src/android/net/http/cts/SslErrorTest.java b/tests/cts/net/src/android/net/http/cts/SslErrorTest.java index 850a8b61e6..0058c90ac4 100644 --- a/tests/cts/net/src/android/net/http/cts/SslErrorTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslErrorTest.java @@ -77,4 +77,9 @@ public class SslErrorTest extends TestCase { SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); assertEquals(error.getUrl(), ""); } + + public void testGetCertificate() { + SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); + assertEquals(mCertificate, error.getCertificate()); + } } From 4b1fab0dd0ea0e4f1bc42b8dc7426ef7b2ab148a Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 8 Apr 2019 19:54:05 +0800 Subject: [PATCH 0593/1415] DnsResolver cts changes to match API council requests Bug: 129261432 Test: atest DnsResolverTest Change-Id: I803f10218a01614ba7fb26597971853e602273c6 --- .../src/android/net/cts/DnsResolverTest.java | 384 +++++++++--------- 1 file changed, 181 insertions(+), 203 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 0ff6cd8bac..40d64cf49b 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -39,13 +39,14 @@ import android.system.ErrnoException; import android.test.AndroidTestCase; import android.util.Log; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; public class DnsResolverTest extends AndroidTestCase { private static final String TAG = "DnsResolverTest"; @@ -53,7 +54,9 @@ public class DnsResolverTest extends AndroidTestCase { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static final int TIMEOUT_MS = 12_000; + static final int CANCEL_TIMEOUT_MS = 3_000; static final int CANCEL_RETRY_TIMES = 5; + static final int NXDOMAIN = 3; private ConnectivityManager mCM; private Executor mExecutor; @@ -94,73 +97,26 @@ public class DnsResolverTest extends AndroidTestCase { return testableNetworks.toArray(new Network[0]); } - public void testQueryWithInetAddressCallback() { - final String dname = "www.google.com"; - final String msg = "Query with InetAddressAnswerCallback " + dname; - for (Network network : getTestableNetworks()) { - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference> answers = new AtomicReference<>(); - final DnsResolver.InetAddressAnswerCallback callback = - new DnsResolver.InetAddressAnswerCallback() { - @Override - public void onAnswer(@NonNull List answerList) { - answers.set(answerList); - for (InetAddress addr : answerList) { - Log.d(TAG, "Reported addr: " + addr.toString()); - } - latch.countDown(); - } - - @Override - public void onParseException(@NonNull ParseException e) { - fail(msg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(msg + e.getMessage()); - } - }; - mDns.query(network, dname, CLASS_IN, TYPE_A, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); - try { - assertTrue(msg + " but no valid answer after " + TIMEOUT_MS + "ms.", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - assertGreaterThan(msg + " returned 0 result", answers.get().size(), 0); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } - } - } - static private void assertGreaterThan(String msg, int first, int second) { assertTrue(msg + " Excepted " + first + " to be greater than " + second, first > second); } - static private void assertValidAnswer(String msg, @NonNull DnsAnswer ans) { - // Check rcode field.(0, No error condition). - assertTrue(msg + " Response error, rcode: " + ans.getRcode(), ans.getRcode() == 0); - // Check answer counts. - assertGreaterThan(msg + " No answer found", ans.getANCount(), 0); - // Check question counts. - assertGreaterThan(msg + " No question found", ans.getQDCount(), 0); - } + private static class DnsParseException extends Exception { + public DnsParseException(String msg) { + super(msg); + } - static private void assertValidEmptyAnswer(String msg, @NonNull DnsAnswer ans) { - // Check rcode field.(0, No error condition). - assertTrue(msg + " Response error, rcode: " + ans.getRcode(), ans.getRcode() == 0); - // Check answer counts. Expect 0 answer. - assertTrue(msg + " Not an empty answer", ans.getANCount() == 0); - // Check question counts. - assertGreaterThan(msg + " No question found", ans.getQDCount(), 0); + public DnsParseException(String msg, Throwable cause) { + super(msg, cause); + } } private static class DnsAnswer extends DnsPacket { - DnsAnswer(@NonNull byte[] data) throws ParseException { + DnsAnswer(@NonNull byte[] data) throws DnsParseException { super(data); // Check QR field.(query (0), or a response (1)). if ((mHeader.flags & (1 << 15)) == 0) { - throw new ParseException("Not an answer packet"); + throw new DnsParseException("Not an answer packet"); } } @@ -175,63 +131,116 @@ public class DnsResolverTest extends AndroidTestCase { } } - class RawAnswerCallbackImpl extends DnsResolver.RawAnswerCallback { + /** + * A query callback that ensures that the query is cancelled and that onAnswer is never + * called. If the query succeeds before it is cancelled, needRetry will return true so the + * test can retry. + */ + class VerifyCancelCallback implements DnsResolver.Callback { private final CountDownLatch mLatch = new CountDownLatch(1); private final String mMsg; - private final int mTimeout; + private final CancellationSignal mCancelSignal; + private int mRcode; + private DnsAnswer mDnsAnswer; - RawAnswerCallbackImpl(@NonNull String msg, int timeout) { + VerifyCancelCallback(@NonNull String msg, @Nullable CancellationSignal cancel) { this.mMsg = msg; - this.mTimeout = timeout; + this.mCancelSignal = cancel; + this.mDnsAnswer = null; } - RawAnswerCallbackImpl(@NonNull String msg) { - this(msg, TIMEOUT_MS); + VerifyCancelCallback(@NonNull String msg) { + this(msg, null); + } + + public boolean waitForAnswer(int timeout) throws InterruptedException { + return mLatch.await(timeout, TimeUnit.MILLISECONDS); } public boolean waitForAnswer() throws InterruptedException { - return mLatch.await(mTimeout, TimeUnit.MILLISECONDS); + return waitForAnswer(TIMEOUT_MS); + } + + public boolean needRetry() throws InterruptedException { + return mLatch.await(CANCEL_TIMEOUT_MS, TimeUnit.MILLISECONDS); } @Override - public void onAnswer(@NonNull byte[] answer) { + public void onAnswer(@NonNull byte[] answer, int rcode) { + if (mCancelSignal != null && mCancelSignal.isCanceled()) { + fail(mMsg + " should not have returned any answers"); + } + + mRcode = rcode; try { - assertValidAnswer(mMsg, new DnsAnswer(answer)); - Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); - mLatch.countDown(); - } catch (ParseException e) { + mDnsAnswer = new DnsAnswer(answer); + } catch (DnsParseException e) { fail(mMsg + e.getMessage()); } + Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); + mLatch.countDown(); } @Override - public void onParseException(@NonNull ParseException e) { - fail(mMsg + e.getMessage()); + public void onError(@NonNull DnsResolver.DnsException error) { + fail(mMsg + error.getMessage()); } - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(mMsg + e.getMessage()); + private void assertValidAnswer() { + assertTrue(mMsg + "No valid answer", mDnsAnswer != null); + assertTrue(mMsg + " Unexpected error: reported rcode" + mRcode + + " blob's rcode " + mDnsAnswer.getRcode(), mRcode == mDnsAnswer.getRcode()); + } + + public void assertHasAnswer() { + assertValidAnswer(); + // Check rcode field.(0, No error condition). + assertTrue(mMsg + " Response error, rcode: " + mRcode, mRcode == 0); + // Check answer counts. + assertGreaterThan(mMsg + " No answer found", mDnsAnswer.getANCount(), 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); + } + + public void assertNXDomain() { + assertValidAnswer(); + // Check rcode field.(3, NXDomain). + assertTrue(mMsg + " Unexpected rcode: " + mRcode, mRcode == NXDOMAIN); + // Check answer counts. Expect 0 answer. + assertTrue(mMsg + " Not an empty answer", mDnsAnswer.getANCount() == 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); + } + + public void assertEmptyAnswer() { + assertValidAnswer(); + // Check rcode field.(0, No error condition). + assertTrue(mMsg + " Response error, rcode: " + mRcode, mRcode == 0); + // Check answer counts. Expect 0 answer. + assertTrue(mMsg + " Not an empty answer", mDnsAnswer.getANCount() == 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); } } - public void testQueryWithRawAnswerCallback() { + public void testRawQuery() { final String dname = "www.google.com"; - final String msg = "Query with RawAnswerCallback " + dname; + final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { - final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); + callback.assertHasAnswer(); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } } } - public void testQueryBlobWithRawAnswerCallback() { + public void testRawQueryBlob() { final byte[] blob = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -246,137 +255,58 @@ public class DnsResolverTest extends AndroidTestCase { 0x00, 0x01, /* Type */ 0x00, 0x01 /* Class */ }; - final String msg = "Query with RawAnswerCallback " + byteArrayToHexString(blob); + final String msg = "RawQuery blob " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { - final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); - mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); + callback.assertHasAnswer(); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } } } - public void testQueryRoot() { + public void testRawQueryRoot() { final String dname = ""; - final String msg = "Query with RawAnswerCallback empty dname(ROOT) "; + final String msg = "RawQuery empty dname(ROOT) "; for (Network network : getTestableNetworks()) { - final CountDownLatch latch = new CountDownLatch(1); - final DnsResolver.RawAnswerCallback callback = new DnsResolver.RawAnswerCallback() { - @Override - public void onAnswer(@NonNull byte[] answer) { - try { - // Except no answer record because of querying with empty dname(ROOT) - assertValidEmptyAnswer(msg, new DnsAnswer(answer)); - latch.countDown(); - } catch (ParseException e) { - fail(msg + e.getMessage()); - } - } - - @Override - public void onParseException(@NonNull ParseException e) { - fail(msg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(msg + e.getMessage()); - } - }; - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { - assertTrue(msg + "but no answer after " + TIMEOUT_MS + "ms.", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + // Except no answer record because of querying with empty dname(ROOT) + callback.assertEmptyAnswer(); } catch (InterruptedException e) { fail(msg + "Waiting for DNS lookup was interrupted"); } } } - public void testQueryNXDomain() { + public void testRawQueryNXDomain() { final String dname = "test1-nx.metric.gstatic.com"; - final String msg = "Query with InetAddressAnswerCallback " + dname; + final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { - final CountDownLatch latch = new CountDownLatch(1); - final DnsResolver.InetAddressAnswerCallback callback = - new DnsResolver.InetAddressAnswerCallback() { - @Override - public void onAnswer(@NonNull List answerList) { - if (answerList.size() == 0) { - latch.countDown(); - return; - } - fail(msg + " but get valid answers"); - } - - @Override - public void onParseException(@NonNull ParseException e) { - fail(msg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(msg + e.getMessage()); - } - }; - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + callback.waitForAnswer()); + callback.assertNXDomain(); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } } } - /** - * A query callback that ensures that the query is cancelled and that onAnswer is never - * called. If the query succeeds before it is cancelled, needRetry will return true so the - * test can retry. - */ - class VerifyCancelCallback extends DnsResolver.RawAnswerCallback { - private static final int CANCEL_TIMEOUT = 3_000; - - private final CountDownLatch mLatch = new CountDownLatch(1); - private final String mMsg; - private final CancellationSignal mCancelSignal; - - VerifyCancelCallback(@NonNull String msg, @NonNull CancellationSignal cancelSignal) { - this.mMsg = msg; - this.mCancelSignal = cancelSignal; - } - - public boolean needRetry() throws InterruptedException { - return mLatch.await(CANCEL_TIMEOUT, TimeUnit.MILLISECONDS); - } - - @Override - public void onAnswer(@NonNull byte[] answer) { - if (mCancelSignal.isCanceled()) { - fail(mMsg + " should not have returned any answers"); - } - mLatch.countDown(); - } - - @Override - public void onParseException(@NonNull ParseException e) { - fail(mMsg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(mMsg + e.getMessage()); - } - } - - public void testQueryCancel() throws ErrnoException { + public void testRawQueryCancel() throws ErrnoException { final String dname = "www.google.com"; - final String msg = "Test cancel query " + dname; + final String msg = "Test cancel RawQuery " + dname; // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -390,7 +320,7 @@ public class DnsResolverTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); @@ -399,7 +329,7 @@ public class DnsResolverTest extends AndroidTestCase { try { retry = callback.needRetry(); assertTrue(msg + " query was not cancelled", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail(msg + "Waiting for DNS lookup was interrupted"); } @@ -407,7 +337,7 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryBlobCancel() throws ErrnoException { + public void testRawQueryBlobCancel() throws ErrnoException { final byte[] blob = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -422,7 +352,7 @@ public class DnsResolverTest extends AndroidTestCase { 0x00, 0x01, /* Type */ 0x00, 0x01 /* Class */ }; - final String msg = "Test cancel raw Query " + byteArrayToHexString(blob); + final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(blob); // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -436,7 +366,7 @@ public class DnsResolverTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); - mDns.query(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mDns.rawQuery(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); latch.countDown(); @@ -444,7 +374,7 @@ public class DnsResolverTest extends AndroidTestCase { try { retry = callback.needRetry(); assertTrue(msg + " cancel is not done", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } @@ -454,16 +384,16 @@ public class DnsResolverTest extends AndroidTestCase { public void testCancelBeforeQuery() throws ErrnoException { final String dname = "www.google.com"; - final String msg = "Test cancelled query " + dname; + final String msg = "Test cancelled RawQuery " + dname; for (Network network : getTestableNetworks()) { - final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg, 3_000); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); final CancellationSignal cancelSignal = new CancellationSignal(); cancelSignal.cancel(); - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, mExecutor, cancelSignal, callback); try { assertTrue(msg + " should not return any answers", - !callback.waitForAnswer()); + !callback.waitForAnswer(CANCEL_TIMEOUT_MS)); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } @@ -476,9 +406,7 @@ public class DnsResolverTest extends AndroidTestCase { * before it is cancelled, needRetry will return true so the * test can retry. */ - class VerifyCancelInetAddressCallback extends DnsResolver.InetAddressAnswerCallback { - private static final int CANCEL_TIMEOUT = 3_000; - + class VerifyCancelInetAddressCallback implements DnsResolver.Callback> { private final CountDownLatch mLatch = new CountDownLatch(1); private final String mMsg; private final List mAnswers; @@ -495,31 +423,43 @@ public class DnsResolverTest extends AndroidTestCase { } public boolean needRetry() throws InterruptedException { - return mLatch.await(CANCEL_TIMEOUT, TimeUnit.MILLISECONDS); + return mLatch.await(CANCEL_TIMEOUT_MS, TimeUnit.MILLISECONDS); } public boolean isAnswerEmpty() { return mAnswers.isEmpty(); } + public boolean hasIpv6Answer() { + for (InetAddress answer : mAnswers) { + if (answer instanceof Inet6Address) return true; + } + return false; + } + + public boolean hasIpv4Answer() { + for (InetAddress answer : mAnswers) { + if (answer instanceof Inet4Address) return true; + } + return false; + } + @Override - public void onAnswer(@NonNull List answerList) { + public void onAnswer(@NonNull List answerList, int rcode) { if (mCancelSignal != null && mCancelSignal.isCanceled()) { fail(mMsg + " should not have returned any answers"); } + for (InetAddress addr : answerList) { + Log.d(TAG, "Reported addr: " + addr.toString()); + } mAnswers.clear(); mAnswers.addAll(answerList); mLatch.countDown(); } @Override - public void onParseException(@NonNull ParseException e) { - fail(mMsg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(mMsg + e.getMessage()); + public void onError(@NonNull DnsResolver.DnsException error) { + fail(mMsg + error.getMessage()); } } @@ -544,8 +484,8 @@ public class DnsResolverTest extends AndroidTestCase { public void testQueryCancelForInetAddress() throws ErrnoException { final String dname = "www.google.com"; final String msg = "Test cancel query for InetAddress " + dname; - // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect - // that the query is cancelled before it succeeds. If it is not cancelled before it + // Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to + // expect that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. for (Network network : getTestableNetworks()) { boolean retry = false; @@ -566,11 +506,49 @@ public class DnsResolverTest extends AndroidTestCase { try { retry = callback.needRetry(); assertTrue(msg + " query was not cancelled", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail(msg + "Waiting for DNS lookup was interrupted"); } } while (retry); } } + + public void testQueryForInetAddressIpv4() { + final String dname = "www.google.com"; + final String msg = "Test query for IPv4 InetAddress " + dname; + for (Network network : getTestableNetworks()) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + mDns.query(network, dname, TYPE_A, FLAG_NO_CACHE_LOOKUP, + mExecutor, null, callback); + try { + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer()); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } + } + + public void testQueryForInetAddressIpv6() { + final String dname = "www.google.com"; + final String msg = "Test query for IPv6 InetAddress " + dname; + for (Network network : getTestableNetworks()) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + mDns.query(network, dname, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mExecutor, null, callback); + try { + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer()); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } + } } From ad17ee9e9273a53e3bb141f750c09eb27e76372e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 25 Mar 2019 21:12:51 +0900 Subject: [PATCH 0594/1415] Add instant and ABI XML tags for hostside networking tests. These are not multi-ABI because the behaviour does not depend on the ABI of the app. Some of the APIs are ultimately backed by JNI code in the system server, but that only depends on the system server's ABI, not the app's. Enable instant mode because these applications are subject to the same network restrictions as other apps. Fix: 123364589 Test: atest CtsHostsideNetworkTests Test: cts-tradefed run commandAndExit cts --enable-parameterized-modules --module-parameter instant_app -m CtsHostsideNetworkTests Change-Id: Ib3c4cd365ffe95889d51a236f035ea84516f0abd --- tests/cts/hostside/AndroidTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 0656cae3ca..c7cab7b0ba 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -16,6 +16,9 @@

    Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like + * + * @param plaintext the plaintext bytes to check for + * @param startIndex the index in the list to check for + */ + public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { + Predicate verifier = + (pkt) -> { + return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) + != -1; + }; + return getFirstMatchingPacket(verifier, startIndex) != null; + } + + public byte[] getEspPacket(int spi, boolean encap, int startIndex) { + return getFirstMatchingPacket( + (pkt) -> { + return isEsp(pkt, spi, encap); + }, + startIndex); + } + + public byte[] awaitEspPacketNoPlaintext( + int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + long endTime = System.currentTimeMillis() + TIMEOUT; + int startIndex = 0; + + synchronized (mPackets) { + while (System.currentTimeMillis() < endTime) { + byte[] espPkt = getEspPacket(spi, useEncap, startIndex); + if (espPkt != null) { + // Validate packet size + assertEquals(expectedPacketSize, espPkt.length); + + // Always check plaintext from start + assertFalse(hasPlaintextPacket(plaintext, 0)); + return espPkt; // We've found the packet we're looking for. + } + + startIndex = mPackets.size(); + + // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout + long waitTimeout = endTime - System.currentTimeMillis(); + if (waitTimeout > 0) { + mPackets.wait(waitTimeout); + } + } + + fail("No such ESP packet found with SPI " + spi); + } + return null; + } + + private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { + // Check SPI byte by byte. + return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) + && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) + && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) + && pkt[espOffset + 3] == (byte) (spi & 0xff); + } + + private static boolean isEsp(byte[] pkt, int spi, boolean encap) { + if (isIpv6(pkt)) { + // IPv6 UDP encap not supported by kernels; assume non-encap. + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP + && isSpiEqual(pkt, IpSecBaseTest.IP6_HDRLEN, spi); + } else { + // Use default IPv4 header length (assuming no options) + if (encap) { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP + && isSpiEqual( + pkt, IpSecBaseTest.IP4_HDRLEN + IpSecBaseTest.UDP_HDRLEN, spi); + } else { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP + && isSpiEqual(pkt, IpSecBaseTest.IP4_HDRLEN, spi); + } + } + } + + private static boolean isIpv6(byte[] pkt) { + // First nibble shows IP version. 0x60 for IPv6 + return (pkt[0] & (byte) 0xF0) == (byte) 0x60; + } + + private static byte[] getReflectedPacket(byte[] pkt) { + byte[] reflected = Arrays.copyOf(pkt, pkt.length); + + if (isIpv6(pkt)) { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset + reflected, // dst + IP6_ADDR_OFFSET, // dst offset + IP6_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET, // src offset + reflected, // dst + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset + IP6_ADDR_LEN); // len + } else { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset + reflected, // dst + IP4_ADDR_OFFSET, // dst offset + IP4_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET, // src offset + reflected, // dst + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset + IP4_ADDR_LEN); // len + } + return reflected; + } + + /** Takes all captured packets, flips the src/dst, and re-injects them. */ + public void reflectPackets() throws IOException { + synchronized (mPackets) { + for (byte[] pkt : mPackets) { + injectPacket(getReflectedPacket(pkt)); + } + } + } + + public void injectPacket(byte[] pkt) throws IOException { + FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor()); + out.write(pkt); + out.flush(); + } +} From af4330f7770cdcc853b5a61a52f49a734635ffc4 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 7 May 2019 19:11:26 -0700 Subject: [PATCH 0612/1415] Check for IPSEC_TUNNELS feature before running CTS tests If tunnel feature does is not present, skip tests. Bug: 117183273 Test: This Change-Id: I62fcc2cbca8bf3d2b70da5646303a7059a0df663 Merged-In: I62fcc2cbca8bf3d2b70da5646303a7059a0df663 (cherry picked from commit 698c99fcf03a4e1afb028ac66852140762a7f2b1) --- .../src/android/net/cts/IpSecManagerTunnelTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 5dc9b63b87..c8c99f4a37 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import android.content.pm.PackageManager; import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecTransform; @@ -56,6 +57,12 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { setAppop(false); } + private boolean hasTunnelsFeature() { + return getContext() + .getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + } + private void setAppop(boolean allow) { // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted by the // telephony framework, and the only permission that is sufficient is NETWORK_STACK. So we @@ -69,6 +76,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } public void testSecurityExceptionsCreateTunnelInterface() throws Exception { + if (!hasTunnelsFeature()) return; + // Ensure we don't have the appop. Permission is not requested in the Manifest setAppop(false); @@ -81,6 +90,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } public void testSecurityExceptionsBuildTunnelTransform() throws Exception { + if (!hasTunnelsFeature()) return; + // Ensure we don't have the appop. Permission is not requested in the Manifest setAppop(false); @@ -97,6 +108,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { private void checkTunnel(InetAddress inner, InetAddress outer, boolean useEncap) throws Exception { + if (!hasTunnelsFeature()) return; + setAppop(true); int innerPrefixLen = inner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; From 75fb3d002e91d3cff5db5ac625acb592108afcb1 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 4 Apr 2019 17:20:38 -0700 Subject: [PATCH 0613/1415] Add utilities to generate packets This change adds utility methods to generate packets incrementally. It supports UDP, ESP, IPv4, IPv6 packet generation. For ESP, it exclusively does AES-CBC, HMAC-SHA256. Bug: 72950854 Test: This Change-Id: Icffeed2ebb2005d79faf04f48fd5126d1d6fb175 --- .../src/android/net/cts/IpSecBaseTest.java | 11 - .../src/android/net/cts/IpSecManagerTest.java | 37 +- .../net/src/android/net/cts/PacketUtils.java | 460 ++++++++++++++++++ .../cts/net/src/android/net/cts/TunUtils.java | 16 +- 4 files changed, 483 insertions(+), 41 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/PacketUtils.java diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index cbb9c195d0..35d0f485e0 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -52,17 +52,6 @@ public class IpSecBaseTest extends AndroidTestCase { protected static final int[] DIRECTIONS = new int[] {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}; - protected static final int TCP_HDRLEN_WITH_OPTIONS = 32; - protected static final int UDP_HDRLEN = 8; - protected static final int IP4_HDRLEN = 20; - protected static final int IP6_HDRLEN = 40; - - // Encryption parameters - protected static final int AES_GCM_IV_LEN = 8; - protected static final int AES_CBC_IV_LEN = 16; - protected static final int AES_GCM_BLK_SIZE = 4; - protected static final int AES_CBC_BLK_SIZE = 16; - protected static final byte[] TEST_DATA = "Best test data ever!".getBytes(); protected static final int DATA_BUFFER_LEN = 4096; protected static final int SOCK_TIMEOUT = 500; diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index e788d9602f..60d1c03ee2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -16,6 +16,14 @@ package android.net.cts; +import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; +import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_GCM_IV_LEN; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.TCP_HDRLEN_WITH_TIMESTAMP_OPT; +import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertArrayEquals; @@ -421,19 +429,6 @@ public class IpSecManagerTest extends IpSecBaseTest { } } - /** Helper function to calculate expected ESP packet size. */ - private int calculateEspPacketSize( - int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { - final int ESP_HDRLEN = 4 + 4; // SPI + Seq# - final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length - payloadLen += cryptIvLength; // Initialization Vector - payloadLen += 2; // ESP trailer - - // Align to block size of encryption algorithm - payloadLen += (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; - return payloadLen + ESP_HDRLEN + ICV_LEN; - } - public void checkTransform( int protocol, String localAddress, @@ -474,7 +469,7 @@ public class IpSecManagerTest extends IpSecBaseTest { try (IpSecTransform transform = transformBuilder.buildTransportModeTransform(local, spi)) { if (protocol == IPPROTO_TCP) { - transportHdrLen = TCP_HDRLEN_WITH_OPTIONS; + transportHdrLen = TCP_HDRLEN_WITH_TIMESTAMP_OPT; checkTcp(transform, local, sendCount, useJavaSockets); } else if (protocol == IPPROTO_UDP) { transportHdrLen = UDP_HDRLEN; @@ -511,7 +506,7 @@ public class IpSecManagerTest extends IpSecBaseTest { int innerPacketSize = TEST_DATA.length + transportHdrLen + ipHdrLen; int outerPacketSize = - calculateEspPacketSize( + PacketUtils.calculateEspPacketSize( TEST_DATA.length + transportHdrLen, ivLen, blkSize, truncLenBits) + udpEncapLen + ipHdrLen; @@ -529,13 +524,13 @@ public class IpSecManagerTest extends IpSecBaseTest { // Add TCP ACKs for data packets if (protocol == IPPROTO_TCP) { int encryptedTcpPktSize = - calculateEspPacketSize(TCP_HDRLEN_WITH_OPTIONS, ivLen, blkSize, truncLenBits); + PacketUtils.calculateEspPacketSize( + TCP_HDRLEN_WITH_TIMESTAMP_OPT, ivLen, blkSize, truncLenBits); - - // Add data packet ACKs - expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount); - expectedInnerBytes += (TCP_HDRLEN_WITH_OPTIONS + ipHdrLen) * (sendCount); - expectedPackets += sendCount; + // Add data packet ACKs + expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount); + expectedInnerBytes += (TCP_HDRLEN_WITH_TIMESTAMP_OPT + ipHdrLen) * (sendCount); + expectedPackets += sendCount; } StatsChecker.waitForNumPackets(expectedPackets); diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java new file mode 100644 index 0000000000..6177827ba6 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/PacketUtils.java @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2018 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.system.OsConstants.IPPROTO_IPV6; +import static android.system.OsConstants.IPPROTO_UDP; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class PacketUtils { + private static final String TAG = PacketUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + + static final int IP4_HDRLEN = 20; + static final int IP6_HDRLEN = 40; + static final int UDP_HDRLEN = 8; + static final int TCP_HDRLEN = 20; + static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12; + + // Not defined in OsConstants + static final int IPPROTO_IPV4 = 4; + static final int IPPROTO_ESP = 50; + + // Encryption parameters + static final int AES_GCM_IV_LEN = 8; + static final int AES_CBC_IV_LEN = 16; + static final int AES_GCM_BLK_SIZE = 4; + static final int AES_CBC_BLK_SIZE = 16; + + // Encryption algorithms + static final String AES = "AES"; + static final String AES_CBC = "AES/CBC/NoPadding"; + static final String HMAC_SHA_256 = "HmacSHA256"; + + public interface Payload { + byte[] getPacketBytes(IpHeader header) throws Exception; + + void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception; + + short length(); + + int getProtocolId(); + } + + public abstract static class IpHeader { + + public final byte proto; + public final InetAddress srcAddr; + public final InetAddress dstAddr; + public final Payload payload; + + public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) { + this.proto = (byte) proto; + this.srcAddr = src; + this.dstAddr = dst; + this.payload = payload; + } + + public abstract byte[] getPacketBytes() throws Exception; + + public abstract int getProtocolId(); + } + + public static class Ip4Header extends IpHeader { + private short checksum; + + public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) { + super(proto, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer resultBuffer = buildHeader(); + payload.addPacketBytes(this, resultBuffer); + + return getByteArrayFromBuffer(resultBuffer); + } + + public ByteBuffer buildHeader() { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version, IHL + bb.put((byte) (0x45)); + + // DCSP, ECN + bb.put((byte) 0); + + // Total Length + bb.putShort((short) (IP4_HDRLEN + payload.length())); + + // Empty for Identification, Flags and Fragment Offset + bb.putShort((short) 0); + bb.put((byte) 0x40); + bb.put((byte) 0x00); + + // TTL + bb.put((byte) 64); + + // Protocol + bb.put(proto); + + // Header Checksum + final int ipChecksumOffset = bb.position(); + bb.putShort((short) 0); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + bb.putShort(ipChecksumOffset, calculateChecksum(bb)); + + return bb; + } + + private short calculateChecksum(ByteBuffer bb) { + int checksum = 0; + + // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit + // aligned, so no special cases needed for unaligned values. + ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer(); + while (shortBuffer.hasRemaining()) { + short val = shortBuffer.get(); + + // Wrap as needed + checksum = addAndWrapForChecksum(checksum, val); + } + + return onesComplement(checksum); + } + + public int getProtocolId() { + return IPPROTO_IPV4; + } + } + + public static class Ip6Header extends IpHeader { + public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) { + super(nextHeader, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version | Traffic Class (First 4 bits) + bb.put((byte) 0x60); + + // Traffic class (Last 4 bits), Flow Label + bb.put((byte) 0); + bb.put((byte) 0); + bb.put((byte) 0); + + // Payload Length + bb.putShort((short) payload.length()); + + // Next Header + bb.put(proto); + + // Hop Limit + bb.put((byte) 64); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + // Payload + payload.addPacketBytes(this, bb); + + return getByteArrayFromBuffer(bb); + } + + public int getProtocolId() { + return IPPROTO_IPV6; + } + } + + public static class BytePayload implements Payload { + public final byte[] payload; + + public BytePayload(byte[] payload) { + this.payload = payload; + } + + public int getProtocolId() { + return -1; + } + + public byte[] getPacketBytes(IpHeader header) { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) { + resultBuffer.put(payload); + } + + public short length() { + return (short) payload.length; + } + } + + public static class UdpHeader implements Payload { + + public final short srcPort; + public final short dstPort; + public final Payload payload; + + public UdpHeader(int srcPort, int dstPort, Payload payload) { + this.srcPort = (short) srcPort; + this.dstPort = (short) dstPort; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_UDP; + } + + public short length() { + return (short) (payload.length() + 8); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + // Source, Destination port + resultBuffer.putShort(srcPort); + resultBuffer.putShort(dstPort); + + // Payload Length + resultBuffer.putShort(length()); + + // Get payload bytes for checksum + payload + ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + payload.addPacketBytes(header, payloadBuffer); + byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer); + + // Checksum + resultBuffer.putShort(calculateChecksum(header, payloadBytes)); + + // Payload + resultBuffer.put(payloadBytes); + } + + private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception { + int newChecksum = 0; + ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer(); + ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer(); + + while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) { + short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get(); + + // Wrap as needed + newChecksum = addAndWrapForChecksum(newChecksum, val); + } + + // Add pseudo-header values. Proto is 0-padded, so just use the byte. + newChecksum = addAndWrapForChecksum(newChecksum, header.proto); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + newChecksum = addAndWrapForChecksum(newChecksum, srcPort); + newChecksum = addAndWrapForChecksum(newChecksum, dstPort); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + + ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer(); + while (payloadShortBuffer.hasRemaining()) { + newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get()); + } + if (payload.length() % 2 != 0) { + newChecksum = + addAndWrapForChecksum( + newChecksum, (payloadBytes[payloadBytes.length - 1] << 8)); + } + + return onesComplement(newChecksum); + } + } + + public static class EspHeader implements Payload { + public final int nextHeader; + public final int spi; + public final int seqNum; + public final byte[] key; + public final byte[] payload; + + /** + * Generic constructor for ESP headers. + * + *

    For Tunnel mode, payload will be a full IP header + attached payloads + * + *

    For Transport mode, payload will be only the attached payloads, but with the checksum + * calculated using the pre-encryption IP header + */ + public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) { + this.nextHeader = nextHeader; + this.spi = spi; + this.seqNum = seqNum; + this.key = key; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_ESP; + } + + public short length() { + // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len) + return (short) + calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + espPayloadBuffer.putInt(spi); + espPayloadBuffer.putInt(seqNum); + espPayloadBuffer.put(getCiphertext(key)); + + espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16); + resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer)); + } + + private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException { + Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256); + SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256); + sha256HMAC.init(authKey); + + return sha256HMAC.doFinal(authenticatedSection); + } + + /** + * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks + * + *

    The ciphertext does NOT include the SPI/Sequence numbers, or the ICV. + */ + private byte[] getCiphertext(byte[] key) throws GeneralSecurityException { + int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE); + ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen); + paddedPayload.put(payload); + + // Add padding - consecutive integers from 0x01 + int pad = 1; + while (paddedPayload.position() < paddedPayload.limit()) { + paddedPayload.put((byte) pad++); + } + + paddedPayload.position(paddedPayload.limit() - 2); + paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length + paddedPayload.put((byte) nextHeader); + + // Generate Initialization Vector + byte[] iv = new byte[AES_CBC_IV_LEN]; + new SecureRandom().nextBytes(iv); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); + + // Encrypt payload + Cipher cipher = Cipher.getInstance(AES_CBC); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload)); + + // Build ciphertext + ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length); + cipherText.put(iv); + cipherText.put(encrypted); + + return getByteArrayFromBuffer(cipherText); + } + } + + private static int addAndWrapForChecksum(int currentChecksum, int value) { + currentChecksum += value & 0x0000ffff; + + // Wrap anything beyond the first 16 bits, and add to lower order bits + return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff); + } + + private static short onesComplement(int val) { + val = (val >>> 16) + (val & 0xffff); + + if (val == 0) return 0; + return (short) ((~val) & 0xffff); + } + + public static int calculateEspPacketSize( + int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { + final int ESP_HDRLEN = 4 + 4; // SPI + Seq# + final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length + payloadLen += cryptIvLength; // Initialization Vector + + // Align to block size of encryption algorithm + payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize); + return payloadLen + ESP_HDRLEN + ICV_LEN; + } + + private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) { + payloadLen += 2; // ESP trailer + + // Align to block size of encryption algorithm + return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize); + } + + private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) { + return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; + } + + private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) { + return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); + } + + /* + * Debug printing + */ + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(hexArray[b >>> 4]); + sb.append(hexArray[b & 0x0F]); + sb.append(' '); + } + return sb.toString(); + } +} diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index ca233ce1e8..4d5533fc62 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -16,6 +16,10 @@ package android.net.cts; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.IPPROTO_ESP; +import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -46,9 +50,6 @@ public class TunUtils { private static final int IP6_ADDR_OFFSET = 8; private static final int IP6_ADDR_LEN = 16; - // Not defined in OsConstants - private static final int IPPROTO_ESP = 50; - private final ParcelFileDescriptor mTunFd; private final List mPackets = new ArrayList<>(); private final Thread mReaderThread; @@ -178,17 +179,14 @@ public class TunUtils { private static boolean isEsp(byte[] pkt, int spi, boolean encap) { if (isIpv6(pkt)) { // IPv6 UDP encap not supported by kernels; assume non-encap. - return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP - && isSpiEqual(pkt, IpSecBaseTest.IP6_HDRLEN, spi); + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); } else { // Use default IPv4 header length (assuming no options) if (encap) { return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP - && isSpiEqual( - pkt, IpSecBaseTest.IP4_HDRLEN + IpSecBaseTest.UDP_HDRLEN, spi); + && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi); } else { - return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP - && isSpiEqual(pkt, IpSecBaseTest.IP4_HDRLEN, spi); + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi); } } } From 64e64ff454338ced2e418fa13b65b75a5884ebd5 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Apr 2019 10:15:26 -0700 Subject: [PATCH 0614/1415] Add IPsec Tunnel mode data tests This change adds single-direction tests for the IPsec Tunnel Mode API. In the outbound direction, TUNs are used to capture outgoing packets, and values are inspected. In the inbound direction, packets are built manually, using the PacketUtils framework. Additional testing for end-to-end integration tests will follow in aosp/941021 using packet reflection via the TUN. Bug: 72950854 Test: This; passing Change-Id: Ic4181fc857fa880db5553314efa914f870dbe87c --- .../src/android/net/cts/IpSecBaseTest.java | 43 +- .../net/cts/IpSecManagerTunnelTest.java | 694 ++++++++++++++++-- .../cts/net/src/android/net/cts/TunUtils.java | 7 + 3 files changed, 661 insertions(+), 83 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 35d0f485e0..087dbdaec3 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -28,11 +28,12 @@ import android.system.OsConstants; import android.test.AndroidTestCase; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; -import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -72,8 +73,14 @@ public class IpSecBaseTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); - mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE); - mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mISM = + (IpSecManager) + InstrumentationRegistry.getContext() + .getSystemService(Context.IPSEC_SERVICE); + mCM = + (ConnectivityManager) + InstrumentationRegistry.getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); } protected static byte[] getKey(int bitLength) { @@ -195,6 +202,17 @@ public class IpSecBaseTest extends AndroidTestCase { public static class JavaUdpSocket implements GenericUdpSocket { public final DatagramSocket mSocket; + public JavaUdpSocket(InetAddress localAddr, int port) { + try { + mSocket = new DatagramSocket(port, localAddr); + mSocket.setSoTimeout(SOCK_TIMEOUT); + } catch (SocketException e) { + // Fail loudly if we can't set up sockets properly. And without the timeout, we + // could easily end up in an endless wait. + throw new RuntimeException(e); + } + } + public JavaUdpSocket(InetAddress localAddr) { try { mSocket = new DatagramSocket(0, localAddr); @@ -425,26 +443,25 @@ public class IpSecBaseTest extends AndroidTestCase { } protected static IpSecTransform buildIpSecTransform( - Context mContext, + Context context, IpSecManager.SecurityParameterIndex spi, IpSecManager.UdpEncapsulationSocket encapSocket, InetAddress remoteAddr) throws Exception { - String localAddr = (remoteAddr instanceof Inet4Address) ? IPV4_LOOPBACK : IPV6_LOOPBACK; IpSecTransform.Builder builder = - new IpSecTransform.Builder(mContext) - .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) - .setAuthentication( - new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, - AUTH_KEY, - AUTH_KEY.length * 4)); + new IpSecTransform.Builder(context) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 4)); if (encapSocket != null) { builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); } - return builder.buildTransportModeTransform(InetAddress.getByName(localAddr), spi); + return builder.buildTransportModeTransform(remoteAddr, spi); } private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index c8c99f4a37..e8c0a7a4b2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -16,174 +16,728 @@ package android.net.cts; +import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.IpSecManager.UdpEncapsulationSocket; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; +import static android.net.cts.PacketUtils.BytePayload; +import static android.net.cts.PacketUtils.EspHeader; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.Ip4Header; +import static android.net.cts.PacketUtils.Ip6Header; +import static android.net.cts.PacketUtils.IpHeader; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.net.cts.PacketUtils.UdpHeader; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import android.app.AppOpsManager; +import android.content.Context; import android.content.pm.PackageManager; +import android.net.ConnectivityManager; import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecTransform; +import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkRequest; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.cts.PacketUtils.Payload; +import android.os.Binder; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.compatibility.common.util.SystemUtil; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) public class IpSecManagerTunnelTest extends IpSecBaseTest { - private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName(); - private static final int IP4_PREFIX_LEN = 24; - private static final int IP6_PREFIX_LEN = 48; - private static final InetAddress OUTER_ADDR4 = InetAddress.parseNumericAddress("192.0.2.0"); - private static final InetAddress OUTER_ADDR6 = - InetAddress.parseNumericAddress("2001:db8:f00d::1"); - private static final InetAddress INNER_ADDR4 = InetAddress.parseNumericAddress("10.0.0.1"); - private static final InetAddress INNER_ADDR6 = - InetAddress.parseNumericAddress("2001:db8:d00d::1"); - private Network mUnderlyingNetwork; - private Network mIpSecNetwork; + private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); + private static final InetAddress REMOTE_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.2"); + private static final InetAddress LOCAL_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::1"); + private static final InetAddress REMOTE_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::2"); - protected void setUp() throws Exception { + private static final InetAddress LOCAL_INNER_4 = + InetAddress.parseNumericAddress("198.51.100.1"); + private static final InetAddress REMOTE_INNER_4 = + InetAddress.parseNumericAddress("198.51.100.2"); + private static final InetAddress LOCAL_INNER_6 = + InetAddress.parseNumericAddress("2001:db8:2::1"); + private static final InetAddress REMOTE_INNER_6 = + InetAddress.parseNumericAddress("2001:db8:2::2"); + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 128; + + private static final int TIMEOUT_MS = 500; + + // Static state to reduce setup/teardown + private static ConnectivityManager sCM; + private static TestNetworkManager sTNM; + private static ParcelFileDescriptor sTunFd; + private static TestNetworkCallback sTunNetworkCallback; + private static Network sTunNetwork; + private static TunUtils sTunUtils; + + private static Context sContext = InstrumentationRegistry.getContext(); + private static IBinder sBinder = new Binder(); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and + // a standard permission is insufficient. So we shell out the appop, to give us the + // right appop permissions. + setAppop(OP_MANAGE_IPSEC_TUNNELS, true); + + TestNetworkInterface testIntf = + sTNM.createTunInterface( + new LinkAddress[] { + new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), + new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN) + }); + + sTunFd = testIntf.getFileDescriptor(); + sTunNetworkCallback = setupAndGetTestNetwork(testIntf.getInterfaceName()); + sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); + + sTunUtils = new TunUtils(sTunFd); + } + + @Before + public void setUp() throws Exception { super.setUp(); + + // Set to true before every run; some tests flip this. + setAppop(OP_MANAGE_IPSEC_TUNNELS, true); + + // Clear sTunUtils state + sTunUtils.reset(); } - protected void tearDown() { - setAppop(false); + @AfterClass + public static void tearDownAfterClass() throws Exception { + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); + + sCM.unregisterNetworkCallback(sTunNetworkCallback); + + sTNM.teardownTestNetwork(sTunNetwork); + sTunFd.close(); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); } - private boolean hasTunnelsFeature() { - return getContext() - .getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + private static boolean hasTunnelsFeature() { + return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); } - private void setAppop(boolean allow) { - // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted by the - // telephony framework, and the only permission that is sufficient is NETWORK_STACK. So we - // shell out the appop manager, to give us the right appop permissions. - String cmd = - "appops set " - + mContext.getPackageName() - + " MANAGE_IPSEC_TUNNELS " - + (allow ? "allow" : "deny"); - SystemUtil.runShellCommand(cmd); + private static void setAppop(int appop, boolean allow) { + String opName = AppOpsManager.opToName(appop); + for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { + String cmd = + String.format( + "appops set %s %s %s", + pkg, // Package name + opName, // Appop + (allow ? "allow" : "deny")); // Action + SystemUtil.runShellCommand(cmd); + } } - public void testSecurityExceptionsCreateTunnelInterface() throws Exception { + private static TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception { + // Build a network request + NetworkRequest nr = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_TEST) + .removeCapability(NET_CAPABILITY_TRUSTED) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .setNetworkSpecifier(ifname) + .build(); + + TestNetworkCallback cb = new TestNetworkCallback(); + sCM.requestNetwork(nr, cb); + + // Setup the test network after network request is filed to prevent Network from being + // reaped due to no requests matching it. + sTNM.setupTestNetwork(ifname, sBinder); + + return cb; + } + + @Test + public void testSecurityExceptionCreateTunnelInterfaceWithoutAppop() throws Exception { if (!hasTunnelsFeature()) return; // Ensure we don't have the appop. Permission is not requested in the Manifest - setAppop(false); + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); // Security exceptions are thrown regardless of IPv4/IPv6. Just test one try { - mISM.createIpSecTunnelInterface(OUTER_ADDR6, OUTER_ADDR6, mUnderlyingNetwork); + mISM.createIpSecTunnelInterface(LOCAL_INNER_6, REMOTE_INNER_6, sTunNetwork); fail("Did not throw SecurityException for Tunnel creation without appop"); } catch (SecurityException expected) { } } - public void testSecurityExceptionsBuildTunnelTransform() throws Exception { + @Test + public void testSecurityExceptionBuildTunnelTransformWithoutAppop() throws Exception { if (!hasTunnelsFeature()) return; // Ensure we don't have the appop. Permission is not requested in the Manifest - setAppop(false); + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); // Security exceptions are thrown regardless of IPv4/IPv6. Just test one try (IpSecManager.SecurityParameterIndex spi = - mISM.allocateSecurityParameterIndex(OUTER_ADDR4); + mISM.allocateSecurityParameterIndex(LOCAL_INNER_4); IpSecTransform transform = - new IpSecTransform.Builder(mContext) - .buildTunnelModeTransform(OUTER_ADDR4, spi)) { + new IpSecTransform.Builder(sContext) + .buildTunnelModeTransform(REMOTE_INNER_4, spi)) { fail("Did not throw SecurityException for Transform creation without appop"); } catch (SecurityException expected) { } } - private void checkTunnel(InetAddress inner, InetAddress outer, boolean useEncap) + /* Test runnables for callbacks after IPsec tunnels are set up. */ + private interface TestRunnable { + void run(Network ipsecNetwork) throws Exception; + } + + private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CompletableFuture futureNetwork = new CompletableFuture<>(); + + @Override + public void onAvailable(Network network) { + futureNetwork.complete(network); + } + + public Network getNetworkBlocking() throws Exception { + return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + private int getPacketSize( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) { + int expectedPacketSize = TEST_DATA.length + UDP_HDRLEN; + + // Inner Transport mode packet size + if (transportInTunnelMode) { + expectedPacketSize = + PacketUtils.calculateEspPacketSize( + expectedPacketSize, + AES_CBC_IV_LEN, + AES_CBC_BLK_SIZE, + AUTH_KEY.length * 4); + } + + // Inner IP Header + expectedPacketSize += innerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN; + + // Tunnel mode transform size + expectedPacketSize = + PacketUtils.calculateEspPacketSize( + expectedPacketSize, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, AUTH_KEY.length * 4); + + // UDP encap size + expectedPacketSize += useEncap ? UDP_HDRLEN : 0; + + // Outer IP Header + expectedPacketSize += outerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN; + + return expectedPacketSize; + } + + private interface TestRunnableFactory { + TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) + throws Exception; + } + + private class OutputTestRunnableFactory implements TestRunnableFactory { + public TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) { + return new TestRunnable() { + @Override + public void run(Network ipsecNetwork) throws Exception { + // Build a socket and send traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, inTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, outTransportTransform); + } + + socket.sendTo(TEST_DATA, remoteInner, socket.getPort()); + + // Verify that an encrypted packet is sent. As of right now, checking encrypted + // body is not possible, due to our not knowing some of the fields of the + // inner IP header (flow label, flags, etc) + sTunUtils.awaitEspPacketNoPlaintext( + spi, TEST_DATA, encapPort != 0, expectedPacketSize); + + socket.close(); + } + }; + } + } + + private class InputPacketGeneratorTestRunnableFactory implements TestRunnableFactory { + public TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) + throws Exception { + return new TestRunnable() { + @Override + public void run(Network ipsecNetwork) throws Exception { + // Build a socket and receive traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner); + // JavaUdpSocket socket = new JavaUdpSocket(localInner, socketPort.get()); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform); + } + + byte[] pkt; + if (transportInTunnelMode) { + pkt = + getTransportInTunnelModePacket( + spi, + spi, + remoteInner, + localInner, + remoteOuter, + localOuter, + socket.getPort(), + encapPort); + } else { + pkt = + getTunnelModePacket( + spi, + remoteInner, + localInner, + remoteOuter, + localOuter, + socket.getPort(), + encapPort); + } + sTunUtils.injectPacket(pkt); + + // Receive packet from socket, and validate + receiveAndValidatePacket(socket); + + socket.close(); + } + }; + } + } + + private void checkTunnelOutput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new OutputTestRunnableFactory()); + } + + private void checkTunnelInput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new InputPacketGeneratorTestRunnableFactory()); + } + + public void checkTunnel( + int innerFamily, + int outerFamily, + boolean useEncap, + boolean transportInTunnelMode, + TestRunnableFactory factory) throws Exception { if (!hasTunnelsFeature()) return; - setAppop(true); - int innerPrefixLen = inner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; - try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(outer); + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + // Re-uses the same SPI to ensure that even in cases of symmetric SPIs shared across tunnel + // and transport mode, packets are encrypted/decrypted properly based on the src/dst. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + buildTunnelAndNetwork( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + factory.getTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + expectedPacketSize)); + } + } + + private void buildTunnelAndNetwork( + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + int spi, + UdpEncapsulationSocket encapSocket, + TestRunnable test) + throws Exception { + int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; + TestNetworkCallback testNetworkCb = null; + + try (IpSecManager.SecurityParameterIndex inSpi = + mISM.allocateSecurityParameterIndex(localOuter, spi); + IpSecManager.SecurityParameterIndex outSpi = + mISM.allocateSecurityParameterIndex(remoteOuter, spi); IpSecManager.IpSecTunnelInterface tunnelIntf = - mISM.createIpSecTunnelInterface(outer, outer, mCM.getActiveNetwork()); - IpSecManager.UdpEncapsulationSocket encapSocket = - mISM.openUdpEncapsulationSocket()) { + mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) { + // Build the test network + tunnelIntf.addAddress(localInner, innerPrefixLen); + testNetworkCb = setupAndGetTestNetwork(tunnelIntf.getInterfaceName()); + Network testNetwork = testNetworkCb.getNetworkBlocking(); - IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext); + // Check interface was created + NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); + assertNotNull(netIntf); + + // Check addresses + List intfAddrs = netIntf.getInterfaceAddresses(); + assertEquals(1, intfAddrs.size()); + assertEquals(localInner, intfAddrs.get(0).getAddress()); + assertEquals(innerPrefixLen, intfAddrs.get(0).getNetworkPrefixLength()); + + // Configure Transform parameters + IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); transformBuilder.setEncryption( new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)); transformBuilder.setAuthentication( new IpSecAlgorithm( IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4)); - if (useEncap) { + if (encapSocket != null) { transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); } - // Check transform application - try (IpSecTransform transform = transformBuilder.buildTunnelModeTransform(outer, spi)) { - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, transform); - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, transform); + // Apply transform and check that traffic is properly encrypted + try (IpSecTransform inTransform = + transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi); + IpSecTransform outTransform = + transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) { + mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, inTransform); + mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, outTransform); - // TODO: Test to ensure that send/receive works with these transforms. + test.run(testNetwork); } - // Check interface was created - NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNotNull(netIntf); - - // Add addresses and check - tunnelIntf.addAddress(inner, innerPrefixLen); - for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) { - assertEquals(intfAddr.getAddress(), inner); - assertEquals(intfAddr.getNetworkPrefixLength(), innerPrefixLen); - } + // Teardown the test network + sTNM.teardownTestNetwork(testNetwork); // Remove addresses and check - tunnelIntf.removeAddress(inner, innerPrefixLen); + tunnelIntf.removeAddress(localInner, innerPrefixLen); + netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertTrue(netIntf.getInterfaceAddresses().isEmpty()); // Check interface was cleaned up tunnelIntf.close(); netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertNull(netIntf); + } finally { + if (testNetworkCb != null) { + sCM.unregisterNetworkCallback(testNetworkCb); + } } } - /* - * Create, add and remove addresses, then teardown tunnel - */ + private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { + byte[] socketResponseBytes = socket.receive(); + assertArrayEquals(TEST_DATA, socketResponseBytes); + } + + private int getRandomSpi(InetAddress localOuter, InetAddress remoteOuter) throws Exception { + // Try to allocate both in and out SPIs using the same requested SPI value. + try (IpSecManager.SecurityParameterIndex inSpi = + mISM.allocateSecurityParameterIndex(localOuter); + IpSecManager.SecurityParameterIndex outSpi = + mISM.allocateSecurityParameterIndex(remoteOuter, inSpi.getSpi()); ) { + return inSpi.getSpi(); + } + } + + private IpHeader getIpHeader(int protocol, InetAddress src, InetAddress dst, Payload payload) { + if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { + throw new IllegalArgumentException("Invalid src/dst address combination"); + } + + if (src instanceof Inet6Address) { + return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); + } else { + return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); + } + } + + private EspHeader buildTransportModeEspPacket( + int spi, InetAddress src, InetAddress dst, int port, Payload payload) throws Exception { + IpHeader preEspIpHeader = getIpHeader(payload.getProtocolId(), src, dst, payload); + + return new EspHeader( + payload.getProtocolId(), + spi, + 1, // sequence number + CRYPT_KEY, // Same key for auth and crypt + payload.getPacketBytes(preEspIpHeader)); + } + + private EspHeader buildTunnelModeEspPacket( + int spi, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort, + Payload payload) + throws Exception { + IpHeader innerIp = getIpHeader(payload.getProtocolId(), srcInner, dstInner, payload); + return new EspHeader( + innerIp.getProtocolId(), + spi, + 1, // sequence number + CRYPT_KEY, // Same key for auth and crypt + innerIp.getPacketBytes()); + } + + private IpHeader maybeEncapPacket( + InetAddress src, InetAddress dst, int encapPort, EspHeader espPayload) + throws Exception { + + Payload payload = espPayload; + if (encapPort != 0) { + payload = new UdpHeader(encapPort, encapPort, espPayload); + } + + return getIpHeader(payload.getProtocolId(), src, dst, payload); + } + + private byte[] getTunnelModePacket( + int spi, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort) + throws Exception { + UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); + + EspHeader espPayload = + buildTunnelModeEspPacket( + spi, srcInner, dstInner, srcOuter, dstOuter, port, encapPort, udp); + return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); + } + + private byte[] getTransportInTunnelModePacket( + int spiInner, + int spiOuter, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort) + throws Exception { + UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); + + EspHeader espPayload = buildTransportModeEspPacket(spiInner, srcInner, dstInner, port, udp); + espPayload = + buildTunnelModeEspPacket( + spiOuter, + srcInner, + dstInner, + srcOuter, + dstOuter, + port, + encapPort, + espPayload); + return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); + } + + // Transport-in-Tunnel mode tests + @Test + public void testTransportInTunnelModeV4InV4() throws Exception { + checkTunnelOutput(AF_INET, AF_INET, false, true); + checkTunnelInput(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { + checkTunnelOutput(AF_INET, AF_INET, true, true); + checkTunnelInput(AF_INET, AF_INET, true, true); + } + + @Test + public void testTransportInTunnelModeV4InV6() throws Exception { + checkTunnelOutput(AF_INET, AF_INET6, false, true); + checkTunnelInput(AF_INET, AF_INET6, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4() throws Exception { + checkTunnelOutput(AF_INET6, AF_INET, false, true); + checkTunnelInput(AF_INET6, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { + checkTunnelOutput(AF_INET6, AF_INET, true, true); + checkTunnelInput(AF_INET6, AF_INET, true, true); + } + + @Test + public void testTransportInTunnelModeV6InV6() throws Exception { + checkTunnelOutput(AF_INET, AF_INET6, false, true); + checkTunnelInput(AF_INET, AF_INET6, false, true); + } + + // Tunnel mode tests + @Test public void testTunnelV4InV4() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR4, false); + checkTunnelOutput(AF_INET, AF_INET, false, false); + checkTunnelInput(AF_INET, AF_INET, false, false); } + @Test public void testTunnelV4InV4UdpEncap() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR4, true); + checkTunnelOutput(AF_INET, AF_INET, true, false); + checkTunnelInput(AF_INET, AF_INET, true, false); } + @Test public void testTunnelV4InV6() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR6, false); + checkTunnelOutput(AF_INET, AF_INET6, false, false); + checkTunnelInput(AF_INET, AF_INET6, false, false); } + @Test public void testTunnelV6InV4() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR4, false); + checkTunnelOutput(AF_INET6, AF_INET, false, false); + checkTunnelInput(AF_INET6, AF_INET, false, false); } + @Test public void testTunnelV6InV4UdpEncap() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR4, true); + checkTunnelOutput(AF_INET6, AF_INET, true, false); + checkTunnelInput(AF_INET6, AF_INET, true, false); } + @Test public void testTunnelV6InV6() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR6, false); + checkTunnelOutput(AF_INET6, AF_INET6, false, false); + checkTunnelInput(AF_INET6, AF_INET6, false, false); } } diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index 4d5533fc62..a0307137a5 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -247,4 +247,11 @@ public class TunUtils { out.write(pkt); out.flush(); } + + /** Resets the intercepted packets. */ + public void reset() throws IOException { + synchronized (mPackets) { + mPackets.clear(); + } + } } From 2742923a63e47262044994c70388324a46c891e8 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 26 Dec 2018 14:31:42 -0800 Subject: [PATCH 0615/1415] Add TunUtils as utility to reflect packets This patch adds a TunUtils class, allowing for packet capture over a TUN interface, inspection of some basic header fields, and reflection of packets with flipped src/dst headers. Bug: 72950854 Test: Ran, passing Change-Id: I9fdba4a905886c7a4820d86ef52c0cc1843215b2 Merged-In: I9fdba4a905886c7a4820d86ef52c0cc1843215b2 (cherry picked from commit 2f07cd8551d755a4076e94b9e620bc446a66bf54) --- .../src/android/net/cts/IpSecBaseTest.java | 11 + .../src/android/net/cts/IpSecManagerTest.java | 11 - .../cts/net/src/android/net/cts/TunUtils.java | 252 ++++++++++++++++++ 3 files changed, 263 insertions(+), 11 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/TunUtils.java diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 35d0f485e0..cbb9c195d0 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -52,6 +52,17 @@ public class IpSecBaseTest extends AndroidTestCase { protected static final int[] DIRECTIONS = new int[] {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}; + protected static final int TCP_HDRLEN_WITH_OPTIONS = 32; + protected static final int UDP_HDRLEN = 8; + protected static final int IP4_HDRLEN = 20; + protected static final int IP6_HDRLEN = 40; + + // Encryption parameters + protected static final int AES_GCM_IV_LEN = 8; + protected static final int AES_CBC_IV_LEN = 16; + protected static final int AES_GCM_BLK_SIZE = 4; + protected static final int AES_CBC_BLK_SIZE = 16; + protected static final byte[] TEST_DATA = "Best test data ever!".getBytes(); protected static final int DATA_BUFFER_LEN = 4096; protected static final int SOCK_TIMEOUT = 500; diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 3387064d41..e788d9602f 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -53,17 +53,6 @@ public class IpSecManagerTest extends IpSecBaseTest { private static final byte[] AEAD_KEY = getKey(288); - private static final int TCP_HDRLEN_WITH_OPTIONS = 32; - private static final int UDP_HDRLEN = 8; - private static final int IP4_HDRLEN = 20; - private static final int IP6_HDRLEN = 40; - - // Encryption parameters - private static final int AES_GCM_IV_LEN = 8; - private static final int AES_CBC_IV_LEN = 16; - private static final int AES_GCM_BLK_SIZE = 4; - private static final int AES_CBC_BLK_SIZE = 16; - protected void setUp() throws Exception { super.setUp(); } diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java new file mode 100644 index 0000000000..ca233ce1e8 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2018 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.system.OsConstants.IPPROTO_UDP; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import android.os.ParcelFileDescriptor; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +public class TunUtils { + private static final String TAG = TunUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + private static final int TIMEOUT = 100; + + private static final int IP4_PROTO_OFFSET = 9; + private static final int IP6_PROTO_OFFSET = 6; + + private static final int IP4_ADDR_OFFSET = 12; + private static final int IP4_ADDR_LEN = 4; + private static final int IP6_ADDR_OFFSET = 8; + private static final int IP6_ADDR_LEN = 16; + + // Not defined in OsConstants + private static final int IPPROTO_ESP = 50; + + private final ParcelFileDescriptor mTunFd; + private final List mPackets = new ArrayList<>(); + private final Thread mReaderThread; + + public TunUtils(ParcelFileDescriptor tunFd) { + mTunFd = tunFd; + + // Start background reader thread + mReaderThread = + new Thread( + () -> { + try { + // Loop will exit and thread will quit when tunFd is closed. + // Receiving either EOF or an exception will exit this reader loop. + // FileInputStream in uninterruptable, so there's no good way to + // ensure that this thread shuts down except upon FD closure. + while (true) { + byte[] intercepted = receiveFromTun(); + if (intercepted == null) { + // Exit once we've hit EOF + return; + } else if (intercepted.length > 0) { + // Only save packet if we've received any bytes. + synchronized (mPackets) { + mPackets.add(intercepted); + mPackets.notifyAll(); + } + } + } + } catch (IOException ignored) { + // Simply exit this reader thread + return; + } + }); + mReaderThread.start(); + } + + private byte[] receiveFromTun() throws IOException { + FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor()); + byte[] inBytes = new byte[DATA_BUFFER_LEN]; + int bytesRead = in.read(inBytes); + + if (bytesRead < 0) { + return null; // return null for EOF + } else if (bytesRead >= DATA_BUFFER_LEN) { + throw new IllegalStateException("Too big packet. Fragmentation unsupported"); + } + return Arrays.copyOf(inBytes, bytesRead); + } + + private byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { + synchronized (mPackets) { + for (int i = startIndex; i < mPackets.size(); i++) { + byte[] pkt = mPackets.get(i); + if (verifier.test(pkt)) { + return pkt; + } + } + } + return null; + } + + /** + * Checks if the specified bytes were ever sent in plaintext. + * + *

    Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like + * + * @param plaintext the plaintext bytes to check for + * @param startIndex the index in the list to check for + */ + public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { + Predicate verifier = + (pkt) -> { + return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) + != -1; + }; + return getFirstMatchingPacket(verifier, startIndex) != null; + } + + public byte[] getEspPacket(int spi, boolean encap, int startIndex) { + return getFirstMatchingPacket( + (pkt) -> { + return isEsp(pkt, spi, encap); + }, + startIndex); + } + + public byte[] awaitEspPacketNoPlaintext( + int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + long endTime = System.currentTimeMillis() + TIMEOUT; + int startIndex = 0; + + synchronized (mPackets) { + while (System.currentTimeMillis() < endTime) { + byte[] espPkt = getEspPacket(spi, useEncap, startIndex); + if (espPkt != null) { + // Validate packet size + assertEquals(expectedPacketSize, espPkt.length); + + // Always check plaintext from start + assertFalse(hasPlaintextPacket(plaintext, 0)); + return espPkt; // We've found the packet we're looking for. + } + + startIndex = mPackets.size(); + + // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout + long waitTimeout = endTime - System.currentTimeMillis(); + if (waitTimeout > 0) { + mPackets.wait(waitTimeout); + } + } + + fail("No such ESP packet found with SPI " + spi); + } + return null; + } + + private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { + // Check SPI byte by byte. + return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) + && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) + && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) + && pkt[espOffset + 3] == (byte) (spi & 0xff); + } + + private static boolean isEsp(byte[] pkt, int spi, boolean encap) { + if (isIpv6(pkt)) { + // IPv6 UDP encap not supported by kernels; assume non-encap. + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP + && isSpiEqual(pkt, IpSecBaseTest.IP6_HDRLEN, spi); + } else { + // Use default IPv4 header length (assuming no options) + if (encap) { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP + && isSpiEqual( + pkt, IpSecBaseTest.IP4_HDRLEN + IpSecBaseTest.UDP_HDRLEN, spi); + } else { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP + && isSpiEqual(pkt, IpSecBaseTest.IP4_HDRLEN, spi); + } + } + } + + private static boolean isIpv6(byte[] pkt) { + // First nibble shows IP version. 0x60 for IPv6 + return (pkt[0] & (byte) 0xF0) == (byte) 0x60; + } + + private static byte[] getReflectedPacket(byte[] pkt) { + byte[] reflected = Arrays.copyOf(pkt, pkt.length); + + if (isIpv6(pkt)) { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset + reflected, // dst + IP6_ADDR_OFFSET, // dst offset + IP6_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET, // src offset + reflected, // dst + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset + IP6_ADDR_LEN); // len + } else { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset + reflected, // dst + IP4_ADDR_OFFSET, // dst offset + IP4_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET, // src offset + reflected, // dst + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset + IP4_ADDR_LEN); // len + } + return reflected; + } + + /** Takes all captured packets, flips the src/dst, and re-injects them. */ + public void reflectPackets() throws IOException { + synchronized (mPackets) { + for (byte[] pkt : mPackets) { + injectPacket(getReflectedPacket(pkt)); + } + } + } + + public void injectPacket(byte[] pkt) throws IOException { + FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor()); + out.write(pkt); + out.flush(); + } +} From 2d2a1ab8f7341ba056e622afd98cbcd00501256d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 4 Apr 2019 17:20:38 -0700 Subject: [PATCH 0616/1415] Add utilities to generate packets This change adds utility methods to generate packets incrementally. It supports UDP, ESP, IPv4, IPv6 packet generation. For ESP, it exclusively does AES-CBC, HMAC-SHA256. Bug: 72950854 Test: This Change-Id: Icffeed2ebb2005d79faf04f48fd5126d1d6fb175 Merged-In: Icffeed2ebb2005d79faf04f48fd5126d1d6fb175 (cherry picked from commit 0e4743d56553d698ac45ae548f31019ea6e91541) --- .../src/android/net/cts/IpSecBaseTest.java | 11 - .../src/android/net/cts/IpSecManagerTest.java | 37 +- .../net/src/android/net/cts/PacketUtils.java | 460 ++++++++++++++++++ .../cts/net/src/android/net/cts/TunUtils.java | 16 +- 4 files changed, 483 insertions(+), 41 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/PacketUtils.java diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index cbb9c195d0..35d0f485e0 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -52,17 +52,6 @@ public class IpSecBaseTest extends AndroidTestCase { protected static final int[] DIRECTIONS = new int[] {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}; - protected static final int TCP_HDRLEN_WITH_OPTIONS = 32; - protected static final int UDP_HDRLEN = 8; - protected static final int IP4_HDRLEN = 20; - protected static final int IP6_HDRLEN = 40; - - // Encryption parameters - protected static final int AES_GCM_IV_LEN = 8; - protected static final int AES_CBC_IV_LEN = 16; - protected static final int AES_GCM_BLK_SIZE = 4; - protected static final int AES_CBC_BLK_SIZE = 16; - protected static final byte[] TEST_DATA = "Best test data ever!".getBytes(); protected static final int DATA_BUFFER_LEN = 4096; protected static final int SOCK_TIMEOUT = 500; diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index e788d9602f..60d1c03ee2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -16,6 +16,14 @@ package android.net.cts; +import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; +import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_GCM_IV_LEN; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.TCP_HDRLEN_WITH_TIMESTAMP_OPT; +import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertArrayEquals; @@ -421,19 +429,6 @@ public class IpSecManagerTest extends IpSecBaseTest { } } - /** Helper function to calculate expected ESP packet size. */ - private int calculateEspPacketSize( - int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { - final int ESP_HDRLEN = 4 + 4; // SPI + Seq# - final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length - payloadLen += cryptIvLength; // Initialization Vector - payloadLen += 2; // ESP trailer - - // Align to block size of encryption algorithm - payloadLen += (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; - return payloadLen + ESP_HDRLEN + ICV_LEN; - } - public void checkTransform( int protocol, String localAddress, @@ -474,7 +469,7 @@ public class IpSecManagerTest extends IpSecBaseTest { try (IpSecTransform transform = transformBuilder.buildTransportModeTransform(local, spi)) { if (protocol == IPPROTO_TCP) { - transportHdrLen = TCP_HDRLEN_WITH_OPTIONS; + transportHdrLen = TCP_HDRLEN_WITH_TIMESTAMP_OPT; checkTcp(transform, local, sendCount, useJavaSockets); } else if (protocol == IPPROTO_UDP) { transportHdrLen = UDP_HDRLEN; @@ -511,7 +506,7 @@ public class IpSecManagerTest extends IpSecBaseTest { int innerPacketSize = TEST_DATA.length + transportHdrLen + ipHdrLen; int outerPacketSize = - calculateEspPacketSize( + PacketUtils.calculateEspPacketSize( TEST_DATA.length + transportHdrLen, ivLen, blkSize, truncLenBits) + udpEncapLen + ipHdrLen; @@ -529,13 +524,13 @@ public class IpSecManagerTest extends IpSecBaseTest { // Add TCP ACKs for data packets if (protocol == IPPROTO_TCP) { int encryptedTcpPktSize = - calculateEspPacketSize(TCP_HDRLEN_WITH_OPTIONS, ivLen, blkSize, truncLenBits); + PacketUtils.calculateEspPacketSize( + TCP_HDRLEN_WITH_TIMESTAMP_OPT, ivLen, blkSize, truncLenBits); - - // Add data packet ACKs - expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount); - expectedInnerBytes += (TCP_HDRLEN_WITH_OPTIONS + ipHdrLen) * (sendCount); - expectedPackets += sendCount; + // Add data packet ACKs + expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount); + expectedInnerBytes += (TCP_HDRLEN_WITH_TIMESTAMP_OPT + ipHdrLen) * (sendCount); + expectedPackets += sendCount; } StatsChecker.waitForNumPackets(expectedPackets); diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java new file mode 100644 index 0000000000..6177827ba6 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/PacketUtils.java @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2018 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.system.OsConstants.IPPROTO_IPV6; +import static android.system.OsConstants.IPPROTO_UDP; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class PacketUtils { + private static final String TAG = PacketUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + + static final int IP4_HDRLEN = 20; + static final int IP6_HDRLEN = 40; + static final int UDP_HDRLEN = 8; + static final int TCP_HDRLEN = 20; + static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12; + + // Not defined in OsConstants + static final int IPPROTO_IPV4 = 4; + static final int IPPROTO_ESP = 50; + + // Encryption parameters + static final int AES_GCM_IV_LEN = 8; + static final int AES_CBC_IV_LEN = 16; + static final int AES_GCM_BLK_SIZE = 4; + static final int AES_CBC_BLK_SIZE = 16; + + // Encryption algorithms + static final String AES = "AES"; + static final String AES_CBC = "AES/CBC/NoPadding"; + static final String HMAC_SHA_256 = "HmacSHA256"; + + public interface Payload { + byte[] getPacketBytes(IpHeader header) throws Exception; + + void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception; + + short length(); + + int getProtocolId(); + } + + public abstract static class IpHeader { + + public final byte proto; + public final InetAddress srcAddr; + public final InetAddress dstAddr; + public final Payload payload; + + public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) { + this.proto = (byte) proto; + this.srcAddr = src; + this.dstAddr = dst; + this.payload = payload; + } + + public abstract byte[] getPacketBytes() throws Exception; + + public abstract int getProtocolId(); + } + + public static class Ip4Header extends IpHeader { + private short checksum; + + public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) { + super(proto, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer resultBuffer = buildHeader(); + payload.addPacketBytes(this, resultBuffer); + + return getByteArrayFromBuffer(resultBuffer); + } + + public ByteBuffer buildHeader() { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version, IHL + bb.put((byte) (0x45)); + + // DCSP, ECN + bb.put((byte) 0); + + // Total Length + bb.putShort((short) (IP4_HDRLEN + payload.length())); + + // Empty for Identification, Flags and Fragment Offset + bb.putShort((short) 0); + bb.put((byte) 0x40); + bb.put((byte) 0x00); + + // TTL + bb.put((byte) 64); + + // Protocol + bb.put(proto); + + // Header Checksum + final int ipChecksumOffset = bb.position(); + bb.putShort((short) 0); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + bb.putShort(ipChecksumOffset, calculateChecksum(bb)); + + return bb; + } + + private short calculateChecksum(ByteBuffer bb) { + int checksum = 0; + + // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit + // aligned, so no special cases needed for unaligned values. + ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer(); + while (shortBuffer.hasRemaining()) { + short val = shortBuffer.get(); + + // Wrap as needed + checksum = addAndWrapForChecksum(checksum, val); + } + + return onesComplement(checksum); + } + + public int getProtocolId() { + return IPPROTO_IPV4; + } + } + + public static class Ip6Header extends IpHeader { + public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) { + super(nextHeader, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version | Traffic Class (First 4 bits) + bb.put((byte) 0x60); + + // Traffic class (Last 4 bits), Flow Label + bb.put((byte) 0); + bb.put((byte) 0); + bb.put((byte) 0); + + // Payload Length + bb.putShort((short) payload.length()); + + // Next Header + bb.put(proto); + + // Hop Limit + bb.put((byte) 64); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + // Payload + payload.addPacketBytes(this, bb); + + return getByteArrayFromBuffer(bb); + } + + public int getProtocolId() { + return IPPROTO_IPV6; + } + } + + public static class BytePayload implements Payload { + public final byte[] payload; + + public BytePayload(byte[] payload) { + this.payload = payload; + } + + public int getProtocolId() { + return -1; + } + + public byte[] getPacketBytes(IpHeader header) { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) { + resultBuffer.put(payload); + } + + public short length() { + return (short) payload.length; + } + } + + public static class UdpHeader implements Payload { + + public final short srcPort; + public final short dstPort; + public final Payload payload; + + public UdpHeader(int srcPort, int dstPort, Payload payload) { + this.srcPort = (short) srcPort; + this.dstPort = (short) dstPort; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_UDP; + } + + public short length() { + return (short) (payload.length() + 8); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + // Source, Destination port + resultBuffer.putShort(srcPort); + resultBuffer.putShort(dstPort); + + // Payload Length + resultBuffer.putShort(length()); + + // Get payload bytes for checksum + payload + ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + payload.addPacketBytes(header, payloadBuffer); + byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer); + + // Checksum + resultBuffer.putShort(calculateChecksum(header, payloadBytes)); + + // Payload + resultBuffer.put(payloadBytes); + } + + private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception { + int newChecksum = 0; + ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer(); + ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer(); + + while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) { + short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get(); + + // Wrap as needed + newChecksum = addAndWrapForChecksum(newChecksum, val); + } + + // Add pseudo-header values. Proto is 0-padded, so just use the byte. + newChecksum = addAndWrapForChecksum(newChecksum, header.proto); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + newChecksum = addAndWrapForChecksum(newChecksum, srcPort); + newChecksum = addAndWrapForChecksum(newChecksum, dstPort); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + + ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer(); + while (payloadShortBuffer.hasRemaining()) { + newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get()); + } + if (payload.length() % 2 != 0) { + newChecksum = + addAndWrapForChecksum( + newChecksum, (payloadBytes[payloadBytes.length - 1] << 8)); + } + + return onesComplement(newChecksum); + } + } + + public static class EspHeader implements Payload { + public final int nextHeader; + public final int spi; + public final int seqNum; + public final byte[] key; + public final byte[] payload; + + /** + * Generic constructor for ESP headers. + * + *

    For Tunnel mode, payload will be a full IP header + attached payloads + * + *

    For Transport mode, payload will be only the attached payloads, but with the checksum + * calculated using the pre-encryption IP header + */ + public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) { + this.nextHeader = nextHeader; + this.spi = spi; + this.seqNum = seqNum; + this.key = key; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_ESP; + } + + public short length() { + // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len) + return (short) + calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + espPayloadBuffer.putInt(spi); + espPayloadBuffer.putInt(seqNum); + espPayloadBuffer.put(getCiphertext(key)); + + espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16); + resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer)); + } + + private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException { + Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256); + SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256); + sha256HMAC.init(authKey); + + return sha256HMAC.doFinal(authenticatedSection); + } + + /** + * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks + * + *

    The ciphertext does NOT include the SPI/Sequence numbers, or the ICV. + */ + private byte[] getCiphertext(byte[] key) throws GeneralSecurityException { + int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE); + ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen); + paddedPayload.put(payload); + + // Add padding - consecutive integers from 0x01 + int pad = 1; + while (paddedPayload.position() < paddedPayload.limit()) { + paddedPayload.put((byte) pad++); + } + + paddedPayload.position(paddedPayload.limit() - 2); + paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length + paddedPayload.put((byte) nextHeader); + + // Generate Initialization Vector + byte[] iv = new byte[AES_CBC_IV_LEN]; + new SecureRandom().nextBytes(iv); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); + + // Encrypt payload + Cipher cipher = Cipher.getInstance(AES_CBC); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload)); + + // Build ciphertext + ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length); + cipherText.put(iv); + cipherText.put(encrypted); + + return getByteArrayFromBuffer(cipherText); + } + } + + private static int addAndWrapForChecksum(int currentChecksum, int value) { + currentChecksum += value & 0x0000ffff; + + // Wrap anything beyond the first 16 bits, and add to lower order bits + return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff); + } + + private static short onesComplement(int val) { + val = (val >>> 16) + (val & 0xffff); + + if (val == 0) return 0; + return (short) ((~val) & 0xffff); + } + + public static int calculateEspPacketSize( + int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { + final int ESP_HDRLEN = 4 + 4; // SPI + Seq# + final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length + payloadLen += cryptIvLength; // Initialization Vector + + // Align to block size of encryption algorithm + payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize); + return payloadLen + ESP_HDRLEN + ICV_LEN; + } + + private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) { + payloadLen += 2; // ESP trailer + + // Align to block size of encryption algorithm + return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize); + } + + private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) { + return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; + } + + private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) { + return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); + } + + /* + * Debug printing + */ + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(hexArray[b >>> 4]); + sb.append(hexArray[b & 0x0F]); + sb.append(' '); + } + return sb.toString(); + } +} diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index ca233ce1e8..4d5533fc62 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -16,6 +16,10 @@ package android.net.cts; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.IPPROTO_ESP; +import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -46,9 +50,6 @@ public class TunUtils { private static final int IP6_ADDR_OFFSET = 8; private static final int IP6_ADDR_LEN = 16; - // Not defined in OsConstants - private static final int IPPROTO_ESP = 50; - private final ParcelFileDescriptor mTunFd; private final List mPackets = new ArrayList<>(); private final Thread mReaderThread; @@ -178,17 +179,14 @@ public class TunUtils { private static boolean isEsp(byte[] pkt, int spi, boolean encap) { if (isIpv6(pkt)) { // IPv6 UDP encap not supported by kernels; assume non-encap. - return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP - && isSpiEqual(pkt, IpSecBaseTest.IP6_HDRLEN, spi); + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); } else { // Use default IPv4 header length (assuming no options) if (encap) { return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP - && isSpiEqual( - pkt, IpSecBaseTest.IP4_HDRLEN + IpSecBaseTest.UDP_HDRLEN, spi); + && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi); } else { - return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP - && isSpiEqual(pkt, IpSecBaseTest.IP4_HDRLEN, spi); + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi); } } } From 817d192bc4399ab5f457eaf8c604977e9017ec25 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Apr 2019 10:15:26 -0700 Subject: [PATCH 0617/1415] Add IPsec Tunnel mode data tests This change adds single-direction tests for the IPsec Tunnel Mode API. In the outbound direction, TUNs are used to capture outgoing packets, and values are inspected. In the inbound direction, packets are built manually, using the PacketUtils framework. Additional testing for end-to-end integration tests will follow in aosp/941021 using packet reflection via the TUN. Bug: 72950854 Test: This; passing Change-Id: Ic4181fc857fa880db5553314efa914f870dbe87c Merged-In: Ic4181fc857fa880db5553314efa914f870dbe87c (cherry picked from commit d708a4c217f13c9028427d98031394f0933482bf) --- .../src/android/net/cts/IpSecBaseTest.java | 43 +- .../net/cts/IpSecManagerTunnelTest.java | 694 ++++++++++++++++-- .../cts/net/src/android/net/cts/TunUtils.java | 7 + 3 files changed, 661 insertions(+), 83 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 35d0f485e0..087dbdaec3 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -28,11 +28,12 @@ import android.system.OsConstants; import android.test.AndroidTestCase; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; -import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -72,8 +73,14 @@ public class IpSecBaseTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); - mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE); - mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mISM = + (IpSecManager) + InstrumentationRegistry.getContext() + .getSystemService(Context.IPSEC_SERVICE); + mCM = + (ConnectivityManager) + InstrumentationRegistry.getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); } protected static byte[] getKey(int bitLength) { @@ -195,6 +202,17 @@ public class IpSecBaseTest extends AndroidTestCase { public static class JavaUdpSocket implements GenericUdpSocket { public final DatagramSocket mSocket; + public JavaUdpSocket(InetAddress localAddr, int port) { + try { + mSocket = new DatagramSocket(port, localAddr); + mSocket.setSoTimeout(SOCK_TIMEOUT); + } catch (SocketException e) { + // Fail loudly if we can't set up sockets properly. And without the timeout, we + // could easily end up in an endless wait. + throw new RuntimeException(e); + } + } + public JavaUdpSocket(InetAddress localAddr) { try { mSocket = new DatagramSocket(0, localAddr); @@ -425,26 +443,25 @@ public class IpSecBaseTest extends AndroidTestCase { } protected static IpSecTransform buildIpSecTransform( - Context mContext, + Context context, IpSecManager.SecurityParameterIndex spi, IpSecManager.UdpEncapsulationSocket encapSocket, InetAddress remoteAddr) throws Exception { - String localAddr = (remoteAddr instanceof Inet4Address) ? IPV4_LOOPBACK : IPV6_LOOPBACK; IpSecTransform.Builder builder = - new IpSecTransform.Builder(mContext) - .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) - .setAuthentication( - new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, - AUTH_KEY, - AUTH_KEY.length * 4)); + new IpSecTransform.Builder(context) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 4)); if (encapSocket != null) { builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); } - return builder.buildTransportModeTransform(InetAddress.getByName(localAddr), spi); + return builder.buildTransportModeTransform(remoteAddr, spi); } private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index c8c99f4a37..e8c0a7a4b2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -16,174 +16,728 @@ package android.net.cts; +import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.IpSecManager.UdpEncapsulationSocket; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; +import static android.net.cts.PacketUtils.BytePayload; +import static android.net.cts.PacketUtils.EspHeader; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.Ip4Header; +import static android.net.cts.PacketUtils.Ip6Header; +import static android.net.cts.PacketUtils.IpHeader; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.net.cts.PacketUtils.UdpHeader; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import android.app.AppOpsManager; +import android.content.Context; import android.content.pm.PackageManager; +import android.net.ConnectivityManager; import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecTransform; +import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkRequest; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.cts.PacketUtils.Payload; +import android.os.Binder; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.compatibility.common.util.SystemUtil; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) public class IpSecManagerTunnelTest extends IpSecBaseTest { - private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName(); - private static final int IP4_PREFIX_LEN = 24; - private static final int IP6_PREFIX_LEN = 48; - private static final InetAddress OUTER_ADDR4 = InetAddress.parseNumericAddress("192.0.2.0"); - private static final InetAddress OUTER_ADDR6 = - InetAddress.parseNumericAddress("2001:db8:f00d::1"); - private static final InetAddress INNER_ADDR4 = InetAddress.parseNumericAddress("10.0.0.1"); - private static final InetAddress INNER_ADDR6 = - InetAddress.parseNumericAddress("2001:db8:d00d::1"); - private Network mUnderlyingNetwork; - private Network mIpSecNetwork; + private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); + private static final InetAddress REMOTE_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.2"); + private static final InetAddress LOCAL_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::1"); + private static final InetAddress REMOTE_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::2"); - protected void setUp() throws Exception { + private static final InetAddress LOCAL_INNER_4 = + InetAddress.parseNumericAddress("198.51.100.1"); + private static final InetAddress REMOTE_INNER_4 = + InetAddress.parseNumericAddress("198.51.100.2"); + private static final InetAddress LOCAL_INNER_6 = + InetAddress.parseNumericAddress("2001:db8:2::1"); + private static final InetAddress REMOTE_INNER_6 = + InetAddress.parseNumericAddress("2001:db8:2::2"); + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 128; + + private static final int TIMEOUT_MS = 500; + + // Static state to reduce setup/teardown + private static ConnectivityManager sCM; + private static TestNetworkManager sTNM; + private static ParcelFileDescriptor sTunFd; + private static TestNetworkCallback sTunNetworkCallback; + private static Network sTunNetwork; + private static TunUtils sTunUtils; + + private static Context sContext = InstrumentationRegistry.getContext(); + private static IBinder sBinder = new Binder(); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and + // a standard permission is insufficient. So we shell out the appop, to give us the + // right appop permissions. + setAppop(OP_MANAGE_IPSEC_TUNNELS, true); + + TestNetworkInterface testIntf = + sTNM.createTunInterface( + new LinkAddress[] { + new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), + new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN) + }); + + sTunFd = testIntf.getFileDescriptor(); + sTunNetworkCallback = setupAndGetTestNetwork(testIntf.getInterfaceName()); + sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); + + sTunUtils = new TunUtils(sTunFd); + } + + @Before + public void setUp() throws Exception { super.setUp(); + + // Set to true before every run; some tests flip this. + setAppop(OP_MANAGE_IPSEC_TUNNELS, true); + + // Clear sTunUtils state + sTunUtils.reset(); } - protected void tearDown() { - setAppop(false); + @AfterClass + public static void tearDownAfterClass() throws Exception { + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); + + sCM.unregisterNetworkCallback(sTunNetworkCallback); + + sTNM.teardownTestNetwork(sTunNetwork); + sTunFd.close(); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); } - private boolean hasTunnelsFeature() { - return getContext() - .getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + private static boolean hasTunnelsFeature() { + return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); } - private void setAppop(boolean allow) { - // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted by the - // telephony framework, and the only permission that is sufficient is NETWORK_STACK. So we - // shell out the appop manager, to give us the right appop permissions. - String cmd = - "appops set " - + mContext.getPackageName() - + " MANAGE_IPSEC_TUNNELS " - + (allow ? "allow" : "deny"); - SystemUtil.runShellCommand(cmd); + private static void setAppop(int appop, boolean allow) { + String opName = AppOpsManager.opToName(appop); + for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { + String cmd = + String.format( + "appops set %s %s %s", + pkg, // Package name + opName, // Appop + (allow ? "allow" : "deny")); // Action + SystemUtil.runShellCommand(cmd); + } } - public void testSecurityExceptionsCreateTunnelInterface() throws Exception { + private static TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception { + // Build a network request + NetworkRequest nr = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_TEST) + .removeCapability(NET_CAPABILITY_TRUSTED) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .setNetworkSpecifier(ifname) + .build(); + + TestNetworkCallback cb = new TestNetworkCallback(); + sCM.requestNetwork(nr, cb); + + // Setup the test network after network request is filed to prevent Network from being + // reaped due to no requests matching it. + sTNM.setupTestNetwork(ifname, sBinder); + + return cb; + } + + @Test + public void testSecurityExceptionCreateTunnelInterfaceWithoutAppop() throws Exception { if (!hasTunnelsFeature()) return; // Ensure we don't have the appop. Permission is not requested in the Manifest - setAppop(false); + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); // Security exceptions are thrown regardless of IPv4/IPv6. Just test one try { - mISM.createIpSecTunnelInterface(OUTER_ADDR6, OUTER_ADDR6, mUnderlyingNetwork); + mISM.createIpSecTunnelInterface(LOCAL_INNER_6, REMOTE_INNER_6, sTunNetwork); fail("Did not throw SecurityException for Tunnel creation without appop"); } catch (SecurityException expected) { } } - public void testSecurityExceptionsBuildTunnelTransform() throws Exception { + @Test + public void testSecurityExceptionBuildTunnelTransformWithoutAppop() throws Exception { if (!hasTunnelsFeature()) return; // Ensure we don't have the appop. Permission is not requested in the Manifest - setAppop(false); + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); // Security exceptions are thrown regardless of IPv4/IPv6. Just test one try (IpSecManager.SecurityParameterIndex spi = - mISM.allocateSecurityParameterIndex(OUTER_ADDR4); + mISM.allocateSecurityParameterIndex(LOCAL_INNER_4); IpSecTransform transform = - new IpSecTransform.Builder(mContext) - .buildTunnelModeTransform(OUTER_ADDR4, spi)) { + new IpSecTransform.Builder(sContext) + .buildTunnelModeTransform(REMOTE_INNER_4, spi)) { fail("Did not throw SecurityException for Transform creation without appop"); } catch (SecurityException expected) { } } - private void checkTunnel(InetAddress inner, InetAddress outer, boolean useEncap) + /* Test runnables for callbacks after IPsec tunnels are set up. */ + private interface TestRunnable { + void run(Network ipsecNetwork) throws Exception; + } + + private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CompletableFuture futureNetwork = new CompletableFuture<>(); + + @Override + public void onAvailable(Network network) { + futureNetwork.complete(network); + } + + public Network getNetworkBlocking() throws Exception { + return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + private int getPacketSize( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) { + int expectedPacketSize = TEST_DATA.length + UDP_HDRLEN; + + // Inner Transport mode packet size + if (transportInTunnelMode) { + expectedPacketSize = + PacketUtils.calculateEspPacketSize( + expectedPacketSize, + AES_CBC_IV_LEN, + AES_CBC_BLK_SIZE, + AUTH_KEY.length * 4); + } + + // Inner IP Header + expectedPacketSize += innerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN; + + // Tunnel mode transform size + expectedPacketSize = + PacketUtils.calculateEspPacketSize( + expectedPacketSize, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, AUTH_KEY.length * 4); + + // UDP encap size + expectedPacketSize += useEncap ? UDP_HDRLEN : 0; + + // Outer IP Header + expectedPacketSize += outerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN; + + return expectedPacketSize; + } + + private interface TestRunnableFactory { + TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) + throws Exception; + } + + private class OutputTestRunnableFactory implements TestRunnableFactory { + public TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) { + return new TestRunnable() { + @Override + public void run(Network ipsecNetwork) throws Exception { + // Build a socket and send traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, inTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, outTransportTransform); + } + + socket.sendTo(TEST_DATA, remoteInner, socket.getPort()); + + // Verify that an encrypted packet is sent. As of right now, checking encrypted + // body is not possible, due to our not knowing some of the fields of the + // inner IP header (flow label, flags, etc) + sTunUtils.awaitEspPacketNoPlaintext( + spi, TEST_DATA, encapPort != 0, expectedPacketSize); + + socket.close(); + } + }; + } + } + + private class InputPacketGeneratorTestRunnableFactory implements TestRunnableFactory { + public TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) + throws Exception { + return new TestRunnable() { + @Override + public void run(Network ipsecNetwork) throws Exception { + // Build a socket and receive traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner); + // JavaUdpSocket socket = new JavaUdpSocket(localInner, socketPort.get()); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform); + } + + byte[] pkt; + if (transportInTunnelMode) { + pkt = + getTransportInTunnelModePacket( + spi, + spi, + remoteInner, + localInner, + remoteOuter, + localOuter, + socket.getPort(), + encapPort); + } else { + pkt = + getTunnelModePacket( + spi, + remoteInner, + localInner, + remoteOuter, + localOuter, + socket.getPort(), + encapPort); + } + sTunUtils.injectPacket(pkt); + + // Receive packet from socket, and validate + receiveAndValidatePacket(socket); + + socket.close(); + } + }; + } + } + + private void checkTunnelOutput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new OutputTestRunnableFactory()); + } + + private void checkTunnelInput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new InputPacketGeneratorTestRunnableFactory()); + } + + public void checkTunnel( + int innerFamily, + int outerFamily, + boolean useEncap, + boolean transportInTunnelMode, + TestRunnableFactory factory) throws Exception { if (!hasTunnelsFeature()) return; - setAppop(true); - int innerPrefixLen = inner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; - try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(outer); + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + // Re-uses the same SPI to ensure that even in cases of symmetric SPIs shared across tunnel + // and transport mode, packets are encrypted/decrypted properly based on the src/dst. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + buildTunnelAndNetwork( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + factory.getTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + expectedPacketSize)); + } + } + + private void buildTunnelAndNetwork( + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + int spi, + UdpEncapsulationSocket encapSocket, + TestRunnable test) + throws Exception { + int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; + TestNetworkCallback testNetworkCb = null; + + try (IpSecManager.SecurityParameterIndex inSpi = + mISM.allocateSecurityParameterIndex(localOuter, spi); + IpSecManager.SecurityParameterIndex outSpi = + mISM.allocateSecurityParameterIndex(remoteOuter, spi); IpSecManager.IpSecTunnelInterface tunnelIntf = - mISM.createIpSecTunnelInterface(outer, outer, mCM.getActiveNetwork()); - IpSecManager.UdpEncapsulationSocket encapSocket = - mISM.openUdpEncapsulationSocket()) { + mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) { + // Build the test network + tunnelIntf.addAddress(localInner, innerPrefixLen); + testNetworkCb = setupAndGetTestNetwork(tunnelIntf.getInterfaceName()); + Network testNetwork = testNetworkCb.getNetworkBlocking(); - IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext); + // Check interface was created + NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); + assertNotNull(netIntf); + + // Check addresses + List intfAddrs = netIntf.getInterfaceAddresses(); + assertEquals(1, intfAddrs.size()); + assertEquals(localInner, intfAddrs.get(0).getAddress()); + assertEquals(innerPrefixLen, intfAddrs.get(0).getNetworkPrefixLength()); + + // Configure Transform parameters + IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); transformBuilder.setEncryption( new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)); transformBuilder.setAuthentication( new IpSecAlgorithm( IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4)); - if (useEncap) { + if (encapSocket != null) { transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); } - // Check transform application - try (IpSecTransform transform = transformBuilder.buildTunnelModeTransform(outer, spi)) { - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, transform); - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, transform); + // Apply transform and check that traffic is properly encrypted + try (IpSecTransform inTransform = + transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi); + IpSecTransform outTransform = + transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) { + mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, inTransform); + mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, outTransform); - // TODO: Test to ensure that send/receive works with these transforms. + test.run(testNetwork); } - // Check interface was created - NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNotNull(netIntf); - - // Add addresses and check - tunnelIntf.addAddress(inner, innerPrefixLen); - for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) { - assertEquals(intfAddr.getAddress(), inner); - assertEquals(intfAddr.getNetworkPrefixLength(), innerPrefixLen); - } + // Teardown the test network + sTNM.teardownTestNetwork(testNetwork); // Remove addresses and check - tunnelIntf.removeAddress(inner, innerPrefixLen); + tunnelIntf.removeAddress(localInner, innerPrefixLen); + netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertTrue(netIntf.getInterfaceAddresses().isEmpty()); // Check interface was cleaned up tunnelIntf.close(); netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertNull(netIntf); + } finally { + if (testNetworkCb != null) { + sCM.unregisterNetworkCallback(testNetworkCb); + } } } - /* - * Create, add and remove addresses, then teardown tunnel - */ + private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { + byte[] socketResponseBytes = socket.receive(); + assertArrayEquals(TEST_DATA, socketResponseBytes); + } + + private int getRandomSpi(InetAddress localOuter, InetAddress remoteOuter) throws Exception { + // Try to allocate both in and out SPIs using the same requested SPI value. + try (IpSecManager.SecurityParameterIndex inSpi = + mISM.allocateSecurityParameterIndex(localOuter); + IpSecManager.SecurityParameterIndex outSpi = + mISM.allocateSecurityParameterIndex(remoteOuter, inSpi.getSpi()); ) { + return inSpi.getSpi(); + } + } + + private IpHeader getIpHeader(int protocol, InetAddress src, InetAddress dst, Payload payload) { + if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { + throw new IllegalArgumentException("Invalid src/dst address combination"); + } + + if (src instanceof Inet6Address) { + return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); + } else { + return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); + } + } + + private EspHeader buildTransportModeEspPacket( + int spi, InetAddress src, InetAddress dst, int port, Payload payload) throws Exception { + IpHeader preEspIpHeader = getIpHeader(payload.getProtocolId(), src, dst, payload); + + return new EspHeader( + payload.getProtocolId(), + spi, + 1, // sequence number + CRYPT_KEY, // Same key for auth and crypt + payload.getPacketBytes(preEspIpHeader)); + } + + private EspHeader buildTunnelModeEspPacket( + int spi, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort, + Payload payload) + throws Exception { + IpHeader innerIp = getIpHeader(payload.getProtocolId(), srcInner, dstInner, payload); + return new EspHeader( + innerIp.getProtocolId(), + spi, + 1, // sequence number + CRYPT_KEY, // Same key for auth and crypt + innerIp.getPacketBytes()); + } + + private IpHeader maybeEncapPacket( + InetAddress src, InetAddress dst, int encapPort, EspHeader espPayload) + throws Exception { + + Payload payload = espPayload; + if (encapPort != 0) { + payload = new UdpHeader(encapPort, encapPort, espPayload); + } + + return getIpHeader(payload.getProtocolId(), src, dst, payload); + } + + private byte[] getTunnelModePacket( + int spi, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort) + throws Exception { + UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); + + EspHeader espPayload = + buildTunnelModeEspPacket( + spi, srcInner, dstInner, srcOuter, dstOuter, port, encapPort, udp); + return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); + } + + private byte[] getTransportInTunnelModePacket( + int spiInner, + int spiOuter, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort) + throws Exception { + UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); + + EspHeader espPayload = buildTransportModeEspPacket(spiInner, srcInner, dstInner, port, udp); + espPayload = + buildTunnelModeEspPacket( + spiOuter, + srcInner, + dstInner, + srcOuter, + dstOuter, + port, + encapPort, + espPayload); + return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); + } + + // Transport-in-Tunnel mode tests + @Test + public void testTransportInTunnelModeV4InV4() throws Exception { + checkTunnelOutput(AF_INET, AF_INET, false, true); + checkTunnelInput(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { + checkTunnelOutput(AF_INET, AF_INET, true, true); + checkTunnelInput(AF_INET, AF_INET, true, true); + } + + @Test + public void testTransportInTunnelModeV4InV6() throws Exception { + checkTunnelOutput(AF_INET, AF_INET6, false, true); + checkTunnelInput(AF_INET, AF_INET6, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4() throws Exception { + checkTunnelOutput(AF_INET6, AF_INET, false, true); + checkTunnelInput(AF_INET6, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { + checkTunnelOutput(AF_INET6, AF_INET, true, true); + checkTunnelInput(AF_INET6, AF_INET, true, true); + } + + @Test + public void testTransportInTunnelModeV6InV6() throws Exception { + checkTunnelOutput(AF_INET, AF_INET6, false, true); + checkTunnelInput(AF_INET, AF_INET6, false, true); + } + + // Tunnel mode tests + @Test public void testTunnelV4InV4() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR4, false); + checkTunnelOutput(AF_INET, AF_INET, false, false); + checkTunnelInput(AF_INET, AF_INET, false, false); } + @Test public void testTunnelV4InV4UdpEncap() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR4, true); + checkTunnelOutput(AF_INET, AF_INET, true, false); + checkTunnelInput(AF_INET, AF_INET, true, false); } + @Test public void testTunnelV4InV6() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR6, false); + checkTunnelOutput(AF_INET, AF_INET6, false, false); + checkTunnelInput(AF_INET, AF_INET6, false, false); } + @Test public void testTunnelV6InV4() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR4, false); + checkTunnelOutput(AF_INET6, AF_INET, false, false); + checkTunnelInput(AF_INET6, AF_INET, false, false); } + @Test public void testTunnelV6InV4UdpEncap() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR4, true); + checkTunnelOutput(AF_INET6, AF_INET, true, false); + checkTunnelInput(AF_INET6, AF_INET, true, false); } + @Test public void testTunnelV6InV6() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR6, false); + checkTunnelOutput(AF_INET6, AF_INET6, false, false); + checkTunnelInput(AF_INET6, AF_INET6, false, false); } } diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index 4d5533fc62..a0307137a5 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -247,4 +247,11 @@ public class TunUtils { out.write(pkt); out.flush(); } + + /** Resets the intercepted packets. */ + public void reset() throws IOException { + synchronized (mPackets) { + mPackets.clear(); + } + } } From 084c8b47b674afd17ae1f648b1d0f16006812bbf Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 10 May 2019 01:16:10 -0700 Subject: [PATCH 0618/1415] Enforce IPsec Tunnel mode for Android Q This commit adds a second condition to whether the device is expected to have the tunnel mode feature. If a device's first API/launch version is Q or above, require IPsec tunnels Bug: 72950854 Test: Ran on device with first API level < Q and == Q. Change-Id: I7b849ad24a04b6b7899a80f1856236b5ceb5a839 --- .../cts/net/src/android/net/cts/IpSecManagerTunnelTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index e8c0a7a4b2..6e96682b68 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -55,8 +55,10 @@ import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.cts.PacketUtils.Payload; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.SystemProperties; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -167,7 +169,9 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } private static boolean hasTunnelsFeature() { - return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + || SystemProperties.getInt("ro.product.first_api_level", 0) + >= Build.VERSION_CODES.Q; } private static void setAppop(int appop, boolean allow) { From fbbb9c9c04c7323ba25142501885e24a705f8931 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 10 May 2019 11:05:43 -0700 Subject: [PATCH 0619/1415] Enforce IPsec Tunnel mode for Android Q This commit adds a second condition to whether the device is expected to have the tunnel mode feature. If a device's first API/launch version is Q or above, require IPsec tunnels Bug: 72950854 Test: Ran on device with first API level < Q and == Q. Merged-In: I545444bb483b0f5de45d00a07dc45aeb9e9cbdf7 Change-Id: I7b849ad24a04b6b7899a80f1856236b5ceb5a839 (cherry picked from commit d2465991d92ff4d8425c0f620ab8032609312049) --- .../cts/net/src/android/net/cts/IpSecManagerTunnelTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index e8c0a7a4b2..6e96682b68 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -55,8 +55,10 @@ import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.cts.PacketUtils.Payload; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.SystemProperties; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -167,7 +169,9 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } private static boolean hasTunnelsFeature() { - return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + || SystemProperties.getInt("ro.product.first_api_level", 0) + >= Build.VERSION_CODES.Q; } private static void setAppop(int appop, boolean allow) { From 0d08e91fe7c2112f44bc12c4d0d00b386e9bebd7 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 10 May 2019 12:41:42 -0700 Subject: [PATCH 0620/1415] Convert IPsec tests to JUnit4 This patch fixes an incompatibility where some tests in the same hierarchy were using Junit3, and other Junit4 No functional test changes made Bug: 72950854 Test: Ran on devices, working Change-Id: I79d231e202ba25ad5f57b44b387bebd7f012aa95 --- .../src/android/net/cts/IpSecBaseTest.java | 21 ++++- .../src/android/net/cts/IpSecManagerTest.java | 81 ++++++++++++++++++- .../net/cts/IpSecManagerTunnelTest.java | 2 + 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 087dbdaec3..858891f82b 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -25,10 +25,10 @@ import android.net.IpSecManager; import android.net.IpSecTransform; import android.system.Os; import android.system.OsConstants; -import android.test.AndroidTestCase; import android.util.Log; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import java.io.FileDescriptor; import java.io.IOException; @@ -43,7 +43,12 @@ import java.net.SocketException; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; -public class IpSecBaseTest extends AndroidTestCase { +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class IpSecBaseTest { private static final String TAG = IpSecBaseTest.class.getSimpleName(); @@ -70,9 +75,11 @@ public class IpSecBaseTest extends AndroidTestCase { protected ConnectivityManager mCM; protected IpSecManager mISM; + protected Context mContext; - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getContext(); mISM = (IpSecManager) InstrumentationRegistry.getContext() @@ -471,6 +478,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testJavaTcpSocketPair() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -481,6 +489,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testJavaUdpSocketPair() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -492,6 +501,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testJavaUdpSocketPairUnconnected() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -503,6 +513,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testNativeTcpSocketPair() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -514,6 +525,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testNativeUdpSocketPair() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -525,6 +537,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testNativeUdpSocketPairUnconnected() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 60d1c03ee2..8d5a0684a1 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -27,7 +27,9 @@ import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.net.IpSecAlgorithm; import android.net.IpSecManager; @@ -37,6 +39,8 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import androidx.test.runner.AndroidJUnit4; + import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramPacket; @@ -45,6 +49,11 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) public class IpSecManagerTest extends IpSecBaseTest { private static final String TAG = IpSecManagerTest.class.getSimpleName(); @@ -61,7 +70,9 @@ public class IpSecManagerTest extends IpSecBaseTest { private static final byte[] AEAD_KEY = getKey(288); - protected void setUp() throws Exception { + @Before + @Override + public void setUp() throws Exception { super.setUp(); } @@ -71,6 +82,7 @@ public class IpSecManagerTest extends IpSecBaseTest { * Realloc the same SPI that was specifically created (expect SpiUnavailable) * Close SPIs */ + @Test public void testAllocSpi() throws Exception { for (InetAddress addr : GOOGLE_DNS_LIST) { IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null; @@ -222,6 +234,7 @@ public class IpSecManagerTest extends IpSecBaseTest { * release transform * send data (expect exception) */ + @Test public void testCreateTransform() throws Exception { InetAddress localAddr = InetAddress.getByName(IPV4_LOOPBACK); IpSecManager.SecurityParameterIndex spi = @@ -591,6 +604,7 @@ public class IpSecManagerTest extends IpSecBaseTest { } } + @Test public void testIkeOverUdpEncapSocket() throws Exception { // IPv6 not supported for UDP-encap-ESP InetAddress local = InetAddress.getByName(IPV4_LOOPBACK); @@ -649,24 +663,28 @@ public class IpSecManagerTest extends IpSecBaseTest { // checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1000); // } + @Test public void testInterfaceCountersUdp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1000, false); } + @Test public void testInterfaceCountersUdp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1000, false); } + @Test public void testInterfaceCountersUdp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1000, false); } + @Test public void testAesCbcHmacMd5Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -674,6 +692,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacMd5Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -681,6 +700,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacMd5Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -688,6 +708,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacMd5Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -695,6 +716,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha1Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -702,6 +724,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha1Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -709,6 +732,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha1Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -716,6 +740,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha1Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -723,6 +748,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha256Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -730,6 +756,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha256Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -737,6 +764,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha256Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -744,6 +772,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha256Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -751,6 +780,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha384Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -758,6 +788,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha384Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -765,6 +796,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha384Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -772,6 +804,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha384Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -779,6 +812,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha512Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -786,6 +820,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha512Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -793,6 +828,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha512Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -800,6 +836,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha512Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -807,6 +844,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesGcm64Tcp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -814,6 +852,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm64Tcp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -821,6 +860,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm64Udp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -828,6 +868,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm64Udp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -835,6 +876,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm96Tcp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -842,6 +884,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm96Tcp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -849,6 +892,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm96Udp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -856,6 +900,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm96Udp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -863,6 +908,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm128Tcp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -870,6 +916,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm128Tcp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -877,6 +924,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm128Udp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -884,6 +932,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm128Udp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -891,6 +940,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesCbcHmacMd5Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -898,6 +948,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacMd5Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -905,6 +956,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha1Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -912,6 +964,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha1Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -919,6 +972,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha256Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -926,6 +980,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha256Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -933,6 +988,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha384Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -940,6 +996,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha384Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -947,6 +1004,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha512Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -954,6 +1012,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha512Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -961,6 +1020,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesGcm64Tcp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -968,6 +1028,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm64Udp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -975,6 +1036,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm96Tcp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -982,6 +1044,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm96Udp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -989,6 +1052,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm128Tcp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -996,6 +1060,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm128Udp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -1003,78 +1068,91 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testCryptUdp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, false); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, true); } + @Test public void testAuthUdp4() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, false); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, true); } + @Test public void testCryptUdp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, false); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, true); } + @Test public void testAuthUdp6() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, false); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, true); } + @Test public void testCryptTcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, false); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, true); } + @Test public void testAuthTcp4() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, false); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, true); } + @Test public void testCryptTcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false); checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, true); } + @Test public void testAuthTcp6() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false); checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, true); } + @Test public void testCryptUdp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, false); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, true); } + @Test public void testAuthUdp4UdpEncap() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, false); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, true); } + @Test public void testCryptTcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, false); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, true); } + @Test public void testAuthTcp4UdpEncap() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, false); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, true); } + @Test public void testOpenUdpEncapSocketSpecificPort() throws Exception { IpSecManager.UdpEncapsulationSocket encapSocket = null; int port = -1; @@ -1103,6 +1181,7 @@ public class IpSecManagerTest extends IpSecBaseTest { assertTrue("Returned invalid port", encapSocket.getPort() == port); } + @Test public void testOpenUdpEncapSocketRandomPort() throws Exception { try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { assertTrue("Returned invalid port", encapSocket.getPort() != 0); diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index e8c0a7a4b2..9c94dc993a 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -40,6 +40,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.app.AppOpsManager; import android.content.Context; @@ -142,6 +143,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } @Before + @Override public void setUp() throws Exception { super.setUp(); From b41bc72ea31ddab47c483cf23bf4f212f8368a7e Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 2 Apr 2019 11:36:14 +0800 Subject: [PATCH 0621/1415] [KA14] add cts for keepalive limit test. Per SDK requirement, OEM is required to support minimum number of concurrent keepalives. Implement CTS to verify this. Bug: 129371366 Test: atest android.net.cts .ConnectivityManagerTest#testSocketKeepaliveLimit --generate-new-metrics 10 Change-Id: I8be89116bed5c4dedb2ca42b6d633aa9e8c6a49a --- .../net/cts/ConnectivityManagerTest.java | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 4180ea4396..e89a4227cb 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -43,6 +43,8 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.IpSecManager; +import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -52,6 +54,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.SocketKeepalive; +import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; import android.os.Looper; import android.os.MessageQueue; @@ -85,6 +88,7 @@ import java.net.Socket; import java.net.URL; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.concurrent.CountDownLatch; @@ -704,6 +708,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { return wifiNetwork; } + private InetAddress getFirstV4Address(Network network) { + LinkProperties linkProperties = mCm.getLinkProperties(network); + for (InetAddress address : linkProperties.getAddresses()) { + if (address instanceof Inet4Address) { + return address; + } + } + return null; + } + private Socket getBoundSocket(Network network, String host, int port) throws IOException { InetSocketAddress addr = new InetSocketAddress(host, port); Socket s = network.getSocketFactory().createSocket(); @@ -1277,4 +1291,125 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + + private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { + if (!isKeepaliveSupported()) return 0; + + final Network network = ensureWifiConnected(); + + final ArrayList kalist = new ArrayList<>(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + final Executor executor = mContext.getMainExecutor(); + + // Create concurrent TCP keepalives. + for (int i = 0; i < tcpCount; i++) { + // Assert that TCP connections can be established on wifi. The file descriptor of tcp + // sockets will be duplicated and kept valid in service side if the keepalives are + // successfully started. + try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, + 0 /* Unused */, AF_INET)) { + final SocketKeepalive ka = mCm.createSocketKeepalive(network, tcpSocket, executor, + callback); + ka.start(MIN_KEEPALIVE_INTERVAL); + TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); + assertNotNull(cv); + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR + && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { + kalist.add(ka); + } else { + fail("Unexpected error when creating " + (i + 1) + " TCP keepalives: " + cv); + } + } + } + + // Assert that a Nat-T socket can be created. + final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); + final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); + + final InetAddress srcAddr = getFirstV4Address(network); + final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); + assertNotNull(srcAddr); + assertNotNull(dstAddr); + + // Test concurrent Nat-T keepalives. + for (int i = 0; i < nattCount; i++) { + final SocketKeepalive ka = mCm.createSocketKeepalive(network, nattSocket, + srcAddr, dstAddr, executor, callback); + ka.start(MIN_KEEPALIVE_INTERVAL); + TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); + assertNotNull(cv); + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR + && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { + kalist.add(ka); + } else { + fail("Unexpected error when creating " + (i + 1) + " Nat-T keepalives: " + cv); + } + } + + final int ret = kalist.size(); + + // Clean up. + for (final SocketKeepalive ka : kalist) { + ka.stop(); + callback.expectStopped(); + } + kalist.clear(); + nattSocket.close(); + + return ret; + } + + /** + * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't + * get leaked after iterations. + */ + public void testSocketKeepaliveLimit() throws Exception { + adoptShellPermissionIdentity(); + + final Network network = ensureWifiConnected(); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + + // Get number of supported concurrent keepalives for testing network. + final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); + final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + keepalivesPerTransport, nc); + + // Sanity check. + if (!isKeepaliveSupported()) { + assertEquals(0, supported); + return; + } + + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. + assertGreaterOrEqual(supported, KeepaliveUtils.MIN_SUPPORTED_KEEPALIVE_COUNT); + + // Verifies that different types of keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + + // Verifies that different types can be established at the same time. + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + + dropShellPermissionIdentity(); + } + + private static void assertGreaterOrEqual(long greater, long lesser) { + assertTrue("" + greater + " expected to be greater than or equal to " + lesser, + greater >= lesser); + } } From 80ec50b8ae0dadf5333f85a84c17e7d106eac08c Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 8 May 2019 11:46:25 +0800 Subject: [PATCH 0622/1415] add cts for unprivileged keepalive slots Currently, unprivileged Nat-T keepalives are limited to 1 slot per uid. Add CTS to verify that the keepalive slots are limited as customized for unprivileged requests. Bug: 129371366 Test: atest android.net.cts .ConnectivityManagerTest#testSocketKeepaliveUnprivileged --generate-new-metrics 10 Change-Id: I60b9e9ae9cf2b63490493ced9738cd2f402c3f9b --- .../net/cts/ConnectivityManagerTest.java | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index e89a4227cb..ea441a7fff 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -1184,6 +1184,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { return s; } + private int getSupportedKeepalivesFromRes() throws Exception { + final Network network = ensureWifiConnected(); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + + // Get number of supported concurrent keepalives for testing network. + final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); + return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + keepalivesPerTransport, nc); + } + private boolean isKeepaliveSupported() throws Exception { final Network network = ensureWifiConnected(); final Executor executor = mContext.getMainExecutor(); @@ -1293,7 +1303,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { } private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { - if (!isKeepaliveSupported()) return 0; + // Use customization value in resource to prevent the need of privilege. + if (getSupportedKeepalivesFromRes() == 0) return 0; final Network network = ensureWifiConnected(); @@ -1374,16 +1385,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testSocketKeepaliveLimit() throws Exception { adoptShellPermissionIdentity(); - final Network network = ensureWifiConnected(); - final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + final int supported = getSupportedKeepalivesFromRes(); - // Get number of supported concurrent keepalives for testing network. - final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); - final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( - keepalivesPerTransport, nc); - - // Sanity check. if (!isKeepaliveSupported()) { + // Sanity check. assertEquals(0, supported); return; } @@ -1408,6 +1413,34 @@ public class ConnectivityManagerTest extends AndroidTestCase { dropShellPermissionIdentity(); } + /** + * Verifies that the keepalive slots are limited as customized for unprivileged requests. + */ + public void testSocketKeepaliveUnprivileged() throws Exception { + final int supported = getSupportedKeepalivesFromRes(); + + adoptShellPermissionIdentity(); + if (!isKeepaliveSupported()) { + // Sanity check. + assertEquals(0, supported); + return; + } + dropShellPermissionIdentity(); + + final int allowedUnprivilegedPerUid = mContext.getResources().getInteger( + R.integer.config_allowedUnprivilegedKeepalivePerUid); + final int reservedPrivilegedSlots = mContext.getResources().getInteger( + R.integer.config_reservedPrivilegedKeepaliveSlots); + // Verifies that unprivileged request per uid cannot exceed the limit customized in the + // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test + // does not apply to TCP. + assertGreaterOrEqual(supported, reservedPrivilegedSlots); + assertGreaterOrEqual(supported, allowedUnprivilegedPerUid); + final int expectedUnprivileged = + Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); + assertEquals(expectedUnprivileged, createConcurrentSocketKeepalives(supported + 1, 0)); + } + private static void assertGreaterOrEqual(long greater, long lesser) { assertTrue("" + greater + " expected to be greater than or equal to " + lesser, greater >= lesser); From ad4c047f6d6e9b3dc0df58fd80f6511b7351a872 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 2 Apr 2019 11:36:14 +0800 Subject: [PATCH 0623/1415] [KA14] add cts for keepalive limit test. Per SDK requirement, OEM is required to support minimum number of concurrent keepalives. Implement CTS to verify this. Bug: 129371366 Test: atest android.net.cts .ConnectivityManagerTest#testSocketKeepaliveLimit --generate-new-metrics 10 (Clean cherry-pick of aosp/937026) Change-Id: I8be89116bed5c4dedb2ca42b6d633aa9e8c6a49a Merged-In: I8be89116bed5c4dedb2ca42b6d633aa9e8c6a49a --- .../net/cts/ConnectivityManagerTest.java | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index cb1aa09599..f702042f77 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -43,6 +43,8 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.IpSecManager; +import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -52,6 +54,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.SocketKeepalive; +import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; import android.os.Looper; import android.os.MessageQueue; @@ -86,6 +89,7 @@ import java.net.Socket; import java.net.URL; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.concurrent.CountDownLatch; @@ -705,6 +709,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { return wifiNetwork; } + private InetAddress getFirstV4Address(Network network) { + LinkProperties linkProperties = mCm.getLinkProperties(network); + for (InetAddress address : linkProperties.getAddresses()) { + if (address instanceof Inet4Address) { + return address; + } + } + return null; + } + private Socket getBoundSocket(Network network, String host, int port) throws IOException { InetSocketAddress addr = new InetSocketAddress(host, port); Socket s = network.getSocketFactory().createSocket(); @@ -1278,4 +1292,125 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + + private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { + if (!isKeepaliveSupported()) return 0; + + final Network network = ensureWifiConnected(); + + final ArrayList kalist = new ArrayList<>(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + final Executor executor = mContext.getMainExecutor(); + + // Create concurrent TCP keepalives. + for (int i = 0; i < tcpCount; i++) { + // Assert that TCP connections can be established on wifi. The file descriptor of tcp + // sockets will be duplicated and kept valid in service side if the keepalives are + // successfully started. + try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, + 0 /* Unused */, AF_INET)) { + final SocketKeepalive ka = mCm.createSocketKeepalive(network, tcpSocket, executor, + callback); + ka.start(MIN_KEEPALIVE_INTERVAL); + TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); + assertNotNull(cv); + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR + && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { + kalist.add(ka); + } else { + fail("Unexpected error when creating " + (i + 1) + " TCP keepalives: " + cv); + } + } + } + + // Assert that a Nat-T socket can be created. + final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); + final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); + + final InetAddress srcAddr = getFirstV4Address(network); + final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); + assertNotNull(srcAddr); + assertNotNull(dstAddr); + + // Test concurrent Nat-T keepalives. + for (int i = 0; i < nattCount; i++) { + final SocketKeepalive ka = mCm.createSocketKeepalive(network, nattSocket, + srcAddr, dstAddr, executor, callback); + ka.start(MIN_KEEPALIVE_INTERVAL); + TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); + assertNotNull(cv); + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR + && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { + kalist.add(ka); + } else { + fail("Unexpected error when creating " + (i + 1) + " Nat-T keepalives: " + cv); + } + } + + final int ret = kalist.size(); + + // Clean up. + for (final SocketKeepalive ka : kalist) { + ka.stop(); + callback.expectStopped(); + } + kalist.clear(); + nattSocket.close(); + + return ret; + } + + /** + * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't + * get leaked after iterations. + */ + public void testSocketKeepaliveLimit() throws Exception { + adoptShellPermissionIdentity(); + + final Network network = ensureWifiConnected(); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + + // Get number of supported concurrent keepalives for testing network. + final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); + final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + keepalivesPerTransport, nc); + + // Sanity check. + if (!isKeepaliveSupported()) { + assertEquals(0, supported); + return; + } + + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. + assertGreaterOrEqual(supported, KeepaliveUtils.MIN_SUPPORTED_KEEPALIVE_COUNT); + + // Verifies that different types of keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + + // Verifies that different types can be established at the same time. + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + + dropShellPermissionIdentity(); + } + + private static void assertGreaterOrEqual(long greater, long lesser) { + assertTrue("" + greater + " expected to be greater than or equal to " + lesser, + greater >= lesser); + } } From bbf160a93d10af0d521ec96c69be38c9e71803c0 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 8 May 2019 11:46:25 +0800 Subject: [PATCH 0624/1415] add cts for unprivileged keepalive slots Currently, unprivileged Nat-T keepalives are limited to 1 slot per uid. Add CTS to verify that the keepalive slots are limited as customized for unprivileged requests. Bug: 129371366 Test: atest android.net.cts .ConnectivityManagerTest#testSocketKeepaliveUnprivileged --generate-new-metrics 10 (Clean cherry-pick of aosp/957205) Change-Id: I60b9e9ae9cf2b63490493ced9738cd2f402c3f9b Merged-In: I60b9e9ae9cf2b63490493ced9738cd2f402c3f9b --- .../net/cts/ConnectivityManagerTest.java | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index f702042f77..606d3fc772 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -1185,6 +1185,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { return s; } + private int getSupportedKeepalivesFromRes() throws Exception { + final Network network = ensureWifiConnected(); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + + // Get number of supported concurrent keepalives for testing network. + final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); + return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + keepalivesPerTransport, nc); + } + private boolean isKeepaliveSupported() throws Exception { final Network network = ensureWifiConnected(); final Executor executor = mContext.getMainExecutor(); @@ -1294,7 +1304,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { } private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { - if (!isKeepaliveSupported()) return 0; + // Use customization value in resource to prevent the need of privilege. + if (getSupportedKeepalivesFromRes() == 0) return 0; final Network network = ensureWifiConnected(); @@ -1375,16 +1386,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testSocketKeepaliveLimit() throws Exception { adoptShellPermissionIdentity(); - final Network network = ensureWifiConnected(); - final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + final int supported = getSupportedKeepalivesFromRes(); - // Get number of supported concurrent keepalives for testing network. - final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); - final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( - keepalivesPerTransport, nc); - - // Sanity check. if (!isKeepaliveSupported()) { + // Sanity check. assertEquals(0, supported); return; } @@ -1409,6 +1414,34 @@ public class ConnectivityManagerTest extends AndroidTestCase { dropShellPermissionIdentity(); } + /** + * Verifies that the keepalive slots are limited as customized for unprivileged requests. + */ + public void testSocketKeepaliveUnprivileged() throws Exception { + final int supported = getSupportedKeepalivesFromRes(); + + adoptShellPermissionIdentity(); + if (!isKeepaliveSupported()) { + // Sanity check. + assertEquals(0, supported); + return; + } + dropShellPermissionIdentity(); + + final int allowedUnprivilegedPerUid = mContext.getResources().getInteger( + R.integer.config_allowedUnprivilegedKeepalivePerUid); + final int reservedPrivilegedSlots = mContext.getResources().getInteger( + R.integer.config_reservedPrivilegedKeepaliveSlots); + // Verifies that unprivileged request per uid cannot exceed the limit customized in the + // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test + // does not apply to TCP. + assertGreaterOrEqual(supported, reservedPrivilegedSlots); + assertGreaterOrEqual(supported, allowedUnprivilegedPerUid); + final int expectedUnprivileged = + Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); + assertEquals(expectedUnprivileged, createConcurrentSocketKeepalives(supported + 1, 0)); + } + private static void assertGreaterOrEqual(long greater, long lesser) { assertTrue("" + greater + " expected to be greater than or equal to " + lesser, greater >= lesser); From 4af108aacfe7977484d844cefce83a75ac1cafc9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 15 May 2019 00:26:09 -0700 Subject: [PATCH 0625/1415] Fix IPsec CTS tests for interface address checking Fixes two potentially device/kernel specific, or flaky bugs: 1. Java interface checking by name seems to cache the lookup, resulting in interface address checks occasionally failing (on delete). 2. Link-local addresses appear to be added on all links for some set of kernels and devices. This patch addresses both by only checking that the requested address was added via a address-based NetworkInterface lookup. Bug: 72950854 Test: Ran on sargo-eng on qt-dev/HEAD Test: Manually verified that the addresses are indeed added/removed Change-Id: I3babc72dfe72337c4d68facb1695aec15e504c90 --- .../net/cts/IpSecManagerTunnelTest.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 66141960c8..93638ac3b5 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -39,7 +39,6 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.AppOpsManager; @@ -69,9 +68,7 @@ import com.android.compatibility.common.util.SystemUtil; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.InterfaceAddress; import java.net.NetworkInterface; -import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -512,11 +509,10 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertNotNull(netIntf); - // Check addresses - List intfAddrs = netIntf.getInterfaceAddresses(); - assertEquals(1, intfAddrs.size()); - assertEquals(localInner, intfAddrs.get(0).getAddress()); - assertEquals(innerPrefixLen, intfAddrs.get(0).getNetworkPrefixLength()); + // Verify address was added + netIntf = NetworkInterface.getByInetAddress(localInner); + assertNotNull(netIntf); + assertEquals(tunnelIntf.getInterfaceName(), netIntf.getDisplayName()); // Configure Transform parameters IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); @@ -544,15 +540,14 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Teardown the test network sTNM.teardownTestNetwork(testNetwork); - // Remove addresses and check + // Remove addresses and check that interface is still present, but fails lookup-by-addr tunnelIntf.removeAddress(localInner, innerPrefixLen); - netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertTrue(netIntf.getInterfaceAddresses().isEmpty()); + assertNotNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + assertNull(NetworkInterface.getByInetAddress(localInner)); // Check interface was cleaned up tunnelIntf.close(); - netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNull(netIntf); + assertNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); } finally { if (testNetworkCb != null) { sCM.unregisterNetworkCallback(testNetworkCb); From 78e4a184a10c12978391a039f00e155d0dbff276 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 3 May 2019 16:30:46 +0800 Subject: [PATCH 0626/1415] Enable instant app mode for CtsNetTestCases 1. Indicating CtsNetTestCases support instant app mode but ignore some tests that cannot run in instant app mode. 2. Move some tests which need to test on API 23 into CtsNetApi23TestCases module due to instant app package must target at least API 26. Bug: 123366918 Test: atest CtsNetTestCases --instant Test: atest CtsNetApi23TestCases Test: atest FrameworksNetTests Change-Id: I4e828cbc48143e36c1be38b91c3c698122d4be5a --- tests/cts/net/AndroidManifest.xml | 9 +- tests/cts/net/AndroidTest.xml | 3 +- tests/cts/net/api23Test/Android.bp | 51 +++ tests/cts/net/api23Test/AndroidManifest.xml | 42 ++ tests/cts/net/api23Test/AndroidTest.xml | 30 ++ .../ConnectivityManagerApi23Test.java | 399 ++++++++++++++++++ .../cts/api23test}/ConnectivityReceiver.java | 2 +- .../src/android/net/cts/AirplaneModeTest.java | 3 +- .../net/cts/ConnectivityManagerTest.java | 106 +---- .../src/android/net/cts/IpSecBaseTest.java | 7 + .../src/android/net/cts/IpSecManagerTest.java | 3 + .../android/net/cts/NetworkWatchlistTest.java | 2 + .../cts/SSLCertificateSocketFactoryTest.java | 4 + .../src/android/net/cts/TheaterModeTest.java | 4 +- .../src/android/net/cts/TrafficStatsTest.java | 2 + .../src/android/net/cts/VpnServiceTest.java | 4 + .../net/http/cts/ApacheHttpClientTest.java | 2 + .../net/http/cts/HttpResponseCacheTest.java | 2 + .../android/net/rtp/cts/AudioGroupTest.java | 3 +- .../android/net/rtp/cts/AudioStreamTest.java | 2 + .../net/wifi/aware/cts/SingleDeviceTest.java | 2 + .../android/net/wifi/cts/ConcurrencyTest.java | 2 + .../net/wifi/cts/MulticastLockTest.java | 2 + .../android/net/wifi/cts/NsdManagerTest.java | 2 + .../android/net/wifi/cts/ScanResultTest.java | 2 + .../net/wifi/cts/WifiConfigurationTest.java | 2 + .../wifi/cts/WifiEnterpriseConfigTest.java | 2 + .../android/net/wifi/cts/WifiInfoTest.java | 2 + .../android/net/wifi/cts/WifiLockTest.java | 2 + .../android/net/wifi/cts/WifiManagerTest.java | 2 + .../android/net/wifi/rtt/cts/WifiRttTest.java | 2 + 31 files changed, 594 insertions(+), 108 deletions(-) create mode 100644 tests/cts/net/api23Test/Android.bp create mode 100644 tests/cts/net/api23Test/AndroidManifest.xml create mode 100644 tests/cts/net/api23Test/AndroidTest.xml create mode 100644 tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java rename tests/cts/net/{src/android/net/cts => api23Test/src/android/net/cts/api23test}/ConnectivityReceiver.java (98%) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index dbd8fef08e..44a00ef619 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -16,7 +16,8 @@ --> + package="android.net.cts" + android:targetSandboxVersion="2"> @@ -36,12 +37,6 @@ - - - - - -

    This test takes an outbound IPsec packet, reflects it (by flipping IP src/dst), and + * injects it back into the TUN. This test then verifies that a packet with the correct payload + * is found on the specified socket/port. + */ + public void checkTunnelReflected( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + if (!hasTunnelsFeature()) return; + + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; + + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + // Run output direction tests + IpSecTunnelTestRunnable outputIpSecTunnelTestRunnable = + new OutputIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + 0, + expectedPacketSize); + int innerSocketPort = + buildTunnelNetworkAndRunTests( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + outputIpSecTunnelTestRunnable); + + // Input direction tests, with matching inner socket ports. + IpSecTunnelTestRunnable inputIpSecTunnelTestRunnable = + new InputReflectedIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + remoteInner, + localInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + innerSocketPort, + expectedPacketSize); + buildTunnelNetworkAndRunTests( + remoteInner, + localInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + inputIpSecTunnelTestRunnable); + } } public void checkTunnel( @@ -434,7 +577,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { int outerFamily, boolean useEncap, boolean transportInTunnelMode, - TestRunnableFactory factory) + IpSecTunnelTestRunnableFactory factory) throws Exception { if (!hasTunnelsFeature()) return; @@ -461,14 +604,14 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { buildIpSecTransform(sContext, outTransportSpi, null, localInner); UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { - buildTunnelAndNetwork( + buildTunnelNetworkAndRunTests( localInner, remoteInner, localOuter, remoteOuter, spi, useEncap ? encapSocket : null, - factory.getTestRunnable( + factory.getIpSecTunnelTestRunnable( transportInTunnelMode, spi, localInner, @@ -478,21 +621,23 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { inTransportTransform, outTransportTransform, useEncap ? encapSocket.getPort() : 0, + 0, expectedPacketSize)); } } - private void buildTunnelAndNetwork( + private int buildTunnelNetworkAndRunTests( InetAddress localInner, InetAddress remoteInner, InetAddress localOuter, InetAddress remoteOuter, int spi, UdpEncapsulationSocket encapSocket, - TestRunnable test) + IpSecTunnelTestRunnable test) throws Exception { int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; TestNetworkCallback testNetworkCb = null; + int innerSocketPort; try (IpSecManager.SecurityParameterIndex inSpi = mISM.allocateSecurityParameterIndex(localOuter, spi); @@ -534,7 +679,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { mISM.applyTunnelModeTransform( tunnelIface, IpSecManager.DIRECTION_OUT, outTransform); - test.run(testNetwork); + innerSocketPort = test.run(testNetwork); } // Teardown the test network @@ -553,6 +698,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { sCM.unregisterNetworkCallback(testNetworkCb); } } + + return innerSocketPort; } private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { @@ -675,36 +822,66 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { checkTunnelInput(AF_INET, AF_INET, false, true); } + @Test + public void testTransportInTunnelModeV4InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET, AF_INET, true, true); checkTunnelInput(AF_INET, AF_INET, true, true); } + @Test + public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } + @Test + public void testTransportInTunnelModeV4InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, false, true); checkTunnelInput(AF_INET6, AF_INET, false, true); } + @Test + public void testTransportInTunnelModeV6InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, true, true); checkTunnelInput(AF_INET6, AF_INET, true, true); } + @Test + public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } + @Test + public void testTransportInTunnelModeV6InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + // Tunnel mode tests @Test public void testTunnelV4InV4() throws Exception { @@ -712,33 +889,63 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { checkTunnelInput(AF_INET, AF_INET, false, false); } + @Test + public void testTunnelV4InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, false); + } + @Test public void testTunnelV4InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET, AF_INET, true, false); checkTunnelInput(AF_INET, AF_INET, true, false); } + @Test + public void testTunnelV4InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, true, false); + } + @Test public void testTunnelV4InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, false); checkTunnelInput(AF_INET, AF_INET6, false, false); } + @Test + public void testTunnelV4InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET6, false, false); + } + @Test public void testTunnelV6InV4() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, false, false); checkTunnelInput(AF_INET6, AF_INET, false, false); } + @Test + public void testTunnelV6InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET, false, false); + } + @Test public void testTunnelV6InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, true, false); checkTunnelInput(AF_INET6, AF_INET, true, false); } + @Test + public void testTunnelV6InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET, true, false); + } + @Test public void testTunnelV6InV6() throws Exception { checkTunnelOutput(AF_INET6, AF_INET6, false, false); checkTunnelInput(AF_INET6, AF_INET6, false, false); } + + @Test + public void testTunnelV6InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET6, false, false); + } } From 5c79356068f7c9946b7d61e92ec7875e4759e164 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 15 May 2019 00:26:09 -0700 Subject: [PATCH 0631/1415] Fix IPsec CTS tests for interface address checking Fixes two potentially device/kernel specific, or flaky bugs: 1. Java interface checking by name seems to cache the lookup, resulting in interface address checks occasionally failing (on delete). 2. Link-local addresses appear to be added on all links for some set of kernels and devices. This patch addresses both by only checking that the requested address was added via a address-based NetworkInterface lookup. Bug: 72950854 Test: Ran on sargo-eng on qt-dev/HEAD Test: Manually verified that the addresses are indeed added/removed Change-Id: I3babc72dfe72337c4d68facb1695aec15e504c90 Merged-In: I3babc72dfe72337c4d68facb1695aec15e504c90 (cherry picked from commit 4af108aacfe7977484d844cefce83a75ac1cafc9) --- .../net/cts/IpSecManagerTunnelTest.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 66141960c8..93638ac3b5 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -39,7 +39,6 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.AppOpsManager; @@ -69,9 +68,7 @@ import com.android.compatibility.common.util.SystemUtil; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.InterfaceAddress; import java.net.NetworkInterface; -import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -512,11 +509,10 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertNotNull(netIntf); - // Check addresses - List intfAddrs = netIntf.getInterfaceAddresses(); - assertEquals(1, intfAddrs.size()); - assertEquals(localInner, intfAddrs.get(0).getAddress()); - assertEquals(innerPrefixLen, intfAddrs.get(0).getNetworkPrefixLength()); + // Verify address was added + netIntf = NetworkInterface.getByInetAddress(localInner); + assertNotNull(netIntf); + assertEquals(tunnelIntf.getInterfaceName(), netIntf.getDisplayName()); // Configure Transform parameters IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); @@ -544,15 +540,14 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Teardown the test network sTNM.teardownTestNetwork(testNetwork); - // Remove addresses and check + // Remove addresses and check that interface is still present, but fails lookup-by-addr tunnelIntf.removeAddress(localInner, innerPrefixLen); - netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertTrue(netIntf.getInterfaceAddresses().isEmpty()); + assertNotNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + assertNull(NetworkInterface.getByInetAddress(localInner)); // Check interface was cleaned up tunnelIntf.close(); - netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNull(netIntf); + assertNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); } finally { if (testNetworkCb != null) { sCM.unregisterNetworkCallback(testNetworkCb); From 281d757df6eb821a8a1df0399aec25d979d3194b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 17 May 2019 16:04:34 -0700 Subject: [PATCH 0632/1415] Cleanup IPsec CTS tests This commit addresses comments from aosp/963067 and aosp/959617. No behavioral/functional changes were made, only renames and minor style nits addressed. Bug: 72950854 Test: Ran on devices, working Change-Id: I1702b91e245412f0142e9e47b7fb373b9b4e8126 --- .../src/android/net/cts/IpSecManagerTest.java | 6 ---- .../net/cts/IpSecManagerTunnelTest.java | 34 +++++++++---------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 1241785a17..d6b8a968d2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -73,12 +73,6 @@ public class IpSecManagerTest extends IpSecBaseTest { private static final byte[] AEAD_KEY = getKey(288); - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - } - /* * Allocate a random SPI * Allocate a specific SPI using previous randomly created SPI value diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 93638ac3b5..828abccf58 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -127,15 +127,15 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // right appop permissions. setAppop(OP_MANAGE_IPSEC_TUNNELS, true); - TestNetworkInterface testIntf = + TestNetworkInterface testIface = sTNM.createTunInterface( new LinkAddress[] { new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN) }); - sTunFd = testIntf.getFileDescriptor(); - sTunNetworkCallback = setupAndGetTestNetwork(testIntf.getInterfaceName()); + sTunFd = testIface.getFileDescriptor(); + sTunNetworkCallback = setupAndGetTestNetwork(testIface.getInterfaceName()); sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); sTunUtils = new TunUtils(sTunFd); @@ -498,21 +498,20 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { mISM.allocateSecurityParameterIndex(localOuter, spi); IpSecManager.SecurityParameterIndex outSpi = mISM.allocateSecurityParameterIndex(remoteOuter, spi); - IpSecManager.IpSecTunnelInterface tunnelIntf = + IpSecManager.IpSecTunnelInterface tunnelIface = mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) { // Build the test network - tunnelIntf.addAddress(localInner, innerPrefixLen); - testNetworkCb = setupAndGetTestNetwork(tunnelIntf.getInterfaceName()); + tunnelIface.addAddress(localInner, innerPrefixLen); + testNetworkCb = setupAndGetTestNetwork(tunnelIface.getInterfaceName()); Network testNetwork = testNetworkCb.getNetworkBlocking(); // Check interface was created - NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNotNull(netIntf); + assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); // Verify address was added - netIntf = NetworkInterface.getByInetAddress(localInner); - assertNotNull(netIntf); - assertEquals(tunnelIntf.getInterfaceName(), netIntf.getDisplayName()); + final NetworkInterface netIface = NetworkInterface.getByInetAddress(localInner); + assertNotNull(netIface); + assertEquals(tunnelIface.getInterfaceName(), netIface.getDisplayName()); // Configure Transform parameters IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); @@ -531,8 +530,9 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi); IpSecTransform outTransform = transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) { - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, inTransform); - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, outTransform); + mISM.applyTunnelModeTransform(tunnelIface, IpSecManager.DIRECTION_IN, inTransform); + mISM.applyTunnelModeTransform( + tunnelIface, IpSecManager.DIRECTION_OUT, outTransform); test.run(testNetwork); } @@ -541,13 +541,13 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { sTNM.teardownTestNetwork(testNetwork); // Remove addresses and check that interface is still present, but fails lookup-by-addr - tunnelIntf.removeAddress(localInner, innerPrefixLen); - assertNotNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + tunnelIface.removeAddress(localInner, innerPrefixLen); + assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); assertNull(NetworkInterface.getByInetAddress(localInner)); // Check interface was cleaned up - tunnelIntf.close(); - assertNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + tunnelIface.close(); + assertNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); } finally { if (testNetworkCb != null) { sCM.unregisterNetworkCallback(testNetworkCb); From ee4eb2f35bfea66e1b071522fadf2003da9e6521 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 20 May 2019 11:58:26 -0700 Subject: [PATCH 0633/1415] Remove mContext from IpSecBaseTest This commit removes the mContext from IpSecBaseTest, and replaces it with InstrumentationRegistry.getContext(). Bug: 72950854 Test: Ran on devices, passing. Change-Id: If6fa359825aa9d1f7d4c8d49aba7a34925c073ed --- tests/cts/net/src/android/net/cts/IpSecBaseTest.java | 4 +--- tests/cts/net/src/android/net/cts/IpSecManagerTest.java | 8 +++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 26049cc174..10e43e7b6a 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -76,11 +76,9 @@ public class IpSecBaseTest { protected ConnectivityManager mCM; protected IpSecManager mISM; - protected Context mContext; @Before public void setUp() throws Exception { - mContext = InstrumentationRegistry.getContext(); mISM = (IpSecManager) InstrumentationRegistry.getContext() @@ -475,7 +473,7 @@ public class IpSecBaseTest { private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(localAddr)) { - return buildIpSecTransform(mContext, spi, null, localAddr); + return buildIpSecTransform(InstrumentationRegistry.getContext(), spi, null, localAddr); } } diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index d6b8a968d2..355b496829 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -41,6 +41,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import java.io.FileDescriptor; @@ -238,7 +239,7 @@ public class IpSecManagerTest extends IpSecBaseTest { mISM.allocateSecurityParameterIndex(localAddr); IpSecTransform transform = - new IpSecTransform.Builder(mContext) + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) .setAuthentication( new IpSecAlgorithm( @@ -456,7 +457,8 @@ public class IpSecManagerTest extends IpSecBaseTest { IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local)) { - IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext); + IpSecTransform.Builder transformBuilder = + new IpSecTransform.Builder(InstrumentationRegistry.getContext()); if (crypt != null) { transformBuilder.setEncryption(crypt); } @@ -617,7 +619,7 @@ public class IpSecManagerTest extends IpSecBaseTest { try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local); IpSecTransform transform = - new IpSecTransform.Builder(mContext) + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) .setEncryption(crypt) .setAuthentication(auth) .setIpv4Encapsulation(encapSocket, encapSocket.getPort()) From 5f7599b6d5a0846974ad42722ba9e275dc53d8c7 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 24 May 2019 11:32:37 +0800 Subject: [PATCH 0634/1415] Ignore all tests in IpSecManagerTunnelTest with instant apps Test runner will crash while tring to get test network service in IpSecManagerTunnelTest. Because MANAGE_TEST_NETWORKS permission can't be granted to instant apps. So ignore all tests in this file. Bug: 133399750 Test: atest CtsNetTestCases --instant Change-Id: I5a096f20ec168133dbb65d27d3388c01e6ee895b --- tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 6e96682b68..55a09180df 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -59,6 +59,7 @@ import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.SystemProperties; +import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -81,6 +82,7 @@ import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") public class IpSecManagerTunnelTest extends IpSecBaseTest { private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName(); From db6336c0b8d2a69f143978436833c3ff477408ce Mon Sep 17 00:00:00 2001 From: jovanak Date: Tue, 14 May 2019 17:14:13 -0700 Subject: [PATCH 0635/1415] Fixing NetworkWatchlistTest#testGetWatchlistConfigHash for secondary users. Avoids relying on external storage and using the hardcoded /sdcard/ path. Unrooted adb does not have access to non-user 0 sdcard paths, and so the "cp" command fails when the test runs in user 10. Fixes: 121400865 Test: cts-tradefed run cts-dev -m CtsNetTestCases -t android.net.cts.NetworkWatchlistTest#testGetWatchlistConfigHash in user 10. Change-Id: Idc667072bcfbbe159416fa7c7b6b19045b52041d --- .../android/net/cts/NetworkWatchlistTest.java | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java b/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java index e0c03a1e95..8ad7820be6 100644 --- a/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java @@ -24,6 +24,7 @@ import static org.junit.Assume.assumeTrue; import android.content.Context; import android.net.ConnectivityManager; import android.os.FileUtils; +import android.os.ParcelFileDescriptor; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -38,7 +39,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Formatter; @@ -50,8 +51,6 @@ public class NetworkWatchlistTest { private static final String TEST_WATCHLIST_XML = "assets/network_watchlist_config_for_test.xml"; private static final String TEST_EMPTY_WATCHLIST_XML = "assets/network_watchlist_config_empty_for_test.xml"; - private static final String SDCARD_CONFIG_PATH = - "/sdcard/network_watchlist_config_for_test.xml"; private static final String TMP_CONFIG_PATH = "/data/local/tmp/network_watchlist_config_for_test.xml"; // Generated from sha256sum network_watchlist_config_for_test.xml @@ -83,8 +82,7 @@ public class NetworkWatchlistTest { } } - private void cleanup() throws Exception { - runCommand("rm " + SDCARD_CONFIG_PATH); + private void cleanup() throws IOException { runCommand("rm " + TMP_CONFIG_PATH); } @@ -116,22 +114,43 @@ public class NetworkWatchlistTest { } private void saveResourceToFile(String res, String filePath) throws IOException { - InputStream in = getClass().getClassLoader().getResourceAsStream(res); - FileUtils.copyToFileOrThrow(in, new File(filePath)); + // App can't access /data/local/tmp directly, so we pipe resource to file through stdin. + ParcelFileDescriptor stdin = pipeFromStdin(filePath); + pipeResourceToFileDescriptor(res, stdin); + } + + /* Pipe stdin to a file in filePath. Returns PFD for stdin. */ + private ParcelFileDescriptor pipeFromStdin(String filePath) { + // Not all devices have symlink for /dev/stdin, so use /proc/self/fd/0 directly. + // /dev/stdin maps to /proc/self/fd/0. + return runRwCommand("cp /proc/self/fd/0 " + filePath)[1]; + } + + private void pipeResourceToFileDescriptor(String res, ParcelFileDescriptor pfd) + throws IOException { + InputStream resStream = getClass().getClassLoader().getResourceAsStream(res); + FileOutputStream fdStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd); + + FileUtils.copy(resStream, fdStream); + + try { + fdStream.close(); + } catch (IOException e) { + } } private static String runCommand(String command) throws IOException { return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command); } + private static ParcelFileDescriptor[] runRwCommand(String command) { + return InstrumentationRegistry.getInstrumentation() + .getUiAutomation().executeShellCommandRw(command); + } + private void setWatchlistConfig(String watchlistConfigFile) throws Exception { cleanup(); - // Save test watchlist config to sdcard as app can't access /data/local/tmp - saveResourceToFile(watchlistConfigFile, SDCARD_CONFIG_PATH); - // Copy test watchlist config from sdcard to /data/local/tmp as system service - // can't access /sdcard - runCommand("cp " + SDCARD_CONFIG_PATH + " " + TMP_CONFIG_PATH); - // Set test watchlist config to system + saveResourceToFile(watchlistConfigFile, TMP_CONFIG_PATH); final String cmdResult = runCommand( "cmd network_watchlist set-test-config " + TMP_CONFIG_PATH).trim(); assertThat(cmdResult).contains("Success"); From a138c9e4875a658cd55b3f6ae06a317098e10d3c Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Fri, 24 May 2019 18:52:54 -0700 Subject: [PATCH 0636/1415] Ignore all tests in IpSecManagerTunnelTest with instant apps Test runner will crash while tring to get test network service in IpSecManagerTunnelTest. Because MANAGE_TEST_NETWORKS permission can't be granted to instant apps. So ignore all tests in this file. Bug: 133399750 Test: atest CtsNetTestCases --instant Change-Id: I31b7e12a5a0021185851ba4435a6c42d457f34b6 Merged-In: Ia18c6bfe791692f8835b127adf734ce3d2a4ba95 Merged-In: I697333a7a64d794208d80112bdc1d1e50c5d2b56 Merged-In: I31b7e12a5a0021185851ba4435a6c42d457f34b6 (cherry picked from commit eb29c90465bc7ee89fac4ded00b6354b55fb5a8c) --- tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 93638ac3b5..ef6bfc04b2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -59,6 +59,7 @@ import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.SystemProperties; +import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -79,6 +80,7 @@ import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") public class IpSecManagerTunnelTest extends IpSecBaseTest { private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName(); From 971b79519a49640f60d6d0f4f26ca06b4dcd6320 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 24 Apr 2019 21:27:40 -0700 Subject: [PATCH 0637/1415] Convert Android.mk to Android.bp for net cts Bug: 130623306 Test: Run the tests below on Crosshatch, Sailfish, Bonito atest CtsNativeNetTestCases CtsNativeNetDnsTestCases atest CtsNetTestCases Merged-In: I5bb6de7a07494bd13d069212223691968d4f080e (cherry picked from commit db29b055d92c2dd7aef25ee12ad6af9a6bc8558c) Change-Id: I0f1f70794c0ce303158f1aea54f0801379498071 --- tests/cts/net/Android.bp | 64 +++++++++++++++++++++++++ tests/cts/net/Android.mk | 62 ------------------------ tests/cts/net/appForApi23/Android.bp | 33 +++++++++++++ tests/cts/net/appForApi23/Android.mk | 38 --------------- tests/cts/net/jni/Android.bp | 49 +++++++++++++++++++ tests/cts/net/jni/Android.mk | 44 ----------------- tests/cts/net/native/Android.mk | 15 ------ tests/cts/net/native/qtaguid/Android.bp | 53 ++++++++++++++++++++ tests/cts/net/native/qtaguid/Android.mk | 43 ----------------- 9 files changed, 199 insertions(+), 202 deletions(-) create mode 100644 tests/cts/net/Android.bp delete mode 100644 tests/cts/net/Android.mk create mode 100644 tests/cts/net/appForApi23/Android.bp delete mode 100644 tests/cts/net/appForApi23/Android.mk create mode 100644 tests/cts/net/jni/Android.bp delete mode 100644 tests/cts/net/jni/Android.mk delete mode 100644 tests/cts/net/native/Android.mk create mode 100644 tests/cts/net/native/qtaguid/Android.bp delete mode 100644 tests/cts/net/native/qtaguid/Android.mk diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp new file mode 100644 index 0000000000..779d5c4be2 --- /dev/null +++ b/tests/cts/net/Android.bp @@ -0,0 +1,64 @@ +// Copyright (C) 2008 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. + +android_test { + name: "CtsNetTestCases", + defaults: ["cts_defaults"], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", + + libs: [ + "voip-common", + "org.apache.http.legacy", + "android.test.base.stubs", + ], + + jni_libs: [ + "libcts_jni", + "libnativedns_jni", + "libnativemultinetwork_jni", + "libnativehelper_compat_libc++", + ], + + // include CtsTestServer as a temporary hack to free net.cts from cts.stub. + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + + static_libs: [ + "FrameworksNetCommonTests", + "core-tests-support", + "compatibility-device-util-axt", + "ctstestrunner-axt", + "ctstestserver", + "mockwebserver", + "junit", + "junit-params", + "truth-prebuilt", + ], + + // uncomment when b/13249961 is fixed + // sdk_version: "current", + platform_apis: true, + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "vts", + "general-tests", + ], + +} diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk deleted file mode 100644 index 04974702a6..0000000000 --- a/tests/cts/net/Android.mk +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (C) 2008 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. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -# don't include this package in any target -LOCAL_MODULE_TAGS := optional -# and when built explicitly put it in the data partition -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) - -# Include both the 32 and 64 bit versions -LOCAL_MULTILIB := both - -LOCAL_JAVA_LIBRARIES := \ - voip-common \ - org.apache.http.legacy \ - android.test.base.stubs \ - - -LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni \ - libnativemultinetwork_jni libnativehelper_compat_libc++ - -# include CtsTestServer as a temporary hack to free net.cts from cts.stub. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_PACKAGE_NAME := CtsNetTestCases - -LOCAL_STATIC_JAVA_LIBRARIES := \ - FrameworksNetCommonTests \ - core-tests-support \ - compatibility-device-util-axt \ - ctstestrunner-axt \ - ctstestserver \ - mockwebserver \ - junit \ - junit-params \ - truth-prebuilt \ - - -# uncomment when b/13249961 is fixed -#LOCAL_SDK_VERSION := current -LOCAL_PRIVATE_PLATFORM_APIS := true - -# Tag this module as a cts test artifact -LOCAL_COMPATIBILITY_SUITE := cts vts general-tests - -include $(BUILD_CTS_PACKAGE) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/cts/net/appForApi23/Android.bp b/tests/cts/net/appForApi23/Android.bp new file mode 100644 index 0000000000..82e2a08c10 --- /dev/null +++ b/tests/cts/net/appForApi23/Android.bp @@ -0,0 +1,33 @@ +// Copyright (C) 2016 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. + +android_test { + name: "CtsNetTestAppForApi23", + defaults: ["cts_defaults"], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", + + srcs: ["src/**/*.java"], + + sdk_version: "23", + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "vts", + "general-tests", + ], + +} diff --git a/tests/cts/net/appForApi23/Android.mk b/tests/cts/net/appForApi23/Android.mk deleted file mode 100644 index 54b60a0219..0000000000 --- a/tests/cts/net/appForApi23/Android.mk +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2016 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. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -# don't include this package in any target -LOCAL_MODULE_TAGS := optional -# and when built explicitly put it in the data partition -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) - -# Include both the 32 and 64 bit versions -LOCAL_MULTILIB := both - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_PACKAGE_NAME := CtsNetTestAppForApi23 - -LOCAL_SDK_VERSION := 23 - -# Tag this module as a cts test artifact -LOCAL_COMPATIBILITY_SUITE := cts vts general-tests - -include $(BUILD_CTS_PACKAGE) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/cts/net/jni/Android.bp b/tests/cts/net/jni/Android.bp new file mode 100644 index 0000000000..baed48dfae --- /dev/null +++ b/tests/cts/net/jni/Android.bp @@ -0,0 +1,49 @@ +// Copyright (C) 2013 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. + +cc_library_shared { + name: "libnativedns_jni", + + srcs: ["NativeDnsJni.c"], + + shared_libs: [ + "libnativehelper_compat_libc++", + "liblog", + ], + stl: "libc++_static", + + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + +} + +cc_library_shared { + name: "libnativemultinetwork_jni", + + srcs: ["NativeMultinetworkJni.cpp"], + cflags: [ + "-Wall", + "-Werror", + "-Wno-format", + ], + shared_libs: [ + "libandroid", + "libnativehelper_compat_libc++", + "liblog", + ], + stl: "libc++_static", +} diff --git a/tests/cts/net/jni/Android.mk b/tests/cts/net/jni/Android.mk deleted file mode 100644 index ccb1278f94..0000000000 --- a/tests/cts/net/jni/Android.mk +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2013 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. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := libnativedns_jni - -# Don't include this package in any configuration by default. -LOCAL_MODULE_TAGS := optional - -LOCAL_SRC_FILES := NativeDnsJni.c - -LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) - -LOCAL_SHARED_LIBRARIES := libnativehelper_compat_libc++ liblog -LOCAL_CXX_STL := libc++_static - -LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter - -include $(BUILD_SHARED_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_MODULE := libnativemultinetwork_jni -# Don't include this package in any configuration by default. -LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := NativeMultinetworkJni.cpp -LOCAL_CFLAGS := -Wall -Werror -Wno-format -LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) -LOCAL_SHARED_LIBRARIES := libandroid libnativehelper_compat_libc++ liblog -LOCAL_CXX_STL := libc++_static -include $(BUILD_SHARED_LIBRARY) diff --git a/tests/cts/net/native/Android.mk b/tests/cts/net/native/Android.mk deleted file mode 100644 index b798d87878..0000000000 --- a/tests/cts/net/native/Android.mk +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (C) 2017 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. - -include $(call all-subdir-makefiles) diff --git a/tests/cts/net/native/qtaguid/Android.bp b/tests/cts/net/native/qtaguid/Android.bp new file mode 100644 index 0000000000..c0f0613040 --- /dev/null +++ b/tests/cts/net/native/qtaguid/Android.bp @@ -0,0 +1,53 @@ +// Copyright (C) 2017 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. + +// Build the unit tests. + +cc_test { + name: "CtsNativeNetTestCases", + + compile_multilib: "both", + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + + srcs: ["src/NativeQtaguidTest.cpp"], + + shared_libs: [ + "libutils", + "liblog", + ], + + static_libs: [ + "libgtest", + "libqtaguid", + ], + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "vts", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + +} diff --git a/tests/cts/net/native/qtaguid/Android.mk b/tests/cts/net/native/qtaguid/Android.mk deleted file mode 100644 index bf89e5f015..0000000000 --- a/tests/cts/net/native/qtaguid/Android.mk +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (C) 2017 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. - -# Build the unit tests. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := CtsNativeNetTestCases -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest -LOCAL_MULTILIB := both -LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 -LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 - -LOCAL_SRC_FILES := \ - src/NativeQtaguidTest.cpp - -LOCAL_SHARED_LIBRARIES := \ - libutils \ - liblog \ - -LOCAL_STATIC_LIBRARIES := \ - libgtest \ - libqtaguid \ - -LOCAL_CTS_TEST_PACKAGE := android.net.native -# Tag this module as a cts test artifact -LOCAL_COMPATIBILITY_SUITE := cts vts - -LOCAL_CFLAGS := -Werror -Wall - -include $(BUILD_CTS_EXECUTABLE) From 1f5f11e681bd1ae6c1477c238966a5572b8d09f9 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 16 Apr 2019 17:02:53 +0800 Subject: [PATCH 0638/1415] Add bypass private DNS test case and null network test for DnsResolver cts 1. add test case for testing bypass Private DNS 2. add null network test 3. minor change for cleanup Bug: 130594022 Test: atest DnsResolverTest Change-Id: I2da65fc1267a1975e014c0aafe2ae47df075b712 --- .../src/android/net/cts/DnsResolverTest.java | 374 +++++++++++------- 1 file changed, 227 insertions(+), 147 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 945f51dbc8..e16fce09bf 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -21,20 +21,25 @@ import static android.net.DnsResolver.FLAG_EMPTY; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; -import static android.system.OsConstants.EBADF; +import static android.system.OsConstants.ETIMEDOUT; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.ContentResolver; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; import android.net.DnsPacket; import android.net.DnsResolver; +import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.ParseException; import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; +import android.provider.Settings; import android.system.ErrnoException; import android.test.AndroidTestCase; import android.util.Log; @@ -53,20 +58,63 @@ public class DnsResolverTest extends AndroidTestCase { private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + static final String TEST_DOMAIN = "www.google.com"; + static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google"; + static final byte[] TEST_BLOB = new byte[]{ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ + }; static final int TIMEOUT_MS = 12_000; static final int CANCEL_TIMEOUT_MS = 3_000; static final int CANCEL_RETRY_TIMES = 5; static final int NXDOMAIN = 3; + static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; + private ContentResolver mCR; private ConnectivityManager mCM; private Executor mExecutor; private DnsResolver mDns; + private String mOldMode; + private String mOldDnsSpecifier; + + @Override protected void setUp() throws Exception { super.setUp(); mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mDns = DnsResolver.getInstance(); mExecutor = new Handler(Looper.getMainLooper())::post; + mCR = getContext().getContentResolver(); + storePrivateDnsSetting(); + } + + @Override + protected void tearDown() throws Exception { + restorePrivateDnsSetting(); + super.tearDown(); + } + + private void storePrivateDnsSetting() { + // Store private DNS setting + mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); + } + + private void restorePrivateDnsSetting() { + // restore private DNS setting + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); } private static String byteArrayToHexString(byte[] bytes) { @@ -94,6 +142,9 @@ public class DnsResolverTest extends AndroidTestCase { "This test requires that at least one network be connected. " + "Please ensure that the device is connected to a network.", testableNetworks.size() >= 1); + // In order to test query with null network, add null as an element. + // Test cases which query with null network will go on default network. + testableNetworks.add(null); return testableNetworks.toArray(new Network[0]); } @@ -105,15 +156,12 @@ public class DnsResolverTest extends AndroidTestCase { public DnsParseException(String msg) { super(msg); } - - public DnsParseException(String msg, Throwable cause) { - super(msg, cause); - } } private static class DnsAnswer extends DnsPacket { DnsAnswer(@NonNull byte[] data) throws DnsParseException { super(data); + // Check QR field.(query (0), or a response (1)). if ((mHeader.flags & (1 << 15)) == 0) { throw new DnsParseException("Not an answer packet"); @@ -123,10 +171,12 @@ public class DnsResolverTest extends AndroidTestCase { int getRcode() { return mHeader.rcode; } - int getANCount(){ + + int getANCount() { return mHeader.getRecordCount(ANSECTION); } - int getQDCount(){ + + int getQDCount() { return mHeader.getRecordCount(QDSECTION); } } @@ -173,7 +223,7 @@ public class DnsResolverTest extends AndroidTestCase { mRcode = rcode; try { mDnsAnswer = new DnsAnswer(answer); - } catch (DnsParseException e) { + } catch (ParseException | DnsParseException e) { fail(mMsg + e.getMessage()); } Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); @@ -222,90 +272,76 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQuery() { - final String dname = "www.google.com"; - final String msg = "RawQuery " + dname; + public void testRawQuery() throws InterruptedException { + final String msg = "RawQuery " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); - mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - callback.assertHasAnswer(); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertHasAnswer(); } } - public void testRawQueryBlob() { + public void testRawQueryBlob() throws InterruptedException { final byte[] blob = new byte[]{ - /* Header */ - 0x55, 0x66, /* Transaction ID */ - 0x01, 0x00, /* Flags */ - 0x00, 0x01, /* Questions */ - 0x00, 0x00, /* Answer RRs */ - 0x00, 0x00, /* Authority RRs */ - 0x00, 0x00, /* Additional RRs */ - /* Queries */ - 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, - 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01 /* Class */ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ }; final String msg = "RawQuery blob " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - callback.assertHasAnswer(); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertHasAnswer(); } } - public void testRawQueryRoot() { + public void testRawQueryRoot() throws InterruptedException { final String dname = ""; final String msg = "RawQuery empty dname(ROOT) "; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - // Except no answer record because the root does not have AAAA records. - callback.assertEmptyAnswer(); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + // Except no answer record because the root does not have AAAA records. + callback.assertEmptyAnswer(); } } - public void testRawQueryNXDomain() { + public void testRawQueryNXDomain() throws InterruptedException { final String dname = "test1-nx.metric.gstatic.com"; final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - callback.assertNXDomain(); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNXDomain(); } } - public void testRawQueryCancel() throws ErrnoException { - final String dname = "www.google.com"; - final String msg = "Test cancel RawQuery " + dname; + public void testRawQueryCancel() throws InterruptedException { + final String msg = "Test cancel RawQuery " + TEST_DOMAIN; // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -319,39 +355,22 @@ public class DnsResolverTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); - mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); latch.countDown(); }); - try { - retry = callback.needRetry(); - assertTrue(msg + " query was not cancelled", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } while (retry); } } - public void testRawQueryBlobCancel() throws ErrnoException { - final byte[] blob = new byte[]{ - /* Header */ - 0x55, 0x66, /* Transaction ID */ - 0x01, 0x00, /* Flags */ - 0x00, 0x01, /* Questions */ - 0x00, 0x00, /* Answer RRs */ - 0x00, 0x00, /* Authority RRs */ - 0x00, 0x00, /* Additional RRs */ - /* Queries */ - 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, - 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01 /* Class */ - }; - final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(blob); + public void testRawQueryBlobCancel() throws InterruptedException { + final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(TEST_BLOB); // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -365,37 +384,30 @@ public class DnsResolverTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); - mDns.rawQuery(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mDns.rawQuery(network, TEST_BLOB, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); latch.countDown(); }); - try { - retry = callback.needRetry(); - assertTrue(msg + " cancel is not done", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + retry = callback.needRetry(); + assertTrue(msg + " cancel is not done", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } while (retry); } } - public void testCancelBeforeQuery() throws ErrnoException { - final String dname = "www.google.com"; - final String msg = "Test cancelled RawQuery " + dname; + public void testCancelBeforeQuery() throws InterruptedException { + final String msg = "Test cancelled RawQuery " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); final CancellationSignal cancelSignal = new CancellationSignal(); cancelSignal.cancel(); - mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, mExecutor, cancelSignal, callback); - try { - assertTrue(msg + " should not return any answers", - !callback.waitForAnswer(CANCEL_TIMEOUT_MS)); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " should not return any answers", + !callback.waitForAnswer(CANCEL_TIMEOUT_MS)); } } @@ -462,27 +474,21 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddress() { - final String dname = "www.google.com"; - final String msg = "Test query for InetAddress " + dname; + public void testQueryForInetAddress() throws InterruptedException { + final String msg = "Test query for InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); } } - public void testQueryCancelForInetAddress() throws ErrnoException { - final String dname = "www.google.com"; - final String msg = "Test cancel query for InetAddress " + dname; + public void testQueryCancelForInetAddress() throws InterruptedException { + final String msg = "Test cancel query for InetAddress " + TEST_DOMAIN; // Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to // expect that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -497,57 +503,131 @@ public class DnsResolverTest extends AndroidTestCase { final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, cancelSignal); - mDns.query(network, dname, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mDns.query(network, TEST_DOMAIN, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); latch.countDown(); }); - try { - retry = callback.needRetry(); - assertTrue(msg + " query was not cancelled", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } while (retry); } } - public void testQueryForInetAddressIpv4() { - final String dname = "www.google.com"; - final String msg = "Test query for IPv4 InetAddress " + dname; + public void testQueryForInetAddressIpv4() throws InterruptedException { + final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, dname, TYPE_A, FLAG_NO_CACHE_LOOKUP, + mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); - assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer()); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer()); } } - public void testQueryForInetAddressIpv6() { - final String dname = "www.google.com"; - final String msg = "Test query for IPv6 InetAddress " + dname; + public void testQueryForInetAddressIpv6() throws InterruptedException { + final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, dname, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); - assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer()); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer()); + } + } + + private void awaitPrivateDnsSetting(@NonNull String msg, + @NonNull Network network, @NonNull String server) throws InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); + NetworkCallback callback = new NetworkCallback() { + @Override + public void onLinkPropertiesChanged(Network n, LinkProperties lp) { + if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) { + latch.countDown(); + } } + }; + mCM.registerNetworkCallback(request, callback); + assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + mCM.unregisterNetworkCallback(callback); + } + + public void testPrivateDnsBypass() throws InterruptedException { + final Network[] testNetworks = getTestableNetworks(); + + // Set an invalid private DNS server + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); + + final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; + for (Network network : testNetworks) { + // This test cannot be ran with null network because we need to explicitly pass a + // private DNS bypassable network or bind one. + if (network == null) continue; + + // wait for private DNS setting propagating + awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", + network, INVALID_PRIVATE_DNS_SERVER); + + final CountDownLatch latch = new CountDownLatch(1); + final DnsResolver.Callback> errorCallback = + new DnsResolver.Callback>() { + @Override + public void onAnswer(@NonNull List answerList, int rcode) { + fail(msg + " should not get valid answer"); + } + + @Override + public void onError(@NonNull DnsResolver.DnsException error) { + assertEquals(DnsResolver.ERROR_SYSTEM, error.code); + assertEquals(ETIMEDOUT, ((ErrnoException) error.getCause()).errno); + latch.countDown(); + } + }; + // Private DNS strict mode with invalid DNS server is set + // Expect no valid answer returned but ErrnoException with ETIMEDOUT + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, errorCallback); + + assertTrue(msg + " invalid server round. No response after " + TIMEOUT_MS + "ms.", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + // Bypass privateDns, expect query works fine + mDns.query(network.getPrivateDnsBypassingCopy(), + TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + + assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + + // To ensure private DNS bypass still work even if passing null network. + // Bind process network with a private DNS bypassable network. + mCM.bindProcessToNetwork(network.getPrivateDnsBypassingCopy()); + final VerifyCancelInetAddressCallback callbackWithNullNetwork = + new VerifyCancelInetAddressCallback(msg + " with null network ", null); + mDns.query(null, + TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callbackWithNullNetwork); + + assertTrue(msg + " with null network bypass private DNS round. No answer after " + + TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer()); + assertTrue(msg + " with null network returned 0 results", + !callbackWithNullNetwork.isAnswerEmpty()); + + // Reset process network to default. + mCM.bindProcessToNetwork(null); } } } From 063b4e109e41ea63c52724f9a6e978aae25483aa Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 28 May 2019 10:44:43 +0800 Subject: [PATCH 0639/1415] Fix keepalive CTS fail for devices with kernel older than 4.8 If kernel < 4.8 then it doesn't support get socket option TCP_REPAIR_WINDOW, thus TCP keepalive cannot be supported. However, it might still support NAT-T keepalive. Test TCP keepalive only if it is supported by kernel. Bug: 133652079 Test: atest android.net.cts.ConnectivityManagerTest#testMajorMinorVersionCompare \ android.net.cts.ConnectivityManagerTest#testSocketKeepaliveLimit \ android.net.cts.ConnectivityManagerTest#testSocketKeepaliveUnprivileged \ android.net.cts.ConnectivityManagerTest#testKeepaliveUnsupported \ android.net.cts.ConnectivityManagerTest#testCreateTcpKeepalive Change-Id: I3f8456deea2b4ded762a413c8e27b58ce54ce0aa --- .../net/cts/ConnectivityManagerTest.java | 178 ++++++++++++------ 1 file changed, 119 insertions(+), 59 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 4b2c5794ed..fd4fdebea4 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -59,6 +59,7 @@ import android.os.Looper; import android.os.MessageQueue; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.VintfRuntimeInfo; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; import android.system.Os; @@ -66,6 +67,7 @@ import android.system.OsConstants; import android.test.AndroidTestCase; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import androidx.test.InstrumentationRegistry; @@ -1107,30 +1109,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { keepalivesPerTransport, nc); } - private boolean isKeepaliveSupported() throws Exception { - final Network network = ensureWifiConnected(); - final Executor executor = mContext.getMainExecutor(); - final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); - try (Socket s = getConnectedSocket(network, TEST_HOST, - HTTP_PORT, KEEPALIVE_SOCKET_TIMEOUT_MS, AF_INET); - SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { - sk.start(MIN_KEEPALIVE_INTERVAL); - final TestSocketKeepaliveCallback.CallbackValue result = callback.pollCallback(); - switch (result.callbackType) { - case ON_STARTED: - sk.stop(); - callback.expectStopped(); - return true; - case ON_ERROR: - if (result.error == SocketKeepalive.ERROR_UNSUPPORTED) return false; - // else fallthrough. - default: - fail("Got unexpected callback: " + result); - return false; - } - } - } - private void adoptShellPermissionIdentity() { mUiAutomation.adoptShellPermissionIdentity(); mShellPermissionIdentityAdopted = true; @@ -1143,11 +1121,85 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + private static boolean isTcpKeepaliveSupportedByKernel() { + final String kVersionString = VintfRuntimeInfo.getKernelVersion(); + return compareMajorMinorVersion(kVersionString, "4.8") >= 0; + } + + private static Pair getVersionFromString(String version) { + // Only gets major and minor number of the version string. + final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); + final Matcher m = versionPattern.matcher(version); + if (m.matches()) { + final int major = Integer.parseInt(m.group(1)); + final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3)); + return new Pair<>(major, minor); + } else { + return new Pair<>(0, 0); + } + } + + // TODO: Move to util class. + private static int compareMajorMinorVersion(final String s1, final String s2) { + final Pair v1 = getVersionFromString(s1); + final Pair v2 = getVersionFromString(s2); + + if (v1.first == v2.first) { + return Integer.compare(v1.second, v2.second); + } else { + return Integer.compare(v1.first, v2.first); + } + } + + /** + * Verifies that version string compare logic returns expected result for various cases. + * Note that only major and minor number are compared. + */ + public void testMajorMinorVersionCompare() { + assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8")); + assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1")); + assertEquals(1, compareMajorMinorVersion("5.0", "4.8")); + assertEquals(1, compareMajorMinorVersion("5", "4.8")); + assertEquals(0, compareMajorMinorVersion("5", "5.0")); + assertEquals(1, compareMajorMinorVersion("5-beta1", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8.0.0", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8-RC1", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8", "4.8")); + assertEquals(-1, compareMajorMinorVersion("3.10", "4.8.0")); + assertEquals(-1, compareMajorMinorVersion("4.7.10.10", "4.8")); + } + + /** + * Verifies that the keepalive API cannot create any keepalive when the maximum number of + * keepalives is set to 0. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + public void testKeepaliveUnsupported() throws Exception { + if (getSupportedKeepalivesFromRes() != 0) return; + + adoptShellPermissionIdentity(); + + assertEquals(0, createConcurrentSocketKeepalives(1, 0)); + assertEquals(0, createConcurrentSocketKeepalives(0, 1)); + + dropShellPermissionIdentity(); + } + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testCreateTcpKeepalive() throws Exception { adoptShellPermissionIdentity(); - if (!isKeepaliveSupported()) return; + if (getSupportedKeepalivesFromRes() == 0) return; + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support + // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive + // needs to be supported except if the kernel doesn't support it. + if (!isTcpKeepaliveSupportedByKernel()) { + // Sanity check to ensure the callback result is expected. + assertEquals(0, createConcurrentSocketKeepalives(0, 1)); + Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " + + VintfRuntimeInfo.getKernelVersion()); + return; + } final Network network = ensureWifiConnected(); final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); @@ -1212,14 +1264,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { sk.start(MIN_KEEPALIVE_INTERVAL); callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); } - } } + /** + * Creates concurrent keepalives until the specified counts of each type of keepalives are + * reached or the expected error callbacks are received for each type of keepalives. + * + * @return the total number of keepalives created. + */ private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { - // Use customization value in resource to prevent the need of privilege. - if (getSupportedKeepalivesFromRes() == 0) return 0; - final Network network = ensureWifiConnected(); final ArrayList kalist = new ArrayList<>(); @@ -1238,10 +1292,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { ka.start(MIN_KEEPALIVE_INTERVAL); TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); assertNotNull(cv); - if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR - && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { - // Limit reached. - break; + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { + if (i == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { + // Unsupported. + break; + } else if (i != 0 && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } } if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { kalist.add(ka); @@ -1267,10 +1325,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { ka.start(MIN_KEEPALIVE_INTERVAL); TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); assertNotNull(cv); - if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR - && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { - // Limit reached. - break; + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { + if (i == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { + // Unsupported. + break; + } else if (i != 0 && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } } if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { kalist.add(ka); @@ -1298,32 +1360,35 @@ public class ConnectivityManagerTest extends AndroidTestCase { */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testSocketKeepaliveLimit() throws Exception { - adoptShellPermissionIdentity(); - final int supported = getSupportedKeepalivesFromRes(); - - if (!isKeepaliveSupported()) { - // Sanity check. - assertEquals(0, supported); + if (supported == 0) { return; } + adoptShellPermissionIdentity(); + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. assertGreaterOrEqual(supported, KeepaliveUtils.MIN_SUPPORTED_KEEPALIVE_COUNT); - // Verifies that different types of keepalives can be established. + // Verifies that Nat-T keepalives can be established. assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); - assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); - - // Verifies that different types can be established at the same time. - assertEquals(supported, createConcurrentSocketKeepalives( - supported / 2, supported - supported / 2)); - // Verifies that keepalives don't get leaked in second round. assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); - assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); - assertEquals(supported, createConcurrentSocketKeepalives( - supported / 2, supported - supported / 2)); + + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support + // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. + if (isTcpKeepaliveSupportedByKernel()) { + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + + // Verifies that different types can be established at the same time. + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + } dropShellPermissionIdentity(); } @@ -1334,14 +1399,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testSocketKeepaliveUnprivileged() throws Exception { final int supported = getSupportedKeepalivesFromRes(); - - adoptShellPermissionIdentity(); - if (!isKeepaliveSupported()) { - // Sanity check. - assertEquals(0, supported); + if (supported == 0) { return; } - dropShellPermissionIdentity(); final int allowedUnprivilegedPerUid = mContext.getResources().getInteger( R.integer.config_allowedUnprivilegedKeepalivePerUid); From 3cdc25cbc47e08c1f216f18cdedeb3a9337301e7 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 23 May 2019 19:16:47 +0800 Subject: [PATCH 0640/1415] Fix ConnectivityManagerApi23Test failures and remove duplication. 1. All ConnectivityManagerApi23Test were failed due to WifiManager#setWifiEnabled doesn't allow to use since Android Q. So we need to use shell command to enable/disable Wi-Fi instead. 2. Some methods are duplicated between ConnectivityManagerApi23Test and ConnectivityManagerTest, but they are not identical. So put these methods into ConnectivityUtils to clean up duplications and prevent fork happened again. Bug: 133334943 Bug: 133209319 Test: Run the below tests on Crosshatch, Sailfish, Bonito. atest CtsNetApi23TestCases atest CtsNetTestCases Change-Id: Ic37111cb12a46f5c36c2be887250c5d762216f6e --- tests/cts/net/Android.bp | 1 + tests/cts/net/api23Test/Android.bp | 1 + .../ConnectivityManagerApi23Test.java | 279 +------------- .../net/cts/ConnectivityManagerTest.java | 299 +-------------- tests/cts/net/util/Android.bp | 25 ++ .../android/net/cts/util/CtsNetUtils.java | 353 ++++++++++++++++++ 6 files changed, 405 insertions(+), 553 deletions(-) create mode 100644 tests/cts/net/util/Android.bp create mode 100644 tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 779d5c4be2..b6ea4afe80 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -42,6 +42,7 @@ android_test { "FrameworksNetCommonTests", "core-tests-support", "compatibility-device-util-axt", + "cts-net-utils", "ctstestrunner-axt", "ctstestserver", "mockwebserver", diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index 48161cf7e7..ffe854e2e9 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -31,6 +31,7 @@ android_test { static_libs: [ "core-tests-support", "compatibility-device-util-axt", + "cts-net-utils", "ctstestrunner-axt", "ctstestserver", "mockwebserver", diff --git a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java index f38490e60e..cdb66e3d5a 100644 --- a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java +++ b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java @@ -25,58 +25,33 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkInfo.State; -import android.net.NetworkRequest; -import android.net.wifi.WifiManager; +import android.net.cts.util.CtsNetUtils; import android.os.Looper; -import android.system.Os; -import android.system.OsConstants; import android.test.AndroidTestCase; import android.util.Log; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class ConnectivityManagerApi23Test extends AndroidTestCase { private static final String TAG = ConnectivityManagerApi23Test.class.getSimpleName(); - - private static final String TEST_HOST = "connectivitycheck.gstatic.com"; - private static final int SOCKET_TIMEOUT_MS = 2000; private static final int SEND_BROADCAST_TIMEOUT = 30000; - private static final int HTTP_PORT = 80; // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT = "android.net.cts.appForApi23.getWifiConnectivityActionCount"; // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. - private static final String NETWORK_CALLBACK_ACTION = - "ConnectivityManagerTest.NetworkCallbackAction"; - private static final String HTTP_REQUEST = - "GET /generate_204 HTTP/1.0\r\n" + - "Host: " + TEST_HOST + "\r\n" + - "Connection: keep-alive\r\n\r\n"; private Context mContext; - private ConnectivityManager mCm; - private WifiManager mWifiManager; private PackageManager mPackageManager; + private CtsNetUtils mCtsNetUtils; @Override protected void setUp() throws Exception { super.setUp(); Looper.prepare(); mContext = getContext(); - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); } /** @@ -89,7 +64,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { } ConnectivityReceiver.prepare(); - toggleWifi(); + mCtsNetUtils.toggleWifi(); // The connectivity broadcast has been sent; push through a terminal broadcast // to wait for in the receive to confirm it didn't see the connectivity change. @@ -112,7 +87,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); Thread.sleep(200); - toggleWifi(); + mCtsNetUtils.toggleWifi(); Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT); assertEquals(2, sendOrderedBroadcastAndReturnResultCode( @@ -130,7 +105,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(receiver, filter); - toggleWifi(); + mCtsNetUtils.toggleWifi(); Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION); finalIntent.setClass(mContext, ConnectivityReceiver.class); mContext.sendBroadcast(finalIntent); @@ -138,19 +113,6 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { assertTrue(ConnectivityReceiver.waitForBroadcast()); } - // Toggle WiFi twice, leaving it in the state it started in - private void toggleWifi() { - if (mWifiManager.isWifiEnabled()) { - Network wifiNetwork = getWifiNetwork(); - disconnectFromWifi(wifiNetwork); - connectToWifi(); - } else { - connectToWifi(); - Network wifiNetwork = getWifiNetwork(); - disconnectFromWifi(wifiNetwork); - } - } - private int sendOrderedBroadcastAndReturnResultCode( Intent intent, int timeoutMs) throws InterruptedException { final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); @@ -167,233 +129,4 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { return resultCode; } - private Network getWifiNetwork() { - TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network network = null; - try { - network = callback.waitForAvailable(); - } catch (InterruptedException e) { - fail("NetworkCallback wait was interrupted."); - } finally { - mCm.unregisterNetworkCallback(callback); - } - assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); - return network; - } - - /** Disable WiFi and wait for it to become disconnected from the network. */ - private void disconnectFromWifi(Network wifiNetworkToCheck) { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network lostWifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - // Assert that we can establish a TCP connection on wifi. - Socket wifiBoundSocket = null; - if (wifiNetworkToCheck != null) { - try { - wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); - testHttpRequest(wifiBoundSocket); - } catch (IOException e) { - fail("HTTP request before wifi disconnected failed with: " + e); - } - } - - boolean disconnected = false; - try { - assertTrue(mWifiManager.setWifiEnabled(false)); - // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. - lostWifiNetwork = callback.waitForLost(); - assertNotNull(lostWifiNetwork); - disconnected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("disconnectFromWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); - - // Check that the socket is closed when wifi disconnects. - if (wifiBoundSocket != null) { - try { - testHttpRequest(wifiBoundSocket); - fail("HTTP request should not succeed after wifi disconnects"); - } catch (IOException expected) { - assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); - } - } - } - - /** Enable WiFi and wait for it to become connected to a network. */ - private Network connectToWifi() { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network wifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - boolean connected = false; - try { - assertTrue(mWifiManager.setWifiEnabled(true)); - // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. - wifiNetwork = callback.waitForAvailable(); - assertNotNull(wifiNetwork); - connected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("connectToWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi must be configured to connect to an access point for this test.", - connected); - return wifiNetwork; - } - - private NetworkRequest makeWifiNetworkRequest() { - return new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build(); - } - - private void testHttpRequest(Socket s) throws IOException { - OutputStream out = s.getOutputStream(); - InputStream in = s.getInputStream(); - - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); - byte[] responseBytes = new byte[4096]; - out.write(requestBytes); - in.read(responseBytes); - assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); - } - - private Socket getBoundSocket(Network network, String host, int port) throws IOException { - InetSocketAddress addr = new InetSocketAddress(host, port); - Socket s = network.getSocketFactory().createSocket(); - try { - s.setSoTimeout(SOCKET_TIMEOUT_MS); - s.connect(addr, SOCKET_TIMEOUT_MS); - } catch (IOException e) { - s.close(); - throw e; - } - return s; - } - - /** - * Receiver that captures the last connectivity change's network type and state. Recognizes - * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. - */ - private class ConnectivityActionReceiver extends BroadcastReceiver { - - private final CountDownLatch mReceiveLatch = new CountDownLatch(1); - - private final int mNetworkType; - private final NetworkInfo.State mNetState; - - ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) { - mNetworkType = networkType; - mNetState = netState; - } - - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - NetworkInfo networkInfo = null; - - // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable - // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is - // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. - if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { - networkInfo = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo); - } else if (NETWORK_CALLBACK_ACTION.equals(action)) { - Network network = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); - networkInfo = mCm.getNetworkInfo(network); - if (networkInfo == null) { - // When disconnecting, it seems like we get an intent sent with an invalid - // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), - // it is invalid. Ignore these. - Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " - + "invalid network"); - return; - } - } else { - fail("ConnectivityActionReceiver received unxpected intent action: " + action); - } - - assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); - int networkType = networkInfo.getType(); - State networkState = networkInfo.getState(); - Log.i(TAG, "Network type: " + networkType + " state: " + networkState); - if (networkType == mNetworkType && networkInfo.getState() == mNetState) { - mReceiveLatch.countDown(); - } - } - - public boolean waitForState() throws InterruptedException { - return mReceiveLatch.await(30, TimeUnit.SECONDS); - } - } - - /** - * Callback used in testRegisterNetworkCallback that allows caller to block on - * {@code onAvailable}. - */ - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CountDownLatch mAvailableLatch = new CountDownLatch(1); - private final CountDownLatch mLostLatch = new CountDownLatch(1); - private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); - - public Network currentNetwork; - public Network lastLostNetwork; - - public Network waitForAvailable() throws InterruptedException { - return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; - } - - public Network waitForLost() throws InterruptedException { - return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; - } - - public boolean waitForUnavailable() throws InterruptedException { - return mUnavailableLatch.await(2, TimeUnit.SECONDS); - } - - - @Override - public void onAvailable(Network network) { - currentNetwork = network; - mAvailableLatch.countDown(); - } - - @Override - public void onLost(Network network) { - lastLostNetwork = network; - if (network.equals(currentNetwork)) { - currentNetwork = null; - } - mLostLatch.countDown(); - } - - @Override - public void onUnavailable() { - mUnavailableLatch.countDown(); - } - } } \ No newline at end of file diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index c444445b2a..c3ae793aae 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -21,8 +21,12 @@ import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver; +import static android.net.cts.util.CtsNetUtils.HTTP_PORT; +import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION; +import static android.net.cts.util.CtsNetUtils.TEST_HOST; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; import static android.system.OsConstants.AF_INET; @@ -34,7 +38,6 @@ import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.UiAutomation; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -53,6 +56,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.SocketKeepalive; +import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; import android.os.Looper; @@ -61,15 +65,12 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; -import android.system.Os; -import android.system.OsConstants; import android.test.AndroidTestCase; import android.text.TextUtils; import android.util.Log; import androidx.test.InstrumentationRegistry; -import com.android.compatibility.common.util.SystemUtil; import com.android.internal.R; import com.android.internal.telephony.PhoneConstants; @@ -107,8 +108,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 - private static final String TEST_HOST = "connectivitycheck.gstatic.com"; - private static final int SOCKET_TIMEOUT_MS = 2000; private static final int CONNECT_TIMEOUT_MS = 2000; private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000; private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000; @@ -116,16 +115,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; - private static final int HTTP_PORT = 80; - private static final String HTTP_REQUEST = - "GET /generate_204 HTTP/1.0\r\n" + - "Host: " + TEST_HOST + "\r\n" + - "Connection: keep-alive\r\n\r\n"; - - // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. - private static final String NETWORK_CALLBACK_ACTION = - "ConnectivityManagerTest.NetworkCallbackAction"; - // device could have only one interface: data, wifi. private static final int MIN_NUM_NETWORK_TYPES = 1; @@ -137,8 +126,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { private final HashMap mNetworks = new HashMap(); boolean mWifiConnectAttempted; - private TestNetworkCallback mCellNetworkCallback; private UiAutomation mUiAutomation; + private CtsNetUtils mCtsNetUtils; private boolean mShellPermissionIdentityAdopted; @Override @@ -150,6 +139,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); mWifiConnectAttempted = false; // Get com.android.internal.R.array.networkAttributes @@ -174,10 +164,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { protected void tearDown() throws Exception { // Return WiFi to its original disabled state after tests that explicitly connect. if (mWifiConnectAttempted) { - disconnectFromWifi(null); + mCtsNetUtils.disconnectFromWifi(null); } - if (cellConnectAttempted()) { - disconnectFromCell(); + if (mCtsNetUtils.cellConnectAttempted()) { + mCtsNetUtils.disconnectFromCell(); } dropShellPermissionIdentity(); super.tearDown(); @@ -190,10 +180,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { */ private Network ensureWifiConnected() { if (mWifiManager.isWifiEnabled()) { - return getWifiNetwork(); + return mCtsNetUtils.getWifiNetwork(); } mWifiConnectAttempted = true; - return connectToWifi(); + return mCtsNetUtils.connectToWifi(); } public void testIsNetworkTypeValid() { @@ -301,8 +291,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { return; } - Network wifiNetwork = connectToWifi(); - Network cellNetwork = connectToCell(); + Network wifiNetwork = mCtsNetUtils.connectToWifi(); + Network cellNetwork = mCtsNetUtils.connectToCell(); // This server returns the requestor's IP address as the response body. URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text"); String wifiAddressString = httpGet(wifiNetwork, url); @@ -320,33 +310,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork)); } - private Network connectToCell() throws InterruptedException { - if (cellConnectAttempted()) { - throw new IllegalStateException("Already connected"); - } - NetworkRequest cellRequest = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NET_CAPABILITY_INTERNET) - .build(); - mCellNetworkCallback = new TestNetworkCallback(); - mCm.requestNetwork(cellRequest, mCellNetworkCallback); - final Network cellNetwork = mCellNetworkCallback.waitForAvailable(); - assertNotNull("Cell network not available within timeout", cellNetwork); - return cellNetwork; - } - - private boolean cellConnectAttempted() { - return mCellNetworkCallback != null; - } - - private void disconnectFromCell() { - if (!cellConnectAttempted()) { - throw new IllegalStateException("Cell connection not attempted"); - } - mCm.unregisterNetworkCallback(mCellNetworkCallback); - mCellNetworkCallback = null; - } - /** * Performs a HTTP GET to the specified URL on the specified Network, and returns * the response body decoded as UTF-8. @@ -508,7 +471,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { filter.addAction(NETWORK_CALLBACK_ACTION); ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); mContext.registerReceiver(receiver, filter); // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION. @@ -567,7 +530,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testRequestNetworkCallback_onUnavailable() { final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); if (previousWifiEnabledState) { - disconnectFromWifi(null); + mCtsNetUtils.disconnectFromWifi(null); } final TestNetworkCallback callback = new TestNetworkCallback(); @@ -584,42 +547,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { } finally { mCm.unregisterNetworkCallback(callback); if (previousWifiEnabledState) { - connectToWifi(); + mCtsNetUtils.connectToWifi(); } } } - /** Enable WiFi and wait for it to become connected to a network. */ - private Network connectToWifi() { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network wifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - boolean connected = false; - try { - SystemUtil.runShellCommand("svc wifi enable"); - // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. - wifiNetwork = callback.waitForAvailable(); - assertNotNull(wifiNetwork); - connected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("connectToWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi must be configured to connect to an access point for this test.", - connected); - return wifiNetwork; - } - private InetAddress getFirstV4Address(Network network) { LinkProperties linkProperties = mCm.getLinkProperties(network); for (InetAddress address : linkProperties.getAddresses()) { @@ -630,199 +562,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { return null; } - private Socket getBoundSocket(Network network, String host, int port) throws IOException { - InetSocketAddress addr = new InetSocketAddress(host, port); - Socket s = network.getSocketFactory().createSocket(); - try { - s.setSoTimeout(SOCKET_TIMEOUT_MS); - s.connect(addr, SOCKET_TIMEOUT_MS); - } catch (IOException e) { - s.close(); - throw e; - } - return s; - } - - private void testHttpRequest(Socket s) throws IOException { - OutputStream out = s.getOutputStream(); - InputStream in = s.getInputStream(); - - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); - byte[] responseBytes = new byte[4096]; - out.write(requestBytes); - in.read(responseBytes); - assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); - } - - /** Disable WiFi and wait for it to become disconnected from the network. */ - private void disconnectFromWifi(Network wifiNetworkToCheck) { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network lostWifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - // Assert that we can establish a TCP connection on wifi. - Socket wifiBoundSocket = null; - if (wifiNetworkToCheck != null) { - try { - wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); - testHttpRequest(wifiBoundSocket); - } catch (IOException e) { - fail("HTTP request before wifi disconnected failed with: " + e); - } - } - - boolean disconnected = false; - try { - SystemUtil.runShellCommand("svc wifi disable"); - // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. - lostWifiNetwork = callback.waitForLost(); - assertNotNull(lostWifiNetwork); - disconnected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("disconnectFromWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); - - // Check that the socket is closed when wifi disconnects. - if (wifiBoundSocket != null) { - try { - testHttpRequest(wifiBoundSocket); - fail("HTTP request should not succeed after wifi disconnects"); - } catch (IOException expected) { - assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); - } - } - } - - /** - * Receiver that captures the last connectivity change's network type and state. Recognizes - * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. - */ - private class ConnectivityActionReceiver extends BroadcastReceiver { - - private final CountDownLatch mReceiveLatch = new CountDownLatch(1); - - private final int mNetworkType; - private final NetworkInfo.State mNetState; - - ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) { - mNetworkType = networkType; - mNetState = netState; - } - - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - NetworkInfo networkInfo = null; - - // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable - // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is - // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. - if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { - networkInfo = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo); - } else if (NETWORK_CALLBACK_ACTION.equals(action)) { - Network network = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); - networkInfo = mCm.getNetworkInfo(network); - if (networkInfo == null) { - // When disconnecting, it seems like we get an intent sent with an invalid - // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), - // it is invalid. Ignore these. - Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " - + "invalid network"); - return; - } - } else { - fail("ConnectivityActionReceiver received unxpected intent action: " + action); - } - - assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); - int networkType = networkInfo.getType(); - State networkState = networkInfo.getState(); - Log.i(TAG, "Network type: " + networkType + " state: " + networkState); - if (networkType == mNetworkType && networkInfo.getState() == mNetState) { - mReceiveLatch.countDown(); - } - } - - public boolean waitForState() throws InterruptedException { - return mReceiveLatch.await(30, TimeUnit.SECONDS); - } - } - - /** - * Callback used in testRegisterNetworkCallback that allows caller to block on - * {@code onAvailable}. - */ - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CountDownLatch mAvailableLatch = new CountDownLatch(1); - private final CountDownLatch mLostLatch = new CountDownLatch(1); - private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); - - public Network currentNetwork; - public Network lastLostNetwork; - - public Network waitForAvailable() throws InterruptedException { - return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; - } - - public Network waitForLost() throws InterruptedException { - return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; - } - - public boolean waitForUnavailable() throws InterruptedException { - return mUnavailableLatch.await(2, TimeUnit.SECONDS); - } - - - @Override - public void onAvailable(Network network) { - currentNetwork = network; - mAvailableLatch.countDown(); - } - - @Override - public void onLost(Network network) { - lastLostNetwork = network; - if (network.equals(currentNetwork)) { - currentNetwork = null; - } - mLostLatch.countDown(); - } - - @Override - public void onUnavailable() { - mUnavailableLatch.countDown(); - } - } - - private Network getWifiNetwork() { - TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network network = null; - try { - network = callback.waitForAvailable(); - } catch (InterruptedException e) { - fail("NetworkCallback wait was interrupted."); - } finally { - mCm.unregisterNetworkCallback(callback); - } - assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); - return network; - } - /** Verify restricted networks cannot be requested. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") public void testRestrictedNetworks() { @@ -1151,7 +890,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (!isKeepaliveSupported()) return; final Network network = ensureWifiConnected(); - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8"); // So far only ipv4 tcp keepalive offload is supported. // TODO: add test case for ipv6 tcp keepalive offload when it is supported. try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp new file mode 100644 index 0000000000..1f94613ffb --- /dev/null +++ b/tests/cts/net/util/Android.bp @@ -0,0 +1,25 @@ +// +// Copyright (C) 2019 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. +// + +// Common utilities for cts net tests. +java_library { + name: "cts-net-utils", + srcs: ["java/**/*.java", "java/**/*.kt"], + static_libs: [ + "compatibility-device-util-axt", + "junit", + ], +} \ No newline at end of file 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 new file mode 100644 index 0000000000..e19d2bafb7 --- /dev/null +++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2019 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.util; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkInfo.State; +import android.net.NetworkRequest; +import android.net.wifi.WifiManager; +import android.system.Os; +import android.system.OsConstants; +import android.util.Log; + +import com.android.compatibility.common.util.SystemUtil; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public final class CtsNetUtils { + private static final String TAG = CtsNetUtils.class.getSimpleName(); + private static final int DURATION = 10000; + private static final int SOCKET_TIMEOUT_MS = 2000; + + public static final int HTTP_PORT = 80; + public static final String TEST_HOST = "connectivitycheck.gstatic.com"; + public static final String HTTP_REQUEST = + "GET /generate_204 HTTP/1.0\r\n" + + "Host: " + TEST_HOST + "\r\n" + + "Connection: keep-alive\r\n\r\n"; + // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. + public static final String NETWORK_CALLBACK_ACTION = + "ConnectivityManagerTest.NetworkCallbackAction"; + + private Context mContext; + private ConnectivityManager mCm; + private WifiManager mWifiManager; + private TestNetworkCallback mCellNetworkCallback; + + public CtsNetUtils(Context context) { + mContext = context; + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + } + + // Toggle WiFi twice, leaving it in the state it started in + public void toggleWifi() { + if (mWifiManager.isWifiEnabled()) { + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); + connectToWifi(); + } else { + connectToWifi(); + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); + } + } + + /** Enable WiFi and wait for it to become connected to a network. */ + public Network connectToWifi() { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network wifiNetwork = null; + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + boolean connected = false; + try { + SystemUtil.runShellCommand("svc wifi enable"); + // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. + wifiNetwork = callback.waitForAvailable(); + assertNotNull(wifiNetwork); + connected = receiver.waitForState(); + } catch (InterruptedException ex) { + fail("connectToWifi was interrupted"); + } finally { + mCm.unregisterNetworkCallback(callback); + mContext.unregisterReceiver(receiver); + } + + assertTrue("Wifi must be configured to connect to an access point for this test.", + connected); + return wifiNetwork; + } + + /** Disable WiFi and wait for it to become disconnected from the network. */ + public void disconnectFromWifi(Network wifiNetworkToCheck) { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network lostWifiNetwork = null; + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + // Assert that we can establish a TCP connection on wifi. + Socket wifiBoundSocket = null; + if (wifiNetworkToCheck != null) { + try { + wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); + testHttpRequest(wifiBoundSocket); + } catch (IOException e) { + fail("HTTP request before wifi disconnected failed with: " + e); + } + } + + boolean disconnected = false; + try { + SystemUtil.runShellCommand("svc wifi disable"); + // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. + lostWifiNetwork = callback.waitForLost(); + assertNotNull(lostWifiNetwork); + disconnected = receiver.waitForState(); + } catch (InterruptedException ex) { + fail("disconnectFromWifi was interrupted"); + } finally { + mCm.unregisterNetworkCallback(callback); + mContext.unregisterReceiver(receiver); + } + + assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); + + // Check that the socket is closed when wifi disconnects. + if (wifiBoundSocket != null) { + try { + testHttpRequest(wifiBoundSocket); + fail("HTTP request should not succeed after wifi disconnects"); + } catch (IOException expected) { + assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); + } + } + } + + public Network getWifiNetwork() { + TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network network = null; + try { + network = callback.waitForAvailable(); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + } + assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); + return network; + } + + public Network connectToCell() throws InterruptedException { + if (cellConnectAttempted()) { + throw new IllegalStateException("Already connected"); + } + NetworkRequest cellRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + mCellNetworkCallback = new TestNetworkCallback(); + mCm.requestNetwork(cellRequest, mCellNetworkCallback); + final Network cellNetwork = mCellNetworkCallback.waitForAvailable(); + assertNotNull("Cell network not available. " + + "Please ensure the device has working mobile data.", cellNetwork); + return cellNetwork; + } + + public void disconnectFromCell() { + if (!cellConnectAttempted()) { + throw new IllegalStateException("Cell connection not attempted"); + } + mCm.unregisterNetworkCallback(mCellNetworkCallback); + mCellNetworkCallback = null; + } + + public boolean cellConnectAttempted() { + return mCellNetworkCallback != null; + } + + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + + private void testHttpRequest(Socket s) throws IOException { + OutputStream out = s.getOutputStream(); + InputStream in = s.getInputStream(); + + final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + byte[] responseBytes = new byte[4096]; + out.write(requestBytes); + in.read(responseBytes); + assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); + } + + private Socket getBoundSocket(Network network, String host, int port) throws IOException { + InetSocketAddress addr = new InetSocketAddress(host, port); + Socket s = network.getSocketFactory().createSocket(); + try { + s.setSoTimeout(SOCKET_TIMEOUT_MS); + s.connect(addr, SOCKET_TIMEOUT_MS); + } catch (IOException e) { + s.close(); + throw e; + } + return s; + } + + /** + * Receiver that captures the last connectivity change's network type and state. Recognizes + * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. + */ + public static class ConnectivityActionReceiver extends BroadcastReceiver { + + private final CountDownLatch mReceiveLatch = new CountDownLatch(1); + + private final int mNetworkType; + private final NetworkInfo.State mNetState; + private final ConnectivityManager mCm; + + public ConnectivityActionReceiver(ConnectivityManager cm, int networkType, + NetworkInfo.State netState) { + this.mCm = cm; + mNetworkType = networkType; + mNetState = netState; + } + + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + NetworkInfo networkInfo = null; + + // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable + // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is + // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { + networkInfo = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", + networkInfo); + } else if (NETWORK_CALLBACK_ACTION.equals(action)) { + Network network = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); + networkInfo = this.mCm.getNetworkInfo(network); + if (networkInfo == null) { + // When disconnecting, it seems like we get an intent sent with an invalid + // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), + // it is invalid. Ignore these. + Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " + + "invalid network"); + return; + } + } else { + fail("ConnectivityActionReceiver received unxpected intent action: " + action); + } + + assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); + int networkType = networkInfo.getType(); + State networkState = networkInfo.getState(); + Log.i(TAG, "Network type: " + networkType + " state: " + networkState); + if (networkType == mNetworkType && networkInfo.getState() == mNetState) { + mReceiveLatch.countDown(); + } + } + + public boolean waitForState() throws InterruptedException { + return mReceiveLatch.await(30, TimeUnit.SECONDS); + } + } + + /** + * Callback used in testRegisterNetworkCallback that allows caller to block on + * {@code onAvailable}. + */ + public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CountDownLatch mAvailableLatch = new CountDownLatch(1); + private final CountDownLatch mLostLatch = new CountDownLatch(1); + private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); + + public Network currentNetwork; + public Network lastLostNetwork; + + public Network waitForAvailable() throws InterruptedException { + return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; + } + + public Network waitForLost() throws InterruptedException { + return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; + } + + public boolean waitForUnavailable() throws InterruptedException { + return mUnavailableLatch.await(2, TimeUnit.SECONDS); + } + + + @Override + public void onAvailable(Network network) { + currentNetwork = network; + mAvailableLatch.countDown(); + } + + @Override + public void onLost(Network network) { + lastLostNetwork = network; + if (network.equals(currentNetwork)) { + currentNetwork = null; + } + mLostLatch.countDown(); + } + + @Override + public void onUnavailable() { + mUnavailableLatch.countDown(); + } + } +} From e3288fddcd7c91572c91c4c06a242d9aed14865e Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 23 May 2019 19:16:47 +0800 Subject: [PATCH 0641/1415] Fix ConnectivityManagerApi23Test failures and remove duplication. 1. All ConnectivityManagerApi23Test were failed due to WifiManager#setWifiEnabled doesn't allow to use since Android Q. So we need to use shell command to enable/disable Wi-Fi instead. 2. Some methods are duplicated between ConnectivityManagerApi23Test and ConnectivityManagerTest, but they are not identical. So put these methods into ConnectivityUtils to clean up duplications and prevent fork happened again. Bug: 133334943 Bug: 133209319 Test: Run the below tests on Crosshatch, Sailfish, Bonito. atest CtsNetApi23TestCases atest CtsNetTestCases Change-Id: Ic37111cb12a46f5c36c2be887250c5d762216f6e Merged-In: I075b7408d2a1e1145c7a9031075e07fa1db37fed Merged-In: I0c02357eff07b98c1745de35d08ae6b8349de7fb Merged-In: I04d1e1d096bcd4a9626cf9f00396fca7f9892a82 --- tests/cts/net/Android.bp | 1 + tests/cts/net/api23Test/Android.bp | 1 + .../ConnectivityManagerApi23Test.java | 279 +------------- .../net/cts/ConnectivityManagerTest.java | 298 +-------------- tests/cts/net/util/Android.bp | 25 ++ .../android/net/cts/util/CtsNetUtils.java | 353 ++++++++++++++++++ 6 files changed, 405 insertions(+), 552 deletions(-) create mode 100644 tests/cts/net/util/Android.bp create mode 100644 tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 779d5c4be2..b6ea4afe80 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -42,6 +42,7 @@ android_test { "FrameworksNetCommonTests", "core-tests-support", "compatibility-device-util-axt", + "cts-net-utils", "ctstestrunner-axt", "ctstestserver", "mockwebserver", diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index 48161cf7e7..ffe854e2e9 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -31,6 +31,7 @@ android_test { static_libs: [ "core-tests-support", "compatibility-device-util-axt", + "cts-net-utils", "ctstestrunner-axt", "ctstestserver", "mockwebserver", diff --git a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java index f38490e60e..cdb66e3d5a 100644 --- a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java +++ b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java @@ -25,58 +25,33 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkInfo.State; -import android.net.NetworkRequest; -import android.net.wifi.WifiManager; +import android.net.cts.util.CtsNetUtils; import android.os.Looper; -import android.system.Os; -import android.system.OsConstants; import android.test.AndroidTestCase; import android.util.Log; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class ConnectivityManagerApi23Test extends AndroidTestCase { private static final String TAG = ConnectivityManagerApi23Test.class.getSimpleName(); - - private static final String TEST_HOST = "connectivitycheck.gstatic.com"; - private static final int SOCKET_TIMEOUT_MS = 2000; private static final int SEND_BROADCAST_TIMEOUT = 30000; - private static final int HTTP_PORT = 80; // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT = "android.net.cts.appForApi23.getWifiConnectivityActionCount"; // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. - private static final String NETWORK_CALLBACK_ACTION = - "ConnectivityManagerTest.NetworkCallbackAction"; - private static final String HTTP_REQUEST = - "GET /generate_204 HTTP/1.0\r\n" + - "Host: " + TEST_HOST + "\r\n" + - "Connection: keep-alive\r\n\r\n"; private Context mContext; - private ConnectivityManager mCm; - private WifiManager mWifiManager; private PackageManager mPackageManager; + private CtsNetUtils mCtsNetUtils; @Override protected void setUp() throws Exception { super.setUp(); Looper.prepare(); mContext = getContext(); - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); } /** @@ -89,7 +64,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { } ConnectivityReceiver.prepare(); - toggleWifi(); + mCtsNetUtils.toggleWifi(); // The connectivity broadcast has been sent; push through a terminal broadcast // to wait for in the receive to confirm it didn't see the connectivity change. @@ -112,7 +87,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); Thread.sleep(200); - toggleWifi(); + mCtsNetUtils.toggleWifi(); Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT); assertEquals(2, sendOrderedBroadcastAndReturnResultCode( @@ -130,7 +105,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(receiver, filter); - toggleWifi(); + mCtsNetUtils.toggleWifi(); Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION); finalIntent.setClass(mContext, ConnectivityReceiver.class); mContext.sendBroadcast(finalIntent); @@ -138,19 +113,6 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { assertTrue(ConnectivityReceiver.waitForBroadcast()); } - // Toggle WiFi twice, leaving it in the state it started in - private void toggleWifi() { - if (mWifiManager.isWifiEnabled()) { - Network wifiNetwork = getWifiNetwork(); - disconnectFromWifi(wifiNetwork); - connectToWifi(); - } else { - connectToWifi(); - Network wifiNetwork = getWifiNetwork(); - disconnectFromWifi(wifiNetwork); - } - } - private int sendOrderedBroadcastAndReturnResultCode( Intent intent, int timeoutMs) throws InterruptedException { final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); @@ -167,233 +129,4 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { return resultCode; } - private Network getWifiNetwork() { - TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network network = null; - try { - network = callback.waitForAvailable(); - } catch (InterruptedException e) { - fail("NetworkCallback wait was interrupted."); - } finally { - mCm.unregisterNetworkCallback(callback); - } - assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); - return network; - } - - /** Disable WiFi and wait for it to become disconnected from the network. */ - private void disconnectFromWifi(Network wifiNetworkToCheck) { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network lostWifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - // Assert that we can establish a TCP connection on wifi. - Socket wifiBoundSocket = null; - if (wifiNetworkToCheck != null) { - try { - wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); - testHttpRequest(wifiBoundSocket); - } catch (IOException e) { - fail("HTTP request before wifi disconnected failed with: " + e); - } - } - - boolean disconnected = false; - try { - assertTrue(mWifiManager.setWifiEnabled(false)); - // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. - lostWifiNetwork = callback.waitForLost(); - assertNotNull(lostWifiNetwork); - disconnected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("disconnectFromWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); - - // Check that the socket is closed when wifi disconnects. - if (wifiBoundSocket != null) { - try { - testHttpRequest(wifiBoundSocket); - fail("HTTP request should not succeed after wifi disconnects"); - } catch (IOException expected) { - assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); - } - } - } - - /** Enable WiFi and wait for it to become connected to a network. */ - private Network connectToWifi() { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network wifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - boolean connected = false; - try { - assertTrue(mWifiManager.setWifiEnabled(true)); - // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. - wifiNetwork = callback.waitForAvailable(); - assertNotNull(wifiNetwork); - connected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("connectToWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi must be configured to connect to an access point for this test.", - connected); - return wifiNetwork; - } - - private NetworkRequest makeWifiNetworkRequest() { - return new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build(); - } - - private void testHttpRequest(Socket s) throws IOException { - OutputStream out = s.getOutputStream(); - InputStream in = s.getInputStream(); - - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); - byte[] responseBytes = new byte[4096]; - out.write(requestBytes); - in.read(responseBytes); - assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); - } - - private Socket getBoundSocket(Network network, String host, int port) throws IOException { - InetSocketAddress addr = new InetSocketAddress(host, port); - Socket s = network.getSocketFactory().createSocket(); - try { - s.setSoTimeout(SOCKET_TIMEOUT_MS); - s.connect(addr, SOCKET_TIMEOUT_MS); - } catch (IOException e) { - s.close(); - throw e; - } - return s; - } - - /** - * Receiver that captures the last connectivity change's network type and state. Recognizes - * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. - */ - private class ConnectivityActionReceiver extends BroadcastReceiver { - - private final CountDownLatch mReceiveLatch = new CountDownLatch(1); - - private final int mNetworkType; - private final NetworkInfo.State mNetState; - - ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) { - mNetworkType = networkType; - mNetState = netState; - } - - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - NetworkInfo networkInfo = null; - - // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable - // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is - // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. - if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { - networkInfo = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo); - } else if (NETWORK_CALLBACK_ACTION.equals(action)) { - Network network = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); - networkInfo = mCm.getNetworkInfo(network); - if (networkInfo == null) { - // When disconnecting, it seems like we get an intent sent with an invalid - // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), - // it is invalid. Ignore these. - Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " - + "invalid network"); - return; - } - } else { - fail("ConnectivityActionReceiver received unxpected intent action: " + action); - } - - assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); - int networkType = networkInfo.getType(); - State networkState = networkInfo.getState(); - Log.i(TAG, "Network type: " + networkType + " state: " + networkState); - if (networkType == mNetworkType && networkInfo.getState() == mNetState) { - mReceiveLatch.countDown(); - } - } - - public boolean waitForState() throws InterruptedException { - return mReceiveLatch.await(30, TimeUnit.SECONDS); - } - } - - /** - * Callback used in testRegisterNetworkCallback that allows caller to block on - * {@code onAvailable}. - */ - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CountDownLatch mAvailableLatch = new CountDownLatch(1); - private final CountDownLatch mLostLatch = new CountDownLatch(1); - private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); - - public Network currentNetwork; - public Network lastLostNetwork; - - public Network waitForAvailable() throws InterruptedException { - return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; - } - - public Network waitForLost() throws InterruptedException { - return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; - } - - public boolean waitForUnavailable() throws InterruptedException { - return mUnavailableLatch.await(2, TimeUnit.SECONDS); - } - - - @Override - public void onAvailable(Network network) { - currentNetwork = network; - mAvailableLatch.countDown(); - } - - @Override - public void onLost(Network network) { - lastLostNetwork = network; - if (network.equals(currentNetwork)) { - currentNetwork = null; - } - mLostLatch.countDown(); - } - - @Override - public void onUnavailable() { - mUnavailableLatch.countDown(); - } - } } \ No newline at end of file diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 4b2c5794ed..c3ae793aae 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -21,8 +21,12 @@ import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver; +import static android.net.cts.util.CtsNetUtils.HTTP_PORT; +import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION; +import static android.net.cts.util.CtsNetUtils.TEST_HOST; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; import static android.system.OsConstants.AF_INET; @@ -34,7 +38,6 @@ import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.UiAutomation; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -53,6 +56,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.SocketKeepalive; +import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; import android.os.Looper; @@ -61,8 +65,6 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; -import android.system.Os; -import android.system.OsConstants; import android.test.AndroidTestCase; import android.text.TextUtils; import android.util.Log; @@ -106,8 +108,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 - private static final String TEST_HOST = "connectivitycheck.gstatic.com"; - private static final int SOCKET_TIMEOUT_MS = 2000; private static final int CONNECT_TIMEOUT_MS = 2000; private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000; private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000; @@ -115,16 +115,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; - private static final int HTTP_PORT = 80; - private static final String HTTP_REQUEST = - "GET /generate_204 HTTP/1.0\r\n" + - "Host: " + TEST_HOST + "\r\n" + - "Connection: keep-alive\r\n\r\n"; - - // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. - private static final String NETWORK_CALLBACK_ACTION = - "ConnectivityManagerTest.NetworkCallbackAction"; - // device could have only one interface: data, wifi. private static final int MIN_NUM_NETWORK_TYPES = 1; @@ -136,8 +126,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { private final HashMap mNetworks = new HashMap(); boolean mWifiConnectAttempted; - private TestNetworkCallback mCellNetworkCallback; private UiAutomation mUiAutomation; + private CtsNetUtils mCtsNetUtils; private boolean mShellPermissionIdentityAdopted; @Override @@ -149,6 +139,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); mWifiConnectAttempted = false; // Get com.android.internal.R.array.networkAttributes @@ -173,10 +164,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { protected void tearDown() throws Exception { // Return WiFi to its original disabled state after tests that explicitly connect. if (mWifiConnectAttempted) { - disconnectFromWifi(null); + mCtsNetUtils.disconnectFromWifi(null); } - if (cellConnectAttempted()) { - disconnectFromCell(); + if (mCtsNetUtils.cellConnectAttempted()) { + mCtsNetUtils.disconnectFromCell(); } dropShellPermissionIdentity(); super.tearDown(); @@ -189,10 +180,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { */ private Network ensureWifiConnected() { if (mWifiManager.isWifiEnabled()) { - return getWifiNetwork(); + return mCtsNetUtils.getWifiNetwork(); } mWifiConnectAttempted = true; - return connectToWifi(); + return mCtsNetUtils.connectToWifi(); } public void testIsNetworkTypeValid() { @@ -300,8 +291,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { return; } - Network wifiNetwork = connectToWifi(); - Network cellNetwork = connectToCell(); + Network wifiNetwork = mCtsNetUtils.connectToWifi(); + Network cellNetwork = mCtsNetUtils.connectToCell(); // This server returns the requestor's IP address as the response body. URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text"); String wifiAddressString = httpGet(wifiNetwork, url); @@ -319,33 +310,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork)); } - private Network connectToCell() throws InterruptedException { - if (cellConnectAttempted()) { - throw new IllegalStateException("Already connected"); - } - NetworkRequest cellRequest = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NET_CAPABILITY_INTERNET) - .build(); - mCellNetworkCallback = new TestNetworkCallback(); - mCm.requestNetwork(cellRequest, mCellNetworkCallback); - final Network cellNetwork = mCellNetworkCallback.waitForAvailable(); - assertNotNull("Cell network not available within timeout", cellNetwork); - return cellNetwork; - } - - private boolean cellConnectAttempted() { - return mCellNetworkCallback != null; - } - - private void disconnectFromCell() { - if (!cellConnectAttempted()) { - throw new IllegalStateException("Cell connection not attempted"); - } - mCm.unregisterNetworkCallback(mCellNetworkCallback); - mCellNetworkCallback = null; - } - /** * Performs a HTTP GET to the specified URL on the specified Network, and returns * the response body decoded as UTF-8. @@ -507,7 +471,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { filter.addAction(NETWORK_CALLBACK_ACTION); ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); mContext.registerReceiver(receiver, filter); // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION. @@ -566,7 +530,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testRequestNetworkCallback_onUnavailable() { final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); if (previousWifiEnabledState) { - disconnectFromWifi(null); + mCtsNetUtils.disconnectFromWifi(null); } final TestNetworkCallback callback = new TestNetworkCallback(); @@ -583,42 +547,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { } finally { mCm.unregisterNetworkCallback(callback); if (previousWifiEnabledState) { - connectToWifi(); + mCtsNetUtils.connectToWifi(); } } } - /** Enable WiFi and wait for it to become connected to a network. */ - private Network connectToWifi() { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network wifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - boolean connected = false; - try { - assertTrue(mWifiManager.setWifiEnabled(true)); - // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. - wifiNetwork = callback.waitForAvailable(); - assertNotNull(wifiNetwork); - connected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("connectToWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi must be configured to connect to an access point for this test.", - connected); - return wifiNetwork; - } - private InetAddress getFirstV4Address(Network network) { LinkProperties linkProperties = mCm.getLinkProperties(network); for (InetAddress address : linkProperties.getAddresses()) { @@ -629,199 +562,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { return null; } - private Socket getBoundSocket(Network network, String host, int port) throws IOException { - InetSocketAddress addr = new InetSocketAddress(host, port); - Socket s = network.getSocketFactory().createSocket(); - try { - s.setSoTimeout(SOCKET_TIMEOUT_MS); - s.connect(addr, SOCKET_TIMEOUT_MS); - } catch (IOException e) { - s.close(); - throw e; - } - return s; - } - - private void testHttpRequest(Socket s) throws IOException { - OutputStream out = s.getOutputStream(); - InputStream in = s.getInputStream(); - - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); - byte[] responseBytes = new byte[4096]; - out.write(requestBytes); - in.read(responseBytes); - assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); - } - - /** Disable WiFi and wait for it to become disconnected from the network. */ - private void disconnectFromWifi(Network wifiNetworkToCheck) { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network lostWifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - // Assert that we can establish a TCP connection on wifi. - Socket wifiBoundSocket = null; - if (wifiNetworkToCheck != null) { - try { - wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); - testHttpRequest(wifiBoundSocket); - } catch (IOException e) { - fail("HTTP request before wifi disconnected failed with: " + e); - } - } - - boolean disconnected = false; - try { - assertTrue(mWifiManager.setWifiEnabled(false)); - // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. - lostWifiNetwork = callback.waitForLost(); - assertNotNull(lostWifiNetwork); - disconnected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("disconnectFromWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); - - // Check that the socket is closed when wifi disconnects. - if (wifiBoundSocket != null) { - try { - testHttpRequest(wifiBoundSocket); - fail("HTTP request should not succeed after wifi disconnects"); - } catch (IOException expected) { - assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); - } - } - } - - /** - * Receiver that captures the last connectivity change's network type and state. Recognizes - * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. - */ - private class ConnectivityActionReceiver extends BroadcastReceiver { - - private final CountDownLatch mReceiveLatch = new CountDownLatch(1); - - private final int mNetworkType; - private final NetworkInfo.State mNetState; - - ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) { - mNetworkType = networkType; - mNetState = netState; - } - - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - NetworkInfo networkInfo = null; - - // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable - // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is - // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. - if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { - networkInfo = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo); - } else if (NETWORK_CALLBACK_ACTION.equals(action)) { - Network network = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); - networkInfo = mCm.getNetworkInfo(network); - if (networkInfo == null) { - // When disconnecting, it seems like we get an intent sent with an invalid - // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), - // it is invalid. Ignore these. - Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " - + "invalid network"); - return; - } - } else { - fail("ConnectivityActionReceiver received unxpected intent action: " + action); - } - - assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); - int networkType = networkInfo.getType(); - State networkState = networkInfo.getState(); - Log.i(TAG, "Network type: " + networkType + " state: " + networkState); - if (networkType == mNetworkType && networkInfo.getState() == mNetState) { - mReceiveLatch.countDown(); - } - } - - public boolean waitForState() throws InterruptedException { - return mReceiveLatch.await(30, TimeUnit.SECONDS); - } - } - - /** - * Callback used in testRegisterNetworkCallback that allows caller to block on - * {@code onAvailable}. - */ - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CountDownLatch mAvailableLatch = new CountDownLatch(1); - private final CountDownLatch mLostLatch = new CountDownLatch(1); - private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); - - public Network currentNetwork; - public Network lastLostNetwork; - - public Network waitForAvailable() throws InterruptedException { - return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; - } - - public Network waitForLost() throws InterruptedException { - return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; - } - - public boolean waitForUnavailable() throws InterruptedException { - return mUnavailableLatch.await(2, TimeUnit.SECONDS); - } - - - @Override - public void onAvailable(Network network) { - currentNetwork = network; - mAvailableLatch.countDown(); - } - - @Override - public void onLost(Network network) { - lastLostNetwork = network; - if (network.equals(currentNetwork)) { - currentNetwork = null; - } - mLostLatch.countDown(); - } - - @Override - public void onUnavailable() { - mUnavailableLatch.countDown(); - } - } - - private Network getWifiNetwork() { - TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network network = null; - try { - network = callback.waitForAvailable(); - } catch (InterruptedException e) { - fail("NetworkCallback wait was interrupted."); - } finally { - mCm.unregisterNetworkCallback(callback); - } - assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); - return network; - } - /** Verify restricted networks cannot be requested. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") public void testRestrictedNetworks() { @@ -1150,7 +890,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (!isKeepaliveSupported()) return; final Network network = ensureWifiConnected(); - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8"); // So far only ipv4 tcp keepalive offload is supported. // TODO: add test case for ipv6 tcp keepalive offload when it is supported. try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp new file mode 100644 index 0000000000..1f94613ffb --- /dev/null +++ b/tests/cts/net/util/Android.bp @@ -0,0 +1,25 @@ +// +// Copyright (C) 2019 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. +// + +// Common utilities for cts net tests. +java_library { + name: "cts-net-utils", + srcs: ["java/**/*.java", "java/**/*.kt"], + static_libs: [ + "compatibility-device-util-axt", + "junit", + ], +} \ No newline at end of file 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 new file mode 100644 index 0000000000..e19d2bafb7 --- /dev/null +++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2019 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.util; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkInfo.State; +import android.net.NetworkRequest; +import android.net.wifi.WifiManager; +import android.system.Os; +import android.system.OsConstants; +import android.util.Log; + +import com.android.compatibility.common.util.SystemUtil; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public final class CtsNetUtils { + private static final String TAG = CtsNetUtils.class.getSimpleName(); + private static final int DURATION = 10000; + private static final int SOCKET_TIMEOUT_MS = 2000; + + public static final int HTTP_PORT = 80; + public static final String TEST_HOST = "connectivitycheck.gstatic.com"; + public static final String HTTP_REQUEST = + "GET /generate_204 HTTP/1.0\r\n" + + "Host: " + TEST_HOST + "\r\n" + + "Connection: keep-alive\r\n\r\n"; + // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. + public static final String NETWORK_CALLBACK_ACTION = + "ConnectivityManagerTest.NetworkCallbackAction"; + + private Context mContext; + private ConnectivityManager mCm; + private WifiManager mWifiManager; + private TestNetworkCallback mCellNetworkCallback; + + public CtsNetUtils(Context context) { + mContext = context; + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + } + + // Toggle WiFi twice, leaving it in the state it started in + public void toggleWifi() { + if (mWifiManager.isWifiEnabled()) { + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); + connectToWifi(); + } else { + connectToWifi(); + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); + } + } + + /** Enable WiFi and wait for it to become connected to a network. */ + public Network connectToWifi() { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network wifiNetwork = null; + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + boolean connected = false; + try { + SystemUtil.runShellCommand("svc wifi enable"); + // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. + wifiNetwork = callback.waitForAvailable(); + assertNotNull(wifiNetwork); + connected = receiver.waitForState(); + } catch (InterruptedException ex) { + fail("connectToWifi was interrupted"); + } finally { + mCm.unregisterNetworkCallback(callback); + mContext.unregisterReceiver(receiver); + } + + assertTrue("Wifi must be configured to connect to an access point for this test.", + connected); + return wifiNetwork; + } + + /** Disable WiFi and wait for it to become disconnected from the network. */ + public void disconnectFromWifi(Network wifiNetworkToCheck) { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network lostWifiNetwork = null; + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + // Assert that we can establish a TCP connection on wifi. + Socket wifiBoundSocket = null; + if (wifiNetworkToCheck != null) { + try { + wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); + testHttpRequest(wifiBoundSocket); + } catch (IOException e) { + fail("HTTP request before wifi disconnected failed with: " + e); + } + } + + boolean disconnected = false; + try { + SystemUtil.runShellCommand("svc wifi disable"); + // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. + lostWifiNetwork = callback.waitForLost(); + assertNotNull(lostWifiNetwork); + disconnected = receiver.waitForState(); + } catch (InterruptedException ex) { + fail("disconnectFromWifi was interrupted"); + } finally { + mCm.unregisterNetworkCallback(callback); + mContext.unregisterReceiver(receiver); + } + + assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); + + // Check that the socket is closed when wifi disconnects. + if (wifiBoundSocket != null) { + try { + testHttpRequest(wifiBoundSocket); + fail("HTTP request should not succeed after wifi disconnects"); + } catch (IOException expected) { + assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); + } + } + } + + public Network getWifiNetwork() { + TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network network = null; + try { + network = callback.waitForAvailable(); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + } + assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); + return network; + } + + public Network connectToCell() throws InterruptedException { + if (cellConnectAttempted()) { + throw new IllegalStateException("Already connected"); + } + NetworkRequest cellRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + mCellNetworkCallback = new TestNetworkCallback(); + mCm.requestNetwork(cellRequest, mCellNetworkCallback); + final Network cellNetwork = mCellNetworkCallback.waitForAvailable(); + assertNotNull("Cell network not available. " + + "Please ensure the device has working mobile data.", cellNetwork); + return cellNetwork; + } + + public void disconnectFromCell() { + if (!cellConnectAttempted()) { + throw new IllegalStateException("Cell connection not attempted"); + } + mCm.unregisterNetworkCallback(mCellNetworkCallback); + mCellNetworkCallback = null; + } + + public boolean cellConnectAttempted() { + return mCellNetworkCallback != null; + } + + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + + private void testHttpRequest(Socket s) throws IOException { + OutputStream out = s.getOutputStream(); + InputStream in = s.getInputStream(); + + final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + byte[] responseBytes = new byte[4096]; + out.write(requestBytes); + in.read(responseBytes); + assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); + } + + private Socket getBoundSocket(Network network, String host, int port) throws IOException { + InetSocketAddress addr = new InetSocketAddress(host, port); + Socket s = network.getSocketFactory().createSocket(); + try { + s.setSoTimeout(SOCKET_TIMEOUT_MS); + s.connect(addr, SOCKET_TIMEOUT_MS); + } catch (IOException e) { + s.close(); + throw e; + } + return s; + } + + /** + * Receiver that captures the last connectivity change's network type and state. Recognizes + * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. + */ + public static class ConnectivityActionReceiver extends BroadcastReceiver { + + private final CountDownLatch mReceiveLatch = new CountDownLatch(1); + + private final int mNetworkType; + private final NetworkInfo.State mNetState; + private final ConnectivityManager mCm; + + public ConnectivityActionReceiver(ConnectivityManager cm, int networkType, + NetworkInfo.State netState) { + this.mCm = cm; + mNetworkType = networkType; + mNetState = netState; + } + + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + NetworkInfo networkInfo = null; + + // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable + // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is + // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { + networkInfo = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", + networkInfo); + } else if (NETWORK_CALLBACK_ACTION.equals(action)) { + Network network = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); + networkInfo = this.mCm.getNetworkInfo(network); + if (networkInfo == null) { + // When disconnecting, it seems like we get an intent sent with an invalid + // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), + // it is invalid. Ignore these. + Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " + + "invalid network"); + return; + } + } else { + fail("ConnectivityActionReceiver received unxpected intent action: " + action); + } + + assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); + int networkType = networkInfo.getType(); + State networkState = networkInfo.getState(); + Log.i(TAG, "Network type: " + networkType + " state: " + networkState); + if (networkType == mNetworkType && networkInfo.getState() == mNetState) { + mReceiveLatch.countDown(); + } + } + + public boolean waitForState() throws InterruptedException { + return mReceiveLatch.await(30, TimeUnit.SECONDS); + } + } + + /** + * Callback used in testRegisterNetworkCallback that allows caller to block on + * {@code onAvailable}. + */ + public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CountDownLatch mAvailableLatch = new CountDownLatch(1); + private final CountDownLatch mLostLatch = new CountDownLatch(1); + private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); + + public Network currentNetwork; + public Network lastLostNetwork; + + public Network waitForAvailable() throws InterruptedException { + return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; + } + + public Network waitForLost() throws InterruptedException { + return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; + } + + public boolean waitForUnavailable() throws InterruptedException { + return mUnavailableLatch.await(2, TimeUnit.SECONDS); + } + + + @Override + public void onAvailable(Network network) { + currentNetwork = network; + mAvailableLatch.countDown(); + } + + @Override + public void onLost(Network network) { + lastLostNetwork = network; + if (network.equals(currentNetwork)) { + currentNetwork = null; + } + mLostLatch.countDown(); + } + + @Override + public void onUnavailable() { + mUnavailableLatch.countDown(); + } + } +} From 87ac083a3b72ee3462f15b296dde541e07797daf Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 29 May 2019 22:34:02 -0700 Subject: [PATCH 0642/1415] Fix keepalive CTS fail for devices with kernel older than 4.8 If kernel < 4.8 then it doesn't support get socket option TCP_REPAIR_WINDOW, thus TCP keepalive cannot be supported. However, it might still support NAT-T keepalive. Test TCP keepalive only if it is supported by kernel. Bug: 133652079 Test: atest android.net.cts.ConnectivityManagerTest#testMajorMinorVersionCompare \ android.net.cts.ConnectivityManagerTest#testSocketKeepaliveLimit \ android.net.cts.ConnectivityManagerTest#testSocketKeepaliveUnprivileged \ android.net.cts.ConnectivityManagerTest#testKeepaliveUnsupported \ android.net.cts.ConnectivityManagerTest#testCreateTcpKeepalive Change-Id: I0a3ff07c482bb7c8cb05663678c10afcc0500861 Merged-In: I3f8456deea2b4ded762a413c8e27b58ce54ce0aa (cherry picked from commit 57d91e6276b50bf0dd78f3643c4a979f584fcf38) --- .../net/cts/ConnectivityManagerTest.java | 178 ++++++++++++------ 1 file changed, 119 insertions(+), 59 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index c3ae793aae..8c9bf6ee21 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -63,11 +63,13 @@ import android.os.Looper; import android.os.MessageQueue; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.VintfRuntimeInfo; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; import android.test.AndroidTestCase; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import androidx.test.InstrumentationRegistry; @@ -847,30 +849,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { keepalivesPerTransport, nc); } - private boolean isKeepaliveSupported() throws Exception { - final Network network = ensureWifiConnected(); - final Executor executor = mContext.getMainExecutor(); - final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); - try (Socket s = getConnectedSocket(network, TEST_HOST, - HTTP_PORT, KEEPALIVE_SOCKET_TIMEOUT_MS, AF_INET); - SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { - sk.start(MIN_KEEPALIVE_INTERVAL); - final TestSocketKeepaliveCallback.CallbackValue result = callback.pollCallback(); - switch (result.callbackType) { - case ON_STARTED: - sk.stop(); - callback.expectStopped(); - return true; - case ON_ERROR: - if (result.error == SocketKeepalive.ERROR_UNSUPPORTED) return false; - // else fallthrough. - default: - fail("Got unexpected callback: " + result); - return false; - } - } - } - private void adoptShellPermissionIdentity() { mUiAutomation.adoptShellPermissionIdentity(); mShellPermissionIdentityAdopted = true; @@ -883,11 +861,85 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + private static boolean isTcpKeepaliveSupportedByKernel() { + final String kVersionString = VintfRuntimeInfo.getKernelVersion(); + return compareMajorMinorVersion(kVersionString, "4.8") >= 0; + } + + private static Pair getVersionFromString(String version) { + // Only gets major and minor number of the version string. + final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); + final Matcher m = versionPattern.matcher(version); + if (m.matches()) { + final int major = Integer.parseInt(m.group(1)); + final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3)); + return new Pair<>(major, minor); + } else { + return new Pair<>(0, 0); + } + } + + // TODO: Move to util class. + private static int compareMajorMinorVersion(final String s1, final String s2) { + final Pair v1 = getVersionFromString(s1); + final Pair v2 = getVersionFromString(s2); + + if (v1.first == v2.first) { + return Integer.compare(v1.second, v2.second); + } else { + return Integer.compare(v1.first, v2.first); + } + } + + /** + * Verifies that version string compare logic returns expected result for various cases. + * Note that only major and minor number are compared. + */ + public void testMajorMinorVersionCompare() { + assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8")); + assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1")); + assertEquals(1, compareMajorMinorVersion("5.0", "4.8")); + assertEquals(1, compareMajorMinorVersion("5", "4.8")); + assertEquals(0, compareMajorMinorVersion("5", "5.0")); + assertEquals(1, compareMajorMinorVersion("5-beta1", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8.0.0", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8-RC1", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8", "4.8")); + assertEquals(-1, compareMajorMinorVersion("3.10", "4.8.0")); + assertEquals(-1, compareMajorMinorVersion("4.7.10.10", "4.8")); + } + + /** + * Verifies that the keepalive API cannot create any keepalive when the maximum number of + * keepalives is set to 0. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + public void testKeepaliveUnsupported() throws Exception { + if (getSupportedKeepalivesFromRes() != 0) return; + + adoptShellPermissionIdentity(); + + assertEquals(0, createConcurrentSocketKeepalives(1, 0)); + assertEquals(0, createConcurrentSocketKeepalives(0, 1)); + + dropShellPermissionIdentity(); + } + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testCreateTcpKeepalive() throws Exception { adoptShellPermissionIdentity(); - if (!isKeepaliveSupported()) return; + if (getSupportedKeepalivesFromRes() == 0) return; + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support + // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive + // needs to be supported except if the kernel doesn't support it. + if (!isTcpKeepaliveSupportedByKernel()) { + // Sanity check to ensure the callback result is expected. + assertEquals(0, createConcurrentSocketKeepalives(0, 1)); + Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " + + VintfRuntimeInfo.getKernelVersion()); + return; + } final Network network = ensureWifiConnected(); final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8"); @@ -952,14 +1004,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { sk.start(MIN_KEEPALIVE_INTERVAL); callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); } - } } + /** + * Creates concurrent keepalives until the specified counts of each type of keepalives are + * reached or the expected error callbacks are received for each type of keepalives. + * + * @return the total number of keepalives created. + */ private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { - // Use customization value in resource to prevent the need of privilege. - if (getSupportedKeepalivesFromRes() == 0) return 0; - final Network network = ensureWifiConnected(); final ArrayList kalist = new ArrayList<>(); @@ -978,10 +1032,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { ka.start(MIN_KEEPALIVE_INTERVAL); TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); assertNotNull(cv); - if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR - && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { - // Limit reached. - break; + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { + if (i == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { + // Unsupported. + break; + } else if (i != 0 && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } } if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { kalist.add(ka); @@ -1007,10 +1065,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { ka.start(MIN_KEEPALIVE_INTERVAL); TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); assertNotNull(cv); - if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR - && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { - // Limit reached. - break; + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { + if (i == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { + // Unsupported. + break; + } else if (i != 0 && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } } if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { kalist.add(ka); @@ -1038,32 +1100,35 @@ public class ConnectivityManagerTest extends AndroidTestCase { */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testSocketKeepaliveLimit() throws Exception { - adoptShellPermissionIdentity(); - final int supported = getSupportedKeepalivesFromRes(); - - if (!isKeepaliveSupported()) { - // Sanity check. - assertEquals(0, supported); + if (supported == 0) { return; } + adoptShellPermissionIdentity(); + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. assertGreaterOrEqual(supported, KeepaliveUtils.MIN_SUPPORTED_KEEPALIVE_COUNT); - // Verifies that different types of keepalives can be established. + // Verifies that Nat-T keepalives can be established. assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); - assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); - - // Verifies that different types can be established at the same time. - assertEquals(supported, createConcurrentSocketKeepalives( - supported / 2, supported - supported / 2)); - // Verifies that keepalives don't get leaked in second round. assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); - assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); - assertEquals(supported, createConcurrentSocketKeepalives( - supported / 2, supported - supported / 2)); + + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support + // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. + if (isTcpKeepaliveSupportedByKernel()) { + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + + // Verifies that different types can be established at the same time. + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + } dropShellPermissionIdentity(); } @@ -1074,14 +1139,9 @@ public class ConnectivityManagerTest extends AndroidTestCase { @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testSocketKeepaliveUnprivileged() throws Exception { final int supported = getSupportedKeepalivesFromRes(); - - adoptShellPermissionIdentity(); - if (!isKeepaliveSupported()) { - // Sanity check. - assertEquals(0, supported); + if (supported == 0) { return; } - dropShellPermissionIdentity(); final int allowedUnprivilegedPerUid = mContext.getResources().getInteger( R.integer.config_allowedUnprivilegedKeepalivePerUid); From 0b35214faaca44f77e9d0972c2cfd12f2c2c8523 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 30 May 2019 04:46:32 -0700 Subject: [PATCH 0643/1415] Add bypass private DNS test case and null network test for DnsResolver cts 1. add test case for testing bypass Private DNS 2. add null network test 3. minor change for cleanup Bug: 130594022 Test: atest DnsResolverTest Merged-In: I8dd48f11baf92d953ded237204a3c2cd3b58581d (cherry picked from commit da665a0a78a2919c3e2edabafec463de3de9ddb7) Change-Id: Iabb100c51fd80eca5ab0284bc891f4fb98492e8b --- .../src/android/net/cts/DnsResolverTest.java | 374 +++++++++++------- 1 file changed, 227 insertions(+), 147 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 945f51dbc8..e16fce09bf 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -21,20 +21,25 @@ import static android.net.DnsResolver.FLAG_EMPTY; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; -import static android.system.OsConstants.EBADF; +import static android.system.OsConstants.ETIMEDOUT; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.ContentResolver; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; import android.net.DnsPacket; import android.net.DnsResolver; +import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.ParseException; import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; +import android.provider.Settings; import android.system.ErrnoException; import android.test.AndroidTestCase; import android.util.Log; @@ -53,20 +58,63 @@ public class DnsResolverTest extends AndroidTestCase { private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + static final String TEST_DOMAIN = "www.google.com"; + static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google"; + static final byte[] TEST_BLOB = new byte[]{ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ + }; static final int TIMEOUT_MS = 12_000; static final int CANCEL_TIMEOUT_MS = 3_000; static final int CANCEL_RETRY_TIMES = 5; static final int NXDOMAIN = 3; + static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; + private ContentResolver mCR; private ConnectivityManager mCM; private Executor mExecutor; private DnsResolver mDns; + private String mOldMode; + private String mOldDnsSpecifier; + + @Override protected void setUp() throws Exception { super.setUp(); mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mDns = DnsResolver.getInstance(); mExecutor = new Handler(Looper.getMainLooper())::post; + mCR = getContext().getContentResolver(); + storePrivateDnsSetting(); + } + + @Override + protected void tearDown() throws Exception { + restorePrivateDnsSetting(); + super.tearDown(); + } + + private void storePrivateDnsSetting() { + // Store private DNS setting + mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); + } + + private void restorePrivateDnsSetting() { + // restore private DNS setting + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); } private static String byteArrayToHexString(byte[] bytes) { @@ -94,6 +142,9 @@ public class DnsResolverTest extends AndroidTestCase { "This test requires that at least one network be connected. " + "Please ensure that the device is connected to a network.", testableNetworks.size() >= 1); + // In order to test query with null network, add null as an element. + // Test cases which query with null network will go on default network. + testableNetworks.add(null); return testableNetworks.toArray(new Network[0]); } @@ -105,15 +156,12 @@ public class DnsResolverTest extends AndroidTestCase { public DnsParseException(String msg) { super(msg); } - - public DnsParseException(String msg, Throwable cause) { - super(msg, cause); - } } private static class DnsAnswer extends DnsPacket { DnsAnswer(@NonNull byte[] data) throws DnsParseException { super(data); + // Check QR field.(query (0), or a response (1)). if ((mHeader.flags & (1 << 15)) == 0) { throw new DnsParseException("Not an answer packet"); @@ -123,10 +171,12 @@ public class DnsResolverTest extends AndroidTestCase { int getRcode() { return mHeader.rcode; } - int getANCount(){ + + int getANCount() { return mHeader.getRecordCount(ANSECTION); } - int getQDCount(){ + + int getQDCount() { return mHeader.getRecordCount(QDSECTION); } } @@ -173,7 +223,7 @@ public class DnsResolverTest extends AndroidTestCase { mRcode = rcode; try { mDnsAnswer = new DnsAnswer(answer); - } catch (DnsParseException e) { + } catch (ParseException | DnsParseException e) { fail(mMsg + e.getMessage()); } Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); @@ -222,90 +272,76 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQuery() { - final String dname = "www.google.com"; - final String msg = "RawQuery " + dname; + public void testRawQuery() throws InterruptedException { + final String msg = "RawQuery " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); - mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - callback.assertHasAnswer(); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertHasAnswer(); } } - public void testRawQueryBlob() { + public void testRawQueryBlob() throws InterruptedException { final byte[] blob = new byte[]{ - /* Header */ - 0x55, 0x66, /* Transaction ID */ - 0x01, 0x00, /* Flags */ - 0x00, 0x01, /* Questions */ - 0x00, 0x00, /* Answer RRs */ - 0x00, 0x00, /* Authority RRs */ - 0x00, 0x00, /* Additional RRs */ - /* Queries */ - 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, - 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01 /* Class */ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ }; final String msg = "RawQuery blob " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - callback.assertHasAnswer(); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertHasAnswer(); } } - public void testRawQueryRoot() { + public void testRawQueryRoot() throws InterruptedException { final String dname = ""; final String msg = "RawQuery empty dname(ROOT) "; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - // Except no answer record because the root does not have AAAA records. - callback.assertEmptyAnswer(); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + // Except no answer record because the root does not have AAAA records. + callback.assertEmptyAnswer(); } } - public void testRawQueryNXDomain() { + public void testRawQueryNXDomain() throws InterruptedException { final String dname = "test1-nx.metric.gstatic.com"; final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - callback.assertNXDomain(); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNXDomain(); } } - public void testRawQueryCancel() throws ErrnoException { - final String dname = "www.google.com"; - final String msg = "Test cancel RawQuery " + dname; + public void testRawQueryCancel() throws InterruptedException { + final String msg = "Test cancel RawQuery " + TEST_DOMAIN; // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -319,39 +355,22 @@ public class DnsResolverTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); - mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); latch.countDown(); }); - try { - retry = callback.needRetry(); - assertTrue(msg + " query was not cancelled", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } while (retry); } } - public void testRawQueryBlobCancel() throws ErrnoException { - final byte[] blob = new byte[]{ - /* Header */ - 0x55, 0x66, /* Transaction ID */ - 0x01, 0x00, /* Flags */ - 0x00, 0x01, /* Questions */ - 0x00, 0x00, /* Answer RRs */ - 0x00, 0x00, /* Authority RRs */ - 0x00, 0x00, /* Additional RRs */ - /* Queries */ - 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, - 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01 /* Class */ - }; - final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(blob); + public void testRawQueryBlobCancel() throws InterruptedException { + final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(TEST_BLOB); // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -365,37 +384,30 @@ public class DnsResolverTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); - mDns.rawQuery(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mDns.rawQuery(network, TEST_BLOB, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); latch.countDown(); }); - try { - retry = callback.needRetry(); - assertTrue(msg + " cancel is not done", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + retry = callback.needRetry(); + assertTrue(msg + " cancel is not done", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } while (retry); } } - public void testCancelBeforeQuery() throws ErrnoException { - final String dname = "www.google.com"; - final String msg = "Test cancelled RawQuery " + dname; + public void testCancelBeforeQuery() throws InterruptedException { + final String msg = "Test cancelled RawQuery " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); final CancellationSignal cancelSignal = new CancellationSignal(); cancelSignal.cancel(); - mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, mExecutor, cancelSignal, callback); - try { - assertTrue(msg + " should not return any answers", - !callback.waitForAnswer(CANCEL_TIMEOUT_MS)); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " should not return any answers", + !callback.waitForAnswer(CANCEL_TIMEOUT_MS)); } } @@ -462,27 +474,21 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddress() { - final String dname = "www.google.com"; - final String msg = "Test query for InetAddress " + dname; + public void testQueryForInetAddress() throws InterruptedException { + final String msg = "Test query for InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); } } - public void testQueryCancelForInetAddress() throws ErrnoException { - final String dname = "www.google.com"; - final String msg = "Test cancel query for InetAddress " + dname; + public void testQueryCancelForInetAddress() throws InterruptedException { + final String msg = "Test cancel query for InetAddress " + TEST_DOMAIN; // Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to // expect that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -497,57 +503,131 @@ public class DnsResolverTest extends AndroidTestCase { final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, cancelSignal); - mDns.query(network, dname, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mDns.query(network, TEST_DOMAIN, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); latch.countDown(); }); - try { - retry = callback.needRetry(); - assertTrue(msg + " query was not cancelled", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } while (retry); } } - public void testQueryForInetAddressIpv4() { - final String dname = "www.google.com"; - final String msg = "Test query for IPv4 InetAddress " + dname; + public void testQueryForInetAddressIpv4() throws InterruptedException { + final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, dname, TYPE_A, FLAG_NO_CACHE_LOOKUP, + mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); - assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer()); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer()); } } - public void testQueryForInetAddressIpv6() { - final String dname = "www.google.com"; - final String msg = "Test query for IPv6 InetAddress " + dname; + public void testQueryForInetAddressIpv6() throws InterruptedException { + final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, dname, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); - try { - assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - callback.waitForAnswer()); - assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); - assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer()); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer()); + } + } + + private void awaitPrivateDnsSetting(@NonNull String msg, + @NonNull Network network, @NonNull String server) throws InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); + NetworkCallback callback = new NetworkCallback() { + @Override + public void onLinkPropertiesChanged(Network n, LinkProperties lp) { + if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) { + latch.countDown(); + } } + }; + mCM.registerNetworkCallback(request, callback); + assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + mCM.unregisterNetworkCallback(callback); + } + + public void testPrivateDnsBypass() throws InterruptedException { + final Network[] testNetworks = getTestableNetworks(); + + // Set an invalid private DNS server + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); + + final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; + for (Network network : testNetworks) { + // This test cannot be ran with null network because we need to explicitly pass a + // private DNS bypassable network or bind one. + if (network == null) continue; + + // wait for private DNS setting propagating + awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", + network, INVALID_PRIVATE_DNS_SERVER); + + final CountDownLatch latch = new CountDownLatch(1); + final DnsResolver.Callback> errorCallback = + new DnsResolver.Callback>() { + @Override + public void onAnswer(@NonNull List answerList, int rcode) { + fail(msg + " should not get valid answer"); + } + + @Override + public void onError(@NonNull DnsResolver.DnsException error) { + assertEquals(DnsResolver.ERROR_SYSTEM, error.code); + assertEquals(ETIMEDOUT, ((ErrnoException) error.getCause()).errno); + latch.countDown(); + } + }; + // Private DNS strict mode with invalid DNS server is set + // Expect no valid answer returned but ErrnoException with ETIMEDOUT + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, errorCallback); + + assertTrue(msg + " invalid server round. No response after " + TIMEOUT_MS + "ms.", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + // Bypass privateDns, expect query works fine + mDns.query(network.getPrivateDnsBypassingCopy(), + TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + + assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + + // To ensure private DNS bypass still work even if passing null network. + // Bind process network with a private DNS bypassable network. + mCM.bindProcessToNetwork(network.getPrivateDnsBypassingCopy()); + final VerifyCancelInetAddressCallback callbackWithNullNetwork = + new VerifyCancelInetAddressCallback(msg + " with null network ", null); + mDns.query(null, + TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callbackWithNullNetwork); + + assertTrue(msg + " with null network bypass private DNS round. No answer after " + + TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer()); + assertTrue(msg + " with null network returned 0 results", + !callbackWithNullNetwork.isAnswerEmpty()); + + // Reset process network to default. + mCM.bindProcessToNetwork(null); } } } From a0279520f04a3c820ee554c78af8d67a92f8eb53 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 31 May 2019 06:23:01 -0700 Subject: [PATCH 0644/1415] Cleanup IPsec CTS tests This commit addresses comments from aosp/963067 and aosp/959617. No behavioral/functional changes were made, only renames and minor style nits addressed. Bug: 72950854 Test: Ran on devices, working Merged-In: I1702b91e245412f0142e9e47b7fb373b9b4e8126 Change-Id: I1702b91e245412f0142e9e47b7fb373b9b4e8126 (cherry picked from commit 68237a11f9532ca6c59d579adb374fe40b0b3bee) --- .../src/android/net/cts/IpSecManagerTest.java | 6 ---- .../net/cts/IpSecManagerTunnelTest.java | 34 +++++++++---------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 1241785a17..d6b8a968d2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -73,12 +73,6 @@ public class IpSecManagerTest extends IpSecBaseTest { private static final byte[] AEAD_KEY = getKey(288); - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - } - /* * Allocate a random SPI * Allocate a specific SPI using previous randomly created SPI value diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 93638ac3b5..828abccf58 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -127,15 +127,15 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // right appop permissions. setAppop(OP_MANAGE_IPSEC_TUNNELS, true); - TestNetworkInterface testIntf = + TestNetworkInterface testIface = sTNM.createTunInterface( new LinkAddress[] { new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN) }); - sTunFd = testIntf.getFileDescriptor(); - sTunNetworkCallback = setupAndGetTestNetwork(testIntf.getInterfaceName()); + sTunFd = testIface.getFileDescriptor(); + sTunNetworkCallback = setupAndGetTestNetwork(testIface.getInterfaceName()); sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); sTunUtils = new TunUtils(sTunFd); @@ -498,21 +498,20 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { mISM.allocateSecurityParameterIndex(localOuter, spi); IpSecManager.SecurityParameterIndex outSpi = mISM.allocateSecurityParameterIndex(remoteOuter, spi); - IpSecManager.IpSecTunnelInterface tunnelIntf = + IpSecManager.IpSecTunnelInterface tunnelIface = mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) { // Build the test network - tunnelIntf.addAddress(localInner, innerPrefixLen); - testNetworkCb = setupAndGetTestNetwork(tunnelIntf.getInterfaceName()); + tunnelIface.addAddress(localInner, innerPrefixLen); + testNetworkCb = setupAndGetTestNetwork(tunnelIface.getInterfaceName()); Network testNetwork = testNetworkCb.getNetworkBlocking(); // Check interface was created - NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNotNull(netIntf); + assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); // Verify address was added - netIntf = NetworkInterface.getByInetAddress(localInner); - assertNotNull(netIntf); - assertEquals(tunnelIntf.getInterfaceName(), netIntf.getDisplayName()); + final NetworkInterface netIface = NetworkInterface.getByInetAddress(localInner); + assertNotNull(netIface); + assertEquals(tunnelIface.getInterfaceName(), netIface.getDisplayName()); // Configure Transform parameters IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); @@ -531,8 +530,9 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi); IpSecTransform outTransform = transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) { - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, inTransform); - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, outTransform); + mISM.applyTunnelModeTransform(tunnelIface, IpSecManager.DIRECTION_IN, inTransform); + mISM.applyTunnelModeTransform( + tunnelIface, IpSecManager.DIRECTION_OUT, outTransform); test.run(testNetwork); } @@ -541,13 +541,13 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { sTNM.teardownTestNetwork(testNetwork); // Remove addresses and check that interface is still present, but fails lookup-by-addr - tunnelIntf.removeAddress(localInner, innerPrefixLen); - assertNotNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + tunnelIface.removeAddress(localInner, innerPrefixLen); + assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); assertNull(NetworkInterface.getByInetAddress(localInner)); // Check interface was cleaned up - tunnelIntf.close(); - assertNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + tunnelIface.close(); + assertNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); } finally { if (testNetworkCb != null) { sCM.unregisterNetworkCallback(testNetworkCb); From 2cb7034baf20565153a6c7f2f830e69ff4bbf659 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Apr 2019 11:18:27 -0700 Subject: [PATCH 0645/1415] Add reflected-packet based data tests This commit adds tests that reflect outgoing packets, flipping the outer src/dst headers to avoid the need to tear down and rebuild the outer TUN. This allows us to at least test that our implementation can interoperate with itself. Bug: 72950854 Test: this, passing Merged-In: Ia969f78f4c1a0c0a017f5aad425a68852ff4433a Change-Id: Ia969f78f4c1a0c0a017f5aad425a68852ff4433a (cherry picked from commit 144937f3df37ee0b1d5484f10e8c86a8a70a9cb5) --- .../net/cts/IpSecManagerTunnelTest.java | 251 ++++++++++++++++-- 1 file changed, 229 insertions(+), 22 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 828abccf58..d1438ec56d 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -240,8 +240,16 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } /* Test runnables for callbacks after IPsec tunnels are set up. */ - private interface TestRunnable { - void run(Network ipsecNetwork) throws Exception; + private abstract class IpSecTunnelTestRunnable { + /** + * Runs the test code, and returns the inner socket port, if any. + * + * @param ipsecNetwork The IPsec Interface based Network for binding sockets on + * @return the integer port of the inner socket if outbound, or 0 if inbound + * IpSecTunnelTestRunnable + * @throws Exception if any part of the test failed. + */ + public abstract int run(Network ipsecNetwork) throws Exception; } private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { @@ -288,8 +296,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { return expectedPacketSize; } - private interface TestRunnableFactory { - TestRunnable getTestRunnable( + private interface IpSecTunnelTestRunnableFactory { + IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( boolean transportInTunnelMode, int spi, InetAddress localInner, @@ -299,12 +307,13 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, int encapPort, + int innerSocketPort, int expectedPacketSize) throws Exception; } - private class OutputTestRunnableFactory implements TestRunnableFactory { - public TestRunnable getTestRunnable( + private class OutputIpSecTunnelTestRunnableFactory implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( boolean transportInTunnelMode, int spi, InetAddress localInner, @@ -314,13 +323,15 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, int encapPort, + int unusedInnerSocketPort, int expectedPacketSize) { - return new TestRunnable() { + return new IpSecTunnelTestRunnable() { @Override - public void run(Network ipsecNetwork) throws Exception { + public int run(Network ipsecNetwork) throws Exception { // Build a socket and send traffic JavaUdpSocket socket = new JavaUdpSocket(localInner); ipsecNetwork.bindSocket(socket.mSocket); + int innerSocketPort = socket.getPort(); // For Transport-In-Tunnel mode, apply transform to socket if (transportInTunnelMode) { @@ -333,19 +344,22 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { socket.sendTo(TEST_DATA, remoteInner, socket.getPort()); // Verify that an encrypted packet is sent. As of right now, checking encrypted - // body is not possible, due to our not knowing some of the fields of the + // body is not possible, due to the test not knowing some of the fields of the // inner IP header (flow label, flags, etc) sTunUtils.awaitEspPacketNoPlaintext( spi, TEST_DATA, encapPort != 0, expectedPacketSize); socket.close(); + + return innerSocketPort; } }; } } - private class InputPacketGeneratorTestRunnableFactory implements TestRunnableFactory { - public TestRunnable getTestRunnable( + private class InputReflectedIpSecTunnelTestRunnableFactory + implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( boolean transportInTunnelMode, int spi, InetAddress localInner, @@ -355,14 +369,57 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, int encapPort, + int innerSocketPort, int expectedPacketSize) throws Exception { - return new TestRunnable() { + return new IpSecTunnelTestRunnable() { @Override - public void run(Network ipsecNetwork) throws Exception { + public int run(Network ipsecNetwork) throws Exception { + // Build a socket and receive traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner, innerSocketPort); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform); + } + + sTunUtils.reflectPackets(); + + // Receive packet from socket, and validate that the payload is correct + receiveAndValidatePacket(socket); + + socket.close(); + + return 0; + } + }; + } + } + + private class InputPacketGeneratorIpSecTunnelTestRunnableFactory + implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int innerSocketPort, + int expectedPacketSize) + throws Exception { + return new IpSecTunnelTestRunnable() { + @Override + public int run(Network ipsecNetwork) throws Exception { // Build a socket and receive traffic JavaUdpSocket socket = new JavaUdpSocket(localInner); - // JavaUdpSocket socket = new JavaUdpSocket(localInner, socketPort.get()); ipsecNetwork.bindSocket(socket.mSocket); // For Transport-In-Tunnel mode, apply transform to socket @@ -402,6 +459,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { receiveAndValidatePacket(socket); socket.close(); + + return 0; } }; } @@ -415,7 +474,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { outerFamily, useEncap, transportInTunnelMode, - new OutputTestRunnableFactory()); + new OutputIpSecTunnelTestRunnableFactory()); } private void checkTunnelInput( @@ -426,7 +485,91 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { outerFamily, useEncap, transportInTunnelMode, - new InputPacketGeneratorTestRunnableFactory()); + new InputPacketGeneratorIpSecTunnelTestRunnableFactory()); + } + + /** + * Validates that the kernel can talk to itself. + * + *

    This test takes an outbound IPsec packet, reflects it (by flipping IP src/dst), and + * injects it back into the TUN. This test then verifies that a packet with the correct payload + * is found on the specified socket/port. + */ + public void checkTunnelReflected( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + if (!hasTunnelsFeature()) return; + + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; + + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + // Run output direction tests + IpSecTunnelTestRunnable outputIpSecTunnelTestRunnable = + new OutputIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + 0, + expectedPacketSize); + int innerSocketPort = + buildTunnelNetworkAndRunTests( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + outputIpSecTunnelTestRunnable); + + // Input direction tests, with matching inner socket ports. + IpSecTunnelTestRunnable inputIpSecTunnelTestRunnable = + new InputReflectedIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + remoteInner, + localInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + innerSocketPort, + expectedPacketSize); + buildTunnelNetworkAndRunTests( + remoteInner, + localInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + inputIpSecTunnelTestRunnable); + } } public void checkTunnel( @@ -434,7 +577,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { int outerFamily, boolean useEncap, boolean transportInTunnelMode, - TestRunnableFactory factory) + IpSecTunnelTestRunnableFactory factory) throws Exception { if (!hasTunnelsFeature()) return; @@ -461,14 +604,14 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { buildIpSecTransform(sContext, outTransportSpi, null, localInner); UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { - buildTunnelAndNetwork( + buildTunnelNetworkAndRunTests( localInner, remoteInner, localOuter, remoteOuter, spi, useEncap ? encapSocket : null, - factory.getTestRunnable( + factory.getIpSecTunnelTestRunnable( transportInTunnelMode, spi, localInner, @@ -478,21 +621,23 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { inTransportTransform, outTransportTransform, useEncap ? encapSocket.getPort() : 0, + 0, expectedPacketSize)); } } - private void buildTunnelAndNetwork( + private int buildTunnelNetworkAndRunTests( InetAddress localInner, InetAddress remoteInner, InetAddress localOuter, InetAddress remoteOuter, int spi, UdpEncapsulationSocket encapSocket, - TestRunnable test) + IpSecTunnelTestRunnable test) throws Exception { int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; TestNetworkCallback testNetworkCb = null; + int innerSocketPort; try (IpSecManager.SecurityParameterIndex inSpi = mISM.allocateSecurityParameterIndex(localOuter, spi); @@ -534,7 +679,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { mISM.applyTunnelModeTransform( tunnelIface, IpSecManager.DIRECTION_OUT, outTransform); - test.run(testNetwork); + innerSocketPort = test.run(testNetwork); } // Teardown the test network @@ -553,6 +698,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { sCM.unregisterNetworkCallback(testNetworkCb); } } + + return innerSocketPort; } private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { @@ -675,36 +822,66 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { checkTunnelInput(AF_INET, AF_INET, false, true); } + @Test + public void testTransportInTunnelModeV4InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET, AF_INET, true, true); checkTunnelInput(AF_INET, AF_INET, true, true); } + @Test + public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } + @Test + public void testTransportInTunnelModeV4InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, false, true); checkTunnelInput(AF_INET6, AF_INET, false, true); } + @Test + public void testTransportInTunnelModeV6InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, true, true); checkTunnelInput(AF_INET6, AF_INET, true, true); } + @Test + public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } + @Test + public void testTransportInTunnelModeV6InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + // Tunnel mode tests @Test public void testTunnelV4InV4() throws Exception { @@ -712,33 +889,63 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { checkTunnelInput(AF_INET, AF_INET, false, false); } + @Test + public void testTunnelV4InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, false); + } + @Test public void testTunnelV4InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET, AF_INET, true, false); checkTunnelInput(AF_INET, AF_INET, true, false); } + @Test + public void testTunnelV4InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, true, false); + } + @Test public void testTunnelV4InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, false); checkTunnelInput(AF_INET, AF_INET6, false, false); } + @Test + public void testTunnelV4InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET6, false, false); + } + @Test public void testTunnelV6InV4() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, false, false); checkTunnelInput(AF_INET6, AF_INET, false, false); } + @Test + public void testTunnelV6InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET, false, false); + } + @Test public void testTunnelV6InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, true, false); checkTunnelInput(AF_INET6, AF_INET, true, false); } + @Test + public void testTunnelV6InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET, true, false); + } + @Test public void testTunnelV6InV6() throws Exception { checkTunnelOutput(AF_INET6, AF_INET6, false, false); checkTunnelInput(AF_INET6, AF_INET6, false, false); } + + @Test + public void testTunnelV6InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET6, false, false); + } } From d8a36dd745f358a242b4a494c1c8a1e7725af47a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 20 May 2019 11:58:26 -0700 Subject: [PATCH 0646/1415] Remove mContext from IpSecBaseTest This commit removes the mContext from IpSecBaseTest, and replaces it with InstrumentationRegistry.getContext(). Bug: 72950854 Test: Ran on devices, passing. Merged-In: If6fa359825aa9d1f7d4c8d49aba7a34925c073ed Change-Id: If6fa359825aa9d1f7d4c8d49aba7a34925c073ed (cherry picked from commit 69760fb5b62ae0e36c2a88bb20502dead3d7589b) --- tests/cts/net/src/android/net/cts/IpSecBaseTest.java | 4 +--- tests/cts/net/src/android/net/cts/IpSecManagerTest.java | 8 +++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 26049cc174..10e43e7b6a 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -76,11 +76,9 @@ public class IpSecBaseTest { protected ConnectivityManager mCM; protected IpSecManager mISM; - protected Context mContext; @Before public void setUp() throws Exception { - mContext = InstrumentationRegistry.getContext(); mISM = (IpSecManager) InstrumentationRegistry.getContext() @@ -475,7 +473,7 @@ public class IpSecBaseTest { private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(localAddr)) { - return buildIpSecTransform(mContext, spi, null, localAddr); + return buildIpSecTransform(InstrumentationRegistry.getContext(), spi, null, localAddr); } } diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index d6b8a968d2..355b496829 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -41,6 +41,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import java.io.FileDescriptor; @@ -238,7 +239,7 @@ public class IpSecManagerTest extends IpSecBaseTest { mISM.allocateSecurityParameterIndex(localAddr); IpSecTransform transform = - new IpSecTransform.Builder(mContext) + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) .setAuthentication( new IpSecAlgorithm( @@ -456,7 +457,8 @@ public class IpSecManagerTest extends IpSecBaseTest { IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local)) { - IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext); + IpSecTransform.Builder transformBuilder = + new IpSecTransform.Builder(InstrumentationRegistry.getContext()); if (crypt != null) { transformBuilder.setEncryption(crypt); } @@ -617,7 +619,7 @@ public class IpSecManagerTest extends IpSecBaseTest { try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local); IpSecTransform transform = - new IpSecTransform.Builder(mContext) + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) .setEncryption(crypt) .setAuthentication(auth) .setIpv4Encapsulation(encapSocket, encapSocket.getPort()) From 66fe5244ad2916c4ec9c7eda977df234fb88d572 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 31 May 2019 15:13:31 -0700 Subject: [PATCH 0647/1415] Fix testNetworkSettingsPermission for headless User 0 This test fails on devices with headless user 0 when it tries to verify apps with android:sharedUserId="android.uid.system" (and without explicit ask for NETWORK_SETTINGS). Such apps get this permission by default, but when running on user 1 they get UID 1001000, what doesn't match SYSTEM_UID=1000. By the chance of modifying this code, let's also add more verbose error message (with UID), simplify it and reduce indentation count. Bug: 120143468 Test: atest android.net.wifi.cts.WifiManagerTest#testNetworkSettingsPermission Change-Id: Ifc09320cf738a518003126fad1ce31f5e38a3aff --- tests/cts/net/AndroidManifest.xml | 1 + .../android/net/wifi/cts/WifiManagerTest.java | 30 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 44a00ef619..c2b3bf77ad 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -27,6 +27,7 @@ + diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 75764508c8..fbf1abd3b8 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -36,6 +36,7 @@ import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.os.Process; import android.os.SystemClock; +import android.os.UserHandle; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; import android.support.test.uiautomator.UiDevice; @@ -770,21 +771,20 @@ public class WifiManagerTest extends AndroidTestCase { }, PackageManager.MATCH_UNINSTALLED_PACKAGES); for (PackageInfo pi : holding) { String packageName = pi.packageName; - if (allowedPackages.contains(packageName)) { - // this is an explicitly allowed package - } else { - // now check if the packages are from allowed UIDs - boolean allowed = false; - try { - if (allowedUIDs.contains(pm.getPackageUid(packageName, 0))) { - allowed = true; - Log.d(TAG, packageName + " is on an allowed UID"); - } - } catch (PackageManager.NameNotFoundException e) { } - if (!allowed) { - fail("The NETWORK_SETTINGS permission must not be held by " - + packageName + " and must be revoked for security reasons"); - } + + // this is an explicitly allowed package + if (allowedPackages.contains(packageName)) continue; + + // now check if the packages are from allowed UIDs + int uid = -1; + try { + uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM); + } catch (PackageManager.NameNotFoundException e) { + continue; + } + if (!allowedUIDs.contains(uid)) { + fail("The NETWORK_SETTINGS permission must not be held by " + packageName + + ":" + uid + " and must be revoked for security reasons"); } } } From 802549c8de99517e1fa4a174abbf7c06078526dc Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 5 Jun 2019 18:27:40 -0700 Subject: [PATCH 0648/1415] Skip battery saver related tests on unsupported devices. Bug: 133761301 Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: Ifec84425febf38d732367fae6b43fa80c427c79f --- .../net/hostside/AbstractAppIdleTestCase.java | 5 ++++ .../AbstractBatterySaverModeTestCase.java | 18 +++++++++---- ...ractRestrictBackgroundNetworkTestCase.java | 8 ++++++ .../cts/net/hostside/MixedModesTest.java | 25 +++++++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 7bf7bd44f4..55bd406c64 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -150,6 +150,11 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork } public void testAppIdleNetworkAccess_whenCharging() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; // Check that app is paroled when charging diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index 28175b8784..931376b9fe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -16,6 +16,7 @@ package com.android.cts.net.hostside; +import android.text.TextUtils; import android.util.Log; /** @@ -52,12 +53,19 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou @Override protected boolean isSupported() throws Exception { - boolean supported = isDozeModeEnabled(); - if (!supported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); + String unSupported = ""; + if (!isDozeModeEnabled()) { + unSupported += "Doze mode,"; } - return supported; + if (!isBatterySaverSupported()) { + unSupported += "Battery saver mode,"; + } + if (!TextUtils.isEmpty(unSupported)) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support " + unSupported); + return false; + } + return true; } /** diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 6dfa2f3aef..40d7e34fcc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -34,6 +34,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -43,12 +44,15 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; +import android.os.SystemProperties; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.test.InstrumentationTestCase; import android.text.TextUtils; import android.util.Log; +import com.android.compatibility.common.util.BatteryUtils; + import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -311,6 +315,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return mSupported; } + protected boolean isBatterySaverSupported() { + return BatteryUtils.isBatterySaverSupported(); + } + /** * Asserts that an app always have access while on foreground or running a foreground service. * diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index 74875cd2c9..b1a21867b3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -71,6 +71,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); @@ -141,6 +146,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * networks. */ public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; if (!setUnmeteredNetwork()) { @@ -206,6 +216,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * are enabled. */ public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } @@ -285,6 +300,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } @@ -361,6 +381,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } From 8371c77499889e22437eafeece7ac022069e5d64 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 5 Jun 2019 18:27:40 -0700 Subject: [PATCH 0649/1415] Skip battery saver related tests on unsupported devices. Bug: 133761301 Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: Ifec84425febf38d732367fae6b43fa80c427c79f Merged-In: Ifec84425febf38d732367fae6b43fa80c427c79f --- .../net/hostside/AbstractAppIdleTestCase.java | 5 +++++ .../AbstractBatterySaverModeTestCase.java | 18 ++++++++++++----- ...ractRestrictBackgroundNetworkTestCase.java | 7 +++++++ .../cts/net/hostside/MixedModesTest.java | 20 +++++++++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 0e141c05ad..1f5984a704 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -150,6 +150,11 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork } public void testAppIdleNetworkAccess_whenCharging() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; // Check that app is paroled when charging diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index 28175b8784..931376b9fe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -16,6 +16,7 @@ package com.android.cts.net.hostside; +import android.text.TextUtils; import android.util.Log; /** @@ -52,12 +53,19 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou @Override protected boolean isSupported() throws Exception { - boolean supported = isDozeModeEnabled(); - if (!supported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); + String unSupported = ""; + if (!isDozeModeEnabled()) { + unSupported += "Doze mode,"; } - return supported; + if (!isBatterySaverSupported()) { + unSupported += "Battery saver mode,"; + } + if (!TextUtils.isEmpty(unSupported)) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support " + unSupported); + return false; + } + return true; } /** diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 5232372047..1844878f64 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -38,6 +38,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -53,6 +54,8 @@ import android.test.InstrumentationTestCase; import android.text.TextUtils; import android.util.Log; +import com.android.compatibility.common.util.BatteryUtils; + /** * Superclass for tests related to background network restrictions. */ @@ -301,6 +304,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return mSupported; } + protected boolean isBatterySaverSupported() throws Exception { + return BatteryUtils.isBatterySaverSupported(); + } + /** * Asserts that an app always have access while on foreground or running a foreground service. * diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index 87f9d7738d..7f65b55b48 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -71,6 +71,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); @@ -141,6 +146,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * networks. */ public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; if (!setUnmeteredNetwork()) { @@ -206,6 +216,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * are enabled. */ public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } @@ -285,6 +300,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } From 8eeaa698c67596486d9635ac15aa0286ede3c153 Mon Sep 17 00:00:00 2001 From: Pete Bentley Date: Fri, 7 Jun 2019 18:41:48 +0100 Subject: [PATCH 0650/1415] Update test host used for TLS host verification. Temporary fix, this is still brittle to certificate changes on the test host. Bug: 134532880 Test: atest android.net.cts.SSLCertificateSocketFactoryTest Change-Id: I6e8c8757963ef46009767925bfa512127d9daba7 --- .../src/android/net/cts/SSLCertificateSocketFactoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 525045057b..01ac3fda08 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -92,7 +92,7 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { // a host and port that are expected to be available but have // a cert with a different CN, in this case CN=mail.google.com - private static String TEST_CREATE_SOCKET_HOST = "googlemail.com"; + private static String TEST_CREATE_SOCKET_HOST = "www3.l.google.com"; private static int TEST_CREATE_SOCKET_PORT = 443; /** From 50795d03cddf9ad6f8e3c7f5926b82c60ffe21d6 Mon Sep 17 00:00:00 2001 From: Pete Bentley Date: Fri, 7 Jun 2019 18:41:48 +0100 Subject: [PATCH 0651/1415] Update test host used for TLS host verification. Temporary fix, this is still brittle to certificate changes on the test host. Bug: 134532880 Test: atest android.net.cts.SSLCertificateSocketFactoryTest Change-Id: I6e8c8757963ef46009767925bfa512127d9daba7 Merged-In: I6e8c8757963ef46009767925bfa512127d9daba7 (cherry picked from commit 166e7121b173f2a4e3d6a9ded213e4c8679a9cfb) --- .../src/android/net/cts/SSLCertificateSocketFactoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 525045057b..01ac3fda08 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -92,7 +92,7 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { // a host and port that are expected to be available but have // a cert with a different CN, in this case CN=mail.google.com - private static String TEST_CREATE_SOCKET_HOST = "googlemail.com"; + private static String TEST_CREATE_SOCKET_HOST = "www3.l.google.com"; private static int TEST_CREATE_SOCKET_PORT = 443; /** From c80f04858ebffafd330448e4fead4b4ed340a603 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 10 Jun 2019 14:16:41 +0800 Subject: [PATCH 0652/1415] Fix DnsResolverTest for instant mode add AppModeFull@ to DnsResolverTest since WRITE_SECURE_SETTINGS could not be ganted in instant mode. Bug: 134897744 Test: atest DnsResolverTest atest DnsResolverTest --instant Change-Id: I267c19af1a1c5544ca752a364335ec728a478bb2 --- tests/cts/net/src/android/net/cts/DnsResolverTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index e16fce09bf..1ff2090bc5 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -39,6 +39,7 @@ import android.net.ParseException; import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; +import android.platform.test.annotations.AppModeFull; import android.provider.Settings; import android.system.ErrnoException; import android.test.AndroidTestCase; @@ -53,6 +54,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") public class DnsResolverTest extends AndroidTestCase { private static final String TAG = "DnsResolverTest"; private static final char[] HEX_CHARS = { From 1053db1f82c989540704a2020971a7fefad5bda3 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 11 Jun 2019 15:49:08 +0800 Subject: [PATCH 0653/1415] Add test with inline executor for DnsResolverTest Makes general query test cases also take inline executor. The new added test case testSequentialQuery with inline executor will only pass after aosp/980686. Bug: 134310704 Test: atest DnsResolverTest atest DnsResolverTest --instant Change-Id: I135358fe45652277ed795a2f359f44f4db787c08 --- .../src/android/net/cts/DnsResolverTest.java | 115 +++++++++++++++--- 1 file changed, 101 insertions(+), 14 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 1ff2090bc5..ef8badd32a 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -80,12 +80,14 @@ public class DnsResolverTest extends AndroidTestCase { static final int TIMEOUT_MS = 12_000; static final int CANCEL_TIMEOUT_MS = 3_000; static final int CANCEL_RETRY_TIMES = 5; + static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; private ContentResolver mCR; private ConnectivityManager mCM; private Executor mExecutor; + private Executor mExecutorInline; private DnsResolver mDns; private String mOldMode; @@ -97,6 +99,7 @@ public class DnsResolverTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mDns = DnsResolver.getInstance(); mExecutor = new Handler(Looper.getMainLooper())::post; + mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); storePrivateDnsSetting(); } @@ -274,12 +277,44 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQuery() throws InterruptedException { + public void testRawQuery() throws Exception { + doTestRawQuery(mExecutor); + } + + public void testRawQueryInline() throws Exception { + doTestRawQuery(mExecutorInline); + } + + public void testRawQueryBlob() throws Exception { + doTestRawQueryBlob(mExecutor); + } + + public void testRawQueryBlobInline() throws Exception { + doTestRawQueryBlob(mExecutorInline); + } + + public void testRawQueryRoot() throws Exception { + doTestRawQueryRoot(mExecutor); + } + + public void testRawQueryRootInline() throws Exception { + doTestRawQueryRoot(mExecutorInline); + } + + public void testRawQueryNXDomain() throws Exception { + doTestRawQueryNXDomain(mExecutor); + } + + public void testRawQueryNXDomainInline() throws Exception { + doTestRawQueryNXDomain(mExecutorInline); + } + + public void doTestRawQuery(Executor executor) throws InterruptedException { final String msg = "RawQuery " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -287,7 +322,7 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryBlob() throws InterruptedException { + public void doTestRawQueryBlob(Executor executor) throws InterruptedException { final byte[] blob = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -305,7 +340,7 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery blob " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); - mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -313,13 +348,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryRoot() throws InterruptedException { + public void doTestRawQueryRoot(Executor executor) throws InterruptedException { final String dname = ""; final String msg = "RawQuery empty dname(ROOT) "; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -328,13 +363,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryNXDomain() throws InterruptedException { + public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException { final String dname = "test1-nx.metric.gstatic.com"; final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -476,12 +511,44 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddress() throws InterruptedException { + public void testQueryForInetAddress() throws Exception { + doTestQueryForInetAddress(mExecutor); + } + + public void testQueryForInetAddressInline() throws Exception { + doTestQueryForInetAddress(mExecutorInline); + } + + public void testQueryForInetAddressIpv4() throws Exception { + doTestQueryForInetAddressIpv4(mExecutor); + } + + public void testQueryForInetAddressIpv4Inline() throws Exception { + doTestQueryForInetAddressIpv4(mExecutorInline); + } + + public void testQueryForInetAddressIpv6() throws Exception { + doTestQueryForInetAddressIpv6(mExecutor); + } + + public void testQueryForInetAddressIpv6Inline() throws Exception { + doTestQueryForInetAddressIpv6(mExecutorInline); + } + + public void testContinuousQueries() throws Exception { + doTestContinuousQueries(mExecutor); + } + + public void testContinuousQueriesInline() throws Exception { + doTestContinuousQueries(mExecutorInline); + } + + public void doTestQueryForInetAddress(Executor executor) throws InterruptedException { final String msg = "Test query for InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -518,13 +585,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddressIpv4() throws InterruptedException { + public void doTestQueryForInetAddressIpv4(Executor executor) throws InterruptedException { final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -533,13 +600,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddressIpv6() throws InterruptedException { + public void doTestQueryForInetAddressIpv6(Executor executor) throws InterruptedException { final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -632,4 +699,24 @@ public class DnsResolverTest extends AndroidTestCase { mCM.bindProcessToNetwork(null); } } + + public void doTestContinuousQueries(Executor executor) throws InterruptedException { + final String msg = "Test continuous " + QUERY_TIMES + " queries " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + for (int i = 0; i < QUERY_TIMES ; ++i) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + // query v6/v4 in turn + boolean queryV6 = (i % 2 == 0); + mDns.query(network, TEST_DOMAIN, queryV6 ? TYPE_AAAA : TYPE_A, + FLAG_NO_CACHE_LOOKUP, executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results", + queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer()); + } + } + } } From d3b7dec47352efcd4342bbc1adf82687bb442efe Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 10 Jun 2019 14:16:41 +0800 Subject: [PATCH 0654/1415] Fix DnsResolverTest for instant mode add AppModeFull@ to DnsResolverTest since WRITE_SECURE_SETTINGS could not be ganted in instant mode. Bug: 134897744 Test: atest DnsResolverTest atest DnsResolverTest --instant Change-Id: I267c19af1a1c5544ca752a364335ec728a478bb2 (cherry picked from commit 2af244f4127883ed967089f550f2cfe07936416d) --- tests/cts/net/src/android/net/cts/DnsResolverTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index e16fce09bf..1ff2090bc5 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -39,6 +39,7 @@ import android.net.ParseException; import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; +import android.platform.test.annotations.AppModeFull; import android.provider.Settings; import android.system.ErrnoException; import android.test.AndroidTestCase; @@ -53,6 +54,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") public class DnsResolverTest extends AndroidTestCase { private static final String TAG = "DnsResolverTest"; private static final char[] HEX_CHARS = { From 5e43421294d03f6ae69527ee4de9c05dd0a8c877 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 11 Jun 2019 15:49:08 +0800 Subject: [PATCH 0655/1415] Add test with inline executor for DnsResolverTest Makes general query test cases also take inline executor. The new added test case testSequentialQuery with inline executor will only pass after aosp/980686. Bug: 134310704 Test: atest DnsResolverTest atest DnsResolverTest --instant Change-Id: I135358fe45652277ed795a2f359f44f4db787c08 (cherry picked from commit 04596294eea3e5db4fd487cf6f8ef598daac606a) --- .../src/android/net/cts/DnsResolverTest.java | 115 +++++++++++++++--- 1 file changed, 101 insertions(+), 14 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 1ff2090bc5..ef8badd32a 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -80,12 +80,14 @@ public class DnsResolverTest extends AndroidTestCase { static final int TIMEOUT_MS = 12_000; static final int CANCEL_TIMEOUT_MS = 3_000; static final int CANCEL_RETRY_TIMES = 5; + static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; private ContentResolver mCR; private ConnectivityManager mCM; private Executor mExecutor; + private Executor mExecutorInline; private DnsResolver mDns; private String mOldMode; @@ -97,6 +99,7 @@ public class DnsResolverTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mDns = DnsResolver.getInstance(); mExecutor = new Handler(Looper.getMainLooper())::post; + mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); storePrivateDnsSetting(); } @@ -274,12 +277,44 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQuery() throws InterruptedException { + public void testRawQuery() throws Exception { + doTestRawQuery(mExecutor); + } + + public void testRawQueryInline() throws Exception { + doTestRawQuery(mExecutorInline); + } + + public void testRawQueryBlob() throws Exception { + doTestRawQueryBlob(mExecutor); + } + + public void testRawQueryBlobInline() throws Exception { + doTestRawQueryBlob(mExecutorInline); + } + + public void testRawQueryRoot() throws Exception { + doTestRawQueryRoot(mExecutor); + } + + public void testRawQueryRootInline() throws Exception { + doTestRawQueryRoot(mExecutorInline); + } + + public void testRawQueryNXDomain() throws Exception { + doTestRawQueryNXDomain(mExecutor); + } + + public void testRawQueryNXDomainInline() throws Exception { + doTestRawQueryNXDomain(mExecutorInline); + } + + public void doTestRawQuery(Executor executor) throws InterruptedException { final String msg = "RawQuery " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -287,7 +322,7 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryBlob() throws InterruptedException { + public void doTestRawQueryBlob(Executor executor) throws InterruptedException { final byte[] blob = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -305,7 +340,7 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery blob " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); - mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -313,13 +348,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryRoot() throws InterruptedException { + public void doTestRawQueryRoot(Executor executor) throws InterruptedException { final String dname = ""; final String msg = "RawQuery empty dname(ROOT) "; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -328,13 +363,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryNXDomain() throws InterruptedException { + public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException { final String dname = "test1-nx.metric.gstatic.com"; final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -476,12 +511,44 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddress() throws InterruptedException { + public void testQueryForInetAddress() throws Exception { + doTestQueryForInetAddress(mExecutor); + } + + public void testQueryForInetAddressInline() throws Exception { + doTestQueryForInetAddress(mExecutorInline); + } + + public void testQueryForInetAddressIpv4() throws Exception { + doTestQueryForInetAddressIpv4(mExecutor); + } + + public void testQueryForInetAddressIpv4Inline() throws Exception { + doTestQueryForInetAddressIpv4(mExecutorInline); + } + + public void testQueryForInetAddressIpv6() throws Exception { + doTestQueryForInetAddressIpv6(mExecutor); + } + + public void testQueryForInetAddressIpv6Inline() throws Exception { + doTestQueryForInetAddressIpv6(mExecutorInline); + } + + public void testContinuousQueries() throws Exception { + doTestContinuousQueries(mExecutor); + } + + public void testContinuousQueriesInline() throws Exception { + doTestContinuousQueries(mExecutorInline); + } + + public void doTestQueryForInetAddress(Executor executor) throws InterruptedException { final String msg = "Test query for InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -518,13 +585,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddressIpv4() throws InterruptedException { + public void doTestQueryForInetAddressIpv4(Executor executor) throws InterruptedException { final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -533,13 +600,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddressIpv6() throws InterruptedException { + public void doTestQueryForInetAddressIpv6(Executor executor) throws InterruptedException { final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -632,4 +699,24 @@ public class DnsResolverTest extends AndroidTestCase { mCM.bindProcessToNetwork(null); } } + + public void doTestContinuousQueries(Executor executor) throws InterruptedException { + final String msg = "Test continuous " + QUERY_TIMES + " queries " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + for (int i = 0; i < QUERY_TIMES ; ++i) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + // query v6/v4 in turn + boolean queryV6 = (i % 2 == 0); + mDns.query(network, TEST_DOMAIN, queryV6 ? TYPE_AAAA : TYPE_A, + FLAG_NO_CACHE_LOOKUP, executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results", + queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer()); + } + } + } } From 487b0401c0e3cb9bd27a5d26a0bffbc4dc06aec8 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 3 Jun 2019 10:26:08 +0800 Subject: [PATCH 0656/1415] Add CTS for creating keepalive offloads on cellular Bug: 134352656 Test: atest android.net.cts.ConnectivityManagerTest (--instant) Change-Id: Ia7b1111abe687efad032a8c9205990c97a769fcd --- .../net/cts/ConnectivityManagerTest.java | 245 ++++++++++++------ 1 file changed, 168 insertions(+), 77 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 8c9bf6ee21..e9deec9f1e 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -35,6 +35,7 @@ import static android.system.OsConstants.AF_UNSPEC; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import android.annotation.NonNull; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.UiAutomation; @@ -59,6 +60,7 @@ import android.net.SocketKeepalive; import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; +import android.os.Build; import android.os.Looper; import android.os.MessageQueue; import android.os.SystemClock; @@ -99,6 +101,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -113,6 +116,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final int CONNECT_TIMEOUT_MS = 2000; private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000; private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000; + private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500; + private static final int MAX_KEEPALIVE_RETRY_COUNT = 3; private static final int MIN_KEEPALIVE_INTERVAL = 10; private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; @@ -120,6 +125,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { // device could have only one interface: data, wifi. private static final int MIN_NUM_NETWORK_TYPES = 1; + // Minimum supported keepalive counts for wifi and cellular. + public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1; + public static final int MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT = 3; + private Context mContext; private Instrumentation mInstrumentation; private ConnectivityManager mCm; @@ -839,8 +848,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { return s; } - private int getSupportedKeepalivesFromRes() throws Exception { - final Network network = ensureWifiConnected(); + private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception { final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); // Get number of supported concurrent keepalives for testing network. @@ -914,34 +922,46 @@ public class ConnectivityManagerTest extends AndroidTestCase { * keepalives is set to 0. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") - public void testKeepaliveUnsupported() throws Exception { - if (getSupportedKeepalivesFromRes() != 0) return; + public void testKeepaliveWifiUnsupported() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + if (getSupportedKeepalivesForNet(network) != 0) return; adoptShellPermissionIdentity(); - assertEquals(0, createConcurrentSocketKeepalives(1, 0)); - assertEquals(0, createConcurrentSocketKeepalives(0, 1)); + assertEquals(0, createConcurrentSocketKeepalives(network, 1, 0)); + assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); dropShellPermissionIdentity(); } @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testCreateTcpKeepalive() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi"); + return; + } + adoptShellPermissionIdentity(); - if (getSupportedKeepalivesFromRes() == 0) return; + final Network network = ensureWifiConnected(); + if (getSupportedKeepalivesForNet(network) == 0) return; // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive // needs to be supported except if the kernel doesn't support it. if (!isTcpKeepaliveSupportedByKernel()) { // Sanity check to ensure the callback result is expected. - assertEquals(0, createConcurrentSocketKeepalives(0, 1)); + assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " + VintfRuntimeInfo.getKernelVersion()); return; } - final Network network = ensureWifiConnected(); final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8"); // So far only ipv4 tcp keepalive offload is supported. // TODO: add test case for ipv6 tcp keepalive offload when it is supported. @@ -1007,80 +1027,102 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } - /** - * Creates concurrent keepalives until the specified counts of each type of keepalives are - * reached or the expected error callbacks are received for each type of keepalives. - * - * @return the total number of keepalives created. - */ - private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { - final Network network = ensureWifiConnected(); - + private ArrayList createConcurrentKeepalivesOfType( + int requestCount, @NonNull TestSocketKeepaliveCallback callback, + Supplier kaFactory) { final ArrayList kalist = new ArrayList<>(); - final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); - final Executor executor = mContext.getMainExecutor(); - // Create concurrent TCP keepalives. - for (int i = 0; i < tcpCount; i++) { - // Assert that TCP connections can be established on wifi. The file descriptor of tcp - // sockets will be duplicated and kept valid in service side if the keepalives are - // successfully started. - try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, - 0 /* Unused */, AF_INET)) { - final SocketKeepalive ka = mCm.createSocketKeepalive(network, tcpSocket, executor, - callback); - ka.start(MIN_KEEPALIVE_INTERVAL); - TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); - assertNotNull(cv); - if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { - if (i == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { - // Unsupported. - break; - } else if (i != 0 && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { - // Limit reached. - break; - } - } - if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { - kalist.add(ka); - } else { - fail("Unexpected error when creating " + (i + 1) + " TCP keepalives: " + cv); - } - } - } + int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT; - // Assert that a Nat-T socket can be created. - final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); - final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); - - final InetAddress srcAddr = getFirstV4Address(network); - final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); - assertNotNull(srcAddr); - assertNotNull(dstAddr); - - // Test concurrent Nat-T keepalives. - for (int i = 0; i < nattCount; i++) { - final SocketKeepalive ka = mCm.createSocketKeepalive(network, nattSocket, - srcAddr, dstAddr, executor, callback); + // Test concurrent keepalives with the given supplier. + while (kalist.size() < requestCount) { + final SocketKeepalive ka = kaFactory.get(); ka.start(MIN_KEEPALIVE_INTERVAL); TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); assertNotNull(cv); if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { - if (i == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { + if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { // Unsupported. break; - } else if (i != 0 && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { - // Limit reached. + } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached or temporary unavailable due to stopped slot is not yet + // released. + if (remainingRetries > 0) { + SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS); + remainingRetries--; + continue; + } break; } } if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { kalist.add(ka); } else { - fail("Unexpected error when creating " + (i + 1) + " Nat-T keepalives: " + cv); + fail("Unexpected error when creating " + (kalist.size() + 1) + " " + + ka.getClass().getSimpleName() + ": " + cv); } } + return kalist; + } + + private @NonNull ArrayList createConcurrentNattSocketKeepalives( + @NonNull Network network, int requestCount, + @NonNull TestSocketKeepaliveCallback callback) throws Exception { + + final Executor executor = mContext.getMainExecutor(); + + // Initialize a real NaT-T socket. + final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); + final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); + final InetAddress srcAddr = getFirstV4Address(network); + final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); + assertNotNull(srcAddr); + assertNotNull(dstAddr); + + // Test concurrent Nat-T keepalives. + final ArrayList result = createConcurrentKeepalivesOfType(requestCount, + callback, () -> mCm.createSocketKeepalive(network, nattSocket, + srcAddr, dstAddr, executor, callback)); + + nattSocket.close(); + return result; + } + + private @NonNull ArrayList createConcurrentTcpSocketKeepalives( + @NonNull Network network, int requestCount, + @NonNull TestSocketKeepaliveCallback callback) { + final Executor executor = mContext.getMainExecutor(); + + // Create concurrent TCP keepalives. + return createConcurrentKeepalivesOfType(requestCount, callback, () -> { + // Assert that TCP connections can be established. The file descriptor of tcp + // sockets will be duplicated and kept valid in service side if the keepalives are + // successfully started. + try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, + 0 /* Unused */, AF_INET)) { + return mCm.createSocketKeepalive(network, tcpSocket, executor, callback); + } catch (Exception e) { + fail("Unexpected error when creating TCP socket: " + e); + } + return null; + }); + } + + /** + * Creates concurrent keepalives until the specified counts of each type of keepalives are + * reached or the expected error callbacks are received for each type of keepalives. + * + * @return the total number of keepalives created. + */ + private int createConcurrentSocketKeepalives( + @NonNull Network network, int nattCount, int tcpCount) throws Exception { + final ArrayList kalist = new ArrayList<>(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + + kalist.addAll(createConcurrentNattSocketKeepalives(network, nattCount, callback)); + kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback)); + final int ret = kalist.size(); // Clean up. @@ -1089,7 +1131,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { callback.expectStopped(); } kalist.clear(); - nattSocket.close(); return ret; } @@ -1099,8 +1140,15 @@ public class ConnectivityManagerTest extends AndroidTestCase { * get leaked after iterations. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") - public void testSocketKeepaliveLimit() throws Exception { - final int supported = getSupportedKeepalivesFromRes(); + public void testSocketKeepaliveLimitWifi() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + final int supported = getSupportedKeepalivesForNet(network); if (supported == 0) { return; } @@ -1108,37 +1156,79 @@ public class ConnectivityManagerTest extends AndroidTestCase { adoptShellPermissionIdentity(); // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. - assertGreaterOrEqual(supported, KeepaliveUtils.MIN_SUPPORTED_KEEPALIVE_COUNT); + assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); // Verifies that Nat-T keepalives can be established. - assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0)); // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. if (isTcpKeepaliveSupportedByKernel()) { - assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported + 1)); // Verifies that different types can be established at the same time. - assertEquals(supported, createConcurrentSocketKeepalives( + assertEquals(supported, createConcurrentSocketKeepalives(network, supported / 2, supported - supported / 2)); // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); - assertEquals(supported, createConcurrentSocketKeepalives( + assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported)); + assertEquals(supported, createConcurrentSocketKeepalives(network, supported / 2, supported - supported / 2)); } dropShellPermissionIdentity(); } + /** + * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and + * don't get leaked after iterations. + */ + @AppModeFull(reason = "Cannot request network in instant app mode") + public void testSocketKeepaliveLimitTelephony() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { + Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" + + " supports telephony"); + return; + } + + final int firstSdk = Build.VERSION.FIRST_SDK_INT; + if (firstSdk < Build.VERSION_CODES.Q) { + Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching" + + " before Q: " + firstSdk); + return; + } + + final Network network = mCtsNetUtils.connectToCell(); + final int supported = getSupportedKeepalivesForNet(network); + + adoptShellPermissionIdentity(); + + // Verifies that the supported keepalive slots meet minimum requirement. + assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); + + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0)); + + dropShellPermissionIdentity(); + } + /** * Verifies that the keepalive slots are limited as customized for unprivileged requests. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testSocketKeepaliveUnprivileged() throws Exception { - final int supported = getSupportedKeepalivesFromRes(); + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + final int supported = getSupportedKeepalivesForNet(network); if (supported == 0) { return; } @@ -1154,7 +1244,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertGreaterOrEqual(supported, allowedUnprivilegedPerUid); final int expectedUnprivileged = Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); - assertEquals(expectedUnprivileged, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(expectedUnprivileged, + createConcurrentSocketKeepalives(network, supported + 1, 0)); } private static void assertGreaterOrEqual(long greater, long lesser) { From d51ae5760d7850d28911557e08e5110559d78bed Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 21 Nov 2018 22:56:31 +0800 Subject: [PATCH 0657/1415] Exempt adb socket for hostside VpnTest Vpn test would destroy socket. If adb run over network, adb socket would be killed during Vpn test. Then, test stop due to adb disconnect. Bug: 119382723 Bug: 135225500 Test: - build pass Change-Id: I91b4ab018a9e7fc73dcb7969e4a6520d6b27d629 Merged-In: I91b4ab018a9e7fc73dcb7969e4a6520d6b27d629 Merged-In: Id6f986aacc3cadf713ebbc8305ca535b861390fc (cherry picked from commit de0f268f789222dd17d3c28c0f07656f2c168d81) --- tests/cts/hostside/app/Android.mk | 5 ++++- .../com/android/cts/net/hostside/VpnTest.java | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index 1c1a798fab..b1a4494d25 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -19,10 +19,13 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SDK_VERSION := current +#LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \ CtsHostsideNetworkTestsAidl +LOCAL_JAVA_LIBRARIES := android.test.runner + LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsHostsideNetworkTestsApp diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index bc982cec78..b3f61c486d 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -29,6 +29,7 @@ import android.net.NetworkRequest; import android.net.VpnService; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.SystemProperties; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; @@ -537,6 +538,14 @@ public class VpnTest extends InstrumentationTestCase { public void testDefault() throws Exception { if (!supportedHardware()) return; + // If adb TCP port opened, this test may running by adb over network. + // All of socket would be destroyed in this test. So this test don't + // support adb over network, see b/119382723. + if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 + || SystemProperties.getInt("service.adb.tcp.port", -1) > -1) { + Log.i(TAG, "adb is running over the network, so skip this test"); + return; + } FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); @@ -554,6 +563,7 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + // Shell app must not be put in here or it would kill the ADB-over-network use case String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, @@ -571,6 +581,12 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); String disallowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + // If adb TCP port opened, this test may running by adb over TCP. + // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test, + // see b/119382723. + // Note: The test don't support running adb over network for root device + disallowedApps = disallowedApps + ",com.android.shell"; + Log.i(TAG, "Append shell app to disallowedApps: " + disallowedApps); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, "", disallowedApps); From bd43e6d4fbe4e97f7dc6a0d475d45d3586f1361c Mon Sep 17 00:00:00 2001 From: Julien Desprez Date: Wed, 19 Jun 2019 15:25:08 -0700 Subject: [PATCH 0658/1415] Mark module as "secondary_user" since it uncovered bug before This will allow running this module against a secondary user in continuous infra to uncover bugs. Test: run cts-unit-tests Bug: 130892086 Change-Id: Ic8af2e3e77e24db340b2894c2d36e3501962952c --- tests/cts/hostside/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index c7cab7b0ba..dbff1794e9 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -18,6 +18,7 @@

    This method should return a socket which is fully connected (i.e. TLS handshake complete) + * and whose peer TLS certificate has been verified to have the correct hostname. + * + *

    {@link SSLCertificateSocketFactory} is documented to verify hostnames using + * the {@link HostnameVerifier} returned by + * {@link HttpsURLConnection#getDefaultHostnameVerifier}, so this test connects twice, + * once with the system default {@link HostnameVerifier} which is expected to succeed, + * and once after installing a {@link NegativeHostnameVerifier} which will cause + * {@link SSLCertificateSocketFactory#verifyHostname} to throw a + * {@link SSLPeerUnverifiedException}. + * + *

    These tests only test the hostname verification logic in SSLCertificateSocketFactory, + * other TLS failure modes and the default HostnameVerifier are tested elsewhere, see + * {@link com.squareup.okhttp.internal.tls.HostnameVerifierTest} and + * https://android.googlesource.com/platform/external/boringssl/+/refs/heads/master/src/ssl/test + * + *

    Tests the following behaviour:- + *

      + *
    • TEST_SERVER is available and has a valid TLS certificate + *
    • {@code createSocket()} verifies the remote hostname is correct using + * {@link HttpsURLConnection#getDefaultHostnameVerifier} + *
    • {@link SSLPeerUnverifiedException} is thrown when the remote hostname is invalid + *
    + * + *

    See also http://b/2807618. + */ + @Test + public void createSocket_simple_with_hostname_verification() throws Exception { + Socket socket = mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT); + assertConnectedSocket(socket); + socket.close(); + + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + try { + mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(Socket, String, int, boolean)}. + * + *

    This method should return a socket which is fully connected (i.e. TLS handshake complete) + * and whose peer TLS certificate has been verified to have the correct hostname. + * + *

    The TLS socket returned is wrapped around the plain socket passed into + * {@code createSocket()}. + * + *

    See {@link #createSocket_simple_with_hostname_verification()} for test methodology. + */ + @Test + public void createSocket_wrapped_with_hostname_verification() throws Exception { + Socket underlying = new Socket(TEST_HOST, HTTPS_PORT); + Socket socket = mSocketFactory.createSocket(underlying, TEST_HOST, HTTPS_PORT, true); + assertConnectedSocket(socket); + socket.close(); + + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + try { + underlying = new Socket(TEST_HOST, HTTPS_PORT); + mSocketFactory.createSocket(underlying, TEST_HOST, HTTPS_PORT, true); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(String, int, InetAddress, int)}. + * + *

    This method should return a socket which is fully connected (i.e. TLS handshake complete) + * and whose peer TLS certificate has been verified to have the correct hostname. + * + *

    The TLS socket returned is also bound to the local address determined in {@link #setUp} to + * be used for connections to TEST_HOST, and a wildcard port. + * + *

    See {@link #createSocket_simple_with_hostname_verification()} for test methodology. + */ + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void createSocket_bound_with_hostname_verification() throws Exception { + Socket socket = mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT, mLocalAddress, 0); + assertConnectedSocket(socket); + socket.close(); + + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + try { + mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT, mLocalAddress, 0); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(InetAddress, int)}. + * + *

    This method should return a socket which the documentation describes as "unconnected", + * which actually means that the socket is fully connected at the TCP layer but TLS handshaking + * and hostname verification have not yet taken place. + * + *

    Behaviour is tested by installing a {@link NegativeHostnameVerifier} and by calling + * {@link #assertConnectedSocket} to ensure TLS handshaking but no hostname verification takes + * place. Next, {@link SSLCertificateSocketFactory#verifyHostname} is called to ensure + * that hostname verification is using the {@link HostnameVerifier} returned by + * {@link HttpsURLConnection#getDefaultHostnameVerifier} as documented. + * + *

    Tests the following behaviour:- + *

      + *
    • TEST_SERVER is available and has a valid TLS certificate + *
    • {@code createSocket()} does not verify the remote hostname + *
    • Calling {@link SSLCertificateSocketFactory#verifyHostname} on the returned socket + * throws {@link SSLPeerUnverifiedException} if the remote hostname is invalid + *
    + */ + @Test + public void createSocket_simple_no_hostname_verification() throws Exception{ + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + Socket socket = mSocketFactory.createSocket(mTestHostAddress, HTTPS_PORT); + // Need to provide the expected hostname here or the TLS handshake will + // be unable to supply SNI to the remote host. + mSocketFactory.setHostname(socket, TEST_HOST); + assertConnectedSocket(socket); + try { + SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier); + SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + socket.close(); + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(InetAddress, int, InetAddress, int)}. + * + *

    This method should return a socket which the documentation describes as "unconnected", + * which actually means that the socket is fully connected at the TCP layer but TLS handshaking + * and hostname verification have not yet taken place. + * + *

    The TLS socket returned is also bound to the local address determined in {@link #setUp} to + * be used for connections to TEST_HOST, and a wildcard port. + * + *

    See {@link #createSocket_simple_no_hostname_verification()} for test methodology. + */ + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void createSocket_bound_no_hostname_verification() throws Exception{ + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + Socket socket = + mSocketFactory.createSocket(mTestHostAddress, HTTPS_PORT, mLocalAddress, 0); + // Need to provide the expected hostname here or the TLS handshake will + // be unable to supply SNI to the peer. + mSocketFactory.setHostname(socket, TEST_HOST); + assertConnectedSocket(socket); + try { + SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier); + SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + socket.close(); + } + + /** + * Asserts a socket is fully connected to the expected peer. + * + *

    For the variants of createSocket which verify the remote hostname, + * {@code socket} should already be fully connected. + * + *

    For the non-verifying variants, retrieving the input stream will trigger a TLS handshake + * and so may throw an exception, for example if the peer's certificate is invalid. + * + *

    Does no hostname verification. + */ + private void assertConnectedSocket(Socket socket) throws Exception { assertNotNull(socket); - assertNotNull(socket.getOutputStream()); + assertTrue(socket.isConnected()); assertNotNull(socket.getInputStream()); - - // it throw exception when calling createSocket(String, int, InetAddress, int) - // The socket level is invalid. - } - - // a host and port that are expected to be available but have - // a cert with a different CN, in this case CN=mail.google.com - private static String TEST_CREATE_SOCKET_HOST = "www3.l.google.com"; - private static int TEST_CREATE_SOCKET_PORT = 443; - - /** - * b/2807618 Make sure that hostname verifcation in cases were it - * is documented to be included by various - * SSLCertificateSocketFactory.createSocket messages. - * - * NOTE: Test will fail if external server is not available. - */ - @AppModeFull(reason = "Socket cannot bind in instant app mode") - public void test_createSocket_simple() throws Exception { - try { - mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT); - fail(); - } catch (SSLPeerUnverifiedException expected) { - // expected - } + assertNotNull(socket.getOutputStream()); + assertTrue(mTestSocketAddresses.contains(socket.getRemoteSocketAddress())); } /** - * b/2807618 Make sure that hostname verifcation in cases were it - * is documented to be included by various - * SSLCertificateSocketFactory.createSocket messages. - * - * NOTE: Test will fail if external server is not available. + * A HostnameVerifier which always returns false to simulate a server returning a + * certificate which does not match the expected hostname. */ - @AppModeFull(reason = "Socket cannot bind in instant app mode") - public void test_createSocket_wrapping() throws Exception { - try { - Socket underlying = new Socket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT); - mFactory.createSocket( - underlying, TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT, true); - fail(); - } catch (SSLPeerUnverifiedException expected) { - // expected - } - } - - /** - * b/2807618 Make sure that hostname verifcation in cases were it - * is documented to be included by various - * SSLCertificateSocketFactory.createSocket messages. - * - * NOTE: Test will fail if external server is not available. - */ - @AppModeFull(reason = "Socket cannot bind in instant app mode") - public void test_createSocket_bind() throws Exception { - try { - mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT, null, 0); - fail(); - } catch (SSLPeerUnverifiedException expected) { - // expected + private static class NegativeHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(String hostname, SSLSession sslSession) { + return false; } } } From 14fae15d0a8e6a7fec551437be49fb0a18260d3c Mon Sep 17 00:00:00 2001 From: Julien Desprez Date: Mon, 24 Jun 2019 09:15:51 -0700 Subject: [PATCH 0661/1415] [Cherry pick] Mark module as "secondary_user" since it uncovered bug before This will allow running this module against a secondary user in continuous infra to uncover bugs. Test: run cts-unit-tests Bug: 130892086 Change-Id: I063a0d29163567ec2cf97d2e4469e88e7203e852 Merged-In: Ic8af2e3e77e24db340b2894c2d36e3501962952c --- tests/cts/hostside/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index c7cab7b0ba..dbff1794e9 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -18,6 +18,7 @@

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - - /** - * Resets the (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void tearDownMeteredNetwork() throws Exception { + setBatterySaverMode(false); } + @Test public void testBackgroundNetworkAccess_enabled() throws Exception { - if (!isSupported()) return; - setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -118,9 +80,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { - if (!isSupported()) return; - setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -140,9 +101,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_disabled() throws Exception { - if (!isSupported()) return; - assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index f20f1d1c4d..6f32c563c1 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -16,20 +16,25 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE; + import android.os.SystemClock; -import android.util.Log; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Base class for metered and non-metered Doze Mode tests. */ +@RequiredProperties({DOZE_MODE}) abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { - @Override - protected final void setUp() throws Exception { + @Before + public final void setUp() throws Exception { super.setUp(); - if (!isSupported()) return; - // Set initial state. removePowerSaveModeWhitelist(TEST_APP2_PKG); removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); @@ -38,48 +43,15 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor registerBroadcastReceiver(); } - @Override - protected final void tearDown() throws Exception { + @After + public final void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - - try { - tearDownMeteredNetwork(); - } finally { - setDozeMode(false); - } - } - - @Override - protected boolean isSupported() throws Exception { - boolean supported = isDozeModeEnabled(); - if (!supported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); - } - return supported; - } - - /** - * Sets the initial (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - - /** - * Resets the (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void tearDownMeteredNetwork() throws Exception { + setDozeMode(false); } + @Test public void testBackgroundNetworkAccess_enabled() throws Exception { - if (!isSupported()) return; - setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -96,9 +68,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { - if (!isSupported()) return; - setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -118,19 +89,18 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_disabled() throws Exception { - if (!isSupported()) return; - assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(true); } + @RequiredProperties({NOT_LOW_RAM_DEVICE}) + @Test public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() throws Exception { - if (!isSupported() || isLowRamDevice()) return; - setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); try { registerNotificationListenerService(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 40d7e34fcc..57b7bb4f8d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -17,14 +17,22 @@ package com.android.cts.net.hostside; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static android.os.BatteryManager.BATTERY_PLUGGED_AC; import static android.os.BatteryManager.BATTERY_PLUGGED_USB; import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; -import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.app.ActivityManager; import android.app.Instrumentation; @@ -34,9 +42,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; @@ -44,24 +50,27 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; -import android.os.SystemProperties; import android.provider.Settings; import android.service.notification.NotificationListenerService; -import android.test.InstrumentationTestCase; -import android.text.TextUtils; import android.util.Log; -import com.android.compatibility.common.util.BatteryUtils; +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.runner.RunWith; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + /** * Superclass for tests related to background network restrictions. */ -abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase { - protected static final String TAG = "RestrictBackgroundNetworkTests"; +@RunWith(AndroidJUnit4.class) +public abstract class AbstractRestrictBackgroundNetworkTestCase { + public static final String TAG = "RestrictBackgroundNetworkTests"; protected static final String TEST_PKG = "com.android.cts.net.hostside"; protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; @@ -98,8 +107,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static int PROCESS_STATE_FOREGROUND_SERVICE; - private static final int PROCESS_STATE_TOP = 2; - private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; protected static final int TYPE_COMPONENT_ACTIVTIY = 0; @@ -126,22 +133,23 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private int mMyUid; - private String mMeteredWifi; private MyServiceClient mServiceClient; private String mDeviceIdleConstantsSetting; - private boolean mSupported; private boolean mIsLocationOn; - @Override + @Rule + public final RuleChain mRuleChain = RuleChain.outerRule(new DumpOnFailureRule()) + .around(new RequiredPropertiesRule()) + .around(new MeterednessConfigurationRule()); + protected void setUp() throws Exception { - super.setUp(); PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null); mInstrumentation = getInstrumentation(); - mContext = mInstrumentation.getContext(); - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mContext = getContext(); + mCm = getConnectivityManager(); + mWfm = getWifiManager(); mUid = getUid(TEST_APP2_PKG); mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); @@ -151,10 +159,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (!mIsLocationOn) { enableLocation(); } - mSupported = setUpActiveNetworkMeteringState(); setAppIdle(false); - Log.i(TAG, "Apps status on " + getName() + ":\n" + Log.i(TAG, "Apps status:\n" + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -165,16 +172,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final String currentConstants = executeShellCommand("settings get global app_idle_constants"); assertEquals(appIdleConstants, currentConstants); - } + } - @Override protected void tearDown() throws Exception { if (!mIsLocationOn) { disableLocation(); } mServiceClient.unbind(); - - super.tearDown(); } private void enableLocation() throws Exception { @@ -259,23 +263,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { final String status = mServiceClient.getRestrictBackgroundStatus(); assertNotNull("didn't get API status from app2", status); - final String actualStatus = toString(Integer.parseInt(status)); - assertEquals("wrong status", toString(expectedStatus), actualStatus); - } - - protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { - final int actualStatus = mCm.getRestrictBackgroundStatus(); - assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); - } - - protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { - final int actualStatus = mCm.getRestrictBackgroundStatus(); - if (expectedStatus != actualStatus) { - Log.d(TAG, "Expected: " + toString(expectedStatus) - + " but actual: " + toString(actualStatus)); - return false; - } - return true; + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(Integer.parseInt(status))); } protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { @@ -297,28 +286,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */); } - /** - * Whether this device suport this type of test. - * - *

    Should be overridden when necessary (but always calling - * {@code super.isSupported()} first), and explicitly used before each test - * Example: - * - *

    
    -     * public void testSomething() {
    -     *    if (!isSupported()) return;
    -     * 
    - * - * @return {@code true} by default. - */ - protected boolean isSupported() throws Exception { - return mSupported; - } - - protected boolean isBatterySaverSupported() { - return BatteryUtils.isBatterySaverSupported(); - } - /** * Asserts that an app always have access while on foreground or running a foreground service. * @@ -387,23 +354,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state ); } - /** - * As per CDD requirements, if the device doesn't support data saver mode then - * ConnectivityManager.getRestrictBackgroundStatus() will always return - * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if - * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns - * RESTRICT_BACKGROUND_STATUS_DISABLED or not. - */ - protected boolean isDataSaverSupported() throws Exception { - assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - try { - setRestrictBackground(true); - return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - } finally { - setRestrictBackground(false); - } - } - /** * Returns whether an app state should be considered "background" for restriction purposes. */ @@ -443,40 +393,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // Exponential back-off. timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS); } - dumpOnFailure(); fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries + " attempts.\nLast error: " + error); } - private void dumpOnFailure() throws Exception { - dumpAllNetworkRules(); - Log.d(TAG, "Usagestats dump: " + getUsageStatsDump()); - executeShellCommand("settings get global app_idle_constants"); - } - - private void dumpAllNetworkRules() throws Exception { - final String networkManagementDump = runShellCommand(mInstrumentation, - "dumpsys network_management").trim(); - final String networkPolicyDump = runShellCommand(mInstrumentation, - "dumpsys netpolicy").trim(); - TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); - splitter.setString(networkManagementDump); - String next; - Log.d(TAG, ">>> Begin network_management dump"); - while (splitter.hasNext()) { - next = splitter.next(); - Log.d(TAG, next); - } - Log.d(TAG, "<<< End network_management dump"); - splitter.setString(networkPolicyDump); - Log.d(TAG, ">>> Begin netpolicy dump"); - while (splitter.hasNext()) { - next = splitter.next(); - Log.d(TAG, next); - } - Log.d(TAG, "<<< End netpolicy dump"); - } - /** * Checks whether the network is available as expected. * @@ -528,22 +448,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return errors.toString(); } - protected boolean isLowRamDevice() { - final ActivityManager am = (ActivityManager) mContext.getSystemService( - Context.ACTIVITY_SERVICE); - return am.isLowRamDevice(); - } - - protected String executeShellCommand(String command) throws Exception { - final String result = runShellCommand(mInstrumentation, command).trim(); - if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'"); - return result; - } - /** * Runs a Shell command which is not expected to generate output. */ - protected void executeSilentShellCommand(String command) throws Exception { + protected void executeSilentShellCommand(String command) { final String result = executeShellCommand(command); assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty()); } @@ -572,10 +480,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation }); } - protected void assertDelayedShellCommand(String command, ExpectResultChecker checker) - throws Exception { - assertDelayedShellCommand(command, 5, 1, checker); - } protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, ExpectResultChecker checker) throws Exception { String result = ""; @@ -592,159 +496,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation + " attempts. Last result: '" + result + "'"); } - /** - * Sets the initial metering state for the active network. - * - *

    It's called on setup and by default does nothing - it's up to the - * subclasses to override. - * - * @return whether the tests in the subclass are supported on this device. - */ - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return true; - } - - /** - * Makes sure the active network is not metered. - * - *

    If the device does not supoprt un-metered networks (for example if it - * only has cellular data but not wi-fi), it should return {@code false}; - * otherwise, it should return {@code true} (or fail if the un-metered - * network could not be set). - * - * @return {@code true} if the network is now unmetered. - */ - protected boolean setUnmeteredNetwork() throws Exception { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - assertNotNull("Could not get active network", info); - if (!mCm.isActiveNetworkMetered()) { - Log.d(TAG, "Active network is not metered: " + info); - } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { - Log.i(TAG, "Setting active WI-FI network as not metered: " + info ); - setWifiMeteredStatus(false); - } else { - Log.d(TAG, "Active network cannot be set to un-metered: " + info); - return false; - } - assertActiveNetworkMetered(false); // Sanity check. - return true; - } - - /** - * Enables metering on the active network if supported. - * - *

    If the device does not support metered networks it should return - * {@code false}; otherwise, it should return {@code true} (or fail if the - * metered network could not be set). - * - * @return {@code true} if the network is now metered. - */ - protected boolean setMeteredNetwork() throws Exception { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - final boolean metered = mCm.isActiveNetworkMetered(); - if (metered) { - Log.d(TAG, "Active network already metered: " + info); - return true; - } else if (info.getType() != ConnectivityManager.TYPE_WIFI) { - Log.w(TAG, "Active network does not support metering: " + info); - return false; - } else { - Log.w(TAG, "Active network not metered: " + info); - } - final String netId = setWifiMeteredStatus(true); - - // Set flag so status is reverted on resetMeteredNetwork(); - mMeteredWifi = netId; - // Sanity check. - assertWifiMeteredStatus(netId, true); - assertActiveNetworkMetered(true); - return true; - } - - /** - * Resets the device metering state to what it was before the test started. - * - *

    This reverts any metering changes made by {@code setMeteredNetwork}. - */ - protected void resetMeteredNetwork() throws Exception { - if (mMeteredWifi != null) { - Log.i(TAG, "resetMeteredNetwork(): SID '" + mMeteredWifi - + "' was set as metered by test case; resetting it"); - setWifiMeteredStatus(mMeteredWifi, false); - assertActiveNetworkMetered(false); // Sanity check. - } - } - - private void assertActiveNetworkMetered(boolean expected) throws Exception { - final int maxTries = 5; - NetworkInfo info = null; - for (int i = 1; i <= maxTries; i++) { - info = mCm.getActiveNetworkInfo(); - if (info == null) { - Log.v(TAG, "No active network info on attempt #" + i - + "; sleeping 1s before polling again"); - } else if (mCm.isActiveNetworkMetered() != expected) { - Log.v(TAG, "Wrong metered status for active network " + info + "; expected=" - + expected + "; sleeping 1s before polling again"); - } else { - break; - } - Thread.sleep(SECOND_IN_MS); - } - assertNotNull("No active network after " + maxTries + " attempts", info); - assertEquals("Wrong metered status for active network " + info, expected, - mCm.isActiveNetworkMetered()); - } - - private String setWifiMeteredStatus(boolean metered) throws Exception { - // We could call setWifiEnabled() here, but it might take sometime to be in a consistent - // state (for example, if one of the saved network is not properly authenticated), so it's - // better to let the hostside test take care of that. - assertTrue("wi-fi is disabled", mWfm.isWifiEnabled()); - // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests - // to make the actual verification of restrictions optional. - final String ssid = mWfm.getConnectionInfo().getSSID(); - return setWifiMeteredStatus(ssid, metered); - } - - private String setWifiMeteredStatus(String ssid, boolean metered) throws Exception { - assertNotNull("null SSID", ssid); - final String netId = ssid.trim().replaceAll("\"", ""); // remove quotes, if any. - assertFalse("empty SSID", ssid.isEmpty()); - - Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); - final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered; - assertDelayedShellCommand(setCommand, ""); - - return netId; - } - - private void assertWifiMeteredStatus(String netId, boolean status) throws Exception { - final String command = "cmd netpolicy list wifi-networks"; - final String expectedLine = netId + ";" + status; - assertDelayedShellCommand(command, new ExpectResultChecker() { - - @Override - public boolean isExpected(String result) { - return result.contains(expectedLine); - } - - @Override - public String getExpected() { - return "line containing " + expectedLine; - } - }); - } - - protected void setRestrictBackground(boolean enabled) throws Exception { - executeShellCommand("cmd netpolicy set restrict-background " + enabled); - final String output = executeShellCommand("cmd netpolicy get restrict-background "); - final String expectedSuffix = enabled ? "enabled" : "disabled"; - // TODO: use MoreAsserts? - assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", - output.endsWith(expectedSuffix)); - } - protected void addRestrictBackgroundWhitelist(int uid) throws Exception { executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); @@ -924,7 +675,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void setDozeMode(boolean enabled) throws Exception { // Sanity check, since tests should check beforehand.... - assertTrue("Device does not support Doze Mode", isDozeModeEnabled()); + assertTrue("Device does not support Doze Mode", isDozeModeSupported()); Log.i(TAG, "Setting Doze Mode to " + enabled); if (enabled) { @@ -944,43 +695,16 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE"); } - protected boolean isDozeModeEnabled() throws Exception { - final String result = executeShellCommand("cmd deviceidle enabled deep").trim(); - return result.equals("1"); - } - protected void setAppIdle(boolean enabled) throws Exception { Log.i(TAG, "Setting app idle to " + enabled); executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); assertAppIdle(enabled); // Sanity check } - private String getUsageStatsDump() throws Exception { - final String output = runShellCommand(mInstrumentation, "dumpsys usagestats").trim(); - final StringBuilder sb = new StringBuilder(); - final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); - splitter.setString(output); - String str; - while (splitter.hasNext()) { - str = splitter.next(); - if (str.contains("package=") - && !str.contains(TEST_PKG) && !str.contains(TEST_APP2_PKG)) { - continue; - } - if (str.trim().startsWith("config=") || str.trim().startsWith("time=")) { - continue; - } - sb.append(str).append('\n'); - } - return sb.toString(); - } - protected void assertAppIdle(boolean enabled) throws Exception { try { assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled); } catch (Throwable e) { - Log.d(TAG, "UsageStats dump:\n" + getUsageStatsDump()); - executeShellCommand("settings get global app_idle_constants"); throw e; } } @@ -1061,12 +785,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // App didn't come to foreground when the activity is started, so try again. assertForegroundNetworkAccess(); } else { - dumpOnFailure(); fail("Network is not available for app2 (" + mUid + "): " + errors[0]); } } } else { - dumpOnFailure(); fail("Timed out waiting for network availability status from app2 (" + mUid + ")"); } } else { @@ -1150,19 +872,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } } - private String toString(int status) { - switch (status) { - case RESTRICT_BACKGROUND_STATUS_DISABLED: - return "DISABLED"; - case RESTRICT_BACKGROUND_STATUS_WHITELISTED: - return "WHITELISTED"; - case RESTRICT_BACKGROUND_STATUS_ENABLED: - return "ENABLED"; - default: - return "UNKNOWN_STATUS_" + status; - } - } - private ProcessState getProcessStateByUid(int uid) throws Exception { return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid)); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java index 622d99361f..f1858d65a5 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class AppIdleMeteredTest extends AbstractAppIdleTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java index bde71f9100..e737a6dabe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java @@ -16,9 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase { - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java index 3071cfe3f1..c78ca2ec77 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index 6d3076fe0e..fb52a540d8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -16,10 +16,9 @@ package com.android.cts.net.hostside; -public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) +public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index cfe6a73a0f..aa2c914e02 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,24 +20,33 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -import android.util.Log; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE; + +import static org.junit.Assert.fail; import com.android.compatibility.common.util.CddTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import androidx.test.filters.LargeTest; + +@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK}) +@LargeTest public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { "com.android.providers.downloads" }; - private boolean mIsDataSaverSupported; - - @Override + @Before public void setUp() throws Exception { super.setUp(); - mIsDataSaverSupported = isDataSaverSupported(); - // Set initial state. setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); @@ -47,36 +56,15 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(0); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - - try { - resetMeteredNetwork(); - } finally { - setRestrictBackground(false); - } - } - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected boolean isSupported() throws Exception { - if (!mIsDataSaverSupported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Data Saver Mode"); - } - return mIsDataSaverSupported && super.isSupported(); + setRestrictBackground(false); } + @Test public void testGetRestrictBackgroundStatus_disabled() throws Exception { - if (!isSupported()) return; - assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted @@ -88,9 +76,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); } + @Test public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { - if (!isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -107,9 +94,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); } + @Test public void testGetRestrictBackgroundStatus_enabled() throws Exception { - if (!isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -142,9 +128,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertBackgroundNetworkAccess(false); } + @Test public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { - if (!isSupported()) return; - addRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -180,9 +165,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); } + @Test public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { - if (!isSupported()) return; - final StringBuilder error = new StringBuilder(); for (String packageName : REQUIRED_WHITELISTED_PACKAGES) { int uid = -1; @@ -202,10 +186,10 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } } + @RequiredProperties({NO_DATA_SAVER_MODE}) @CddTest(requirement="7.4.7/C-2-2") + @Test public void testBroadcastNotSentOnUnsupportedDevices() throws Exception { - if (isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(0); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java index e4189af587..4306c991c2 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class DozeModeMeteredTest extends AbstractDozeModeTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java index edbbb9e1ce..1e89f158a3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java @@ -16,10 +16,8 @@ package com.android.cts.net.hostside; -public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } +@RequiredProperties({NON_METERED_NETWORK}) +public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java new file mode 100644 index 0000000000..cedd62a0bc --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG; + +import android.os.Environment; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import com.android.compatibility.common.util.OnFailureRule; + +import org.junit.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class DumpOnFailureRule extends OnFailureRule { + private File mDumpDir = new File(Environment.getExternalStorageDirectory(), + "CtsHostsideNetworkTests"); + + @Override + public void onTestFailure(Statement base, Description description, Throwable throwable) { + final String testName = description.getClassName() + "_" + description.getMethodName(); + + if (throwable instanceof AssumptionViolatedException) { + Log.d(TAG, "Skipping test " + testName + ": " + throwable); + return; + } + + prepareDumpRootDir(); + final File dumpFile = new File(mDumpDir, "dump-" + testName); + Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath()); + try (FileOutputStream out = new FileOutputStream(dumpFile)) { + for (String cmd : new String[] { + "dumpsys netpolicy", + "dumpsys network_management", + "dumpsys usagestats " + TEST_PKG, + "dumpsys usagestats appstandby", + }) { + dumpCommandOutput(out, cmd); + } + } catch (FileNotFoundException e) { + Log.e(TAG, "Error opening file: " + dumpFile, e); + } catch (IOException e) { + Log.e(TAG, "Error closing file: " + dumpFile, e); + } + } + + void dumpCommandOutput(FileOutputStream out, String cmd) { + final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation() + .getUiAutomation().executeShellCommand(cmd); + try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8)); + FileUtils.copy(in, out); + out.write("\n\n=================================================================\n\n" + .getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + Log.e(TAG, "Error dumping '" + cmd + "'", e); + } + } + + void prepareDumpRootDir() { + if (!mDumpDir.exists() && !mDumpDir.mkdir()) { + Log.e(TAG, "Error creating " + mDumpDir); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java new file mode 100644 index 0000000000..8fadf9e295 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.resetMeteredNetwork; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupMeteredNetwork; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +import android.util.ArraySet; +import android.util.Pair; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class MeterednessConfigurationRule extends BeforeAfterRule { + private Pair mSsidAndInitialMeteredness; + + @Override + public void onBefore(Statement base, Description description) throws Throwable { + final ArraySet requiredProperties + = RequiredPropertiesRule.getRequiredProperties(); + if (requiredProperties.contains(METERED_NETWORK)) { + configureNetworkMeteredness(true); + } else if (requiredProperties.contains(NON_METERED_NETWORK)) { + configureNetworkMeteredness(false); + } + } + + @Override + public void onAfter(Statement base, Description description) throws Throwable { + resetNetworkMeteredness(); + } + + public void configureNetworkMeteredness(boolean metered) throws Exception { + mSsidAndInitialMeteredness = setupMeteredNetwork(metered); + } + + public void resetNetworkMeteredness() throws Exception { + if (mSsidAndInitialMeteredness != null) { + resetMeteredNetwork(mSsidAndInitialMeteredness.first, + mSsidAndInitialMeteredness.second); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index b1a21867b3..c9edda6e0b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -15,9 +15,21 @@ */ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + import android.os.SystemClock; import android.util.Log; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + /** * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode * and Data Saver Mode) are applied simultaneously. @@ -29,12 +41,10 @@ import android.util.Log; public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String TAG = "MixedModesTest"; - @Override + @Before public void setUp() throws Exception { super.setUp(); - if (!isSupported()) return; - // Set initial state. removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); @@ -44,12 +54,10 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { registerBroadcastReceiver(); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - try { setRestrictBackground(false); } finally { @@ -57,34 +65,15 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } - @Override - public boolean isSupported() throws Exception { - if (!isDozeModeEnabled()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); - return false; - } - return true; - } - /** * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, METERED_NETWORK}) + @Test public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) return; - - Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); - if (!setMeteredNetwork()) { - Log.w(TAG, "testDataAndBatterySaverModes_meteredNetwork() skipped because " - + "device cannot use a metered network"); - return; - } - + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); try { setRestrictBackground(true); setBatterySaverMode(true); @@ -137,7 +126,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { removeRestrictBackgroundBlacklist(mUid); removePowerSaveModeWhitelist(TEST_APP2_PKG); } finally { - resetMeteredNetwork(); + meterednessConfiguration.resetNetworkMeteredness(); } } @@ -145,86 +134,75 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered * networks. */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, NON_METERED_NETWORK}) + @Test public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + setRestrictBackground(true); + setBatterySaverMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); } - if (!isSupported()) return; - - if (!setUnmeteredNetwork()) { - Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network" - + " is metered"); - return; - } - Log.i(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() tests"); - setRestrictBackground(true); - setBatterySaverMode(true); - - Log.v(TAG, "Not whitelisted for any."); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - - Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); - addRestrictBackgroundWhitelist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - - Log.v(TAG, "Whitelisted for both."); - addRestrictBackgroundWhitelist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundBlacklist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removeRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); } /** * Tests that powersave whitelists works as expected when doze and battery saver modes * are enabled. */ + @RequiredProperties({DOZE_MODE, BATTERY_SAVER_MODE}) + @Test public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setDozeMode(true); @@ -250,11 +228,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests that powersave whitelists works as expected when doze and appIdle modes * are enabled. */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -276,11 +252,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -299,16 +273,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setAppIdle(true); @@ -330,11 +297,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { /** * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled. */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -353,11 +318,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -380,16 +343,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setAppIdle(true); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index 24dde9d356..ed397b91fc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -16,15 +16,26 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import android.net.Network; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.Objects; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase { - private boolean mIsDataSaverSupported; private Network mNetwork; private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback(); @@ -132,108 +143,122 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } } - @Override + @Before public void setUp() throws Exception { super.setUp(); - mIsDataSaverSupported = isDataSaverSupported(); - mNetwork = mCm.getActiveNetwork(); - // Set initial state. - setBatterySaverMode(false); registerBroadcastReceiver(); - if (!mIsDataSaverSupported) return; - setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(0); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!mIsDataSaverSupported) return; + setRestrictBackground(false); + setBatterySaverMode(false); + } + @RequiredProperties({DATA_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_dataSaver() throws Exception { + // Initial state + setBatterySaverMode(false); + setRestrictBackground(false); + + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); try { - resetMeteredNetwork(); + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable restrict background + setRestrictBackground(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Add to whitelist + addRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Remove from whitelist + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } + + // Set to non-metered network + meterednessConfiguration.configureNetworkMeteredness(false); + try { + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Disable restrict background, should not trigger callback setRestrictBackground(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.assertNoCallback(); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); } } - public void testOnBlockedStatusChanged_data_saver() throws Exception { - if (!mIsDataSaverSupported) return; - - // Prepare metered wifi - if (!setMeteredNetwork()) return; - - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable restrict background - setRestrictBackground(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Add to whitelist - addRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Remove from whitelist - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Set to non-metered network - setUnmeteredNetwork(); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Disable restrict background, should not trigger callback + @RequiredProperties({BATTERY_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_powerSaver() throws Exception { + // Set initial state. + setBatterySaverMode(false); setRestrictBackground(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.assertNoCallback(); - } + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); + try { + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - public void testOnBlockedStatusChanged_power_saver() throws Exception { - // Prepare metered wifi - if (!setMeteredNetwork()) return; + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } // Set to non-metered network - setUnmeteredNetwork(); - mTestNetworkCallback.assertNoCallback(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + mTestNetworkCallback.assertNoCallback(); - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } } // TODO: 1. test against VPN lockdown. diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java new file mode 100644 index 0000000000..ca2864c0b8 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.ActivityManager; +import android.app.Instrumentation; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.wifi.WifiManager; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; + +import com.android.compatibility.common.util.AppStandbyUtils; +import com.android.compatibility.common.util.BatteryUtils; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class NetworkPolicyTestUtils { + + private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 5000; + + private static ConnectivityManager mCm; + private static WifiManager mWm; + + private static Boolean mBatterySaverSupported; + private static Boolean mDataSaverSupported; + private static Boolean mDozeModeSupported; + private static Boolean mAppStandbySupported; + + private NetworkPolicyTestUtils() {} + + public static boolean isBatterySaverSupported() { + if (mBatterySaverSupported == null) { + mBatterySaverSupported = BatteryUtils.isBatterySaverSupported(); + } + return mBatterySaverSupported; + } + + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + public static boolean isDataSaverSupported() { + if (mDataSaverSupported == null) { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + mDataSaverSupported = !isMyRestrictBackgroundStatus( + RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + return mDataSaverSupported; + } + + public static boolean isDozeModeSupported() { + if (mDozeModeSupported == null) { + final String result = executeShellCommand("cmd deviceidle enabled deep"); + mDozeModeSupported = result.equals("1"); + } + return mDozeModeSupported; + } + + public static boolean isAppStandbySupported() { + if (mAppStandbySupported == null) { + mAppStandbySupported = AppStandbyUtils.isAppStandbyEnabled(); + } + return mAppStandbySupported; + } + + public static boolean isLowRamDevice() { + final ActivityManager am = (ActivityManager) getContext().getSystemService( + Context.ACTIVITY_SERVICE); + return am.isLowRamDevice(); + } + + public static boolean isActiveNetworkMetered(boolean metered) { + return getConnectivityManager().isActiveNetworkMetered() == metered; + } + + public static boolean canChangeActiveNetworkMeteredness() { + final Network activeNetwork = getConnectivityManager().getActiveNetwork(); + final NetworkCapabilities networkCapabilities + = getConnectivityManager().getNetworkCapabilities(activeNetwork); + return networkCapabilities.hasTransport(TRANSPORT_WIFI); + } + + public static Pair setupMeteredNetwork(boolean metered) throws Exception { + if (isActiveNetworkMetered(metered)) { + return null; + } + final String ssid = unquoteSSID(getWifiManager().getConnectionInfo().getSSID()); + setWifiMeteredStatus(ssid, metered); + return Pair.create(ssid, !metered); + } + + public static void resetMeteredNetwork(String ssid, boolean metered) throws Exception { + setWifiMeteredStatus(ssid, metered); + } + + public static void setWifiMeteredStatus(String ssid, boolean metered) throws Exception { + assertFalse("SSID should not be empty", TextUtils.isEmpty(ssid)); + final String cmd = "cmd netpolicy set metered-network " + ssid + " " + metered; + executeShellCommand(cmd); + assertWifiMeteredStatus(ssid, metered); + assertActiveNetworkMetered(metered); + } + + public static void assertWifiMeteredStatus(String ssid, boolean expectedMeteredStatus) { + final String result = executeShellCommand("cmd netpolicy list wifi-networks"); + final String expectedLine = ssid + ";" + expectedMeteredStatus; + assertTrue("Expected line: " + expectedLine + "; Actual result: " + result, + result.contains(expectedLine)); + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + public static void assertActiveNetworkMetered(boolean expectedMeteredStatus) throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final NetworkCallback networkCallback = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); + if (metered == expectedMeteredStatus) { + latch.countDown(); + } + } + }; + // Registering a callback here guarantees onCapabilitiesChanged is called immediately + // with the current setting. Therefore, if the setting has already been changed, + // this method will return right away, and if not it will wait for the setting to change. + getConnectivityManager().registerDefaultNetworkCallback(networkCallback); + if (!latch.await(TIMEOUT_CHANGE_METEREDNESS_MS, TimeUnit.MILLISECONDS)) { + fail("Timed out waiting for active network metered status to change to " + + expectedMeteredStatus + " ; network = " + + getConnectivityManager().getActiveNetwork()); + } + getConnectivityManager().unregisterNetworkCallback(networkCallback); + } + + public static void setRestrictBackground(boolean enabled) { + executeShellCommand("cmd netpolicy set restrict-background " + enabled); + final String output = executeShellCommand("cmd netpolicy get restrict-background"); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + + public static boolean isMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "MyRestrictBackgroundStatus: " + + "Expected: " + restrictBackgroundValueToString(expectedStatus) + + "; Actual: " + restrictBackgroundValueToString(actualStatus)); + return false; + } + return true; + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + private static String unquoteSSID(String ssid) { + // SSID is returned surrounded by quotes if it can be decoded as UTF-8. + // Otherwise it's guaranteed not to start with a quote. + if (ssid.charAt(0) == '"') { + return ssid.substring(1, ssid.length() - 1); + } else { + return ssid; + } + } + + public static String restrictBackgroundValueToString(int status) { + switch (status) { + case RESTRICT_BACKGROUND_STATUS_DISABLED: + return "DISABLED"; + case RESTRICT_BACKGROUND_STATUS_WHITELISTED: + return "WHITELISTED"; + case RESTRICT_BACKGROUND_STATUS_ENABLED: + return "ENABLED"; + default: + return "UNKNOWN_STATUS_" + status; + } + } + + public static String executeShellCommand(String command) { + final String result = runShellCommand(command).trim(); + Log.d(TAG, "Output of '" + command + "': '" + result + "'"); + return result; + } + + public static void assertMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(actualStatus)); + } + + public static ConnectivityManager getConnectivityManager() { + if (mCm == null) { + mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + } + return mCm; + } + + public static WifiManager getWifiManager() { + if (mWm == null) { + mWm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + } + return mWm; + } + + public static Context getContext() { + return getInstrumentation().getContext(); + } + + public static Instrumentation getInstrumentation() { + return InstrumentationRegistry.getInstrumentation(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java new file mode 100644 index 0000000000..18805f9613 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDataSaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isLowRamDevice; + +public enum Property { + BATTERY_SAVER_MODE(1 << 0) { + public boolean isSupported() { return isBatterySaverSupported(); } + }, + + DATA_SAVER_MODE(1 << 1) { + public boolean isSupported() { return isDataSaverSupported(); } + }, + + NO_DATA_SAVER_MODE(~DATA_SAVER_MODE.getValue()) { + public boolean isSupported() { return !isDataSaverSupported(); } + }, + + DOZE_MODE(1 << 2) { + public boolean isSupported() { return isDozeModeSupported(); } + }, + + APP_STANDBY_MODE(1 << 3) { + public boolean isSupported() { return isAppStandbySupported(); } + }, + + NOT_LOW_RAM_DEVICE(1 << 4) { + public boolean isSupported() { return !isLowRamDevice(); } + }, + + METERED_NETWORK(1 << 5) { + public boolean isSupported() { + return isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness(); + } + }, + + NON_METERED_NETWORK(~METERED_NETWORK.getValue()) { + public boolean isSupported() { + return isActiveNetworkMetered(false) || canChangeActiveNetworkMeteredness(); + } + }; + + private int mValue; + + Property(int value) { mValue = value; } + + public int getValue() { return mValue; } + + abstract boolean isSupported(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java new file mode 100644 index 0000000000..96838bba0a --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({METHOD, TYPE}) +@Inherited +public @interface RequiredProperties { + Property[] value(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java new file mode 100644 index 0000000000..1e333200db --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.Log; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.Assume; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.util.ArrayList; +import java.util.Collections; + +public class RequiredPropertiesRule extends BeforeAfterRule { + + private static ArraySet mRequiredProperties; + + @Override + public void onBefore(Statement base, Description description) { + mRequiredProperties = getAllRequiredProperties(description); + + final String testName = description.getClassName() + "#" + description.getMethodName(); + assertTestIsValid(testName, mRequiredProperties); + Log.i(TAG, "Running test " + testName + " with required properties: " + + propertiesToString(mRequiredProperties)); + } + + private ArraySet getAllRequiredProperties(Description description) { + final ArraySet allRequiredProperties = new ArraySet<>(); + RequiredProperties requiredProperties = description.getAnnotation(RequiredProperties.class); + if (requiredProperties != null) { + Collections.addAll(allRequiredProperties, requiredProperties.value()); + } + + for (Class clazz = description.getTestClass(); + clazz != null; clazz = clazz.getSuperclass()) { + requiredProperties = clazz.getDeclaredAnnotation(RequiredProperties.class); + if (requiredProperties == null) { + continue; + } + for (Property requiredProperty : requiredProperties.value()) { + if (!allRequiredProperties.contains(~requiredProperty.getValue())) { + allRequiredProperties.add(requiredProperty); + } + } + } + return allRequiredProperties; + } + + private void assertTestIsValid(String testName, ArraySet requiredProperies) { + if (requiredProperies == null) { + return; + } + final ArrayList unsupportedProperties = new ArrayList<>(); + for (Property property : requiredProperies) { + if (!property.isSupported()) { + unsupportedProperties.add(property); + } + } + Assume.assumeTrue("Unsupported properties: " + + propertiesToString(unsupportedProperties), unsupportedProperties.isEmpty()); + } + + public static ArraySet getRequiredProperties() { + return mRequiredProperties; + } + + private static String propertiesToString(Iterable properties) { + return "[" + TextUtils.join(",", properties) + "]"; + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java index 8d6c4acd7d..1312085478 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java @@ -29,14 +29,14 @@ public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase { uninstallPackage(TEST_APP2_PKG, true); } - public void testOnBlockedStatusChanged_data_saver() throws Exception { + public void testOnBlockedStatusChanged_dataSaver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_data_saver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_dataSaver"); } - public void testOnBlockedStatusChanged_power_saver() throws Exception { + public void testOnBlockedStatusChanged_powerSaver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_power_saver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_powerSaver"); } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index a2443b391a..ce203795f9 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -79,7 +79,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void installPackage(String apk) throws FileNotFoundException, DeviceNotAvailableException { CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); - assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false)); + assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), + false /* reinstall */, true /* grantPermissions */)); } protected void uninstallPackage(String packageName, boolean shouldSucceed) From 6ee1049428b80f8813d31f5453200f379691d58d Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Fri, 16 Aug 2019 19:51:54 -0700 Subject: [PATCH 0675/1415] Attempt "fix" the broken QUIC packet to be slightly less broken Bug: 139403355 Merged-In: I372c0730c9bd5329761b5a74b38e0f743bfd8230 (cherry picked from commit d6af2b5225249b178ee69dc5bac9b40c46f08d76) Change-Id: I2955a3f9e733a5e39813a26e4cd630f79ae144a0 --- tests/cts/net/jni/NativeMultinetworkJni.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index a6b5e90b1d..5bd3013819 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -455,13 +455,17 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol-01#section-6.1 - uint8_t quic_packet[] = { - 0x0c, // public flags: 64bit conn ID, 8bit sequence number + // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + uint8_t quic_packet[1200] = { + 0x0d, // public flags: + // - version present (0x01), + // - 64bit connection ID (0x0c), + // - 1 byte packet number (0x00) 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0x01, // sequence number + 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number + 1, // 1 byte packet number 0x00, // private flags - 0x07, // type: regular frame type "PING" + 0x07, // PING frame (cuz why not) }; arc4random_buf(quic_packet + 1, 8); // random connection ID @@ -489,7 +493,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < sent) { + if (rcvd < 9) { ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { ALOGD("Does this network block UDP port %s?", kPort); @@ -505,8 +509,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - // TODO: log, and compare to the IP address encoded in the - // response, since this should be a public reset packet. + // TODO: Replace this quick 'n' dirty test with proper QUIC-capable code. close(fd); return 0; From 2bf54f7c79110e2c063b9eb454749bf5d1ffdce3 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 20 Aug 2019 19:09:35 +0900 Subject: [PATCH 0676/1415] Attempt "fix" the broken QUIC packet to be slightly less broken Bug: 139403355 Signed-off-by: Erik Kline Merged-In: I9c938998b5e30f7d3994b410878b2af6a75f9b5a Test: in I9c938998b5e30f7d3994b410878b2af6a75f9b5a (cherry picked from commit 8ce68f1310fbd968b922d3faa5e64df702458178) Change-Id: If544089eb79801cad7660f3f419fa304387fc402 --- tests/cts/net/jni/NativeMultinetworkJni.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index ad56b510c3..4531f822eb 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -177,13 +177,17 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol-01#section-6.1 - uint8_t quic_packet[] = { - 0x0c, // public flags: 64bit conn ID, 8bit sequence number + // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + uint8_t quic_packet[1200] = { + 0x0d, // public flags: + // - version present (0x01), + // - 64bit connection ID (0x0c), + // - 1 byte packet number (0x00) 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0x01, // sequence number + 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number + 1, // 1 byte packet number 0x00, // private flags - 0x07, // type: regular frame type "PING" + 0x07, // PING frame (cuz why not) }; arc4random_buf(quic_packet + 1, 8); // random connection ID @@ -211,7 +215,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < sent) { + if (rcvd < 9) { ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { ALOGD("Does this network block UDP port %s?", kPort); @@ -227,8 +231,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - // TODO: log, and compare to the IP address encoded in the - // response, since this should be a public reset packet. + // TODO: Replace this quick 'n' dirty test with proper QUIC-capable code. close(fd); return 0; From d6f08f48e04caf9292dfbddce0ed3edd171df01a Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 6 Aug 2019 13:02:28 +0900 Subject: [PATCH 0677/1415] Add test for WifiInfo#getFrequency() Add getFrequency() to WifiInfoTest (along with other missing getters), and test that it is consistent with ScanResult in ScanResultTest. Test: atest android.net.wifi.cts.ScanResultTest Fixes: b/138929469 Merged-In: I070b16661bc72a5c5035b0b227821b680d7d71ba Merged-In: Ie99011acbbe66e9088f73964fd0c39d640594011 (cherry picked from commit 9c97c58656a168568e2a7dd784bb9919ac4997c5) Change-Id: I83416c24c20c6774b2a66bf822419616f8cc5ab2 --- .../android/net/wifi/cts/ScanResultTest.java | 30 +++++++++++++++++++ .../android/net/wifi/cts/WifiInfoTest.java | 3 ++ 2 files changed, 33 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java index ccf5fe2241..9bd1226f52 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.platform.test.annotations.AppModeFull; @@ -54,6 +55,8 @@ public class ScanResultTest extends AndroidTestCase { private static final int ENABLE_WAIT_MSEC = 10000; private static final int SCAN_WAIT_MSEC = 10000; private static final int SCAN_MAX_RETRY_COUNT = 6; + private static final int SCAN_FIND_BSSID_MAX_RETRY_COUNT = 5; + private static final long SCAN_FIND_BSSID_WAIT_MSEC = 5_000L; private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -200,4 +203,31 @@ public class ScanResultTest extends AndroidTestCase { } + public void testScanResultMatchesWifiInfo() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + // This test case should run while connected to Wifi + final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + assertNotNull(wifiInfo); + + ScanResult currentNetwork = null; + for (int i = 0; i < SCAN_FIND_BSSID_MAX_RETRY_COUNT; i++) { + scanAndWait(); + final List scanResults = mWifiManager.getScanResults(); + currentNetwork = scanResults.stream().filter(r -> r.BSSID.equals(wifiInfo.getBSSID())) + .findAny().orElse(null); + + if (currentNetwork != null) { + break; + } + Thread.sleep(SCAN_FIND_BSSID_WAIT_MSEC); + } + assertNotNull("Current network not found in scan results", currentNetwork); + + assertEquals(wifiInfo.getWifiSsid(), currentNetwork.wifiSsid); + assertEquals(wifiInfo.getFrequency(), currentNetwork.frequency); + } } diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 5367722b36..9d9b2a3902 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -139,8 +139,11 @@ public class WifiInfoTest extends AndroidTestCase { } wifiInfo.getBSSID(); + wifiInfo.getFrequency(); wifiInfo.getIpAddress(); wifiInfo.getLinkSpeed(); + wifiInfo.getPasspointFqdn(); + wifiInfo.getPasspointProviderFriendlyName(); wifiInfo.getTxLinkSpeedMbps(); wifiInfo.getRxLinkSpeedMbps(); wifiInfo.getRssi(); From 22d49c06442c65759a8d9fc3409f40b14b0c293b Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 6 Sep 2019 10:33:42 -0700 Subject: [PATCH 0678/1415] Prepare for Android 10 Test Suite R2. --- tests/cts/net/Android.bp | 1 + tests/cts/net/jni/NativeMultinetworkJni.cpp | 19 +++++++----- tests/cts/net/native/dns/Android.bp | 3 +- .../android/net/wifi/cts/ScanResultTest.java | 30 +++++++++++++++++++ .../android/net/wifi/cts/WifiInfoTest.java | 3 ++ 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index b6ea4afe80..b00455d9ef 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -60,6 +60,7 @@ android_test { "cts", "vts", "general-tests", + "mts", ], } diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index a6b5e90b1d..5bd3013819 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -455,13 +455,17 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol-01#section-6.1 - uint8_t quic_packet[] = { - 0x0c, // public flags: 64bit conn ID, 8bit sequence number + // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + uint8_t quic_packet[1200] = { + 0x0d, // public flags: + // - version present (0x01), + // - 64bit connection ID (0x0c), + // - 1 byte packet number (0x00) 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0x01, // sequence number + 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number + 1, // 1 byte packet number 0x00, // private flags - 0x07, // type: regular frame type "PING" + 0x07, // PING frame (cuz why not) }; arc4random_buf(quic_packet + 1, 8); // random connection ID @@ -489,7 +493,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < sent) { + if (rcvd < 9) { ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { ALOGD("Does this network block UDP port %s?", kPort); @@ -505,8 +509,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - // TODO: log, and compare to the IP address encoded in the - // response, since this should be a public reset packet. + // TODO: Replace this quick 'n' dirty test with proper QUIC-capable code. close(fd); return 0; diff --git a/tests/cts/net/native/dns/Android.bp b/tests/cts/net/native/dns/Android.bp index 9fbc3fc83d..1704a2b8f4 100644 --- a/tests/cts/net/native/dns/Android.bp +++ b/tests/cts/net/native/dns/Android.bp @@ -35,5 +35,6 @@ cc_test { }, test_suites: [ "cts", + "mts", ], -} \ No newline at end of file +} diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java index ccf5fe2241..9bd1226f52 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.platform.test.annotations.AppModeFull; @@ -54,6 +55,8 @@ public class ScanResultTest extends AndroidTestCase { private static final int ENABLE_WAIT_MSEC = 10000; private static final int SCAN_WAIT_MSEC = 10000; private static final int SCAN_MAX_RETRY_COUNT = 6; + private static final int SCAN_FIND_BSSID_MAX_RETRY_COUNT = 5; + private static final long SCAN_FIND_BSSID_WAIT_MSEC = 5_000L; private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -200,4 +203,31 @@ public class ScanResultTest extends AndroidTestCase { } + public void testScanResultMatchesWifiInfo() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + // This test case should run while connected to Wifi + final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + assertNotNull(wifiInfo); + + ScanResult currentNetwork = null; + for (int i = 0; i < SCAN_FIND_BSSID_MAX_RETRY_COUNT; i++) { + scanAndWait(); + final List scanResults = mWifiManager.getScanResults(); + currentNetwork = scanResults.stream().filter(r -> r.BSSID.equals(wifiInfo.getBSSID())) + .findAny().orElse(null); + + if (currentNetwork != null) { + break; + } + Thread.sleep(SCAN_FIND_BSSID_WAIT_MSEC); + } + assertNotNull("Current network not found in scan results", currentNetwork); + + assertEquals(wifiInfo.getWifiSsid(), currentNetwork.wifiSsid); + assertEquals(wifiInfo.getFrequency(), currentNetwork.frequency); + } } diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java index 5367722b36..9d9b2a3902 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java @@ -139,8 +139,11 @@ public class WifiInfoTest extends AndroidTestCase { } wifiInfo.getBSSID(); + wifiInfo.getFrequency(); wifiInfo.getIpAddress(); wifiInfo.getLinkSpeed(); + wifiInfo.getPasspointFqdn(); + wifiInfo.getPasspointProviderFriendlyName(); wifiInfo.getTxLinkSpeedMbps(); wifiInfo.getRxLinkSpeedMbps(); wifiInfo.getRssi(); From a261dcd8cd8c0aaaa8e5604e95bca8b4d85ecb02 Mon Sep 17 00:00:00 2001 From: Amit Mahajan Date: Thu, 12 Sep 2019 12:32:37 -0700 Subject: [PATCH 0679/1415] Use update constructor for AudioGroup. Test: basic sanity Bug: 140872785 Change-Id: Ie5bdca10cd80b4b7d0241f9b1b4afdebca8aeb04 --- tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java index 1bd7fadc8e..fee8621c70 100644 --- a/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java +++ b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java @@ -62,7 +62,7 @@ public class AudioGroupTest extends AndroidTestCase { mSocketB.connect(mStreamB.getLocalAddress(), mStreamB.getLocalPort()); mStreamB.associate(mSocketB.getLocalAddress(), mSocketB.getLocalPort()); - mGroup = new AudioGroup(); + mGroup = new AudioGroup(mContext); } @Override From c9068f1b87d206acb91a28d94bfba5229809b330 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Tue, 1 Oct 2019 15:49:42 +0200 Subject: [PATCH 0680/1415] getConnectionOwnerUid: add test for b/141603906 Test: on Marlin and Blueline run cts-tradefed run cts -m CtsHostsideNetworkTests \ -t com.android.cts.net.HostsideVpnTests#testB141603906 Bug: 141603906 Change-Id: I759bc2295b2060e4575d61718c551d201a6455be --- .../com/android/cts/net/hostside/VpnTest.java | 26 +++++++++++++++++++ .../com/android/cts/net/HostsideVpnTests.java | 4 +++ 2 files changed, 30 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index 2fc85f6e3e..c43d4210ec 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -897,6 +897,32 @@ public class VpnTest extends InstrumentationTestCase { assertTrue(mCM.isActiveNetworkMetered()); } + public void testB141603906() throws Exception { + final InetSocketAddress src = new InetSocketAddress(0); + final InetSocketAddress dst = new InetSocketAddress(0); + final int NUM_THREADS = 8; + final int NUM_SOCKETS = 5000; + final Thread[] threads = new Thread[NUM_THREADS]; + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, + "", "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */); + + for (int i = 0; i < NUM_THREADS; i++) { + threads[i] = new Thread(() -> { + for (int j = 0; j < NUM_SOCKETS; j++) { + mCM.getConnectionOwnerUid(IPPROTO_TCP, src, dst); + } + }); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + stopVpn(); + } + private boolean isNetworkMetered(Network network) { NetworkCapabilities nc = mCM.getNetworkCapabilities(network); return !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java index 6e37a24c68..62925ad6ab 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -91,4 +91,8 @@ public class HostsideVpnTests extends HostsideNetworkTestCase { TEST_PKG + ".VpnTest", "testAlwaysMeteredVpnWithNonNullUnderlyingNetwork"); } + + public void testB141603906() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testB141603906"); + } } From 1881bc644fe252d3b4c78fff9d7f8dd958e44f14 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Tue, 8 Oct 2019 14:55:49 -0700 Subject: [PATCH 0681/1415] Change network parole while charging tests. The periodic parole window is the 10 minute window that occurs every 24 hours to let RARE apps run. Now that we have the quota system in place, there's no need to have the periodic parole window. Alarms and jobs will still be allowed to run when charging. Network will continue to be restricted for RARE apps even when charging. JobScheduler requests an exception for RARE jobs in quota, so they will still be able to run. With this change, idle apps should still not get network when charging unless JobScheduler requests it, so we have to update the tests. Bug: 136184981 Test: atest AppStandbyControllerTests Test: atest CtsAlarmManagerTestCases Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests Test: atest com.android.server.AlarmManagerServiceTest Test: atest com.android.server.AppStateTrackerTest Test: atest com.android.server.job.controllers.QuotaControllerTest Change-Id: Icd7b6eff8777f9b53a10eca521b73988f58f2d84 --- tests/cts/hostside/AndroidTest.xml | 2 - .../net/hostside/AbstractAppIdleTestCase.java | 4 +- ...ractRestrictBackgroundNetworkTestCase.java | 8 --- .../cts/net/NetPolicyTestsPreparer.java | 63 ------------------- 4 files changed, 2 insertions(+), 75 deletions(-) delete mode 100644 tests/cts/hostside/src/com/android/cts/net/NetPolicyTestsPreparer.java diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 5479c51a4c..6ba6f42409 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -20,8 +20,6 @@

    This class is not thread safe, it is intended to be used only from the tethering handler + * thread. However the constructor is an exception, as it is called on another thread ; + * therefore for thread safety all members of this class MUST either be final or initialized + * to their default value (0, false or null). + * + * @hide + */ +public class TetheringNotificationUpdater { + private static final String TAG = TetheringNotificationUpdater.class.getSimpleName(); + private static final String CHANNEL_ID = "TETHERING_STATUS"; + private static final boolean NOTIFY_DONE = true; + private static final boolean NO_NOTIFY = false; + // Id to update and cancel tethering notification. Must be unique within the tethering app. + private static final int NOTIFY_ID = 20191115; + @VisibleForTesting + static final int NO_ICON_ID = 0; + @VisibleForTesting + static final int DOWNSTREAM_NONE = 0; + private final Context mContext; + private final NotificationManager mNotificationManager; + private final NotificationChannel mChannel; + // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2. + // This value has to be made 1 2 and 4, and OR'd with the others. + // WARNING : the constructor is called on a different thread. Thread safety therefore + // relies on this value being initialized to 0, and not any other value. If you need + // to change this, you will need to change the thread where the constructor is invoked, + // or to introduce synchronization. + private int mDownstreamTypesMask = DOWNSTREAM_NONE; + + public TetheringNotificationUpdater(@NonNull final Context context) { + mContext = context; + mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0) + .getSystemService(Context.NOTIFICATION_SERVICE); + mChannel = new NotificationChannel( + CHANNEL_ID, + context.getResources().getString(R.string.notification_channel_tethering_status), + NotificationManager.IMPORTANCE_LOW); + mNotificationManager.createNotificationChannel(mChannel); + } + + /** Called when downstream has changed */ + public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) { + if (mDownstreamTypesMask == downstreamTypesMask) return; + mDownstreamTypesMask = downstreamTypesMask; + updateNotification(); + } + + private void updateNotification() { + final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE; + + if (tetheringInactive || setupNotification() == NO_NOTIFY) { + clearNotification(); + } + } + + private void clearNotification() { + mNotificationManager.cancel(null /* tag */, NOTIFY_ID); + } + + /** + * Returns the downstream types mask which convert from given string. + * + * @param types This string has to be made by "WIFI", "USB", "BT", and OR'd with the others. + * + * @return downstream types mask value. + */ + @IntRange(from = 0, to = 7) + private int getDownstreamTypesMask(@NonNull final String types) { + int downstreamTypesMask = DOWNSTREAM_NONE; + final String[] downstreams = types.split("\\|"); + for (String downstream : downstreams) { + if ("USB".equals(downstream.trim())) { + downstreamTypesMask |= (1 << TETHERING_USB); + } else if ("WIFI".equals(downstream.trim())) { + downstreamTypesMask |= (1 << TETHERING_WIFI); + } else if ("BT".equals(downstream.trim())) { + downstreamTypesMask |= (1 << TETHERING_BLUETOOTH); + } + } + return downstreamTypesMask; + } + + /** + * Returns the icons {@link android.util.SparseArray} which get from given string-array resource + * id. + * + * @param id String-array resource id + * + * @return {@link android.util.SparseArray} with downstream types and icon id info. + */ + @NonNull + private SparseArray getIcons(@ArrayRes int id) { + final Resources res = mContext.getResources(); + final String[] array = res.getStringArray(id); + final SparseArray icons = new SparseArray<>(); + for (String config : array) { + if (TextUtils.isEmpty(config)) continue; + + final String[] elements = config.split(";"); + if (elements.length != 2) { + Log.wtf(TAG, + "Unexpected format in Tethering notification configuration : " + config); + continue; + } + + final String[] types = elements[0].split(","); + for (String type : types) { + int mask = getDownstreamTypesMask(type); + if (mask == DOWNSTREAM_NONE) continue; + icons.put(mask, res.getIdentifier( + elements[1].trim(), null /* defType */, null /* defPackage */)); + } + } + return icons; + } + + private boolean setupNotification() { + final Resources res = mContext.getResources(); + final SparseArray downstreamIcons = getIcons(R.array.tethering_notification_icons); + + final int iconId = downstreamIcons.get(mDownstreamTypesMask, NO_ICON_ID); + if (iconId == NO_ICON_ID) return NO_NOTIFY; + + final String title = res.getString(R.string.tethering_notification_title); + final String message = res.getString(R.string.tethering_notification_message); + + showNotification(iconId, title, message); + return NOTIFY_DONE; + } + + private void showNotification(@DrawableRes final int iconId, @NonNull final String title, + @NonNull final String message) { + final Intent intent = new Intent(Settings.ACTION_TETHER_SETTINGS); + final PendingIntent pi = PendingIntent.getActivity( + mContext.createContextAsUser(UserHandle.CURRENT, 0), + 0 /* requestCode */, intent, 0 /* flags */, null /* options */); + final Notification notification = + new Notification.Builder(mContext, mChannel.getId()) + .setSmallIcon(iconId) + .setContentTitle(title) + .setContentText(message) + .setOngoing(true) + .setColor(mContext.getColor( + android.R.color.system_notification_accent_color)) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setCategory(Notification.CATEGORY_STATUS) + .setContentIntent(pi) + .build(); + + mNotificationManager.notify(null /* tag */, NOTIFY_ID, notification); + } +} diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 4581b56f13..88f7968b3f 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -43,6 +43,8 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -50,7 +52,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.notNull; -import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; @@ -184,6 +185,7 @@ public class TetheringTest { @Mock private NetworkRequest mNetworkRequest; @Mock private ConnectivityManager mCm; @Mock private EthernetManager mEm; + @Mock private TetheringNotificationUpdater mNotificationUpdater; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -203,6 +205,7 @@ public class TetheringTest { private PhoneStateListener mPhoneStateListener; private InterfaceConfigurationParcel mInterfaceConfiguration; + private class TestContext extends BroadcastInterceptingContext { TestContext(Context base) { super(base); @@ -245,11 +248,6 @@ public class TetheringTest { if (TelephonyManager.class.equals(serviceClass)) return Context.TELEPHONY_SERVICE; return super.getSystemServiceName(serviceClass); } - - @Override - public Context createContextAsUser(UserHandle user, int flags) { - return mContext; - } } public class MockIpServerDependencies extends IpServer.Dependencies { @@ -311,12 +309,10 @@ public class TetheringTest { public class MockTetheringDependencies extends TetheringDependencies { StateMachine mUpstreamNetworkMonitorMasterSM; ArrayList mIpv6CoordinatorNotifyList; - int mIsTetheringSupportedCalls; public void reset() { mUpstreamNetworkMonitorMasterSM = null; mIpv6CoordinatorNotifyList = null; - mIsTetheringSupportedCalls = 0; } @Override @@ -350,7 +346,6 @@ public class TetheringTest { @Override public boolean isTetheringSupported() { - mIsTetheringSupportedCalls++; return true; } @@ -380,6 +375,11 @@ public class TetheringTest { // TODO: add test for bluetooth tethering. return null; } + + @Override + public TetheringNotificationUpdater getNotificationUpdater(Context ctx) { + return mNotificationUpdater; + } } private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4, @@ -465,7 +465,6 @@ public class TetheringTest { .thenReturn(true); mServiceContext = new TestContext(mContext); - when(mContext.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(null); mContentResolver = new MockContentResolver(mServiceContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mIntents = new Vector<>(); @@ -598,7 +597,8 @@ public class TetheringTest { // it creates a IpServer and sends out a broadcast indicating that the // interface is "available". if (emulateInterfaceStatusChanged) { - assertEquals(1, mTetheringDependencies.mIsTetheringSupportedCalls); + // There is 1 IpServer state change event: STATE_AVAILABLE + verify(mNotificationUpdater, times(1)).onDownstreamChanged(DOWNSTREAM_NONE); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); @@ -682,9 +682,8 @@ public class TetheringTest { verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY); verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks(); - // This will be called twice, one is on entering IpServer.STATE_AVAILABLE, - // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY. - assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls); + // There are 2 IpServer state change events: STATE_AVAILABLE -> STATE_LOCAL_ONLY + verify(mNotificationUpdater, times(2)).onDownstreamChanged(DOWNSTREAM_NONE); // Emulate externally-visible WifiManager effects, when hotspot mode // is being torn down. @@ -910,7 +909,8 @@ public class TetheringTest { sendWifiApStateChanged(WIFI_AP_STATE_ENABLED); mLooper.dispatchAll(); - assertEquals(1, mTetheringDependencies.mIsTetheringSupportedCalls); + // There is 1 IpServer state change event: STATE_AVAILABLE + verify(mNotificationUpdater, times(1)).onDownstreamChanged(DOWNSTREAM_NONE); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); @@ -954,9 +954,9 @@ public class TetheringTest { // In tethering mode, in the default configuration, an explicit request // for a mobile network is also made. verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest(); - // This will be called twice, one is on entering IpServer.STATE_AVAILABLE, - // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY. - assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls); + // There are 2 IpServer state change events: STATE_AVAILABLE -> STATE_TETHERED + verify(mNotificationUpdater, times(1)).onDownstreamChanged(DOWNSTREAM_NONE); + verify(mNotificationUpdater, times(1)).onDownstreamChanged(eq(1 << TETHERING_WIFI)); ///// // We do not currently emulate any upstream being found. @@ -1027,9 +1027,10 @@ public class TetheringTest { TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED); - // There are 3 state change event: - // AVAILABLE -> STATE_TETHERED -> STATE_AVAILABLE. - assertEquals(3, mTetheringDependencies.mIsTetheringSupportedCalls); + // There are 3 IpServer state change event: + // STATE_AVAILABLE -> STATE_TETHERED -> STATE_AVAILABLE. + verify(mNotificationUpdater, times(2)).onDownstreamChanged(DOWNSTREAM_NONE); + verify(mNotificationUpdater, times(1)).onDownstreamChanged(eq(1 << TETHERING_WIFI)); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); // This is called, but will throw. verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); @@ -1063,9 +1064,6 @@ public class TetheringTest { ural.onUserRestrictionsChanged(); - verify(mockTethering, times(expectedInteractionsWithShowNotification)) - .showTetheredNotification(anyInt(), eq(false)); - verify(mockTethering, times(expectedInteractionsWithShowNotification)) .untetherAll(); } @@ -1354,9 +1352,8 @@ public class TetheringTest { verifyNoMoreInteractions(mNetd); verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY); verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks(); - // This will be called twice, one is on entering IpServer.STATE_AVAILABLE, - // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY. - assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls); + // There are 2 IpServer state change events: STATE_AVAILABLE -> STATE_LOCAL_ONLY + verify(mNotificationUpdater, times(2)).onDownstreamChanged(DOWNSTREAM_NONE); assertEquals(TETHER_ERROR_NO_ERROR, mTethering.getLastTetherError(TEST_P2P_IFNAME)); From 05bee8027dda215a5c213cf5fc0bee9fa0341ed2 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 2 Mar 2020 23:27:48 +0800 Subject: [PATCH 0770/1415] Send offload status changed callback The callback would be fired when offload started, stopped, or failed. If offload is not supported, "failed" callback would be fired when user enable tethering. Enabling multiple tethering would not have multiple offload status callbacks because offload should already be started or failed. Bug: 130596697 Test: -build, flash, boot -atest TetheringTests -ON/OFF hotspot Change-Id: Ia0398601144b0e5f61dc0c5771eacf13e7cfbb59 --- .../android/net/ITetheringEventCallback.aidl | 1 + .../net/TetheringCallbackStartedParcel.aidl | 3 +- .../src/android/net/TetheringManager.java | 37 +++++++++ .../connectivity/tethering/Tethering.java | 32 +++++++- .../connectivity/tethering/TetheringTest.java | 75 +++++++++++++++++++ 5 files changed, 146 insertions(+), 2 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl index a554193833..b4e3ba4679 100644 --- a/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl +++ b/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl @@ -35,4 +35,5 @@ oneway interface ITetheringEventCallback void onConfigurationChanged(in TetheringConfigurationParcel config); void onTetherStatesChanged(in TetherStatesParcel states); void onTetherClientsChanged(in List clients); + void onOffloadStatusChanged(int status); } diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl index c064aa4d9a..253eacbd23 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl +++ b/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl @@ -31,4 +31,5 @@ parcelable TetheringCallbackStartedParcel { TetheringConfigurationParcel config; TetherStatesParcel states; List tetheredClients; -} \ No newline at end of file + int offloadStatus; +} diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index bfa962a18c..231de8bc98 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -18,6 +18,7 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -34,6 +35,8 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -172,6 +175,23 @@ public class TetheringManager { public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = false, value = { + TETHER_HARDWARE_OFFLOAD_STOPPED, + TETHER_HARDWARE_OFFLOAD_STARTED, + TETHER_HARDWARE_OFFLOAD_FAILED, + }) + public @interface TetherOffloadStatus { + } + + /** Tethering offload status is stopped. */ + public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; + /** Tethering offload status is started. */ + public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; + /** Fail to start tethering offload. */ + public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; + /** * Create a TetheringManager object for interacting with the tethering service. * @@ -378,6 +398,9 @@ public class TetheringManager { @Override public void onTetherClientsChanged(List clients) { } + @Override + public void onOffloadStatusChanged(int status) { } + public void waitForStarted() { mWaitForCallback.block(DEFAULT_TIMEOUT_MS); throwIfPermissionFailure(mError); @@ -802,6 +825,14 @@ public class TetheringManager { * @param clients The new set of tethered clients; the collection is not ordered. */ public void onClientsChanged(@NonNull Collection clients) {} + + /** + * Called when tethering offload status changes. + * + *

    This will be called immediately after the callback is registered. + * @param status The offload status. + */ + public void onOffloadStatusChanged(@TetherOffloadStatus int status) {} } /** @@ -925,6 +956,7 @@ public class TetheringManager { maybeSendTetherableIfacesChangedCallback(parcel.states); maybeSendTetheredIfacesChangedCallback(parcel.states); callback.onClientsChanged(parcel.tetheredClients); + callback.onOffloadStatusChanged(parcel.offloadStatus); }); } @@ -960,6 +992,11 @@ public class TetheringManager { public void onTetherClientsChanged(final List clients) { executor.execute(() -> callback.onClientsChanged(clients)); } + + @Override + public void onOffloadStatusChanged(final int status) { + executor.execute(() -> callback.onOffloadStatusChanged(status)); + } }; getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg)); mTetheringEventCallbacks.put(callback, remoteCallback); diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 0958e8a1a4..68650f7e7b 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -44,6 +44,9 @@ import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE; import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.util.TetheringMessageBase.BASE_MASTER; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; @@ -237,6 +240,7 @@ public class Tethering { private TetherStatesParcel mTetherStatesParcel; private boolean mDataSaverEnabled = false; private String mWifiP2pTetherInterface = null; + private int mOffloadStatus = TETHER_HARDWARE_OFFLOAD_STOPPED; @GuardedBy("mPublicSync") private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest; @@ -1901,12 +1905,15 @@ public class Tethering { // OffloadController implementation. class OffloadWrapper { public void start() { - mOffloadController.start(); + final int status = mOffloadController.start() ? TETHER_HARDWARE_OFFLOAD_STARTED + : TETHER_HARDWARE_OFFLOAD_FAILED; + updateOffloadStatus(status); sendOffloadExemptPrefixes(); } public void stop() { mOffloadController.stop(); + updateOffloadStatus(TETHER_HARDWARE_OFFLOAD_STOPPED); } public void updateUpstreamNetworkState(UpstreamNetworkState ns) { @@ -1967,6 +1974,13 @@ public class Tethering { mOffloadController.setLocalPrefixes(localPrefixes); } + + private void updateOffloadStatus(final int newStatus) { + if (newStatus == mOffloadStatus) return; + + mOffloadStatus = newStatus; + reportOffloadStatusChanged(mOffloadStatus); + } } } @@ -2001,6 +2015,7 @@ public class Tethering { parcel.tetheredClients = hasListPermission ? mConnectedClientsTracker.getLastTetheredClients() : Collections.emptyList(); + parcel.offloadStatus = mOffloadStatus; try { callback.onCallbackStarted(parcel); } catch (RemoteException e) { @@ -2095,6 +2110,21 @@ public class Tethering { } } + private void reportOffloadStatusChanged(final int status) { + final int length = mTetheringEventCallbacks.beginBroadcast(); + try { + for (int i = 0; i < length; i++) { + try { + mTetheringEventCallbacks.getBroadcastItem(i).onOffloadStatusChanged(status); + } catch (RemoteException e) { + // Not really very much to do here. + } + } + } finally { + mTetheringEventCallbacks.finishBroadcast(); + } + } + void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { // Binder.java closes the resource for us. @SuppressWarnings("resource") diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 4581b56f13..1998cb3aa7 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -34,6 +34,9 @@ import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; @@ -169,6 +172,7 @@ public class TetheringTest { @Mock private Context mContext; @Mock private NetworkStatsManager mStatsManager; @Mock private OffloadHardwareInterface mOffloadHardwareInterface; + @Mock private OffloadHardwareInterface.ForwardedStats mForwardedStats; @Mock private Resources mResources; @Mock private TelephonyManager mTelephonyManager; @Mock private UsbManager mUsbManager; @@ -463,6 +467,9 @@ public class TetheringTest { mInterfaceConfiguration.flags = new String[0]; when(mRouterAdvertisementDaemon.start()) .thenReturn(true); + initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */, + 0 /* defaultDisabled */); + when(mOffloadHardwareInterface.getForwardedStats(any())).thenReturn(mForwardedStats); mServiceContext = new TestContext(mContext); when(mContext.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(null); @@ -1136,6 +1143,7 @@ public class TetheringTest { private final ArrayList mTetheringConfigs = new ArrayList<>(); private final ArrayList mTetherStates = new ArrayList<>(); + private final ArrayList mOffloadStatus = new ArrayList<>(); // This function will remove the recorded callbacks, so it must be called once for // each callback. If this is called after multiple callback, the order matters. @@ -1171,6 +1179,11 @@ public class TetheringTest { assertNoConfigChangeCallback(); } + public void expectOffloadStatusChanged(final int expectedStatus) { + assertOffloadStatusChangedCallback(); + assertEquals(mOffloadStatus.remove(0), new Integer(expectedStatus)); + } + public TetherStatesParcel pollTetherStatesChanged() { assertStateChangeCallback(); return mTetherStates.remove(0); @@ -1196,11 +1209,17 @@ public class TetheringTest { // TODO: check this } + @Override + public void onOffloadStatusChanged(final int status) { + mOffloadStatus.add(status); + } + @Override public void onCallbackStarted(TetheringCallbackStartedParcel parcel) { mActualUpstreams.add(parcel.upstreamNetwork); mTetheringConfigs.add(parcel.config); mTetherStates.add(parcel.states); + mOffloadStatus.add(parcel.offloadStatus); } @Override @@ -1222,6 +1241,10 @@ public class TetheringTest { assertFalse(mTetherStates.isEmpty()); } + public void assertOffloadStatusChangedCallback() { + assertFalse(mOffloadStatus.isEmpty()); + } + public void assertNoCallback() { assertNoUpstreamChangeCallback(); assertNoConfigChangeCallback(); @@ -1270,6 +1293,7 @@ public class TetheringTest { mTethering.getTetheringConfiguration().toStableParcelable()); TetherStatesParcel tetherState = callback.pollTetherStatesChanged(); assertTetherStatesNotNullButEmpty(tetherState); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); // 2. Enable wifi tethering. UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); @@ -1287,6 +1311,7 @@ public class TetheringTest { tetherState = callback.pollTetherStatesChanged(); assertArrayEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME}); callback.expectUpstreamChanged(upstreamState.network); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED); // 3. Register second callback. mTethering.registerTetheringEventCallback(callback2); @@ -1296,6 +1321,7 @@ public class TetheringTest { mTethering.getTetheringConfiguration().toStableParcelable()); tetherState = callback2.pollTetherStatesChanged(); assertEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME}); + callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED); // 4. Unregister first callback and disable wifi tethering mTethering.unregisterTetheringEventCallback(callback); @@ -1307,9 +1333,58 @@ public class TetheringTest { assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME}); mLooper.dispatchAll(); callback2.expectUpstreamChanged(new Network[] {null}); + callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); callback.assertNoCallback(); } + @Test + public void testReportFailCallbackIfOffloadNotSupported() throws Exception { + final UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); + TestTetheringEventCallback callback = new TestTetheringEventCallback(); + mTethering.registerTetheringEventCallback(callback); + mLooper.dispatchAll(); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + + // 1. Offload fail if no OffloadConfig. + initOffloadConfiguration(false /* offloadConfig */, true /* offloadControl */, + 0 /* defaultDisabled */); + runUsbTethering(upstreamState); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); + runStopUSBTethering(); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + reset(mUsbManager); + // 2. Offload fail if no OffloadControl. + initOffloadConfiguration(true /* offloadConfig */, false /* offloadControl */, + 0 /* defaultDisabled */); + runUsbTethering(upstreamState); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); + runStopUSBTethering(); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + reset(mUsbManager); + // 3. Offload fail if disabled by settings. + initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */, + 1 /* defaultDisabled */); + runUsbTethering(upstreamState); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); + runStopUSBTethering(); + callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + } + + private void runStopUSBTethering() { + mTethering.stopTethering(TETHERING_USB); + mLooper.dispatchAll(); + mTethering.interfaceRemoved(TEST_USB_IFNAME); + mLooper.dispatchAll(); + } + + private void initOffloadConfiguration(final boolean offloadConfig, + final boolean offloadControl, final int defaultDisabled) { + when(mOffloadHardwareInterface.initOffloadConfig()).thenReturn(offloadConfig); + when(mOffloadHardwareInterface.initOffloadControl(any())).thenReturn(offloadControl); + when(mOffloadHardwareInterface.getDefaultTetherOffloadDisabled()).thenReturn( + defaultDisabled); + } + @Test public void testMultiSimAware() throws Exception { final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration(); From 9a63e9acad2132cb427d4ef648dec1b80c371d6f Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Sun, 8 Mar 2020 21:22:51 -0700 Subject: [PATCH 0771/1415] Update OWNERship Bug: 151049099 Fixed: 151049099 Test: N/A Change-Id: I3657fe6b220e5d946f9e077539c45762d6b42ee7 --- tests/cts/net/assets/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/cts/net/assets/OWNERS diff --git a/tests/cts/net/assets/OWNERS b/tests/cts/net/assets/OWNERS new file mode 100644 index 0000000000..14edd1d505 --- /dev/null +++ b/tests/cts/net/assets/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 31808 +etancohen@google.com +lorenzo@google.com +satk@google.com From 1b88fd7e3c4669467d71fe3dffae9a1ef94d7e26 Mon Sep 17 00:00:00 2001 From: David Su Date: Mon, 9 Mar 2020 19:38:25 -0700 Subject: [PATCH 0772/1415] WifiLockTest: Test WifiLock.setWorkSource() Bug: 150236894 Test: atest android.net.wifi.cts.WifiLockTest Change-Id: I1a6975590c2a4b885c90690e4269ba35bcaf34ff --- tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java index 6ac92d409c..fee9ef026a 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java @@ -19,6 +19,7 @@ package android.net.wifi.cts; import android.content.Context; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; +import android.os.WorkSource; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; @@ -50,6 +51,7 @@ public class WifiLockTest extends AndroidTestCase { WifiLock wl = wm.createWifiLock(lockType, WIFI_TAG); wl.setReferenceCounted(true); + wl.setWorkSource(new WorkSource()); assertFalse(wl.isHeld()); wl.acquire(); assertTrue(wl.isHeld()); From a3b321401a2ba06f37817d534b1cf20977638d4a Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 10 Mar 2020 16:14:30 +0800 Subject: [PATCH 0773/1415] Wifi: add CTS tests for WifiP2pManager Bug: 150979686 Bug: 150979837 Test: atest android.net.wifi.cts.ConcurrencyTest Change-Id: Id9c18ae602be23cbcc5d9c605c27b10424e1d1d9 --- .../android/net/wifi/cts/ConcurrencyTest.java | 300 +++++++++++++++--- 1 file changed, 260 insertions(+), 40 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java index ba0832f8b6..f7ea750d18 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java @@ -30,15 +30,22 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.wifi.WifiManager; +import android.net.wifi.p2p.WifiP2pDevice; +import android.net.wifi.p2p.WifiP2pGroupList; +import android.net.wifi.p2p.WifiP2pInfo; import android.net.wifi.p2p.WifiP2pManager; +import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; +import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo; import android.provider.Settings; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; import android.util.Log; +import com.android.compatibility.common.util.ShellIdentityUtils; import com.android.compatibility.common.util.SystemUtil; import java.util.Arrays; +import java.util.ArrayList; import java.util.BitSet; import java.util.LinkedList; import java.util.List; @@ -69,6 +76,9 @@ public class ConcurrencyTest extends AndroidTestCase { public int p2pState; public int discoveryState; public NetworkInfo networkInfo; + public WifiP2pInfo p2pInfo; + public String deviceName; + public WifiP2pGroupList persistentGroups; } private WifiManager mWifiManager; @@ -76,6 +86,7 @@ public class ConcurrencyTest extends AndroidTestCase { private WifiP2pManager.Channel mWifiP2pChannel; private MySync mMySync = new MySync(); private MyResponse mMyResponse = new MyResponse(); + private boolean mWasVerboseLoggingEnabled; private static final String TAG = "ConcurrencyTest"; private static final int TIMEOUT_MSEC = 6000; @@ -119,6 +130,27 @@ public class ConcurrencyTest extends AndroidTestCase { } }; + private WifiP2pManager.ActionListener mActionListener = new WifiP2pManager.ActionListener() { + @Override + public void onSuccess() { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.success = true; + mMyResponse.notify(); + } + } + + @Override + public void onFailure(int reason) { + synchronized (mMyResponse) { + Log.d(TAG, "failure reason: " + reason); + mMyResponse.valid = true; + mMyResponse.success = false; + mMyResponse.notify(); + } + } + }; + @Override protected void setUp() throws Exception { super.setUp(); @@ -127,6 +159,7 @@ public class ConcurrencyTest extends AndroidTestCase { // skip the test if WiFi && p2p are not supported return; } + mIntentFilter = new IntentFilter(); mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); @@ -140,6 +173,13 @@ public class ConcurrencyTest extends AndroidTestCase { SystemUtil.runShellCommand("svc wifi disable"); Thread.sleep(DURATION); } + + // turn on verbose logging for tests + mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.isVerboseLoggingEnabled()); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setVerboseLoggingEnabled(true)); + assertTrue(!mWifiManager.isWifiEnabled()); mMySync.expectedWifiState = WifiManager.WIFI_STATE_DISABLED; mMySync.expectedP2pState = WifiP2pManager.WIFI_P2P_STATE_DISABLED; @@ -157,6 +197,9 @@ public class ConcurrencyTest extends AndroidTestCase { } mContext.unregisterReceiver(mReceiver); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); + enableWifi(); super.tearDown(); } @@ -221,6 +264,9 @@ public class ConcurrencyTest extends AndroidTestCase { synchronized (responseObj) { responseObj.valid = false; responseObj.networkInfo = null; + responseObj.p2pInfo = null; + responseObj.deviceName = null; + responseObj.persistentGroups = null; } } @@ -344,26 +390,7 @@ public class ConcurrencyTest extends AndroidTestCase { assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED, mMyResponse.discoveryState); resetResponse(mMyResponse); - mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() { - @Override - public void onSuccess() { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.success = true; - mMyResponse.notify(); - } - } - - @Override - public void onFailure(int reason) { - synchronized (mMyResponse) { - Log.d(TAG, "discoveryPeers failure reason: " + reason); - mMyResponse.valid = true; - mMyResponse.success = false; - mMyResponse.notify(); - } - } - }); + mWifiP2pManager.discoverPeers(mWifiP2pChannel, mActionListener); assertTrue(waitForServiceResponse(mMyResponse)); assertTrue(mMyResponse.success); assertTrue(waitForBroadcasts(MySync.DISCOVERY_STATE)); @@ -411,26 +438,7 @@ public class ConcurrencyTest extends AndroidTestCase { mMySync.expectedNetworkInfo.getDetailedState()); resetResponse(mMyResponse); - mWifiP2pManager.createGroup(mWifiP2pChannel, new WifiP2pManager.ActionListener() { - @Override - public void onSuccess() { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.success = true; - mMyResponse.notify(); - } - } - - @Override - public void onFailure(int reason) { - synchronized (mMyResponse) { - Log.d(TAG, "createGroup failure reason: " + reason); - mMyResponse.valid = true; - mMyResponse.success = false; - mMyResponse.notify(); - } - } - }); + mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener); assertTrue(waitForServiceResponse(mMyResponse)); assertTrue(mMyResponse.success); assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); @@ -455,7 +463,219 @@ public class ConcurrencyTest extends AndroidTestCase { assertEquals(NetworkInfo.DetailedState.CONNECTED, mMyResponse.networkInfo.getDetailedState()); + resetResponse(mMyResponse); + mWifiP2pManager.requestConnectionInfo(mWifiP2pChannel, + new WifiP2pManager.ConnectionInfoListener() { + @Override + public void onConnectionInfoAvailable(WifiP2pInfo info) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.p2pInfo = new WifiP2pInfo(info); + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertNotNull(mMyResponse.p2pInfo); + assertTrue(mMyResponse.p2pInfo.groupFormed); + assertTrue(mMyResponse.p2pInfo.isGroupOwner); + mWifiP2pManager.removeGroup(mWifiP2pChannel, null); } + private String getDeviceName() { + resetResponse(mMyResponse); + mWifiP2pManager.requestDeviceInfo(mWifiP2pChannel, + new WifiP2pManager.DeviceInfoListener() { + @Override + public void onDeviceInfoAvailable(WifiP2pDevice wifiP2pDevice) { + synchronized (mMyResponse) { + mMyResponse.deviceName = wifiP2pDevice.deviceName; + mMyResponse.valid = true; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + return mMyResponse.deviceName; + } + + public void testSetDeviceName() { + if (!setupWifiP2p()) { + return; + } + + String testDeviceName = "test"; + String originalDeviceName = getDeviceName(); + assertNotNull(originalDeviceName); + + ShellIdentityUtils.invokeWithShellPermissions(() -> { + mWifiP2pManager.setDeviceName( + mWifiP2pChannel, testDeviceName, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + }); + + String currentDeviceName = getDeviceName(); + assertEquals(testDeviceName, currentDeviceName); + + // restore the device name at the end + ShellIdentityUtils.invokeWithShellPermissions(() -> { + mWifiP2pManager.setDeviceName( + mWifiP2pChannel, originalDeviceName, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + }); + } + + private WifiP2pGroupList getPersistentGroups() { + resetResponse(mMyResponse); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + mWifiP2pManager.requestPersistentGroupInfo(mWifiP2pChannel, + new WifiP2pManager.PersistentGroupInfoListener() { + @Override + public void onPersistentGroupInfoAvailable(WifiP2pGroupList groups) { + synchronized (mMyResponse) { + mMyResponse.persistentGroups = groups; + mMyResponse.valid = true; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + }); + return mMyResponse.persistentGroups; + } + + public void testPersistentGroupOperation() { + if (!setupWifiP2p()) { + return; + } + + resetResponse(mMyResponse); + mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); + assertNotNull(mMySync.expectedNetworkInfo); + assertEquals(NetworkInfo.DetailedState.CONNECTED, + mMySync.expectedNetworkInfo.getDetailedState()); + + resetResponse(mMyResponse); + mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + + WifiP2pGroupList persistentGroups = getPersistentGroups(); + assertNotNull(persistentGroups); + assertEquals(1, persistentGroups.getGroupList().size()); + + resetResponse(mMyResponse); + final int firstNetworkId = persistentGroups.getGroupList().get(0).getNetworkId(); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + mWifiP2pManager.deletePersistentGroup(mWifiP2pChannel, + firstNetworkId, + mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + }); + + persistentGroups = getPersistentGroups(); + assertNotNull(persistentGroups); + assertEquals(0, persistentGroups.getGroupList().size()); + + resetResponse(mMyResponse); + mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); + assertNotNull(mMySync.expectedNetworkInfo); + assertEquals(NetworkInfo.DetailedState.CONNECTED, + mMySync.expectedNetworkInfo.getDetailedState()); + + resetResponse(mMyResponse); + mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + + resetResponse(mMyResponse); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + mWifiP2pManager.factoryReset(mWifiP2pChannel, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + }); + + persistentGroups = getPersistentGroups(); + assertNotNull(persistentGroups); + assertEquals(0, persistentGroups.getGroupList().size()); + } + + public void testP2pListening() { + if (!setupWifiP2p()) { + return; + } + + resetResponse(mMyResponse); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + mWifiP2pManager.setWifiP2pChannels(mWifiP2pChannel, 6, 11, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + }); + + resetResponse(mMyResponse); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + mWifiP2pManager.startListening(mWifiP2pChannel, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + }); + + resetResponse(mMyResponse); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + mWifiP2pManager.stopListening(mWifiP2pChannel, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + }); + } + + public void testP2pService() { + if (!setupWifiP2p()) { + return; + } + + // This only store the listener to the WifiP2pManager internal variable, nothing to fail. + mWifiP2pManager.setServiceResponseListener(mWifiP2pChannel, + new WifiP2pManager.ServiceResponseListener() { + @Override + public void onServiceAvailable( + int protocolType, byte[] responseData, WifiP2pDevice srcDevice) { + } + }); + + resetResponse(mMyResponse); + List services = new ArrayList(); + services.add("urn:schemas-upnp-org:service:AVTransport:1"); + services.add("urn:schemas-upnp-org:service:ConnectionManager:1"); + WifiP2pServiceInfo rendererService = WifiP2pUpnpServiceInfo.newInstance( + "6859dede-8574-59ab-9332-123456789011", + "urn:schemas-upnp-org:device:MediaRenderer:1", + services); + mWifiP2pManager.addLocalService(mWifiP2pChannel, + rendererService, + mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + + resetResponse(mMyResponse); + mWifiP2pManager.removeLocalService(mWifiP2pChannel, + rendererService, + mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + + resetResponse(mMyResponse); + mWifiP2pManager.clearLocalServices(mWifiP2pChannel, + mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + } } From 73f2d68b301094e421f5f9cf9fe986ae2c15b55a Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 10 Mar 2020 16:33:24 +0800 Subject: [PATCH 0774/1415] Wifi: add CTS tests for WifiP2pWfdInfo Bug: 150979414 Test: atest android.net.wifi.p2p.cts.WifiP2pWfdInfoTest Change-Id: I8537c68ede48a5990695da1261b58bc26d255ef1 --- .../net/wifi/p2p/cts/WifiP2pWfdInfoTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pWfdInfoTest.java diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pWfdInfoTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pWfdInfoTest.java new file mode 100644 index 0000000000..75df5bf928 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pWfdInfoTest.java @@ -0,0 +1,50 @@ +/* + * 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.wifi.p2p.cts; + +import android.net.wifi.p2p.WifiP2pWfdInfo; +import android.test.AndroidTestCase; + +public class WifiP2pWfdInfoTest extends AndroidTestCase { + + private final int TEST_DEVICE_TYPE = WifiP2pWfdInfo.DEVICE_TYPE_WFD_SOURCE; + private final boolean TEST_DEVICE_ENABLE_STATUS = true; + private final boolean TEST_SESSION_STATUS = true; + private final int TEST_CONTROL_PORT = 9999; + private final int TEST_MAX_THROUGHPUT = 1024; + private final boolean TEST_CONTENT_PROTECTION_SUPPORTED_STATUS = true; + + public void testWifiP2pWfdInfo() { + WifiP2pWfdInfo info = new WifiP2pWfdInfo(); + + info.setDeviceType(TEST_DEVICE_TYPE); + info.setEnabled(TEST_DEVICE_ENABLE_STATUS); + info.setSessionAvailable(true); + info.setControlPort(TEST_CONTROL_PORT); + info.setMaxThroughput(TEST_MAX_THROUGHPUT); + info.setContentProtectionSupported(true); + + WifiP2pWfdInfo copiedInfo = new WifiP2pWfdInfo(info); + assertEquals(TEST_DEVICE_TYPE, copiedInfo.getDeviceType()); + assertEquals(TEST_DEVICE_ENABLE_STATUS, copiedInfo.isEnabled()); + assertEquals(TEST_SESSION_STATUS, copiedInfo.isSessionAvailable()); + assertEquals(TEST_CONTROL_PORT, copiedInfo.getControlPort()); + assertEquals(TEST_MAX_THROUGHPUT, copiedInfo.getMaxThroughput()); + assertEquals(TEST_CONTENT_PROTECTION_SUPPORTED_STATUS, + copiedInfo.isContentProtectionSupported()); + } +} From 2344863d542963908fc874ea11c6fc16c834bbd6 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 10 Mar 2020 16:47:15 +0800 Subject: [PATCH 0775/1415] Wifi: add CTS tests for WifiP2pInfo Bug: 150979333 Test: atest android.net.wifi.p2p.cts.WifiP2pInfoTest Change-Id: Ib62975af468182e79a19bf5ce7125876af26ef7d --- .../net/wifi/p2p/cts/WifiP2pInfoTest.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pInfoTest.java diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pInfoTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pInfoTest.java new file mode 100644 index 0000000000..8504f15e43 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pInfoTest.java @@ -0,0 +1,60 @@ +/* + * 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.wifi.p2p.cts; + +import android.net.InetAddresses; +import android.net.wifi.p2p.WifiP2pInfo; +import android.test.AndroidTestCase; + +public class WifiP2pInfoTest extends AndroidTestCase { + + public String TEST_GROUP_OWNER_ADDRESS = "192.168.43.1"; + + public void testWifiP2pInfoNoGroup() { + WifiP2pInfo info = new WifiP2pInfo(); + info.groupFormed = false; + + WifiP2pInfo copiedInfo = new WifiP2pInfo(info); + assertEquals(info.groupFormed, copiedInfo.groupFormed); + assertEquals(info.isGroupOwner, copiedInfo.isGroupOwner); + assertEquals(info.groupOwnerAddress, copiedInfo.groupOwnerAddress); + } + + public void testWifiP2pInfoGroupOwner() { + WifiP2pInfo info = new WifiP2pInfo(); + info.groupFormed = true; + info.isGroupOwner = true; + info.groupOwnerAddress = InetAddresses.parseNumericAddress(TEST_GROUP_OWNER_ADDRESS); + + WifiP2pInfo copiedInfo = new WifiP2pInfo(info); + assertEquals(info.groupFormed, copiedInfo.groupFormed); + assertEquals(info.isGroupOwner, copiedInfo.isGroupOwner); + assertEquals(info.groupOwnerAddress, copiedInfo.groupOwnerAddress); + } + + public void testWifiP2pInfoGroupClient() { + WifiP2pInfo info = new WifiP2pInfo(); + info.groupFormed = true; + info.isGroupOwner = false; + info.groupOwnerAddress = InetAddresses.parseNumericAddress(TEST_GROUP_OWNER_ADDRESS); + + WifiP2pInfo copiedInfo = new WifiP2pInfo(info); + assertEquals(info.groupFormed, copiedInfo.groupFormed); + assertEquals(info.isGroupOwner, copiedInfo.isGroupOwner); + assertEquals(info.groupOwnerAddress, copiedInfo.groupOwnerAddress); + } +} From 1ba90ccc4e925d44c01bab0d88b331d3c45c2c88 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 10 Mar 2020 16:52:19 +0800 Subject: [PATCH 0776/1415] Wifi: add CTS tests for WifiP2pConfig WpsInfo copy constructor is also covered in WifiP2pConfig copy constructor. Bug: 150978801 Bug: 150973669 Test: android.net.wifi.p2p.cts.WifiP2pConfigTest Change-Id: I3d94ddecb5b6b131117bbf2eebe8057a542e17e5 --- .../net/wifi/p2p/cts/WifiP2pConfigTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java index ee7e1ed5bf..0a2a2e6779 100644 --- a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java +++ b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java @@ -28,6 +28,24 @@ public class WifiP2pConfigTest extends AndroidTestCase { private static final int TEST_OWNER_FREQ = 2447; private static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff"; + public void testWifiP2pConfigCopyConstructor() { + WifiP2pConfig config = new WifiP2pConfig.Builder() + .setNetworkName(TEST_NETWORK_NAME) + .setPassphrase(TEST_PASSPHRASE) + .setGroupOperatingBand(TEST_OWNER_BAND) + .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) + .enablePersistentMode(true) + .build(); + + WifiP2pConfig copiedConfig = new WifiP2pConfig(config); + + assertEquals(copiedConfig.deviceAddress, TEST_DEVICE_ADDRESS); + assertEquals(copiedConfig.getNetworkName(), TEST_NETWORK_NAME); + assertEquals(copiedConfig.getPassphrase(), TEST_PASSPHRASE); + assertEquals(copiedConfig.getGroupOwnerBand(), TEST_OWNER_BAND); + assertEquals(copiedConfig.getNetworkId(), WifiP2pGroup.NETWORK_ID_PERSISTENT); + } + public void testWifiP2pConfigBuilderForPersist() { WifiP2pConfig config = new WifiP2pConfig.Builder() .setNetworkName(TEST_NETWORK_NAME) From a35ad640dbcffb9b04ea6cc8a6a43ea59cf1439d Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 10 Mar 2020 17:58:07 +0800 Subject: [PATCH 0777/1415] Wifi: add CTS tests for WifiP2pGroup Bug: 150979638 Test: atest android.net.wifi.cts.ConcurrencyTest Change-Id: I5e9c994129e9eebf7c079c5a064991463afb417d --- .../android/net/wifi/cts/ConcurrencyTest.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java index f7ea750d18..d91bce8319 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java @@ -31,6 +31,7 @@ import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.net.wifi.p2p.WifiP2pDevice; +import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pInfo; import android.net.wifi.p2p.WifiP2pManager; @@ -79,6 +80,7 @@ public class ConcurrencyTest extends AndroidTestCase { public WifiP2pInfo p2pInfo; public String deviceName; public WifiP2pGroupList persistentGroups; + public WifiP2pGroup group = new WifiP2pGroup(); } private WifiManager mWifiManager; @@ -267,6 +269,7 @@ public class ConcurrencyTest extends AndroidTestCase { responseObj.p2pInfo = null; responseObj.deviceName = null; responseObj.persistentGroups = null; + responseObj.group = null; } } @@ -480,7 +483,27 @@ public class ConcurrencyTest extends AndroidTestCase { assertTrue(mMyResponse.p2pInfo.groupFormed); assertTrue(mMyResponse.p2pInfo.isGroupOwner); - mWifiP2pManager.removeGroup(mWifiP2pChannel, null); + resetResponse(mMyResponse); + mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, + new WifiP2pManager.GroupInfoListener() { + @Override + public void onGroupInfoAvailable(WifiP2pGroup group) { + synchronized (mMyResponse) { + mMyResponse.group = new WifiP2pGroup(group); + mMyResponse.valid = true; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertNotNull(mMyResponse.group); + assertNotEquals(0, mMyResponse.group.getFrequency()); + assertTrue(mMyResponse.group.getNetworkId() >= 0); + + resetResponse(mMyResponse); + mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); } private String getDeviceName() { From 5e7dcbd1f1dfcb8e0121de974be9fb90d1843c8e Mon Sep 17 00:00:00 2001 From: xshu Date: Mon, 9 Mar 2020 18:10:21 -0700 Subject: [PATCH 0778/1415] CTS - getFactoryMacAddresses Verify that a valid MAC address is being returned when wifi is connected. Bug: 151117962 Test: atest WifiManagerTest Change-Id: Ia615c7c2787d6312d598f0bb1ef183a4b914541d --- .../android/net/wifi/cts/WifiManagerTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 5bdd7124ea..e89f17566d 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -32,6 +32,7 @@ import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.net.util.MacAddressUtils; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.MacAddress; @@ -42,6 +43,7 @@ import android.net.NetworkRequest; import android.net.wifi.ScanResult; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.net.wifi.WifiNetworkConnectionStatistics; @@ -1392,6 +1394,34 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Tests {@link WifiManager#getFactoryMacAddresses()} returns at least one valid MAC address. + */ + public void testGetFactoryMacAddresses() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + TestActionListener actionListener = new TestActionListener(mLock); + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + int newNetworkId = INVALID_NETWORK_ID; + try { + uiAutomation.adoptShellPermissionIdentity(); + // Obtain the factory MAC address + String[] macAddresses = mWifiManager.getFactoryMacAddresses(); + assertTrue("At list one MAC address should be returned.", macAddresses.length > 0); + try { + MacAddress mac = MacAddress.fromString(macAddresses[0]); + assertNotEquals(WifiInfo.DEFAULT_MAC_ADDRESS, mac); + assertFalse(MacAddressUtils.isMulticastAddress(mac)); + } catch (IllegalArgumentException e) { + fail("Factory MAC address is invalid"); + } + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } + private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback { private final Object mLock; public boolean onStateChangedCalled = false; From 4f36f56f5aa23888db7e2e3feb70eeb4bcac12e0 Mon Sep 17 00:00:00 2001 From: xshu Date: Tue, 10 Mar 2020 13:46:56 -0700 Subject: [PATCH 0779/1415] CTS - feature support API for MAC randomization and PNO scans Bug: 151117962 Test: atest WifiManagerTest Change-Id: Icf2580fbea514af9d524a5f384a1b6834d1d08bb --- .../android/net/wifi/cts/WifiManagerTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index e89f17566d..f4c20e3072 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -1422,6 +1422,39 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Tests {@link WifiManager#isApMacRandomizationSupported()} does not crash. + */ + public void testIsApMacRandomizationSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + mWifiManager.isApMacRandomizationSupported(); + } + + /** + * Tests {@link WifiManager#isConnectedMacRandomizationSupported()} does not crash. + */ + public void testIsConnectedMacRandomizationSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + mWifiManager.isConnectedMacRandomizationSupported(); + } + + /** + * Tests {@link WifiManager#isPreferredNetworkOffloadSupported()} does not crash. + */ + public void testIsPreferredNetworkOffloadSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + mWifiManager.isPreferredNetworkOffloadSupported(); + } + private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback { private final Object mLock; public boolean onStateChangedCalled = false; From dc03d15189b3d6914bb75374bfa616662ed5ac26 Mon Sep 17 00:00:00 2001 From: Ashwini Oruganti Date: Tue, 10 Mar 2020 13:49:18 -0700 Subject: [PATCH 0780/1415] Tethering: Add an exported flag in manifest With b/150232615, we will need an explicit value set for the exported flag when intent filters are present, as the default behavior is changing for S+. This change adds the value reflecting the previous default to the manifest. Bug: 150232615 Test: TH Change-Id: I25b55378df393cd4fb8932b7ae64f97eb9f1aa8e --- Tethering/AndroidManifest.xml | 3 ++- Tethering/AndroidManifest_InProcess.xml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index c71d0d7bc5..b6d88c9512 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml @@ -44,7 +44,8 @@ android:extractNativeLibs="false" android:persistent="true"> + android:permission="android.permission.MAINLINE_NETWORK_STACK" + android:exported="true"> diff --git a/Tethering/AndroidManifest_InProcess.xml b/Tethering/AndroidManifest_InProcess.xml index 02ea551254..bf1f001e03 100644 --- a/Tethering/AndroidManifest_InProcess.xml +++ b/Tethering/AndroidManifest_InProcess.xml @@ -24,7 +24,8 @@ + android:permission="android.permission.MAINLINE_NETWORK_STACK" + android:exported="true"> From ca7e475a863248fb9804470c1a8593a5ae360278 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Tue, 10 Mar 2020 12:55:11 -0700 Subject: [PATCH 0781/1415] [CTS] Add EasyConnectStatusCallback tests Add EasyConnectStatusCallbackTest CTS tests. Bug: 150967363 Test: atest EasyConnectStatusCallbackTest Change-Id: I3d938728ad3df36c8840d3f2fec67905c8929bbf --- .../cts/EasyConnectStatusCallbackTest.java | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java diff --git a/tests/cts/net/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java b/tests/cts/net/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java new file mode 100644 index 0000000000..eef50a0059 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java @@ -0,0 +1,170 @@ +/* + * 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.wifi.cts; + +import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_TIMEOUT; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK; +import static android.net.wifi.WifiManager.EASY_CONNECT_NETWORK_ROLE_STA; + +import android.app.UiAutomation; +import android.content.Context; +import android.net.wifi.EasyConnectStatusCallback; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.HandlerThread; +import android.test.AndroidTestCase; +import android.util.SparseArray; +import androidx.test.platform.app.InstrumentationRegistry; + +import java.util.concurrent.Executor; + +public class EasyConnectStatusCallbackTest extends AndroidTestCase { + private static final String TEST_SSID = "\"testSsid\""; + private static final String TEST_PASSPHRASE = "\"testPassword\""; + private static final int TEST_WAIT_DURATION_MS = 12_000; // Long delay is necessary, see below + private WifiManager mWifiManager; + private static final String TEST_DPP_URI = + "DPP:C:81/1;I:Easy_Connect_Demo;M:000102030405;" + + "K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACDmtXD1Sz6/5B4YRdmTkbkkFLDwk8f0yRnfm1Go" + + "kpx/0=;;"; + private final HandlerThread mHandlerThread = new HandlerThread("EasyConnectTest"); + protected final Executor mExecutor; + { + mHandlerThread.start(); + mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper())); + } + private final Object mLock = new Object(); + private boolean mOnFailureCallback = false; + private int mErrorCode; + + @Override + protected void setUp() throws Exception { + super.setUp(); + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + private EasyConnectStatusCallback mEasyConnectStatusCallback = new EasyConnectStatusCallback() { + @Override + public void onEnrolleeSuccess(int newNetworkId) { + + } + + @Override + public void onConfiguratorSuccess(int code) { + + } + + @Override + public void onProgress(int code) { + + } + + @Override + public void onFailure(int code) { + synchronized (mLock) { + mOnFailureCallback = true; + mErrorCode = code; + mLock.notify(); + } + } + + public void onFailure(int code, String ssid, SparseArray channelListArray, + int[] operatingClassArray) { + synchronized (mLock) { + mOnFailureCallback = true; + mErrorCode = code; + mLock.notify(); + } + } + }; + + /** + * Tests {@link android.net.wifi.EasyConnectStatusCallback} class. + * + * Since Easy Connect requires 2 devices, start Easy Connect session and expect an error. + */ + public void testConfiguratorInitiatorOnFailure() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + WifiConfiguration config; + config = new WifiConfiguration(); + config.SSID = TEST_SSID; + config.preSharedKey = TEST_PASSPHRASE; + config.setSecurityParams(SECURITY_TYPE_PSK); + int networkId = mWifiManager.addNetwork(config); + assertFalse(networkId == -1); + synchronized (mLock) { + mWifiManager.startEasyConnectAsConfiguratorInitiator(TEST_DPP_URI, networkId, + EASY_CONNECT_NETWORK_ROLE_STA, mExecutor, mEasyConnectStatusCallback); + // Note: A long delay is necessary because there is no enrollee, and the system + // tries to discover it. We will wait for a timeout error to occur. + mLock.wait(TEST_WAIT_DURATION_MS); + } + mWifiManager.removeNetwork(networkId); + assertTrue(mOnFailureCallback); + assertEquals(EASY_CONNECT_EVENT_FAILURE_TIMEOUT, mErrorCode); + mWifiManager.stopEasyConnectSession(); + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } + + /** + * Tests {@link android.net.wifi.EasyConnectStatusCallback} class. + * + * Since Easy Connect requires 2 devices, start Easy Connect session and expect an error. + */ + public void testEnrolleeInitiatorOnFailure() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + synchronized (mLock) { + mWifiManager.startEasyConnectAsEnrolleeInitiator(TEST_DPP_URI, mExecutor, + mEasyConnectStatusCallback); + // Note: A long delay is necessary because there is no configurator, and the system + // tries to discover it. We will wait for a timeout error to occur. + mLock.wait(TEST_WAIT_DURATION_MS); + } + assertTrue(mOnFailureCallback); + assertEquals(EASY_CONNECT_EVENT_FAILURE_TIMEOUT, mErrorCode); + mWifiManager.stopEasyConnectSession(); + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } +} From d747cb0c6cf68fdfe50581e022ec11ffc711f8f5 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 12 Mar 2020 17:12:45 +0800 Subject: [PATCH 0782/1415] Wifi: add CTS tests for WifiP2pDevice Bug: 150978692 Test: atest android.net.wifi.p2p.cts.WifiP2pDeviceTest Change-Id: I57edae1cebd906326ba5316cc63c217e384f26d9 --- .../net/wifi/p2p/cts/WifiP2pDeviceTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java new file mode 100644 index 0000000000..1510d7cc1c --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java @@ -0,0 +1,38 @@ +/* + * 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.wifi.p2p.cts; + +import android.net.InetAddresses; +import android.net.wifi.p2p.WifiP2pDevice; +import android.test.AndroidTestCase; + +public class WifiP2pDeviceTest extends AndroidTestCase { + + public void testDefaultWpsMethodSupportCheck() { + WifiP2pDevice dev = new WifiP2pDevice(); + + assertFalse(dev.wpsPbcSupported()); + assertFalse(dev.wpsDisplaySupported()); + assertFalse(dev.wpsKeypadSupported()); + } + + public void testDefaultDeviceCapabilityCheck() { + WifiP2pDevice dev = new WifiP2pDevice(); + + assertFalse(dev.isServiceDiscoveryCapable()); + } +} From 05dabbbdfd34f1bae0d0b2d52222fb3ff02982d3 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 12 Mar 2020 17:45:26 +0800 Subject: [PATCH 0783/1415] Wifi: add CTS tests for WifiP2pServiceRequest Bug: 150978189 Test: atest android.net.wifi.p2p.cts.WifiP2pServiceRequestTest Change-Id: Ib77d2362b079ae44b98e139447cc020e663a9ad2 --- .../p2p/cts/WifiP2pServiceRequestTest.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java new file mode 100644 index 0000000000..b363b1ed19 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java @@ -0,0 +1,75 @@ +/* + * 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.wifi.p2p.cts; + +import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; +import android.net.wifi.p2p.nsd.WifiP2pServiceRequest; +import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +public class WifiP2pServiceRequestTest extends AndroidTestCase { + + private final int TEST_UPNP_VERSION = 0x10; + private final String TEST_UPNP_QUERY = "ssdp:all"; + + private String bin2HexStr(byte[] data) { + StringBuffer sb = new StringBuffer(); + for (byte b: data) { + sb.append(String.format(Locale.US, "%02x", b & 0xff)); + } + return sb.toString(); + } + + public void testValidRawRequest() throws IllegalArgumentException { + StringBuffer sb = new StringBuffer(); + sb.append(String.format(Locale.US, "%02x", TEST_UPNP_VERSION)); + sb.append(bin2HexStr(TEST_UPNP_QUERY.getBytes())); + + WifiP2pServiceRequest rawRequest = + WifiP2pServiceRequest.newInstance( + WifiP2pServiceInfo.SERVICE_TYPE_UPNP, + sb.toString()); + + WifiP2pUpnpServiceRequest upnpRequest = + WifiP2pUpnpServiceRequest.newInstance( + TEST_UPNP_QUERY); + + assertEquals(rawRequest, upnpRequest); + } + + public void testInvalidRawRequest() { + StringBuffer sb = new StringBuffer(); + sb.append(String.format(Locale.US, "%02x", TEST_UPNP_VERSION)); + sb.append(bin2HexStr(TEST_UPNP_QUERY.getBytes())); + sb.append("x"); + + try { + WifiP2pServiceRequest request = + WifiP2pServiceRequest.newInstance( + WifiP2pServiceInfo.SERVICE_TYPE_UPNP, sb.toString()); + fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + return; + } + } +} From 5752baa6b6ccf38206ca07994a7a0f14c3121655 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 6 Mar 2020 14:50:48 +0800 Subject: [PATCH 0784/1415] [SP21] Address comments for API council review about aosp/1172143 Test: atest FrameworksNetTests ImsPhoneCallTrackerTest Test: atest TetheringTests NetworkStackTests Test: m doc-comment-check-docs Fix: 148552904 Change-Id: I141393f229e772d2eb9f7c156849e379bd71b845 --- .../tethering/OffloadController.java | 45 +++++++------- .../tethering/OffloadControllerTest.java | 62 +++++++++---------- 2 files changed, 54 insertions(+), 53 deletions(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java index a402ffa473..d43c5c682f 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java @@ -39,8 +39,7 @@ import android.net.RouteInfo; import android.net.netlink.ConntrackMessage; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkSocket; -import android.net.netstats.provider.AbstractNetworkStatsProvider; -import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.net.util.SharedLog; import android.os.Handler; import android.provider.Settings; @@ -89,8 +88,8 @@ public class OffloadController { private final Handler mHandler; private final OffloadHardwareInterface mHwInterface; private final ContentResolver mContentResolver; - private final @NonNull OffloadTetheringStatsProvider mStatsProvider; - private final @Nullable NetworkStatsProviderCallback mStatsProviderCb; + @Nullable + private final OffloadTetheringStatsProvider mStatsProvider; private final SharedLog mLog; private final HashMap mDownstreams; private boolean mConfigInitialized; @@ -124,19 +123,18 @@ public class OffloadController { mHandler = h; mHwInterface = hwi; mContentResolver = contentResolver; - mStatsProvider = new OffloadTetheringStatsProvider(); mLog = log.forSubComponent(TAG); mDownstreams = new HashMap<>(); mExemptPrefixes = new HashSet<>(); mLastLocalPrefixStrs = new HashSet<>(); - NetworkStatsProviderCallback providerCallback = null; + OffloadTetheringStatsProvider provider = new OffloadTetheringStatsProvider(); try { - providerCallback = nsm.registerNetworkStatsProvider( - getClass().getSimpleName(), mStatsProvider); + nsm.registerNetworkStatsProvider(getClass().getSimpleName(), provider); } catch (RuntimeException e) { Log.wtf(TAG, "Cannot register offload stats provider: " + e); + provider = null; } - mStatsProviderCb = providerCallback; + mStatsProvider = provider; } /** Start hardware offload. */ @@ -185,7 +183,7 @@ public class OffloadController { // and we need to synchronize stats and limits between // software and hardware forwarding. updateStatsForAllUpstreams(); - mStatsProvider.pushTetherStats(); + if (mStatsProvider != null) mStatsProvider.pushTetherStats(); } @Override @@ -198,7 +196,7 @@ public class OffloadController { // limits set take into account any software tethering // traffic that has been happening in the meantime. updateStatsForAllUpstreams(); - mStatsProvider.pushTetherStats(); + if (mStatsProvider != null) mStatsProvider.pushTetherStats(); // [2] (Re)Push all state. computeAndPushLocalPrefixes(UpdateType.FORCE); pushAllDownstreamState(); @@ -217,10 +215,12 @@ public class OffloadController { // TODO: rev the HAL so that it provides an interface name. updateStatsForCurrentUpstream(); - mStatsProvider.pushTetherStats(); - // Push stats to service does not cause the service react to it immediately. - // Inform the service about limit reached. - if (mStatsProviderCb != null) mStatsProviderCb.onLimitReached(); + if (mStatsProvider != null) { + mStatsProvider.pushTetherStats(); + // Push stats to service does not cause the service react to it + // immediately. Inform the service about limit reached. + mStatsProvider.notifyLimitReached(); + } } @Override @@ -263,13 +263,17 @@ public class OffloadController { } @VisibleForTesting - class OffloadTetheringStatsProvider extends AbstractNetworkStatsProvider { + class OffloadTetheringStatsProvider extends NetworkStatsProvider { // These stats must only ever be touched on the handler thread. @NonNull private NetworkStats mIfaceStats = new NetworkStats(0L, 0); @NonNull private NetworkStats mUidStats = new NetworkStats(0L, 0); + /** + * A helper function that collect tether stats from local hashmap. Note that this does not + * invoke binder call. + */ @VisibleForTesting @NonNull NetworkStats getTetherStats(@NonNull StatsType how) { @@ -287,7 +291,7 @@ public class OffloadController { } @Override - public void setLimit(String iface, long quotaBytes) { + public void onSetLimit(String iface, long quotaBytes) { // Listen for all iface is necessary since upstream might be changed after limit // is set. mHandler.post(() -> { @@ -315,13 +319,12 @@ public class OffloadController { */ public void pushTetherStats() { // TODO: remove the accumulated stats and report the diff from HAL directly. - if (null == mStatsProviderCb) return; final NetworkStats ifaceDiff = getTetherStats(StatsType.STATS_PER_IFACE).subtract(mIfaceStats); final NetworkStats uidDiff = getTetherStats(StatsType.STATS_PER_UID).subtract(mUidStats); try { - mStatsProviderCb.onStatsUpdated(0 /* token */, ifaceDiff, uidDiff); + notifyStatsUpdated(0 /* token */, ifaceDiff, uidDiff); mIfaceStats = mIfaceStats.add(ifaceDiff); mUidStats = mUidStats.add(uidDiff); } catch (RuntimeException e) { @@ -330,7 +333,7 @@ public class OffloadController { } @Override - public void requestStatsUpdate(int token) { + public void onRequestStatsUpdate(int token) { // Do not attempt to update stats by querying the offload HAL // synchronously from a different thread than the Handler thread. http://b/64771555. mHandler.post(() -> { @@ -340,7 +343,7 @@ public class OffloadController { } @Override - public void setAlert(long quotaBytes) { + public void onSetAlert(long quotaBytes) { // TODO: Ask offload HAL to notify alert without stopping traffic. } } diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java index 7e62e5aca9..1d100e6321 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java @@ -33,6 +33,8 @@ import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals; +import static junit.framework.Assert.assertNotNull; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -61,8 +63,7 @@ import android.net.LinkProperties; import android.net.NetworkStats; import android.net.NetworkStats.Entry; import android.net.RouteInfo; -import android.net.netstats.provider.AbstractNetworkStatsProvider; -import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.util.SharedLog; import android.os.Handler; import android.os.Looper; @@ -108,12 +109,10 @@ public class OffloadControllerTest { @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; @Mock private NetworkStatsManager mStatsManager; - @Mock private NetworkStatsProviderCallback mTetherStatsProviderCb; + @Mock private INetworkStatsProviderCallback mTetherStatsProviderCb; + private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider; private final ArgumentCaptor mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class); - private final ArgumentCaptor - mTetherStatsProviderCaptor = - ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); private final ArgumentCaptor mControlCallbackCaptor = ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class); private MockContentResolver mContentResolver; @@ -126,8 +125,6 @@ public class OffloadControllerTest { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolver); FakeSettingsProvider.clearSettingsProvider(); - when(mStatsManager.registerNetworkStatsProvider(anyString(), any())) - .thenReturn(mTetherStatsProviderCb); } @After public void tearDown() throws Exception { @@ -154,8 +151,14 @@ public class OffloadControllerTest { private OffloadController makeOffloadController() throws Exception { OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()), mHardware, mContentResolver, mStatsManager, new SharedLog("test")); + final ArgumentCaptor + tetherStatsProviderCaptor = + ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); verify(mStatsManager).registerNetworkStatsProvider(anyString(), - mTetherStatsProviderCaptor.capture()); + tetherStatsProviderCaptor.capture()); + mTetherStatsProvider = tetherStatsProviderCaptor.getValue(); + assertNotNull(mTetherStatsProvider); + mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb); return offload; } @@ -413,9 +416,6 @@ public class OffloadControllerTest { final OffloadController offload = makeOffloadController(); offload.start(); - final OffloadController.OffloadTetheringStatsProvider provider = - mTetherStatsProviderCaptor.getValue(); - final String ethernetIface = "eth1"; final String mobileIface = "rmnet_data0"; @@ -443,8 +443,8 @@ public class OffloadControllerTest { inOrder.verify(mHardware, times(1)).getForwardedStats(eq(mobileIface)); // Verify that the fetched stats are stored. - final NetworkStats ifaceStats = provider.getTetherStats(STATS_PER_IFACE); - final NetworkStats uidStats = provider.getTetherStats(STATS_PER_UID); + final NetworkStats ifaceStats = mTetherStatsProvider.getTetherStats(STATS_PER_IFACE); + final NetworkStats uidStats = mTetherStatsProvider.getTetherStats(STATS_PER_UID); final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2) .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321)); @@ -462,13 +462,12 @@ public class OffloadControllerTest { NetworkStats.class); // Force pushing stats update to verify the stats reported. - provider.pushTetherStats(); - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), - ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); + mTetherStatsProvider.pushTetherStats(); + verify(mTetherStatsProviderCb, times(1)) + .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStatsCaptor.getValue())); assertTrue(orderInsensitiveEquals(expectedUidStats, uidStatsCaptor.getValue())); - when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( new ForwardedStats(100000, 100000)); offload.setUpstreamLinkProperties(null); @@ -483,8 +482,8 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); // Verify that the stored stats is accumulated. - final NetworkStats ifaceStatsAccu = provider.getTetherStats(STATS_PER_IFACE); - final NetworkStats uidStatsAccu = provider.getTetherStats(STATS_PER_UID); + final NetworkStats ifaceStatsAccu = mTetherStatsProvider.getTetherStats(STATS_PER_IFACE); + final NetworkStats uidStatsAccu = mTetherStatsProvider.getTetherStats(STATS_PER_UID); final NetworkStats expectedIfaceStatsAccu = new NetworkStats(0L, 2) .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321)); @@ -498,7 +497,7 @@ public class OffloadControllerTest { // Verify that only diff of stats is reported. reset(mTetherStatsProviderCb); - provider.pushTetherStats(); + mTetherStatsProvider.pushTetherStats(); final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000)); @@ -506,8 +505,8 @@ public class OffloadControllerTest { final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), - ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); + verify(mTetherStatsProviderCb, times(1)) + .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue())); assertTrue(orderInsensitiveEquals(expectedUidStatsDiff, uidStatsCaptor.getValue())); } @@ -529,19 +528,18 @@ public class OffloadControllerTest { lp.setInterfaceName(ethernetIface); offload.setUpstreamLinkProperties(lp); - AbstractNetworkStatsProvider provider = mTetherStatsProviderCaptor.getValue(); final InOrder inOrder = inOrder(mHardware); when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); // Applying an interface quota to the current upstream immediately sends it to the hardware. - provider.setLimit(ethernetIface, ethernetLimit); + mTetherStatsProvider.onSetLimit(ethernetIface, ethernetLimit); waitForIdle(); inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit); inOrder.verifyNoMoreInteractions(); // Applying an interface quota to another upstream does not take any immediate action. - provider.setLimit(mobileIface, mobileLimit); + mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); @@ -554,7 +552,7 @@ public class OffloadControllerTest { // Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set // to Long.MAX_VALUE. - provider.setLimit(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); + mTetherStatsProvider.onSetLimit(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); waitForIdle(); inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE); @@ -562,7 +560,7 @@ public class OffloadControllerTest { when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false); lp.setInterfaceName(ethernetIface); offload.setUpstreamLinkProperties(lp); - provider.setLimit(mobileIface, mobileLimit); + mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); @@ -571,7 +569,7 @@ public class OffloadControllerTest { when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false); lp.setInterfaceName(mobileIface); offload.setUpstreamLinkProperties(lp); - provider.setLimit(mobileIface, mobileLimit); + mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware).getForwardedStats(ethernetIface); inOrder.verify(mHardware).stopOffloadControl(); @@ -587,7 +585,7 @@ public class OffloadControllerTest { OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); callback.onStoppedLimitReached(); - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); } @Test @@ -691,7 +689,7 @@ public class OffloadControllerTest { verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); // TODO: verify the exact stats reported. - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); verifyNoMoreInteractions(mTetherStatsProviderCb); verifyNoMoreInteractions(mHardware); } @@ -756,7 +754,7 @@ public class OffloadControllerTest { // Verify forwarded stats behaviour. verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); verifyNoMoreInteractions(mTetherStatsProviderCb); // TODO: verify local prefixes and downstreams are also pushed to the HAL. From 97eb4abfed7b58de97e597e69b0b9962e42cca96 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 12 Mar 2020 16:41:15 -0700 Subject: [PATCH 0785/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I8c6eed7de942d3b4d67ad1205ccabf5852ef928f --- Tethering/res/values-af/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-am/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ar/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-as/strings.xml | 8 -------- Tethering/res/values-az/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-b+sr+Latn/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-be/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-bg/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-bn/strings.xml | 8 -------- Tethering/res/values-bs/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ca/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-cs/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-da/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-de/strings.xml | 8 -------- Tethering/res/values-el/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-en-rAU/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-en-rCA/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-en-rGB/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-en-rIN/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-en-rXC/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-es-rUS/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-es/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-et/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-eu/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-fa/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-fi/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-fr-rCA/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-fr/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-gl/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-gu/strings.xml | 8 -------- Tethering/res/values-hi/strings.xml | 8 -------- Tethering/res/values-hr/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-hu/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-hy/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-in/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-is/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-it/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-iw/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ja/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ka/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-kk/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-km/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-kn/strings.xml | 8 -------- Tethering/res/values-ko/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ky/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-lo/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-lt/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-lv/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-mk/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ml/strings.xml | 8 -------- Tethering/res/values-mn/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-mr/strings.xml | 8 -------- Tethering/res/values-ms/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-my/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-nb/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ne/strings.xml | 8 -------- Tethering/res/values-nl/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-or/strings.xml | 8 -------- Tethering/res/values-pa/strings.xml | 8 -------- Tethering/res/values-pl/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-pt-rBR/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-pt-rPT/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-pt/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ro/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ru/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-si/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-sk/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-sl/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-sq/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-sr/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-sv/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-sw/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ta/strings.xml | 8 -------- Tethering/res/values-te/strings.xml | 8 -------- Tethering/res/values-th/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-tl/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-tr/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-uk/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-ur/strings.xml | 8 -------- Tethering/res/values-uz/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-vi/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-zh-rCN/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-zh-rHK/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-zh-rTW/strings.xml | 24 ++++++++++++++++++---- Tethering/res/values-zu/strings.xml | 24 ++++++++++++++++++---- 85 files changed, 1420 insertions(+), 396 deletions(-) delete mode 100644 Tethering/res/values-as/strings.xml delete mode 100644 Tethering/res/values-bn/strings.xml delete mode 100644 Tethering/res/values-de/strings.xml delete mode 100644 Tethering/res/values-gu/strings.xml delete mode 100644 Tethering/res/values-hi/strings.xml delete mode 100644 Tethering/res/values-kn/strings.xml delete mode 100644 Tethering/res/values-ml/strings.xml delete mode 100644 Tethering/res/values-mr/strings.xml delete mode 100644 Tethering/res/values-ne/strings.xml delete mode 100644 Tethering/res/values-or/strings.xml delete mode 100644 Tethering/res/values-pa/strings.xml delete mode 100644 Tethering/res/values-ta/strings.xml delete mode 100644 Tethering/res/values-te/strings.xml delete mode 100644 Tethering/res/values-ur/strings.xml diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index 1258805378..f06d1a208f 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -1,8 +1,24 @@ + + - "Verbinding of Wi-Fi-warmkol aktief" - "Tik om op te stel." - "Verbinding is gedeaktiveer" - "Kontak jou administrateur vir besonderhede" + "Verbinding of warmkol is aktief" + "Tik om op te stel." + "Verbinding is gedeaktiveer" + "Kontak jou administrateur vir besonderhede" + "Warmkol- en verbindingstatus" diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 9c36192257..aa0e693449 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -1,8 +1,24 @@ + + - "መሰካት ወይም ገባሪ ድረስ ነጥብ" - "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" - "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" + "ለማዋቀር መታ ያድርጉ።" + "እንደ ሞደም መሰካት ተሰናክሏል" + "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 9f84ce4090..ce7372085b 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -1,8 +1,24 @@ + + - "النطاق أو نقطة الاتصال نشطة" - "انقر للإعداد." - "تم إيقاف التوصيل" - "اتصل بالمشرف للحصول على التفاصيل" + "النطاق نشط أو نقطة الاتصال نشطة" + "انقر للإعداد." + "التوصيل متوقف." + "تواصَل مع المشرف للحصول على التفاصيل." + "حالة نقطة الاتصال والتوصيل" diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml deleted file mode 100644 index 8855822e7c..0000000000 --- a/Tethering/res/values-as/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে" - "ছেট আপ কৰিবলৈ টিপক।" - "টেডাৰিং অক্ষম কৰি থোৱা হৈছে" - "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" - diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index eba50eb636..82661f48e8 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -1,8 +1,24 @@ + + - "Tezerinq və ya hotspot aktivdir" - "Quraşdırmaq üçün tıklayın." - "Birləşmə deaktivdir" - "Məlumat üçün adminlə əlaqə saxlayın" + "Birləşmə və ya hotspot aktivdir" + "Ayarlamaq üçün toxunun." + "Birləşmə deaktivdir" + "Detallar üçün adminlə əlaqə saxlayın" + "Hotspot & birləşmə statusu" diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 5b0e488ba5..0f1fb9e159 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -1,8 +1,24 @@ + + - "Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot" - "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" - "Potražite detalje od administratora" + "Privezivanje ili hotspot je aktivan" + "Dodirnite da biste podesili." + "Privezivanje je onemogućeno" + "Potražite detalje od administratora" + "Status hotspota i privezivanja" diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 5966c7155e..31c6957a3c 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -1,8 +1,24 @@ + + - "USB-мадэм або хот-спот Wi-Fi актыўныя" - "Дакраніцеся, каб наладзіць." - "Рэжым мадэма адключаны" - "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Мадэм або хот-спот актыўныя" + "Дакраніцеся, каб наладзіць." + "Рэжым мадэма выключаны" + "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Стан \"Хот-спот і мадэм\"" diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index ed58d7311a..22d03202f5 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -1,8 +1,24 @@ + + - "Има активна споделена връзка или безжична точка за достъп" - "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" - "Свържете се с администратора си за подробности" + "Има активна споделена връзка или точка за достъп" + "Докоснете, за да настроите." + "Функцията за тетъринг е деактивирана" + "Свържете се с администратора си за подробности" + "Състояние на функцията за точка за достъп и тетъринг" diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml deleted file mode 100644 index 8d9880aa9a..0000000000 --- a/Tethering/res/values-bn/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "টিথারিং বা হটস্পট সক্রিয় আছে" - "সেট-আপ করার জন্য আলতো চাপুন৷" - "টিথারিং অক্ষম করা আছে" - "বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন" - diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index 2361b9dd38..f22180d4d7 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -1,8 +1,24 @@ + + - "Uređaj dijeli vezu ili djeluje kao pristupna tačka" - "Dodirnite za postavke" - "Povezivanje putem mobitela je onemogućeno" - "Kontaktirajte svog administratora za dodatne detalje" + "Aktivno je povezivanje putem mobitela ili pristupna tačka" + "Dodirnite da postavite." + "Povezivanje putem mobitela je onemogućeno" + "Kontaktirajte svog administratora za detalje" + "Status pristupne tačke i povezivanja putem mobitela" diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index 6752b519e2..a91a9b4fbc 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -1,8 +1,24 @@ + + - "Compartició de xarxa o punt d\'accés Wi-Fi activat" - "Toca per configurar." - "La compartició de xarxa està desactivada" - "Contacta amb el teu administrador per obtenir més informació" + "Compartició de xarxa o punt d\'accés Wi‑Fi activat" + "Toca per configurar." + "La compartició de xarxa està desactivada" + "Contacta amb el teu administrador per obtenir més informació" + "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5fdd53adf1..4a8ce53b4c 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -1,8 +1,24 @@ + + - "Sdílené připojení nebo hotspot je aktivní." - "Klepnutím zahájíte nastavení." - "Tethering je zakázán" - "O podrobnosti požádejte administrátora" + "Tethering nebo hotspot je aktivní" + "Klepnutím zahájíte nastavení." + "Tethering je zakázán" + "O podrobnosti požádejte administrátora" + "Stav hotspotu a tetheringu" diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 2775dfa551..1fe048bf58 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -1,8 +1,24 @@ + + - "Netdeling eller hotspot er aktivt" - "Tryk for at konfigurere" - "Netdeling er deaktiveret" - "Kontakt din administrator for at få oplysninger" + "Netdeling eller hotspot er aktivt" + "Tryk for at konfigurere." + "Netdeling er deaktiveret" + "Kontakt din administrator for at få oplysninger" + "Status for hotspot og netdeling" diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml deleted file mode 100644 index 9046cd5e11..0000000000 --- a/Tethering/res/values-de/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "Tethering oder Hotspot aktiv" - "Zum Einrichten tippen." - "Tethering ist deaktiviert" - "Bitte wende dich für weitere Informationen an den Administrator" - diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3b9f53733b..045d707e82 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -1,8 +1,24 @@ + + - "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" - "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" - "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" + "Πατήστε για ρύθμιση." + "Η σύνδεση είναι απενεργοποιημένη" + "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 56b88a5fb3..14bf2aa88f 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 56b88a5fb3..14bf2aa88f 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 56b88a5fb3..14bf2aa88f 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 56b88a5fb3..14bf2aa88f 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 7f47fc89d2..43f504c244 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -1,8 +1,24 @@ + + - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎Tethering is disabled‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index e4618b8cec..8706a93e67 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -1,8 +1,24 @@ + + - "Anclaje a red o zona activa conectados" - "Presiona para configurar." - "Se inhabilitó la conexión mediante dispositivo portátil" - "Para obtener más información, comunícate con el administrador" + "Anclaje a red o zona activa conectados" + "Presiona para configurar esta opción." + "Se inhabilitó la conexión mediante dispositivo portátil" + "Para obtener más información, comunícate con el administrador" + "Estado del hotspot y la conexión mediante dispositivo portátil" diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 8dc1575ce8..67f8f2eb3d 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -1,8 +1,24 @@ + + - "Compartir conexión/Zona Wi-Fi activada" - "Toca para configurar." - "La conexión compartida está inhabilitada" - "Ponte en contacto con el administrador para obtener más información" + "Conexión compartida o punto de acceso activos" + "Toca para configurar." + "La conexión compartida está inhabilitada" + "Solicita más información a tu administrador" + "Estado del punto de acceso y de la conexión compartida" diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index 872c8a74cc..1ebf7b124d 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -1,8 +1,24 @@ + + - "Jagamine või kuumkoht on aktiivne" - "Puudutage seadistamiseks." - "Jagamine on keelatud" - "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Jagamine või kuumkoht on aktiivne" + "Puudutage seadistamiseks." + "Jagamine on keelatud" + "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Kuumkoha ja jagamise olek" diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index 6c4605e616..8e39d4789e 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -1,8 +1,24 @@ + + - "Konexioa partekatzea edo sare publikoa aktibo" - "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" - "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Konexioa partekatzea edo sare publikoa aktibo" + "Sakatu konfiguratzeko." + "Desgaituta dago konexioa partekatzeko aukera" + "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Sare publikoaren eta konexioa partekatzeko eginbidearen egoera" diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index bc2ee23609..ee722ffbe7 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -1,8 +1,24 @@ + + - "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" - "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" - "برای جزئیات، با سرپرستتان تماس بگیرید" + "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" + "برای راه‌اندازی ضربه بزنید." + "اشتراک‌گذاری اینترنت غیرفعال است" + "برای جزئیات، با سرپرستتان تماس بگیرید" + "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index ff0fca6502..fae2e8e9a2 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -1,8 +1,24 @@ + + - "Internetin jakaminen tai yhteyspiste käytössä" - "Määritä napauttamalla." - "Yhteyden jakaminen poistettu käytöstä" - "Kysy lisätietoja järjestelmänvalvojalta." + "Yhteyden jakaminen tai hotspot käytössä" + "Ota käyttöön napauttamalla." + "Yhteyden jakaminen on poistettu käytöstä" + "Pyydä lisätietoja järjestelmänvalvojalta" + "Hotspotin ja yhteyden jakamisen tila" diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 1f5df0ee0c..afe5df8c5b 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -1,8 +1,24 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Touchez pour configurer." - "Le partage de connexion est désactivé" - "Communiquez avec votre administrateur pour obtenir plus de détails" + "Partage de connexion ou point d\'accès sans fil activé" + "Touchez pour configurer." + "Le partage de connexion est désactivé" + "Communiquez avec votre administrateur pour obtenir plus de détails" + "Point d\'accès et partage de connexion" diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index daf7c9d830..4d54be124b 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -1,8 +1,24 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Appuyez ici pour configurer." - "Le partage de connexion est désactivé" - "Pour en savoir plus, contactez votre administrateur" + "Partage de connexion ou point d\'accès activé" + "Appuyez pour effectuer la configuration." + "Le partage de connexion est désactivé" + "Pour en savoir plus, contactez votre administrateur" + "État du point d\'accès et du partage de connexion" diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 0d16a1de09..8f803e9cda 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -1,8 +1,24 @@ + + - "Conexión compartida ou zona wifi activada" - "Tocar para configurar." - "A conexión compartida está desactivada" - "Contacta co administrador para obter información" + "Conexión compartida ou zona wifi activada" + "Toca para configurar." + "A conexión compartida está desactivada" + "Contacta co administrador para obter información" + "Estado da zona wifi e da conexión compartida" diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml deleted file mode 100644 index 9d6b02f85f..0000000000 --- a/Tethering/res/values-gu/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય" - "સેટ કરવા માટે ટૅપ કરો." - "ટિથરિંગ અક્ષમ કરેલ છે" - "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" - diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml deleted file mode 100644 index 9c29d9a8f9..0000000000 --- a/Tethering/res/values-hi/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "टेदरिंग या हॉटस्‍पॉट सक्रिय" - "सेट करने के लिए टैप करें." - "टेदरिंग अक्षम है" - "जानकारी के लिए अपने एडमिन से संपर्क करें" - diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index d0d25bb755..9727bc9dc4 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -1,8 +1,24 @@ + + - "Ograničenje ili aktivan hotspot" - "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" - "Obratite se administratoru da biste saznali pojedinosti" + "Modemsko povezivanje ili žarišna točka aktivni" + "Dodirnite da biste postavili." + "Modemsko je povezivanje onemogućeno" + "Obratite se administratoru da biste saznali pojedinosti" + "Status žarišne točke i modemskog povezivanja" diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index 3129659923..ce4ccbec6c 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -1,8 +1,24 @@ + + - "Megosztás vagy aktív hotspot" - "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" - "A részletekért forduljon rendszergazdájához" + "Megosztás vagy aktív hotspot" + "Koppintson a beállításhoz." + "Az internetmegosztás le van tiltva" + "A részletekért forduljon rendszergazdájához" + "Hotspot és internetmegosztás állapota" diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index 8ba6435fd5..b4a68483af 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -1,8 +1,24 @@ + + - "Մոդեմի ռեժիմը միացված է" - "Հպեք՝ կարգավորելու համար:" - "Մոդեմի ռեժիմն անջատված է" - "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Մոդեմի ռեժիմը միացված է" + "Հպեք՝ կարգավորելու համար։" + "Մոդեմի ռեժիմն անջատված է" + "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 1e093ab237..6f33685eb9 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering (Penambatan) atau hotspot aktif" - "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" - "Hubungi admin untuk mengetahui detailnya" + "Tethering atau hotspot aktif" + "Ketuk untuk menyiapkan." + "Tethering dinonaktifkan" + "Hubungi admin untuk mengetahui detailnya" + "Status hotspot & tethering" diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index f5769d5344..c149818a56 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -1,8 +1,24 @@ + + - "Kveikt á tjóðrun eða aðgangsstað" - "Ýttu til að setja upp." - "Slökkt er á tjóðrun" - "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Kveikt á tjóðrun eða aðgangsstað" + "Ýttu til að setja upp." + "Slökkt er á tjóðrun" + "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Staða heits reits og tjóðrunar" diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index e0b3724325..09d0c92ce6 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering oppure hotspot attivo" - "Tocca per impostare." - "Tethering disattivato" - "Contatta il tuo amministratore per avere informazioni dettagliate" + "Hotspot o tethering attivo" + "Tocca per impostare." + "Tethering disattivato" + "Contatta il tuo amministratore per avere informazioni dettagliate" + "Stato hotspot e tethering" diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c002c44b23..101fb514b4 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -1,8 +1,24 @@ + + - "שיתוף אינטרנט פעיל" - "הקש כדי להגדיר." - "שיתוף האינטרנט בין ניידים מושבת" - "לפרטים, יש לפנות למנהל המערכת" + "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" + "יש להקיש כדי להגדיר." + "שיתוף האינטרנט בין מכשירים מושבת" + "לפרטים, יש לפנות למנהל המערכת" + "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index 314bde00df..214780dfa4 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -1,8 +1,24 @@ + + - "テザリングまたはアクセスポイントが有効です" - "タップしてセットアップします。" - "テザリングは無効に設定されています" - "詳しくは、管理者にお問い合わせください" + "テザリングまたはアクセス ポイントが有効です" + "タップしてセットアップします。" + "テザリングは無効に設定されています" + "詳しくは、管理者にお問い合わせください" + "アクセス ポイントとテザリングのステータス" diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 7bbd81d343..68dcecc174 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -1,8 +1,24 @@ + + - "ტეტერინგი ან უსადენო ქსელი აქტიურია" - "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" - "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "ტეტერინგი ან უსადენო ქსელი აქტიურია" + "შეეხეთ დასაყენებლად." + "ტეტერინგი გათიშულია" + "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "უსადენო ქსელის და ტეტერინგის სტატუსი" diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 7fd87a1596..39de166545 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -1,8 +1,24 @@ + + - "Тетеринг немесе хотспот қосулы" - "Реттеу үшін түртіңіз." - "Тетеринг өшірілді" - "Мәліметтерді әкімшіден алыңыз" + "Тетеринг немесе хотспот қосулы" + "Реттеу үшін түртіңіз." + "Тетеринг өшірілді." + "Мәліметтерді әкімшіден алыңыз." + "Хотспот және тетеринг күйі" diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 2f85224679..be0f0aa69e 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -1,8 +1,24 @@ + + - "ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម" - "ប៉ះដើម្បីកំណត់" - "ការភ្ជាប់​ត្រូវបានបិទ" - "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត" + "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" + "ចុច​ដើម្បី​រៀបចំ។" + "ការភ្ជាប់​ត្រូវបានបិទ" + "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" + "ស្ថានភាពការភ្ជាប់ និងហតស្ប៉ត" diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml deleted file mode 100644 index f11a83ea40..0000000000 --- a/Tethering/res/values-kn/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" - "ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" - "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" - diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index 57f24f5b1a..7ce45a24ef 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -1,8 +1,24 @@ + + - "테더링 또는 핫스팟 사용" - "설정하려면 탭하세요." - "테더링이 사용 중지됨" - "자세한 정보는 관리자에게 문의하세요." + "테더링 또는 핫스팟 사용" + "설정하려면 탭하세요." + "테더링이 사용 중지됨" + "자세한 정보는 관리자에게 문의하세요." + "핫스팟 및 테더링 상태" diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 79854859d4..9a5088e44e 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -1,8 +1,24 @@ + + - "Жалгаштыруу же хотспот жандырылган" - "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" - "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Жалгаштыруу же хотспот жандырылган" + "Жөндөө үчүн таптап коюңуз." + "Жалгаштыруу функциясы өчүрүлгөн" + "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Хотспот жана байланыш түйүнүүн статусу" diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index 78f1585f60..7384237356 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -1,8 +1,24 @@ + + - "ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ" - "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" - "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" + "ແຕະເພື່ອຕັ້ງຄ່າ." + "ການປ່ອຍສັນຍານຖືກປິດໄວ້" + "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index ebff8ac9d1..dc4fdf592d 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -1,8 +1,24 @@ + + - "Susietas ar aktyvus" - "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" - "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" + "Palieskite, kad nustatytumėte." + "Įrenginio kaip modemo naudojimas išjungtas" + "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index 54d0048b52..db0401aa42 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -1,8 +1,24 @@ + + - "Piesaiste vai tīklājs ir aktīvs." - "Pieskarieties, lai iestatītu." - "Piesaiste ir atspējota" - "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Piesaiste vai tīklājs ir aktīvs." + "Pieskarieties, lai to iestatītu." + "Piesaiste ir atspējota" + "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Tīklāja un piesaistes statuss" diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 0fab8aa476..ad255b6201 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -1,8 +1,24 @@ + + - "Поврзувањето или точката на пристап се активни" - "Допрете за поставување." - "Врзувањето е оневозможено" - "Контактирајте со администраторот за детали" + "Активно е врзување или точка на пристап" + "Допрете за поставување." + "Врзувањето е оневозможено" + "Контактирајте со администраторот за детали" + "Статус на точката на пристап и врзувањето" diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml deleted file mode 100644 index fd7e556e38..0000000000 --- a/Tethering/res/values-ml/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" - "സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" - "വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" - diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4596577c5d..ed5b69bb2f 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -1,8 +1,24 @@ + + - "Модем болгох эсвэл идэвхтэй цэг болгох" - "Тохируулахын тулд товшино уу." - "Модем болгох боломжгүй байна" - "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" + "Тохируулахын тулд товшино уу." + "Модем болгохыг идэвхгүй болгосон" + "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Сүлжээний цэг болон модем болгох төлөв" diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml deleted file mode 100644 index 85c9ade4fe..0000000000 --- a/Tethering/res/values-mr/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "टेदरिंग किंवा हॉटस्पॉट सक्रिय" - "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद आहे" - "तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा" - diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index ec6bdbda08..09c5a0e059 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -1,8 +1,24 @@ + + - "Penambatan atau titik panas aktif" - "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" - "Hubungi pentadbir anda untuk maklumat lanjut" + "Penambatan atau tempat liputan aktif" + "Ketik untuk membuat persediaan." + "Penambatan dilumpuhkan" + "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" + "Status tempat liputan & penambatan" diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 83978b67d4..ff96086600 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -1,8 +1,24 @@ + + - "တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" - "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်" - "အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" + "စနစ်ထည့်သွင်းရန် တို့ပါ။" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" + "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 9abf32dd7b..d6e1fee103 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -1,8 +1,24 @@ + + - "Internettdeling eller trådløs sone er aktiv" - "Trykk for å konfigurere." - "Internettdeling er slått av" - "Ta kontakt med administratoren din for å få mer informasjon" + "Internettdeling eller Wi-Fi-sone er aktiv" + "Trykk for å konfigurere." + "Internettdeling er slått av" + "Ta kontakt med administratoren din for å få mer informasjon" + "Status for Wi-Fi-sone og internettdeling" diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml deleted file mode 100644 index c8869298a5..0000000000 --- a/Tethering/res/values-ne/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "टेथर गर्ने वा हटस्पट सक्रिय" - "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङलाई असक्षम पारिएको छ" - "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" - diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 0ec4bff621..49f8fd6ee7 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering of hotspot actief" - "Tik om in te stellen." - "Tethering is uitgeschakeld" - "Neem contact op met je beheerder voor meer informatie" + "Tethering of hotspot actief" + "Tik om in te stellen." + "Tethering is uitgeschakeld" + "Neem contact op met je beheerder voor meer informatie" + "Status van hotspot en tethering" diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml deleted file mode 100644 index 457685795a..0000000000 --- a/Tethering/res/values-or/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି" - "ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।" - "ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି" - "ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" - diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml deleted file mode 100644 index deddf2ea27..0000000000 --- a/Tethering/res/values-pa/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" - "ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ" - "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ" - diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index 48d8468935..98cfbbbddb 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -1,8 +1,24 @@ + + - "Aktywny tethering lub punkt dostępu" - "Kliknij, by skonfigurować." - "Tethering został wyłączony" - "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Aktywny tethering lub punkt dostępu" + "Kliknij, by skonfigurować" + "Tethering został wyłączony" + "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Hotspot i tethering – stan" diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 32c22b8713..338f8fcc1b 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -1,8 +1,24 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 641e22f44f..a06f033f5a 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -1,8 +1,24 @@ + + - "Ligação ponto a ponto ou hotspot activos" - "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." - "Contacte o gestor para obter detalhes." + "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativos" + "Toque para configurar." + "A ligação (à Internet) via telemóvel está desativada." + "Contacte o administrador para obter detalhes." + "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 32c22b8713..338f8fcc1b 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -1,8 +1,24 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index f861f733b4..7480ec559e 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering sau hotspot activ" - "Atingeți ca să configurați." - "Tetheringul este dezactivat" - "Contactați administratorul pentru detalii" + "Tethering sau hotspot activ" + "Atingeți ca să configurați." + "Tetheringul este dezactivat" + "Contactați administratorul pentru detalii" + "Starea hotspotului și a tetheringului" diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 027cb410c5..3153e0b9a0 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -1,8 +1,24 @@ + + - "Включен режим модема" - "Нажмите, чтобы настроить." - "Включить режим модема нельзя" - "Обратитесь к администратору, чтобы узнать подробности." + "Включен режим модема или хот-спот" + "Нажмите, чтобы настроить." + "Использование телефона в качестве модема запрещено" + "Чтобы узнать подробности, обратитесь к администратору." + "Статус хот-спота и режима модема" diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index 7d8599f2c2..2b117bc227 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -1,8 +1,24 @@ + + - "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" - "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" - "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" + "පිහිටුවීමට තට්ටු කරන්න." + "ටෙදරින් අබල කර ඇත" + "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index a8fe297c00..e1db50a41b 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering alebo prístupový bod je aktívny" - "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" - "O podrobnosti požiadajte svojho správcu" + "Tethering alebo prístupový bod je aktívny" + "Klepnutím prejdete na nastavenie." + "Tethering je deaktivovaný" + "O podrobnosti požiadajte svojho správcu" + "Stav hotspotu a tetheringu" diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index b5e5e3856f..bcfe487050 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -1,8 +1,24 @@ + + - "Aktivna povezava z internetom ali dostopna točka sta aktivni" - "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" - "Za podrobnosti se obrnite na skrbnika" + "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" + "Dotaknite se, če želite nastaviti." + "Povezava z internetom prek mobilnega telefona je onemogočena" + "Za podrobnosti se obrnite na skrbnika" + "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index fdd4906cc5..2e56020768 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -1,8 +1,24 @@ + + - "Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive" - "Trokit për ta konfiguruar." - "Lidhja e çiftimit është çaktivizuar" - "Kontakto me administratorin për detaje" + "Ndarja e internetit ose zona e qasjes së internetit është aktive" + "Trokit për ta konfiguruar." + "Ndarja e internetit është çaktivizuar" + "Kontakto me administratorin për detaje" + "Statusi i zonës së qasjes dhe ndarjes së internetit" diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index 9fab345897..09c7c16739 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -1,8 +1,24 @@ + + - "Активно повезивање са интернетом преко мобилног уређаја или хотспот" - "Додирните да бисте подесили." - "Привезивање је онемогућено" - "Потражите детаље од администратора" + "Привезивање или хотспот је активан" + "Додирните да бисте подесили." + "Привезивање је онемогућено" + "Потражите детаље од администратора" + "Статус хотспота и привезивања" diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index 10eeb0fe12..adb6b8184c 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -1,8 +1,24 @@ + + - "Internetdelning eller surfzon aktiverad" - "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" - "Kontakta administratören om du vill veta mer" + "Internetdelning eller surfzon har aktiverats" + "Tryck om du vill konfigurera." + "Internetdelning har inaktiverats" + "Kontakta administratören om du vill veta mer" + "Trådlös surfzon och internetdelning har inaktiverats" diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index 3353963077..3f10e47901 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -1,8 +1,24 @@ + + - "Kushiriki au kusambaza intaneti kumewashwa" - "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" - "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Kusambaza mtandao au mtandaopepe umewashwa" + "Gusa ili uweke mipangilio." + "Umezima kipengele cha kusambaza mtandao" + "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Mtandaopepe na hali ya kusambaza mtandao" diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml deleted file mode 100644 index b1e5cc2413..0000000000 --- a/Tethering/res/values-ta/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது" - "அமைக்க, தட்டவும்." - "இணைப்பு முறை முடக்கப்பட்டுள்ளது" - "விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" - diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml deleted file mode 100644 index aae40dee40..0000000000 --- a/Tethering/res/values-te/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది" - "సెటప్ చేయడానికి నొక్కండి." - "టెథెరింగ్ నిలిపివేయబడింది" - "వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి" - diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index 1b800565ad..33a8b0c592 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -1,8 +1,24 @@ + + - "การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่" - "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" - "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" + "แตะเพื่อตั้งค่า" + "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" + "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 12863f90e1..0f31daf53c 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -1,8 +1,24 @@ + + - "Pagsasama o aktibong hotspot" - "I-tap upang i-set up." - "Naka-disable ang pag-tether" - "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Aktibo ang pag-tether o hotspot" + "I-tap para i-set up." + "Naka-disable ang pag-tether" + "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Status ng hotspot at pag-tether" diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index bfcf1ace2c..aaa264f04d 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -1,8 +1,24 @@ + + - "Tethering veya hotspot etkin" - "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" - "Ayrıntılı bilgi için yöneticinize başvurun" + "Tethering veya hotspot etkin" + "Ayarlamak için dokunun." + "Tethering devre dışı bırakıldı" + "Ayrıntılı bilgi için yöneticinize başvurun" + "Hotspot ve tethering durumu" diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 8e159c0723..875ba84b4e 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -1,8 +1,24 @@ + + - "Прив\'язка чи точка дост. активна" - "Торкніться, щоб налаштувати." - "Використання телефона в режимі модема вимкнено" - "Щоб дізнатися більше, зв’яжіться з адміністратором" + "Модем чи точка доступу активні" + "Натисніть, щоб налаштувати." + "Використання телефона як модема вимкнено" + "Щоб дізнатися більше, зв\'яжіться з адміністратором" + "Статус точки доступу та модема" diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml deleted file mode 100644 index 89195d4aae..0000000000 --- a/Tethering/res/values-ur/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - "ٹیدرنگ یا ہاٹ اسپاٹ فعال" - "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" - "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" - diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 0ac4d4a741..50b3998339 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -1,8 +1,24 @@ + + - "Modem rejimi yoniq" - "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" - "Tafsilotlari uchun administratoringizga murojaat qiling" + "Modem rejimi yoki hotspot yoniq" + "Sozlash uchun bosing." + "Modem rejimi faolsizlantirildi" + "Tafsilotlari uchun administratoringizga murojaat qiling" + "Hotspot va modem rejimi holati" diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 85a4db8aa5..b6e294221c 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -1,8 +1,24 @@ + + - "Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động" - "Nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" - "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Tính năng chia sẻ kết nối hoặc điểm phát sóng đang hoạt động" + "Hãy nhấn để thiết lập." + "Đã tắt tính năng chia sẻ kết nối" + "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Trạng thái điểm phát sóng và trạng thái chia sẻ kết nối" diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index ff1fe03953..55e2f1a76b 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -1,8 +1,24 @@ + + - "网络共享或热点已启用" - "点按即可进行设置。" - "网络共享已停用" - "请与您的管理员联系以了解详情" + "网络共享或热点已启用" + "点按即可设置。" + "网络共享已停用" + "如需了解详情,请与您的管理员联系" + "热点和网络共享状态" diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 0de39fac97..5d4c4e86ff 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -1,8 +1,24 @@ + + - "已啟用網絡共享或熱點" - "輕按即可設定。" - "網絡共享已停用" - "請聯絡您的管理員以瞭解詳情" + "網絡共享或熱點已啟用" + "輕按即可設定。" + "網絡共享已停用" + "請聯絡您的管理員以瞭解詳情" + "熱點和網絡共享狀態" diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9a117bbca4..a6561a2dfe 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -1,8 +1,24 @@ + + - "網路共用或無線基地台已啟用" - "輕觸即可進行設定。" - "數據連線已停用" - "詳情請洽你的管理員" + "數據連線或無線基地台已啟用" + "輕觸即可進行設定。" + "數據連線已停用" + "詳情請洽你的管理員" + "無線基地台與數據連線狀態" diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index 8fe10d86cb..aa65c80df5 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -1,8 +1,24 @@ + + - "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" - "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" - "Xhumana nomphathi wakho ukuze uthole imininingwane" + "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" + "Thepha ukuze usethe." + "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" + "Xhumana nomphathi wakho ukuze uthole imininingwane" + "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" From ad61ab46f7862c7111720ec8081449fe5f674774 Mon Sep 17 00:00:00 2001 From: David Su Date: Thu, 12 Mar 2020 16:16:50 -0700 Subject: [PATCH 0786/1415] CTS WifiManagerTest: Enable scanning if not enabled Previously some Wifi CTS tests would fail if scanning is not enabled. Now we have a new API to enable scanning, so call that if scanning is disabled. Bug: 146661308 Test: atest android.net.wifi.cts.WifiManagerTest Change-Id: I9cc7e54302c7849ce403dbf6f14256a4de3a421d --- .../android/net/wifi/cts/WifiManagerTest.java | 61 ++++++++++++------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index f4c20e3072..870cf72955 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -66,6 +66,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.PollingCheck; import com.android.compatibility.common.util.ShellIdentityUtils; import com.android.compatibility.common.util.SystemUtil; +import com.android.compatibility.common.util.ThrowingRunnable; import java.io.BufferedReader; import java.io.IOException; @@ -76,6 +77,7 @@ import java.net.URL; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -1067,6 +1069,23 @@ public class WifiManagerTest extends AndroidTestCase { } } + private void runWithScanningEnabled(ThrowingRunnable r) throws Exception { + boolean wasScanEnabledForTest = false; + if (!mWifiManager.isScanAlwaysAvailable()) { + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setScanAlwaysAvailable(true)); + wasScanEnabledForTest = true; + } + try { + r.run(); + } finally { + if (wasScanEnabledForTest) { + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setScanAlwaysAvailable(false)); + } + } + } + /** * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled * but location is on. @@ -1085,17 +1104,16 @@ public class WifiManagerTest extends AndroidTestCase { fail("Please enable location for this test - since Marshmallow WiFi scan results are" + " empty when location is disabled!"); } - if(!mWifiManager.isScanAlwaysAvailable()) { - fail("Please enable Wi-Fi scanning for this test!"); - } - setWifiEnabled(false); - turnScreenOn(); - assertWifiScanningIsOn(); - // Toggle screen and verify Wi-Fi scanning is still on. - turnScreenOff(); - assertWifiScanningIsOn(); - turnScreenOn(); - assertWifiScanningIsOn(); + runWithScanningEnabled(() -> { + setWifiEnabled(false); + turnScreenOn(); + assertWifiScanningIsOn(); + // Toggle screen and verify Wi-Fi scanning is still on. + turnScreenOff(); + assertWifiScanningIsOn(); + turnScreenOn(); + assertWifiScanningIsOn(); + }); } /** @@ -1115,17 +1133,16 @@ public class WifiManagerTest extends AndroidTestCase { fail("Please enable location for this test - since Marshmallow WiFi scan results are" + " empty when location is disabled!"); } - if(!mWifiManager.isScanAlwaysAvailable()) { - fail("Please enable Wi-Fi scanning for this test!"); - } - setWifiEnabled(true); - turnScreenOn(); - assertWifiScanningIsOn(); - // Toggle screen and verify Wi-Fi scanning is still on. - turnScreenOff(); - assertWifiScanningIsOn(); - turnScreenOn(); - assertWifiScanningIsOn(); + runWithScanningEnabled(() -> { + setWifiEnabled(true); + turnScreenOn(); + assertWifiScanningIsOn(); + // Toggle screen and verify Wi-Fi scanning is still on. + turnScreenOff(); + assertWifiScanningIsOn(); + turnScreenOn(); + assertWifiScanningIsOn(); + }); } /** From db2a16b8c4fff791d4a7b8b0068ab9c12300b4df Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 12 Mar 2020 15:22:01 +0800 Subject: [PATCH 0787/1415] Give tethering bluetooth privilege permission Permisssion of PanService#setBluetoothTethering is change from BLUETOOTH_ADMIN to BLUETOOTH_PRIVILEGED. Tethering service need bluetooth privilege permission to enable bluetooth tethering. Bug: 146045934 Test: on/off bluetooth tethering Change-Id: Ib87a5d5a5bb49390aa55e52713bb3539d4a52348 --- Tethering/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index c71d0d7bc5..9328611f5d 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml @@ -27,7 +27,7 @@ added to the privileged permissions whitelist for that package. --> - + From dfdf750417f3ec755621f96f173c5d09d2ad9094 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 9 Mar 2020 15:38:45 +0900 Subject: [PATCH 0788/1415] Cleanup the TetheredClients API Add comments to getters as requested in API review, and remove the expirationTime private field that was planned to be replaced with LinkAddress expiration. Test: atest TetheringTests Fixes: 150878126 Change-Id: Iecf65859cdeeaac2fa7b817b4f505c510424ac89 --- .../src/android/net/TetheredClient.java | 41 ++++++++++++------- Tethering/src/android/net/ip/IpServer.java | 7 +++- .../src/android/net/TetheredClientTest.kt | 13 +++++- .../tethering/ConnectedClientsTrackerTest.kt | 17 +++++--- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/Tethering/common/TetheringLib/src/android/net/TetheredClient.java index 8b8b9e57a5..48be0d9642 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheredClient.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheredClient.java @@ -64,16 +64,26 @@ public final class TetheredClient implements Parcelable { dest.writeInt(mTetheringType); } + /** + * Get the MAC address used to identify the client. + */ @NonNull public MacAddress getMacAddress() { return mMacAddress; } + /** + * Get information on the list of addresses that are associated with the client. + */ @NonNull public List getAddresses() { return new ArrayList<>(mAddresses); } + /** + * Get the type of tethering used by the client. + * @return one of the {@code TetheringManager#TETHERING_*} constants. + */ public int getTetheringType() { return mTetheringType; } @@ -115,45 +125,47 @@ public final class TetheredClient implements Parcelable { private final LinkAddress mAddress; @Nullable private final String mHostname; - // TODO: use LinkAddress expiration time once it is supported - private final long mExpirationTime; /** @hide */ public AddressInfo(@NonNull LinkAddress address, @Nullable String hostname) { - this(address, hostname, 0); - } - - /** @hide */ - public AddressInfo(@NonNull LinkAddress address, String hostname, long expirationTime) { this.mAddress = address; this.mHostname = hostname; - this.mExpirationTime = expirationTime; } private AddressInfo(Parcel in) { - this(in.readParcelable(null), in.readString(), in.readLong()); + this(in.readParcelable(null), in.readString()); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeParcelable(mAddress, flags); dest.writeString(mHostname); - dest.writeLong(mExpirationTime); } + /** + * Get the link address (including prefix length and lifetime) used by the client. + * + * This may be an IPv4 or IPv6 address. + */ @NonNull public LinkAddress getAddress() { return mAddress; } + /** + * Get the hostname that was advertised by the client when obtaining its address, if any. + */ @Nullable public String getHostname() { return mHostname; } - /** @hide TODO: use expiration time in LinkAddress */ + /** + * Get the expiration time of the address assigned to the client. + * @hide + */ public long getExpirationTime() { - return mExpirationTime; + return mAddress.getExpirationTime(); } @Override @@ -163,7 +175,7 @@ public final class TetheredClient implements Parcelable { @Override public int hashCode() { - return Objects.hash(mAddress, mHostname, mExpirationTime); + return Objects.hash(mAddress, mHostname); } @Override @@ -173,8 +185,7 @@ public final class TetheredClient implements Parcelable { // Use .equals() for addresses as all changes, including address expiry changes, // should be included. return other.mAddress.equals(mAddress) - && Objects.equals(mHostname, other.mHostname) - && mExpirationTime == other.mExpirationTime; + && Objects.equals(mHostname, other.mHostname); } @NonNull diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 38f8609e21..6c0c432d46 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -24,6 +24,7 @@ import static android.net.util.NetworkConstants.FF; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.net.util.NetworkConstants.asByte; import static android.net.util.TetheringMessageBase.BASE_IPSERVER; +import static android.system.OsConstants.RT_SCOPE_UNIVERSE; import android.net.INetd; import android.net.INetworkStackStatusCallback; @@ -448,7 +449,9 @@ public class IpServer extends StateMachine { final ArrayList leases = new ArrayList<>(); for (DhcpLeaseParcelable lease : leaseParcelables) { final LinkAddress address = new LinkAddress( - intToInet4AddressHTH(lease.netAddr), lease.prefixLength); + intToInet4AddressHTH(lease.netAddr), lease.prefixLength, + 0 /* flags */, RT_SCOPE_UNIVERSE /* as per RFC6724#3.2 */, + lease.expTime /* deprecationTime */, lease.expTime /* expirationTime */); final MacAddress macAddress; try { @@ -460,7 +463,7 @@ public class IpServer extends StateMachine { } final TetheredClient.AddressInfo addressInfo = new TetheredClient.AddressInfo( - address, lease.hostname, lease.expTime); + address, lease.hostname); leases.add(new TetheredClient( macAddress, Collections.singletonList(addressInfo), diff --git a/Tethering/tests/unit/src/android/net/TetheredClientTest.kt b/Tethering/tests/unit/src/android/net/TetheredClientTest.kt index d85389aeb6..a20a0dfd9c 100644 --- a/Tethering/tests/unit/src/android/net/TetheredClientTest.kt +++ b/Tethering/tests/unit/src/android/net/TetheredClientTest.kt @@ -20,6 +20,7 @@ import android.net.InetAddresses.parseNumericAddress import android.net.TetheredClient.AddressInfo import android.net.TetheringManager.TETHERING_BLUETOOTH import android.net.TetheringManager.TETHERING_USB +import android.system.OsConstants.RT_SCOPE_UNIVERSE import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.testutils.assertParcelSane @@ -30,11 +31,19 @@ import kotlin.test.assertNotEquals private val TEST_MACADDR = MacAddress.fromBytes(byteArrayOf(12, 23, 34, 45, 56, 67)) private val TEST_OTHER_MACADDR = MacAddress.fromBytes(byteArrayOf(23, 34, 45, 56, 67, 78)) -private val TEST_ADDR1 = LinkAddress(parseNumericAddress("192.168.113.3"), 24) -private val TEST_ADDR2 = LinkAddress(parseNumericAddress("fe80::1:2:3"), 64) +private val TEST_ADDR1 = makeLinkAddress("192.168.113.3", prefixLength = 24, expTime = 123L) +private val TEST_ADDR2 = makeLinkAddress("fe80::1:2:3", prefixLength = 64, expTime = 456L) private val TEST_ADDRINFO1 = AddressInfo(TEST_ADDR1, "test_hostname") private val TEST_ADDRINFO2 = AddressInfo(TEST_ADDR2, null) +private fun makeLinkAddress(addr: String, prefixLength: Int, expTime: Long) = LinkAddress( + parseNumericAddress(addr), + prefixLength, + 0 /* flags */, + RT_SCOPE_UNIVERSE, + expTime /* deprecationTime */, + expTime /* expirationTime */) + @RunWith(AndroidJUnit4::class) @SmallTest class TetheredClientTest { diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt index 56f3e21cbf..1cdc3bbb99 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt @@ -46,23 +46,28 @@ class ConnectedClientsTrackerTest { private val client1Addr = MacAddress.fromString("01:23:45:67:89:0A") private val client1 = TetheredClient(client1Addr, listOf( - AddressInfo(LinkAddress("192.168.43.44/32"), null /* hostname */, clock.time + 20)), + makeAddrInfo("192.168.43.44/32", null /* hostname */, clock.time + 20)), TETHERING_WIFI) private val wifiClient1 = makeWifiClient(client1Addr) private val client2Addr = MacAddress.fromString("02:34:56:78:90:AB") - private val client2Exp30AddrInfo = AddressInfo( - LinkAddress("192.168.43.45/32"), "my_hostname", clock.time + 30) + private val client2Exp30AddrInfo = makeAddrInfo( + "192.168.43.45/32", "my_hostname", clock.time + 30) private val client2 = TetheredClient(client2Addr, listOf( client2Exp30AddrInfo, - AddressInfo(LinkAddress("2001:db8:12::34/72"), "other_hostname", clock.time + 10)), + makeAddrInfo("2001:db8:12::34/72", "other_hostname", clock.time + 10)), TETHERING_WIFI) private val wifiClient2 = makeWifiClient(client2Addr) private val client3Addr = MacAddress.fromString("03:45:67:89:0A:BC") private val client3 = TetheredClient(client3Addr, - listOf(AddressInfo(LinkAddress("2001:db8:34::34/72"), "other_other_hostname", - clock.time + 10)), + listOf(makeAddrInfo("2001:db8:34::34/72", "other_other_hostname", clock.time + 10)), TETHERING_USB) + private fun makeAddrInfo(addr: String, hostname: String?, expTime: Long) = + LinkAddress(addr).let { + AddressInfo(LinkAddress(it.address, it.prefixLength, it.flags, it.scope, + expTime /* deprecationTime */, expTime /* expirationTime */), hostname) + } + @Test fun testUpdateConnectedClients() { doReturn(emptyList()).`when`(server1).allLeases From aae250f24998f724389f929f2c4d0d37204cf1e8 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Fri, 13 Mar 2020 09:44:46 -0700 Subject: [PATCH 0789/1415] [CTS] Add tests for WPA3/OWE device capability APIs in WifiManager Add CTS coverage for WPA3/OWE device capability APIs in WifiManager: mWifiManager.isEnhancedOpenSupported() mWifiManager.isWpa3SuiteBSupported() mWifiManager.isWpa3SaeSupported() Bug: 151439303 Test: atest WifiManagerTest Change-Id: I5a1510dce1e6d240891ecc18d2aa92509223ac66 --- .../android/net/wifi/cts/WifiManagerTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index f4c20e3072..b92d7259fe 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -1759,4 +1759,37 @@ public class WifiManagerTest extends AndroidTestCase { assertNull(ShellIdentityUtils.invokeWithShellPermissions(mWifiManager::getCurrentNetwork)); } + + /** + * Tests {@link WifiManager#isWpa3SaeSupported()} does not crash. + */ + public void testIsWpa3SaeSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + mWifiManager.isWpa3SaeSupported(); + } + + /** + * Tests {@link WifiManager#isWpa3SuiteBSupported()} does not crash. + */ + public void testIsWpa3SuiteBSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + mWifiManager.isWpa3SuiteBSupported(); + } + + /** + * Tests {@link WifiManager#isEnhancedOpenSupported()} does not crash. + */ + public void testIsEnhancedOpenSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + mWifiManager.isEnhancedOpenSupported(); + } } From 5944b984d2df02209ae2fba40a941b10d464ab14 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Thu, 12 Mar 2020 17:49:25 -0700 Subject: [PATCH 0790/1415] [CTS] Add test for android.net.wifi.hotspot2 classes Add CTS tests for PasspointConfiguration, Credential, Credential.UserCredential, Credential.CertCredential, Credential.SimCredential, and HomeSp Bug: 150977126 Bug: 150978132 Bug: 150978391 Bug: 150978125 Bug: 150977972 Bug: 150977655 Test: atest WifiHotspot2Test Change-Id: Ia75b489e0d12cd23ac62000de8ddb2b289ded87b --- .../net/wifi/cts/WifiHotspot2Test.java | 331 ++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java new file mode 100644 index 0000000000..12efb00fc4 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java @@ -0,0 +1,331 @@ +/* + * 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.wifi.cts; + +import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE; + +import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.hotspot2.pps.Credential; +import android.net.wifi.hotspot2.pps.HomeSp; +import android.test.AndroidTestCase; + +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Arrays; + +public class WifiHotspot2Test extends AndroidTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Tests {@link PasspointConfiguration#getMeteredOverride()} method. + * + * Test default value + */ + public void testGetMeteredOverride() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); + assertEquals(METERED_OVERRIDE_NONE, passpointConfiguration.getMeteredOverride()); + } + + /** + * Tests {@link PasspointConfiguration#getSubscriptionExpirationTimeMillis()} method. + * + * Test default value + */ + public void testGetSubscriptionExpirationTimeMillis() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); + assertEquals(Long.MIN_VALUE, + passpointConfiguration.getSubscriptionExpirationTimeMillis()); + } + + /** + * Tests {@link PasspointConfiguration#getUniqueId()} method. + * + * Test unique identifier is not null + */ + public void testGetUniqueId() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + PasspointConfiguration passpointConfiguration = createConfig(); + assertNotNull(passpointConfiguration.getUniqueId()); + } + + /** + * Tests {@link PasspointConfiguration#isAutojoinEnabled()} method. + * + * Test default value + */ + public void testIsAutojoinEnabled() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); + assertTrue(passpointConfiguration.isAutojoinEnabled()); + } + + /** + * Tests {@link PasspointConfiguration#isMacRandomizationEnabled()} method. + * + * Test default value + */ + public void testIsMacRandomizationEnabled() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); + assertTrue(passpointConfiguration.isMacRandomizationEnabled()); + } + + /** + * Tests {@link PasspointConfiguration#isOsuProvisioned()} method. + * + * Test default value + */ + public void testIsOsuProvisioned() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + PasspointConfiguration passpointConfiguration = createConfig(); + assertFalse(passpointConfiguration.isOsuProvisioned()); + } + + /** + * Tests {@link PasspointConfiguration#PasspointConfiguration(PasspointConfiguration)} method. + * + * Test the PasspointConfiguration copy constructor + */ + public void testPasspointConfigurationCopyConstructor() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + PasspointConfiguration passpointConfiguration = createConfig(); + PasspointConfiguration copyOfPasspointConfiguration = + new PasspointConfiguration(passpointConfiguration); + assertEquals(passpointConfiguration, copyOfPasspointConfiguration); + } + + /** + * Tests {@link HomeSp#HomeSp(HomeSp)} method. + * + * Test the HomeSp copy constructor + */ + public void testHomeSpCopyConstructor() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + HomeSp homeSp = createHomeSp(); + HomeSp copyOfHomeSp = new HomeSp(homeSp); + assertEquals(copyOfHomeSp, homeSp); + } + + /** + * Tests {@link Credential#Credential(Credential)} method. + * + * Test the Credential copy constructor + */ + public void testCredentialCopyConstructor() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + Credential credential = createCredential(); + Credential copyOfCredential = new Credential(credential); + assertEquals(copyOfCredential, credential); + } + + /** + * Tests {@link Credential.UserCredential#UserCredential(Credential.UserCredential)} method. + * + * Test the Credential.UserCredential copy constructor + */ + public void testUserCredentialCopyConstructor() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + Credential.UserCredential userCredential = new Credential.UserCredential(); + userCredential.setUsername("username"); + userCredential.setPassword("password"); + userCredential.setEapType(21 /* EAP_TTLS */); + userCredential.setNonEapInnerMethod("MS-CHAP"); + + Credential.UserCredential copyOfUserCredential = + new Credential.UserCredential(userCredential); + assertEquals(copyOfUserCredential, userCredential); + } + + /** + * Tests {@link Credential.CertificateCredential#CertificateCredential(Credential.CertificateCredential)} + * method. + * + * Test the Credential.CertificateCredential copy constructor + */ + public void testCertCredentialCopyConstructor() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); + certCredential.setCertType("x509v3"); + + Credential.CertificateCredential copyOfCertificateCredential = + new Credential.CertificateCredential(certCredential); + assertEquals(copyOfCertificateCredential, certCredential); + } + + /** + * Tests {@link Credential.SimCredential#SimCredential(Credential.SimCredential)} + * method. + * + * Test the Credential.SimCredential copy constructor + */ + public void testSimCredentialCopyConstructor() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + Credential.SimCredential simCredential = new Credential.SimCredential(); + simCredential.setImsi("1234*"); + simCredential.setEapType(18/* EAP_SIM */); + + Credential.SimCredential copyOfSimCredential = new Credential.SimCredential(simCredential); + assertEquals(copyOfSimCredential, simCredential); + } + + /** + * Tests {@link Credential#getCaCertificate()} method. + * + * Test that getting a set certificate produces the same value + */ + public void testCredentialGetCertificate() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + Credential credential = new Credential(); + credential.setCaCertificate(FakeKeys.CA_CERT0); + + assertEquals(FakeKeys.CA_CERT0, credential.getCaCertificate()); + } + + /** + * Tests {@link Credential#getClientCertificateChain()} and + * {@link Credential#setCaCertificates(X509Certificate[])} methods. + * + * Test that getting a set client certificate chain produces the same value + */ + public void testCredentialClientCertificateChain() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + Credential credential = new Credential(); + X509Certificate[] certificates = new X509Certificate[] {FakeKeys.CLIENT_CERT}; + credential.setClientCertificateChain(certificates); + + assertTrue(Arrays.equals(certificates, credential.getClientCertificateChain())); + } + + /** + * Tests {@link Credential#getClientPrivateKey()} and + * {@link Credential#setClientPrivateKey(PrivateKey)} methods. + * + * Test that getting a set client private key produces the same value + */ + public void testCredentialSetGetClientPrivateKey() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + Credential credential = new Credential(); + credential.setClientPrivateKey(FakeKeys.RSA_KEY1); + + assertEquals(FakeKeys.RSA_KEY1, credential.getClientPrivateKey()); + } + + /** + * Tests {@link Credential#getClientPrivateKey()} and + * {@link Credential#setClientPrivateKey(PrivateKey)} methods. + * + * Test that getting a set client private key produces the same value + */ + public void testCredentialGetClientPrivateKey() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + Credential credential = new Credential(); + credential.setClientPrivateKey(FakeKeys.RSA_KEY1); + + assertEquals(FakeKeys.RSA_KEY1, credential.getClientPrivateKey()); + } + + private static PasspointConfiguration createConfig() { + PasspointConfiguration config = new PasspointConfiguration(); + config.setHomeSp(createHomeSp()); + config.setCredential(createCredential()); + return config; + } + + private static HomeSp createHomeSp() { + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test.com"); + homeSp.setFriendlyName("friendly name"); + homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66}); + return homeSp; + } + + private static Credential createCredential() { + Credential cred = new Credential(); + cred.setRealm("realm"); + cred.setUserCredential(null); + cred.setCertCredential(null); + cred.setSimCredential(new Credential.SimCredential()); + cred.getSimCredential().setImsi("1234*"); + cred.getSimCredential().setEapType(18/* EAP_SIM */); + cred.setCaCertificate(null); + cred.setClientCertificateChain(null); + cred.setClientPrivateKey(null); + return cred; + } +} From 0d56ba33418f3b20088ce810344748bf98e4c69e Mon Sep 17 00:00:00 2001 From: David Su Date: Fri, 13 Mar 2020 17:17:41 -0700 Subject: [PATCH 0791/1415] CTS: Test DeviceWiphyCapabilities Bug: 151092855 Test: atest android.net.wifi.nl80211.cts.DeviceWiphyCapabilitiesTest Change-Id: I91559a3d65d88fd9e12e2aa9cf7aff6b0dcebb0a --- .../src/android/net/wifi/cts/WifiFeature.java | 4 +- .../cts/DeviceWiphyCapabilitiesTest.java | 99 +++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java index 63fa1dd94c..3e9fef406e 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java @@ -20,12 +20,12 @@ import android.content.Context; import android.content.pm.PackageManager; public class WifiFeature { - static boolean isWifiSupported(Context context) { + public static boolean isWifiSupported(Context context) { PackageManager packageManager = context.getPackageManager(); return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI); } - static boolean isP2pSupported(Context context) { + public static boolean isP2pSupported(Context context) { PackageManager packageManager = context.getPackageManager(); return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT); } diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java new file mode 100644 index 0000000000..d8f5e579da --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java @@ -0,0 +1,99 @@ +/* + * 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.wifi.nl80211.cts; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.wifi.ScanResult; +import android.net.wifi.cts.WifiFeature; +import android.net.wifi.nl80211.DeviceWiphyCapabilities; +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** CTS tests for {@link DeviceWiphyCapabilities}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class DeviceWiphyCapabilitiesTest { + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + // skip tests if Wifi is not supported + assumeTrue(WifiFeature.isWifiSupported(context)); + } + + /** + * Test that a {@link DeviceWiphyCapabilities} object can be serialized and deserialized, + * while keeping its values unchanged. + */ + @Test + public void canSerializeAndDeserialize() { + DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities(); + + capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true); + capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true); + capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false); + + Parcel parcel = Parcel.obtain(); + capa.writeToParcel(parcel, 0); + // Rewind the pointer to the head of the parcel. + parcel.setDataPosition(0); + DeviceWiphyCapabilities capaDeserialized = + DeviceWiphyCapabilities.CREATOR.createFromParcel(parcel); + + assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N)).isTrue(); + assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC)) + .isTrue(); + assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX)) + .isFalse(); + assertThat(capaDeserialized).isEqualTo(capa); + assertThat(capaDeserialized.hashCode()).isEqualTo(capa.hashCode()); + } + + /** Test mapping wifi standard support into channel width support */ + @Test + public void testMappingWifiStandardIntoChannelWidthSupport() { + DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities(); + + capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, false); + capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, false); + capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue(); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isFalse(); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isFalse(); + + capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue(); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isTrue(); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isFalse(); + + capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue(); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isTrue(); + assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isTrue(); + } +} From af95a3aa1ce6980c4f3e3c8a16b45da164bd88ea Mon Sep 17 00:00:00 2001 From: David Su Date: Fri, 13 Mar 2020 17:41:38 -0700 Subject: [PATCH 0792/1415] CTS: Test RadioChainInfo Bug: 150978866 Test: atest android.net.wifi.nl80211.cts.RadioChainInfoTest Change-Id: Ia7b86a4b511bd77abcc629fca78f4b960946cfec --- .../wifi/nl80211/cts/RadioChainInfoTest.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java new file mode 100644 index 0000000000..0a76bdbe32 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java @@ -0,0 +1,83 @@ +/* + * 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.wifi.nl80211.cts; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.wifi.cts.WifiFeature; +import android.net.wifi.nl80211.RadioChainInfo; +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** CTS tests for {@link RadioChainInfo}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class RadioChainInfoTest { + + private static final int TEST_CHAIN_ID = 1; + private static final int TEST_CHAIN_ID2 = 2; + private static final int TEST_LEVEL_DBM = -50; + private static final int TEST_LEVEL_DBM2 = -80; + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + // skip tests if Wifi is not supported + assumeTrue(WifiFeature.isWifiSupported(context)); + } + + @Test + public void testGetters() { + RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM); + assertThat(info.getChainId()).isEqualTo(TEST_CHAIN_ID); + assertThat(info.getLevelDbm()).isEqualTo(TEST_LEVEL_DBM); + } + + @Test + public void canSerializeAndDeserialize() { + RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM); + + Parcel parcel = Parcel.obtain(); + info.writeToParcel(parcel, 0); + // Rewind the pointer to the head of the parcel. + parcel.setDataPosition(0); + RadioChainInfo infoDeserialized = RadioChainInfo.CREATOR.createFromParcel(parcel); + + assertThat(infoDeserialized.getChainId()).isEqualTo(TEST_CHAIN_ID); + assertThat(infoDeserialized.getLevelDbm()).isEqualTo(TEST_LEVEL_DBM); + assertThat(infoDeserialized).isEqualTo(info); + assertThat(infoDeserialized.hashCode()).isEqualTo(info.hashCode()); + } + + @Test + public void testEquals() { + RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM); + RadioChainInfo info2 = new RadioChainInfo(TEST_CHAIN_ID2, TEST_LEVEL_DBM2); + + assertThat(info2).isNotEqualTo(info); + } +} From c365dac402f8b4d430069df1de5e561931ee5a06 Mon Sep 17 00:00:00 2001 From: David Su Date: Fri, 13 Mar 2020 18:16:32 -0700 Subject: [PATCH 0793/1415] CTS: Test PnoNetwork Bug: 150978685 Test: atest android.net.wifi.nl80211.cts.PnoNetworkTest Change-Id: I1cf32ec4d7775f6d8d398fd2039dfe948e7a8d89 --- .../net/wifi/nl80211/cts/PnoNetworkTest.java | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java new file mode 100644 index 0000000000..f3a8f05927 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java @@ -0,0 +1,97 @@ +/* + * 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.wifi.nl80211.cts; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.wifi.cts.WifiFeature; +import android.net.wifi.nl80211.PnoNetwork; +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** CTS tests for {@link PnoNetwork}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class PnoNetworkTest { + + private static final byte[] TEST_SSID = { 's', 's', 'i', 'd' }; + private static final int[] TEST_FREQUENCIES = { 2412, 2417, 5035 }; + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + // skip tests if Wifi is not supported + assumeTrue(WifiFeature.isWifiSupported(context)); + } + + @Test + public void testGetters() { + PnoNetwork network = new PnoNetwork(); + network.setSsid(TEST_SSID); + network.setFrequenciesMhz(TEST_FREQUENCIES); + network.setHidden(true); + + assertThat(network.getSsid()).isEqualTo(TEST_SSID); + assertThat(network.getFrequenciesMhz()).isEqualTo(TEST_FREQUENCIES); + assertThat(network.isHidden()).isTrue(); + } + + @Test + public void canSerializeAndDeserialize() { + PnoNetwork network = new PnoNetwork(); + network.setSsid(TEST_SSID); + network.setFrequenciesMhz(TEST_FREQUENCIES); + network.setHidden(true); + + Parcel parcel = Parcel.obtain(); + network.writeToParcel(parcel, 0); + // Rewind the pointer to the head of the parcel. + parcel.setDataPosition(0); + PnoNetwork networkDeserialized = PnoNetwork.CREATOR.createFromParcel(parcel); + + assertThat(networkDeserialized.getSsid()).isEqualTo(TEST_SSID); + assertThat(networkDeserialized.getFrequenciesMhz()).isEqualTo(TEST_FREQUENCIES); + assertThat(networkDeserialized.isHidden()).isTrue(); + assertThat(networkDeserialized).isEqualTo(network); + assertThat(networkDeserialized.hashCode()).isEqualTo(network.hashCode()); + } + + @Test + public void testEquals() { + PnoNetwork network = new PnoNetwork(); + network.setSsid(TEST_SSID); + network.setFrequenciesMhz(TEST_FREQUENCIES); + network.setHidden(true); + + PnoNetwork network2 = new PnoNetwork(); + network.setSsid(new byte[] { 'a', 's', 'd', 'f'}); + network.setFrequenciesMhz(new int[] { 1, 2, 3 }); + network.setHidden(false); + + assertThat(network2).isNotEqualTo(network); + } +} From 5d4c9c647272caa1e1ffb135e33fa51f5104f7c5 Mon Sep 17 00:00:00 2001 From: David Su Date: Fri, 13 Mar 2020 18:23:52 -0700 Subject: [PATCH 0794/1415] CTS: Test NativeWifiClient Bug: 150978742 Test: atest android.net.wifi.nl80211.cts.NativeWifiClientTest Change-Id: If393bb087cd6296852473d6c8a994e7ee99c6e71 --- .../nl80211/cts/NativeWifiClientTest.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java new file mode 100644 index 0000000000..3149b54abd --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java @@ -0,0 +1,81 @@ +/* + * 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.wifi.nl80211.cts; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.MacAddress; +import android.net.wifi.cts.WifiFeature; +import android.net.wifi.nl80211.NativeWifiClient; +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** CTS tests for {@link NativeWifiClient}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class NativeWifiClientTest { + + private static final byte[] TEST_MAC = { 1, 2, 3, 4, 5, 6 }; + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + // skip tests if Wifi is not supported + assumeTrue(WifiFeature.isWifiSupported(context)); + } + + @Test + public void testGetters() { + NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC)); + + assertThat(client.getMacAddress().toByteArray()).isEqualTo(TEST_MAC); + } + + @Test + public void canSerializeAndDeserialize() { + NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC)); + + Parcel parcel = Parcel.obtain(); + client.writeToParcel(parcel, 0); + // Rewind the pointer to the head of the parcel. + parcel.setDataPosition(0); + NativeWifiClient clientDeserialized = NativeWifiClient.CREATOR.createFromParcel(parcel); + + assertThat(clientDeserialized.getMacAddress().toByteArray()).isEqualTo(TEST_MAC); + assertThat(clientDeserialized).isEqualTo(client); + assertThat(clientDeserialized.hashCode()).isEqualTo(client.hashCode()); + } + + @Test + public void testEquals() { + NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC)); + NativeWifiClient client2 = + new NativeWifiClient(MacAddress.fromBytes(new byte[] { 7, 8, 9, 10, 11, 12 })); + + assertThat(client2).isNotEqualTo(client); + } +} From 0696191fc39295ab152d71aeb9c553ece5c21084 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Fri, 13 Mar 2020 18:38:56 -0700 Subject: [PATCH 0795/1415] [CTS] WifiHotspot2Test: Add more uniqueId tests Add additional test for PasspointConfiguration unique ID. Bug: 151478195 Test: atest WifiHotspot2Test Change-Id: If01cd5ae98b74f3df083af8131c95c3d91f27de9 --- .../net/wifi/cts/WifiHotspot2Test.java | 188 ++++++++++++++---- 1 file changed, 147 insertions(+), 41 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java index 12efb00fc4..96e1caaebe 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java @@ -23,11 +23,18 @@ import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.test.AndroidTestCase; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Arrays; public class WifiHotspot2Test extends AndroidTestCase { + static final int SIM_CREDENTIAL = 0; + static final int USER_CREDENTIAL = 1; + static final int CERT_CREDENTIAL = 2; + @Override protected void setUp() throws Exception { super.setUp(); @@ -44,7 +51,7 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link PasspointConfiguration#getMeteredOverride()} method. - * + *

    * Test default value */ public void testGetMeteredOverride() throws Exception { @@ -58,7 +65,7 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link PasspointConfiguration#getSubscriptionExpirationTimeMillis()} method. - * + *

    * Test default value */ public void testGetSubscriptionExpirationTimeMillis() throws Exception { @@ -73,7 +80,7 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link PasspointConfiguration#getUniqueId()} method. - * + *

    * Test unique identifier is not null */ public void testGetUniqueId() throws Exception { @@ -81,13 +88,32 @@ public class WifiHotspot2Test extends AndroidTestCase { // skip the test if WiFi is not supported return; } - PasspointConfiguration passpointConfiguration = createConfig(); - assertNotNull(passpointConfiguration.getUniqueId()); + + // Create a configuration and make sure the unique ID is not null + PasspointConfiguration passpointConfiguration1 = createConfig(SIM_CREDENTIAL, "123456*", + 18 /* EAP_SIM */); + String uniqueId1 = passpointConfiguration1.getUniqueId(); + assertNotNull(uniqueId1); + + // Create another configuration and make sure the unique ID is not null + PasspointConfiguration passpointConfiguration2 = createConfig(SIM_CREDENTIAL, "567890*", + 23 /* EAP_AKA */); + String uniqueId2 = passpointConfiguration2.getUniqueId(); + assertNotNull(uniqueId2); + + // Make sure the IDs are not equal + assertFalse(uniqueId1.equals(uniqueId2)); + + passpointConfiguration2 = createConfig(USER_CREDENTIAL); + assertFalse(uniqueId1.equals(passpointConfiguration2.getUniqueId())); + + passpointConfiguration2 = createConfig(CERT_CREDENTIAL); + assertFalse(uniqueId1.equals(passpointConfiguration2.getUniqueId())); } /** * Tests {@link PasspointConfiguration#isAutojoinEnabled()} method. - * + *

    * Test default value */ public void testIsAutojoinEnabled() throws Exception { @@ -101,7 +127,7 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link PasspointConfiguration#isMacRandomizationEnabled()} method. - * + *

    * Test default value */ public void testIsMacRandomizationEnabled() throws Exception { @@ -115,7 +141,7 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link PasspointConfiguration#isOsuProvisioned()} method. - * + *

    * Test default value */ public void testIsOsuProvisioned() throws Exception { @@ -123,13 +149,13 @@ public class WifiHotspot2Test extends AndroidTestCase { // skip the test if WiFi is not supported return; } - PasspointConfiguration passpointConfiguration = createConfig(); + PasspointConfiguration passpointConfiguration = createConfig(USER_CREDENTIAL); assertFalse(passpointConfiguration.isOsuProvisioned()); } /** * Tests {@link PasspointConfiguration#PasspointConfiguration(PasspointConfiguration)} method. - * + *

    * Test the PasspointConfiguration copy constructor */ public void testPasspointConfigurationCopyConstructor() throws Exception { @@ -137,7 +163,7 @@ public class WifiHotspot2Test extends AndroidTestCase { // skip the test if WiFi is not supported return; } - PasspointConfiguration passpointConfiguration = createConfig(); + PasspointConfiguration passpointConfiguration = createConfig(USER_CREDENTIAL); PasspointConfiguration copyOfPasspointConfiguration = new PasspointConfiguration(passpointConfiguration); assertEquals(passpointConfiguration, copyOfPasspointConfiguration); @@ -145,7 +171,7 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link HomeSp#HomeSp(HomeSp)} method. - * + *

    * Test the HomeSp copy constructor */ public void testHomeSpCopyConstructor() throws Exception { @@ -160,7 +186,7 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link Credential#Credential(Credential)} method. - * + *

    * Test the Credential copy constructor */ public void testCredentialCopyConstructor() throws Exception { @@ -168,14 +194,14 @@ public class WifiHotspot2Test extends AndroidTestCase { // skip the test if WiFi is not supported return; } - Credential credential = createCredential(); + Credential credential = createCredentialWithSimCredential("123456*", 18 /* EAP_SIM */); Credential copyOfCredential = new Credential(credential); assertEquals(copyOfCredential, credential); } /** * Tests {@link Credential.UserCredential#UserCredential(Credential.UserCredential)} method. - * + *

    * Test the Credential.UserCredential copy constructor */ public void testUserCredentialCopyConstructor() throws Exception { @@ -195,9 +221,10 @@ public class WifiHotspot2Test extends AndroidTestCase { } /** - * Tests {@link Credential.CertificateCredential#CertificateCredential(Credential.CertificateCredential)} + * Tests + * {@link Credential.CertificateCredential#CertificateCredential(Credential.CertificateCredential)} * method. - * + *

    * Test the Credential.CertificateCredential copy constructor */ public void testCertCredentialCopyConstructor() throws Exception { @@ -214,9 +241,8 @@ public class WifiHotspot2Test extends AndroidTestCase { } /** - * Tests {@link Credential.SimCredential#SimCredential(Credential.SimCredential)} - * method. - * + * Tests {@link Credential.SimCredential#SimCredential(Credential.SimCredential)} method. + *

    * Test the Credential.SimCredential copy constructor */ public void testSimCredentialCopyConstructor() throws Exception { @@ -234,7 +260,7 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link Credential#getCaCertificate()} method. - * + *

    * Test that getting a set certificate produces the same value */ public void testCredentialGetCertificate() throws Exception { @@ -249,9 +275,9 @@ public class WifiHotspot2Test extends AndroidTestCase { } /** - * Tests {@link Credential#getClientCertificateChain()} and - * {@link Credential#setCaCertificates(X509Certificate[])} methods. - * + * Tests {@link Credential#getClientCertificateChain()} and {@link + * Credential#setCaCertificates(X509Certificate[])} methods. + *

    * Test that getting a set client certificate chain produces the same value */ public void testCredentialClientCertificateChain() throws Exception { @@ -260,7 +286,7 @@ public class WifiHotspot2Test extends AndroidTestCase { return; } Credential credential = new Credential(); - X509Certificate[] certificates = new X509Certificate[] {FakeKeys.CLIENT_CERT}; + X509Certificate[] certificates = new X509Certificate[]{FakeKeys.CLIENT_CERT}; credential.setClientCertificateChain(certificates); assertTrue(Arrays.equals(certificates, credential.getClientCertificateChain())); @@ -268,8 +294,9 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link Credential#getClientPrivateKey()} and - * {@link Credential#setClientPrivateKey(PrivateKey)} methods. - * + * {@link Credential#setClientPrivateKey(PrivateKey)} + * methods. + *

    * Test that getting a set client private key produces the same value */ public void testCredentialSetGetClientPrivateKey() throws Exception { @@ -285,8 +312,9 @@ public class WifiHotspot2Test extends AndroidTestCase { /** * Tests {@link Credential#getClientPrivateKey()} and - * {@link Credential#setClientPrivateKey(PrivateKey)} methods. - * + * {@link Credential#setClientPrivateKey(PrivateKey)} + * methods. + *

    * Test that getting a set client private key produces the same value */ public void testCredentialGetClientPrivateKey() throws Exception { @@ -300,32 +328,110 @@ public class WifiHotspot2Test extends AndroidTestCase { assertEquals(FakeKeys.RSA_KEY1, credential.getClientPrivateKey()); } - private static PasspointConfiguration createConfig() { + private static PasspointConfiguration createConfig(int type) throws Exception { + return createConfig(type, "123456*", 18 /* EAP_SIM */); + } + + private static PasspointConfiguration createConfig(int type, String imsi, int eapType) + throws Exception { PasspointConfiguration config = new PasspointConfiguration(); config.setHomeSp(createHomeSp()); - config.setCredential(createCredential()); + switch (type) { + default: + case SIM_CREDENTIAL: + config.setCredential( + createCredentialWithSimCredential(imsi, eapType)); + break; + case USER_CREDENTIAL: + config.setCredential(createCredentialWithUserCredential()); + break; + case CERT_CREDENTIAL: + config.setCredential(createCredentialWithCertificateCredential()); + break; + } + return config; } + /** + * Helper function for generating HomeSp for testing. + * + * @return {@link HomeSp} + */ private static HomeSp createHomeSp() { HomeSp homeSp = new HomeSp(); homeSp.setFqdn("test.com"); homeSp.setFriendlyName("friendly name"); - homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66}); + homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66}); return homeSp; } - private static Credential createCredential() { + /** + * Helper function for generating Credential for testing. + * + * @param userCred Instance of UserCredential + * @param certCred Instance of CertificateCredential + * @param simCred Instance of SimCredential + * @param clientCertificateChain Chain of client certificates + * @param clientPrivateKey Client private key + * @param caCerts CA certificates + * @return {@link Credential} + */ + private static Credential createCredential(Credential.UserCredential userCred, + Credential.CertificateCredential certCred, + Credential.SimCredential simCred, + X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey, + X509Certificate... caCerts) { Credential cred = new Credential(); cred.setRealm("realm"); - cred.setUserCredential(null); - cred.setCertCredential(null); - cred.setSimCredential(new Credential.SimCredential()); - cred.getSimCredential().setImsi("1234*"); - cred.getSimCredential().setEapType(18/* EAP_SIM */); - cred.setCaCertificate(null); - cred.setClientCertificateChain(null); - cred.setClientPrivateKey(null); + cred.setUserCredential(userCred); + cred.setCertCredential(certCred); + cred.setSimCredential(simCred); return cred; } + + /** + * Helper function for generating certificate credential for testing. + * + * @return {@link Credential} + */ + private static Credential createCredentialWithCertificateCredential() + throws NoSuchAlgorithmException, CertificateEncodingException { + Credential.CertificateCredential certCred = new Credential.CertificateCredential(); + certCred.setCertType("x509v3"); + certCred.setCertSha256Fingerprint( + MessageDigest.getInstance("SHA-256").digest( + FakeKeys.CLIENT_CERT.getEncoded())); + return createCredential(null, certCred, null, new X509Certificate[]{ + FakeKeys.CLIENT_CERT}, + FakeKeys.RSA_KEY1, FakeKeys.CA_CERT0, + FakeKeys.CA_CERT1); + } + + /** + * Helper function for generating SIM credential for testing. + * + * @return {@link Credential} + */ + private static Credential createCredentialWithSimCredential(String imsi, int eapType) { + Credential.SimCredential simCred = new Credential.SimCredential(); + simCred.setImsi(imsi); + simCred.setEapType(eapType); + return createCredential(null, null, simCred, null, null, (X509Certificate[]) null); + } + + /** + * Helper function for generating user credential for testing. + * + * @return {@link Credential} + */ + private static Credential createCredentialWithUserCredential() { + Credential.UserCredential userCred = new Credential.UserCredential(); + userCred.setUsername("username"); + userCred.setPassword("password"); + userCred.setEapType(21 /* EAP_TTLS */); + userCred.setNonEapInnerMethod("MS-CHAP"); + return createCredential(userCred, null, null, null, null, + FakeKeys.CA_CERT0); + } } From 7c4a11141d66990225026a4e4a41d26461bd1791 Mon Sep 17 00:00:00 2001 From: David Su Date: Fri, 13 Mar 2020 18:43:14 -0700 Subject: [PATCH 0796/1415] CTS: Test PnoSettings Bug: 150978920 Test: atest android.net.wifi.nl80211.cts Change-Id: Id8ec63178e67dac8ab3d5e90689c0a4139c17fc0 --- .../net/wifi/nl80211/cts/PnoSettingsTest.java | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java new file mode 100644 index 0000000000..59f5d993a3 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java @@ -0,0 +1,124 @@ +/* + * 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.wifi.nl80211.cts; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.wifi.cts.WifiFeature; +import android.net.wifi.nl80211.PnoNetwork; +import android.net.wifi.nl80211.PnoSettings; +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +/** CTS tests for {@link PnoSettings}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class PnoSettingsTest { + + private static List createTestNetworks() { + PnoNetwork network1 = new PnoNetwork(); + network1.setSsid(new byte[] { 's', 's', 'i', 'd' }); + network1.setFrequenciesMhz(new int[] { 2412, 2417, 5035 }); + network1.setHidden(true); + + PnoNetwork network2 = new PnoNetwork(); + network2.setSsid(new byte[] { 'a', 's', 'd', 'f' }); + network2.setFrequenciesMhz(new int[] { 2422, 2427, 5040 }); + network2.setHidden(false); + + return Arrays.asList(network1, network2); + } + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + // skip tests if Wifi is not supported + assumeTrue(WifiFeature.isWifiSupported(context)); + } + + @Test + public void testGetters() { + PnoSettings settings = new PnoSettings(); + settings.setIntervalMillis(1000); + settings.setMin2gRssiDbm(-70); + settings.setMin5gRssiDbm(-60); + settings.setMin6gRssiDbm(-50); + settings.setPnoNetworks(createTestNetworks()); + + assertThat(settings.getIntervalMillis()).isEqualTo(1000); + assertThat(settings.getMin2gRssiDbm()).isEqualTo(-70); + assertThat(settings.getMin5gRssiDbm()).isEqualTo(-60); + assertThat(settings.getMin6gRssiDbm()).isEqualTo(-50); + assertThat(settings.getPnoNetworks()).isEqualTo(createTestNetworks()); + } + + @Test + public void canSerializeAndDeserialize() { + PnoSettings settings = new PnoSettings(); + settings.setIntervalMillis(1000); + settings.setMin2gRssiDbm(-70); + settings.setMin5gRssiDbm(-60); + settings.setMin6gRssiDbm(-50); + settings.setPnoNetworks(createTestNetworks()); + + Parcel parcel = Parcel.obtain(); + settings.writeToParcel(parcel, 0); + // Rewind the pointer to the head of the parcel. + parcel.setDataPosition(0); + PnoSettings settingsDeserialized = PnoSettings.CREATOR.createFromParcel(parcel); + + assertThat(settingsDeserialized.getIntervalMillis()).isEqualTo(1000); + assertThat(settingsDeserialized.getMin2gRssiDbm()).isEqualTo(-70); + assertThat(settingsDeserialized.getMin5gRssiDbm()).isEqualTo(-60); + assertThat(settingsDeserialized.getMin6gRssiDbm()).isEqualTo(-50); + assertThat(settingsDeserialized.getPnoNetworks()).isEqualTo(createTestNetworks()); + assertThat(settingsDeserialized).isEqualTo(settings); + assertThat(settingsDeserialized.hashCode()).isEqualTo(settings.hashCode()); + } + + @Test + public void testEquals() { + PnoSettings settings = new PnoSettings(); + settings.setIntervalMillis(1000); + settings.setMin2gRssiDbm(-70); + settings.setMin5gRssiDbm(-60); + settings.setMin6gRssiDbm(-50); + settings.setPnoNetworks(createTestNetworks()); + + PnoSettings settings2 = new PnoSettings(); + settings.setIntervalMillis(2000); + settings.setMin2gRssiDbm(-70); + settings.setMin5gRssiDbm(-60); + settings.setMin6gRssiDbm(-50); + settings.setPnoNetworks(createTestNetworks()); + + assertThat(settings2).isNotEqualTo(settings); + } +} From 205d45f2df300e4b5f3106d9cecc1ef9b47bfc47 Mon Sep 17 00:00:00 2001 From: David Su Date: Fri, 13 Mar 2020 19:12:19 -0700 Subject: [PATCH 0797/1415] CTS: Test WifiNl80211Manager.OemSecurityType Bug: 150979317 Test: atest android.net.wifi.nl80211.cts Change-Id: I1ad45223641e4e4b88be1fc8f5396b6b4f6abd61 --- .../nl80211/cts/WifiNl80211ManagerTest.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java new file mode 100644 index 0000000000..fa8447d2da --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java @@ -0,0 +1,67 @@ +/* + * 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.wifi.nl80211.cts; + +import static android.net.wifi.nl80211.WifiNl80211Manager.OemSecurityType; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.wifi.ScanResult; +import android.net.wifi.cts.WifiFeature; +import android.net.wifi.nl80211.WifiNl80211Manager; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; + +/** CTS tests for {@link WifiNl80211Manager}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class WifiNl80211ManagerTest { + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + // skip tests if Wifi is not supported + assumeTrue(WifiFeature.isWifiSupported(context)); + } + + @Test + public void testOemSecurityTypeConstructor() { + OemSecurityType securityType = new OemSecurityType( + ScanResult.PROTOCOL_WPA, + Arrays.asList(ScanResult.KEY_MGMT_PSK, ScanResult.KEY_MGMT_SAE), + Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP), + ScanResult.CIPHER_CCMP); + + assertThat(securityType.protocol).isEqualTo(ScanResult.PROTOCOL_WPA); + assertThat(securityType.keyManagement) + .isEqualTo(Arrays.asList(ScanResult.KEY_MGMT_PSK, ScanResult.KEY_MGMT_SAE)); + assertThat(securityType.pairwiseCipher) + .isEqualTo(Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP)); + assertThat(securityType.groupCipher).isEqualTo(ScanResult.CIPHER_CCMP); + } +} From 00e72f57df065f0873570c20e175bf0228564e4d Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 12 Mar 2020 17:06:36 -0700 Subject: [PATCH 0798/1415] Add tests for support of Wifi bands and standards This commit adds the CTS support for the following APIs: WifiManager#is5GHzBandSupported() WifiManager#is6GHzBandSupported() WifiManager#isWifiStandardSupported() Bug: 151372208 Test: atest android.net.wifi.cts.WifiManagerTest Change-Id: Id8ff303eba878db222e75bd514f7430efc754edb --- .../android/net/wifi/cts/WifiManagerTest.java | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 46d4e7f371..2e3f18811b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -1809,4 +1809,135 @@ public class WifiManagerTest extends AndroidTestCase { } mWifiManager.isEnhancedOpenSupported(); } + + /** + * Test that {@link WifiManager#is5GHzBandSupported()} returns successfully in + * both WiFi enabled/disabled states. + * Note that the response depends on device support and hence both true/false + * are valid responses. + */ + public void testIs5GhzBandSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + // Check for 5GHz support with wifi enabled + setWifiEnabled(true); + PollingCheck.check( + "Wifi not enabled!", + 20000, + () -> mWifiManager.isWifiEnabled()); + boolean isSupportedEnabled = mWifiManager.is5GHzBandSupported(); + + // Check for 5GHz support with wifi disabled + setWifiEnabled(false); + PollingCheck.check( + "Wifi not disabled!", + 20000, + () -> !mWifiManager.isWifiEnabled()); + boolean isSupportedDisabled = mWifiManager.is5GHzBandSupported(); + + // If Support is true when WiFi is disable, then it has to be true when it is enabled. + // Note, the reverse is a valid case. + if (isSupportedDisabled) { + assertTrue(isSupportedEnabled); + } + } + + /** + * Test that {@link WifiManager#is6GHzBandSupported()} returns successfully in + * both Wifi enabled/disabled states. + * Note that the response depends on device support and hence both true/false + * are valid responses. + */ + public void testIs6GhzBandSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + // Check for 6GHz support with wifi enabled + setWifiEnabled(true); + PollingCheck.check( + "Wifi not enabled!", + 20000, + () -> mWifiManager.isWifiEnabled()); + boolean isSupportedEnabled = mWifiManager.is6GHzBandSupported(); + + // Check for 6GHz support with wifi disabled + setWifiEnabled(false); + PollingCheck.check( + "Wifi not disabled!", + 20000, + () -> !mWifiManager.isWifiEnabled()); + boolean isSupportedDisabled = mWifiManager.is6GHzBandSupported(); + + // If Support is true when WiFi is disable, then it has to be true when it is enabled. + // Note, the reverse is a valid case. + if (isSupportedDisabled) { + assertTrue(isSupportedEnabled); + } + } + + /** + * Test that {@link WifiManager#isWifiStandardSupported()} returns successfully in + * both Wifi enabled/disabled states. The test is to be performed on + * {@link WifiAnnotations}'s {@code WIFI_STANDARD_} + * Note that the response depends on device support and hence both true/false + * are valid responses. + */ + public void testIsWifiStandardsSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + // Check for WiFi standards support with wifi enabled + setWifiEnabled(true); + PollingCheck.check( + "Wifi not enabled!", + 20000, + () -> mWifiManager.isWifiEnabled()); + boolean isLegacySupportedEnabled = + mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY); + boolean is11nSupporedEnabled = + mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N); + boolean is11acSupportedEnabled = + mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC); + boolean is11axSupportedEnabled = + mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX); + + // Check for WiFi standards support with wifi disabled + setWifiEnabled(false); + PollingCheck.check( + "Wifi not disabled!", + 20000, + () -> !mWifiManager.isWifiEnabled()); + + boolean isLegacySupportedDisabled = + mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY); + boolean is11nSupportedDisabled = + mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N); + boolean is11acSupportedDisabled = + mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC); + boolean is11axSupportedDisabled = + mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX); + + if (isLegacySupportedDisabled) { + assertTrue(isLegacySupportedEnabled); + } + + if (is11nSupportedDisabled) { + assertTrue(is11nSupporedEnabled); + } + + if (is11acSupportedDisabled) { + assertTrue(is11acSupportedEnabled); + } + + if (is11axSupportedDisabled) { + assertTrue(is11axSupportedEnabled); + } + } } From 4b896ba32bb7982b1aae05bf08025cd67ac5337c Mon Sep 17 00:00:00 2001 From: markchien Date: Sun, 15 Mar 2020 22:54:57 +0800 Subject: [PATCH 0799/1415] Change TetheringConstants class to final Bug: 151322331 Test: m doc-comment-check-docs Change-Id: Ia02be3d1d91a08ae4a56b25560ed448c96a693db --- .../common/TetheringLib/src/android/net/TetheringConstants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java index a18f5da60c..fd6f171487 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java @@ -32,7 +32,7 @@ import android.os.ResultReceiver; * @hide */ @SystemApi(client = MODULE_LIBRARIES) -public class TetheringConstants { +public final class TetheringConstants { /** An explicit private class to avoid exposing constructor.*/ private TetheringConstants() { } From 7f53eead8b34f59b588d3e5365fae24ef4143a55 Mon Sep 17 00:00:00 2001 From: lesl Date: Wed, 11 Mar 2020 19:30:49 +0800 Subject: [PATCH 0800/1415] cts: Add SoftAp API test in CTS Bug: 150307166 Bug: 150972516 Bug: 150972218 Bug: 150972206 Bug: 150969780 Bug: 150969541 Bug: 150969225 Bug: 150967334 Bug: 150643333 Test: atest android.net.wifi.cts.WifiManagerTest Change-Id: I10e19223b6370c6e149c48f43da45a64e235bccf --- .../android/net/wifi/cts/WifiManagerTest.java | 327 +++++++++++++++++- 1 file changed, 326 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index f4c20e3072..c8ace7c611 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -40,8 +40,12 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; +import android.net.TetheringManager; import android.net.wifi.ScanResult; +import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; +import android.net.wifi.SoftApInfo; +import android.net.wifi.WifiClient; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -73,6 +77,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -90,6 +95,7 @@ public class WifiManagerTest extends AndroidTestCase { private WifiManager mWifiManager; private ConnectivityManager mConnectivityManager; + private TetheringManager mTetheringManager; private WifiLock mWifiLock; private static MySync mMySync; private List mScanResults = null; @@ -97,6 +103,7 @@ public class WifiManagerTest extends AndroidTestCase { private final Object mLock = new Object(); private UiDevice mUiDevice; private boolean mWasVerboseLoggingEnabled; + private SoftApConfiguration mOriginalSoftApConfig = null; // Please refer to WifiManager private static final int MIN_RSSI = -100; @@ -199,7 +206,9 @@ public class WifiManagerTest extends AndroidTestCase { mContext.registerReceiver(mReceiver, mIntentFilter); mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); mConnectivityManager = getContext().getSystemService(ConnectivityManager.class); + mTetheringManager = getContext().getSystemService(TetheringManager.class); assertNotNull(mWifiManager); + assertNotNull(mTetheringManager); // turn on verbose logging for tests mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( @@ -222,6 +231,10 @@ public class WifiManagerTest extends AndroidTestCase { List savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( mWifiManager::getConfiguredNetworks); assertFalse("Need at least one saved network", savedNetworks.isEmpty()); + + // Get original config for restore + mOriginalSoftApConfig = ShellIdentityUtils.invokeWithShellPermissions( + mWifiManager::getSoftApConfiguration); } @Override @@ -237,6 +250,9 @@ public class WifiManagerTest extends AndroidTestCase { mContext.unregisterReceiver(mReceiver); ShellIdentityUtils.invokeWithShellPermissions( () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); + // restore original softap config + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setSoftApConfiguration(mOriginalSoftApConfig)); Thread.sleep(DURATION); super.tearDown(); } @@ -506,6 +522,140 @@ public class WifiManagerTest extends AndroidTestCase { } } + public class TestSoftApCallback implements WifiManager.SoftApCallback { + Object softApLock; + int currentState; + int currentFailureReason; + List currentClientList; + SoftApInfo currentSoftApInfo; + SoftApCapability currentSoftApCapability; + MacAddress lastBlockedClientMacAddress; + int lastBlockedClientReason; + boolean onStateChangedCalled = false; + boolean onSoftapInfoChangedCalled = false; + boolean onSoftApCapabilityChangedCalled = false; + boolean onConnectedClientCalled = false; + boolean onBlockedClientConnectingCalled = false; + + TestSoftApCallback(Object lock) { + softApLock = lock; + } + + public boolean getOnStateChangedCalled() { + synchronized(softApLock) { + return onStateChangedCalled; + } + } + + public boolean getOnSoftapInfoChangedCalled() { + synchronized(softApLock) { + return onSoftapInfoChangedCalled; + } + } + + public boolean getOnSoftApCapabilityChangedCalled() { + synchronized(softApLock) { + return onSoftApCapabilityChangedCalled; + } + } + + public boolean getOnConnectedClientCalled() { + synchronized(softApLock) { + return onConnectedClientCalled; + } + } + + public boolean getOnBlockedClientConnectingCalled() { + synchronized(softApLock) { + return onBlockedClientConnectingCalled; + } + } + + public int getCurrentState() { + synchronized(softApLock) { + return currentState; + } + } + + public int getCurrentStateFailureReason() { + synchronized(softApLock) { + return currentFailureReason; + } + } + + public List getCurrentClientList() { + synchronized(softApLock) { + return currentClientList; + } + } + + public SoftApInfo getCurrentSoftApInfo() { + synchronized(softApLock) { + return currentSoftApInfo; + } + } + + public SoftApCapability getCurrentSoftApCapability() { + synchronized(softApLock) { + return currentSoftApCapability; + } + } + + public MacAddress getLastBlockedClientMacAddress() { + synchronized(softApLock) { + return lastBlockedClientMacAddress; + } + } + + public int getLastBlockedClientReason() { + synchronized(softApLock) { + return lastBlockedClientReason; + } + } + + @Override + public void onStateChanged(int state, int failureReason) { + synchronized(softApLock) { + currentState = state; + currentFailureReason = failureReason; + onStateChangedCalled = true; + } + } + + @Override + public void onConnectedClientsChanged(List clients) { + synchronized(softApLock) { + currentClientList = new ArrayList<>(clients); + onConnectedClientCalled = true; + } + } + + @Override + public void onInfoChanged(SoftApInfo softApInfo) { + synchronized(softApLock) { + currentSoftApInfo = softApInfo; + onSoftapInfoChangedCalled = true; + } + } + + @Override + public void onCapabilityChanged(SoftApCapability softApCapability) { + synchronized(softApLock) { + currentSoftApCapability = softApCapability; + onSoftApCapabilityChangedCalled = true; + } + } + + @Override + public void onBlockedClientConnecting(WifiClient client, int blockedReason) { + synchronized(softApLock) { + lastBlockedClientMacAddress = client.getMacAddress(); + lastBlockedClientReason = blockedReason; + onBlockedClientConnectingCalled = true; + } + } + } + private static class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback { Object hotspotLock; WifiManager.LocalOnlyHotspotReservation reservation = null; @@ -561,7 +711,10 @@ public class WifiManagerTest extends AndroidTestCase { } // check if we got the callback assertTrue(callback.onStartedCalled); - assertNotNull(callback.reservation.getSoftApConfiguration()); + + SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); + assertNotNull(softApConfig); + assertNotNull(softApConfig.toWifiConfiguration()); if (!hasAutomotiveFeature()) { assertEquals( SoftApConfiguration.BAND_2GHZ, @@ -1141,6 +1294,178 @@ public class WifiManagerTest extends AndroidTestCase { > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP); } + private void verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback) + throws Exception{ + // Register callback to get SoftApCapability + mWifiManager.registerSoftApCallback(executor, callback); + PollingCheck.check( + "SoftAp register failed!", 1_000, + () -> { executor.runAll(); + // Verify callback is run on the supplied executor and called + return callback.getOnStateChangedCalled() && + callback.getOnSoftapInfoChangedCalled() && + callback.getOnSoftApCapabilityChangedCalled() && + callback.getOnConnectedClientCalled(); + }); + } + + private void verifySetGetSoftApConfig(SoftApConfiguration targetConfig) { + mWifiManager.setSoftApConfiguration(targetConfig); + // Bssid set dodesn't support for tethered hotspot + SoftApConfiguration currentConfig = mWifiManager.getSoftApConfiguration(); + assertNull(currentConfig.getBssid()); + compareSoftApConfiguration(targetConfig, currentConfig); + } + + private void compareSoftApConfiguration(SoftApConfiguration currentConfig, + SoftApConfiguration testSoftApConfig) { + assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid()); + assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType()); + assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase()); + assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid()); + assertEquals(currentConfig.getBand(), testSoftApConfig.getBand()); + assertEquals(currentConfig.getChannel(), testSoftApConfig.getChannel()); + assertEquals(currentConfig.getMaxNumberOfClients(), + testSoftApConfig.getMaxNumberOfClients()); + assertEquals(currentConfig.isAutoShutdownEnabled(), + testSoftApConfig.isAutoShutdownEnabled()); + assertEquals(currentConfig.getShutdownTimeoutMillis(), + testSoftApConfig.getShutdownTimeoutMillis()); + assertEquals(currentConfig.isClientControlByUserEnabled(), + testSoftApConfig.isClientControlByUserEnabled()); + assertEquals(currentConfig.getAllowedClientList(), + testSoftApConfig.getAllowedClientList()); + assertEquals(currentConfig.getBlockedClientList(), + testSoftApConfig.getBlockedClientList()); + } + + private void turnOffWifiAndTetheredHotspotIfEnabled() throws Exception { + if (mWifiManager.isWifiEnabled()) { + Log.d(TAG, "Turn off WiFi"); + mWifiManager.setWifiEnabled(false); + PollingCheck.check( + "Wifi turn off failed!", 2_000, + () -> mWifiManager.isWifiEnabled() == false); + } + if (mWifiManager.isWifiApEnabled()) { + mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); + Log.d(TAG, "Turn off tethered Hotspot"); + PollingCheck.check( + "SoftAp turn off failed!", 2_000, + () -> mWifiManager.isWifiApEnabled() == false); + mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); + } + } + + /** + * Verify that the configuration from getSoftApConfiguration is same as the configuration which + * set by setSoftApConfiguration. And depends softap capability callback to test different + * configuration. + * @throws Exception + */ + public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception { + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + turnOffWifiAndTetheredHotspotIfEnabled(); + TestExecutor executor = new TestExecutor(); + TestSoftApCallback callback = new TestSoftApCallback(mLock); + verifyRegisterSoftApCallback(executor, callback); + + SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder() + .setSsid(TEST_SSID_UNQUOTED) + .setBssid(TEST_MAC) + .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) + .setAutoShutdownEnabled(true) + .setShutdownTimeoutMillis(100000) + .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ) + .setHiddenSsid(false); + + // Test SoftApConfiguration set and get + verifySetGetSoftApConfig(softApConfigBuilder.build()); + + // Test CLIENT_FORCE_DISCONNECT supported config. + if (callback.getCurrentSoftApCapability() + .areFeaturesSupported( + SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { + softApConfigBuilder.setMaxNumberOfClients(10); + softApConfigBuilder.setClientControlByUserEnabled(true); + softApConfigBuilder.setBlockedClientList(new ArrayList<>()); + softApConfigBuilder.setAllowedClientList(new ArrayList<>()); + verifySetGetSoftApConfig(softApConfigBuilder.build()); + } + + // Test SAE config + if (callback.getCurrentSoftApCapability() + .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) { + softApConfigBuilder + .setPassphrase(TEST_PASSPHRASE, + SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION); + verifySetGetSoftApConfig(softApConfigBuilder.build()); + softApConfigBuilder + .setPassphrase(TEST_PASSPHRASE, + SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); + verifySetGetSoftApConfig(softApConfigBuilder.build()); + } + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } + + /** + * Verify that startTetheredHotspot with specific channel config. + * @throws Exception + */ + public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback() + throws Exception { + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + turnOffWifiAndTetheredHotspotIfEnabled(); + TestExecutor executor = new TestExecutor(); + TestSoftApCallback callback = new TestSoftApCallback(mLock); + verifyRegisterSoftApCallback(executor, callback); + + SoftApConfiguration testSoftApConfig = new SoftApConfiguration.Builder() + .setSsid(TEST_SSID_UNQUOTED) + .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) + .setChannel(11, SoftApConfiguration.BAND_2GHZ) // Channel 11 = Freq 2462 + .build(); + + mWifiManager.setSoftApConfiguration(testSoftApConfig); + + // start tethering which used to verify startTetheredHotspot + mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor, + new TetheringManager.StartTetheringCallback() { + @Override + public void onTetheringFailed(final int result) { + } + }); + + // Verify state and info callback value as expected + PollingCheck.check( + "SoftAp channel and state mismatch!!!", 5_000, + () -> { executor.runAll(); + return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState() && + 2462 == callback.getCurrentSoftApInfo().getFrequency(); + }); + + // stop tethering which used to verify stopSoftAp + mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); + + // Verify clean up + PollingCheck.check( + "Stop Softap failed", 2_000, + () -> { executor.runAll(); + return WifiManager.WIFI_AP_STATE_DISABLED == callback.getCurrentState() && + 0 == callback.getCurrentSoftApInfo().getBandwidth() && + 0 == callback.getCurrentSoftApInfo().getFrequency(); + }); + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } + private static class TestActionListener implements WifiManager.ActionListener { private final Object mLock; public boolean onSuccessCalled = false; From 768315232018eb96fa225cc3858fbc1404b01bfa Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Fri, 13 Mar 2020 07:13:45 +0000 Subject: [PATCH 0801/1415] Add IpConfigurationTest for new @SystemApi Add new cts for @SystemApi in IpConfiguration. Bug: 139268426 Bug: 135998869 Test: atest android.net.cts.IpConfigurationTest Change-Id: I942791abbdccc10d0e2a0018339a2ee4f74c7645 Merged-In: I942791abbdccc10d0e2a0018339a2ee4f74c7645 (cherry picked from aosp/1171795) --- .../android/net/cts/IpConfigurationTest.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/IpConfigurationTest.java diff --git a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java new file mode 100644 index 0000000000..21be35142d --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2019 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.net.IpConfiguration; +import android.net.LinkAddress; +import android.net.ProxyInfo; +import android.net.StaticIpConfiguration; + +import androidx.test.runner.AndroidJUnit4; + +import libcore.net.InetAddressUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.ArrayList; + +@RunWith(AndroidJUnit4.class) +public final class IpConfigurationTest { + private static final int TYPE_IPASSIGNMENT_STATIC = 0; + private static final int TYPE_IPASSIGNMENT_DHCP = 1; + + private static final int TYPE_PROXY_SETTINGS_NONE = 0; + private static final int TYPE_PROXY_SETTINGS_STATIC = 1; + private static final int TYPE_PROXY_SETTINGS_PAC = 2; + + private static final LinkAddress LINKADDR = new LinkAddress("192.0.2.2/25"); + private static final InetAddress GATEWAY = InetAddressUtils.parseNumericAddress("192.0.2.1"); + private static final InetAddress DNS1 = InetAddressUtils.parseNumericAddress("8.8.8.8"); + private static final InetAddress DNS2 = InetAddressUtils.parseNumericAddress("8.8.4.4"); + private static final String DOMAINS = "example.com"; + + private static final ArrayList dnsServers = new ArrayList<>(); + + private StaticIpConfiguration mStaticIpConfig; + private ProxyInfo mProxy; + + @Before + public void setUp() { + dnsServers.add(DNS1); + dnsServers.add(DNS2); + mStaticIpConfig = new StaticIpConfiguration.Builder() + .setIpAddress(LINKADDR) + .setGateway(GATEWAY) + .setDnsServers(dnsServers) + .setDomains(DOMAINS) + .build(); + + mProxy = ProxyInfo.buildDirectProxy("test", 8888); + } + + @Test + public void testConstructor() { + IpConfiguration ipConfig = new IpConfiguration(); + checkEmpty(ipConfig); + assertIpConfigurationEqual(ipConfig, new IpConfiguration()); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_STATIC, + TYPE_PROXY_SETTINGS_PAC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_STATIC, + TYPE_PROXY_SETTINGS_STATIC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, + TYPE_PROXY_SETTINGS_PAC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, + TYPE_PROXY_SETTINGS_STATIC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, + TYPE_PROXY_SETTINGS_NONE); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + } + + private void checkEmpty(IpConfiguration config) { + assertEquals(IpConfiguration.IpAssignment.UNASSIGNED, + config.getIpAssignment().UNASSIGNED); + assertEquals(IpConfiguration.ProxySettings.UNASSIGNED, + config.getProxySettings().UNASSIGNED); + assertNull(config.getStaticIpConfiguration()); + assertNull(config.getHttpProxy()); + } + + private IpConfiguration createIpConfiguration(int ipAssignmentType, + int proxySettingType) { + + final IpConfiguration ipConfig = new IpConfiguration(); + + switch (ipAssignmentType) { + case TYPE_IPASSIGNMENT_STATIC: + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); + break; + case TYPE_IPASSIGNMENT_DHCP: + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + break; + default: + throw new IllegalArgumentException("Unknown ip assignment type."); + } + + switch (proxySettingType) { + case TYPE_PROXY_SETTINGS_NONE: + ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE); + break; + case TYPE_PROXY_SETTINGS_STATIC: + ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); + break; + case TYPE_PROXY_SETTINGS_PAC: + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); + break; + default: + throw new IllegalArgumentException("Unknown proxy setting type."); + } + + ipConfig.setStaticIpConfiguration(mStaticIpConfig); + ipConfig.setHttpProxy(mProxy); + + return ipConfig; + } + + private void assertIpConfigurationEqual(IpConfiguration source, IpConfiguration target) { + assertEquals(source.getIpAssignment(), target.getIpAssignment()); + assertEquals(source.getProxySettings(), target.getProxySettings()); + assertEquals(source.getHttpProxy(), target.getHttpProxy()); + assertEquals(source.getStaticIpConfiguration(), target.getStaticIpConfiguration()); + } +} From d40827d1bef331fada15359c105501ca65133d9d Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Mon, 16 Mar 2020 07:35:50 -0700 Subject: [PATCH 0802/1415] [CTS] Add test for WifiManager#addOrUpdatePasspointConfiguration Bug: 151613705 Test: atest WifiManagerTest Change-Id: I5f2537c501b065006d3a2f56cf671382e20cd737 --- .../android/net/wifi/cts/WifiManagerTest.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 2e3f18811b..5db348fd7d 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -49,6 +49,8 @@ import android.net.wifi.WifiManager.WifiLock; import android.net.wifi.WifiNetworkConnectionStatistics; import android.net.wifi.hotspot2.ConfigParser; import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.hotspot2.pps.Credential; +import android.net.wifi.hotspot2.pps.HomeSp; import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; @@ -1940,4 +1942,46 @@ public class WifiManagerTest extends AndroidTestCase { assertTrue(is11axSupportedEnabled); } } + + private static PasspointConfiguration createPasspointConfiguration() { + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test.com"); + homeSp.setFriendlyName("friendly name"); + homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66}); + config.setHomeSp(homeSp); + Credential.SimCredential simCred = new Credential.SimCredential(); + simCred.setImsi("123456*"); + simCred.setEapType(23 /* EAP_AKA */); + Credential cred = new Credential(); + cred.setRealm("realm"); + cred.setSimCredential(simCred); + config.setCredential(cred); + + return config; + } + + /** + * Tests {@link WifiManager#addOrUpdatePasspointConfiguration(PasspointConfiguration)} + * adds a Passpoint configuration correctly by getting it once it is added, and comparing it + * to the local copy of the configuration. + */ + public void testAddOrUpdatePasspointConfiguration() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + // Create and install a Passpoint configuration + PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); + mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); + + // Compare configurations + List configurations = mWifiManager.getPasspointConfigurations(); + assertNotNull(configurations); + assertEquals(passpointConfiguration, configurations.get(0)); + + // Clean up + mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); + } } From 064ed493ce49d507ba73d6b453cf04cefb654ed4 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Sat, 7 Mar 2020 12:36:42 +0000 Subject: [PATCH 0803/1415] Create all variants of stubs for tethering Add separate publicapi, systemapi and module_libs stubs for tethering. Bug: 147768409 Test: m Test: m framework-tethering-stubs-{public,system,module_libs_}api Change-Id: I0ed44691b4e7080818442a9d0eb37d874f707195 Merged-In: I0ed44691b4e7080818442a9d0eb37d874f707195 --- Tethering/common/TetheringLib/Android.bp | 68 ++++++++++++++++++------ 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 5b73dd53a2..2fbba68f1e 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -62,26 +62,14 @@ java_library { apex_available: ["com.android.tethering"], } -droidstubs { - name: "framework-tethering-stubs-sources", - defaults: ["framework-module-stubs-defaults-module_libs_api"], +stubs_defaults { + name: "framework-tethering-stubs-defaults", srcs: [ "src/android/net/TetheredClient.java", "src/android/net/TetheringManager.java", "src/android/net/TetheringConstants.java", ], - libs: [ - "tethering-aidl-interfaces-java", - "framework-all", - ], - sdk_version: "core_platform", -} - -java_library { - name: "framework-tethering-stubs", - srcs: [":framework-tethering-stubs-sources"], - libs: ["framework-all"], - sdk_version: "core_platform", + libs: ["tethering-aidl-interfaces-java"], } filegroup { @@ -101,3 +89,53 @@ filegroup { ], path: "src" } + +droidstubs { + name: "framework-tethering-stubs-srcs-publicapi", + defaults: [ + "framework-module-stubs-defaults-publicapi", + "framework-tethering-stubs-defaults", + ], +} + +droidstubs { + name: "framework-tethering-stubs-srcs-systemapi", + defaults: [ + "framework-module-stubs-defaults-systemapi", + "framework-tethering-stubs-defaults", + ], +} + +droidstubs { + name: "framework-tethering-api-module_libs_api", + defaults: [ + "framework-module-api-defaults-module_libs_api", + "framework-tethering-stubs-defaults", + ], +} + +droidstubs { + name: "framework-tethering-stubs-srcs-module_libs_api", + defaults: [ + "framework-module-stubs-defaults-module_libs_api", + "framework-tethering-stubs-defaults", + ], +} + +java_library { + name: "framework-tethering-stubs-publicapi", + srcs: [":framework-tethering-stubs-srcs-publicapi"], + sdk_version: "current", +} + +java_library { + name: "framework-tethering-stubs-systemapi", + srcs: [":framework-tethering-stubs-srcs-systemapi"], + sdk_version: "system_current", +} + +java_library { + name: "framework-tethering-stubs-module_libs_api", + srcs: [":framework-tethering-stubs-srcs-module_libs_api"], + sdk_version: "module_current", +} From f053e4b6f5f559274a85de41a09a4e673216e415 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 16 Mar 2020 21:49:48 +0800 Subject: [PATCH 0804/1415] Support static address configuration Application can specify static ipv4 server and client address to setup tethering and this is one shot configuration. Tethering service would not save the configuration and the configuration would be reset when tethering stop or start failure. When startTethering callback fired, it just mean tethering is requested successful. Therefore, callers may call startTethering again if startTethering successful but do not receive following tethering active notification for a while. Tethering service never actually does anything synchronously when startTethering is called: -startProvisioningIfNeeded just posts a message to the handler thread. -enableTetheringInternal doesn't do anything synchronously, it just asks the downstreams to get their interfaces ready and waits for callbacks. If tethering is already enabled with a different request, tethering would be disabled and re-enabled. Bug: 141256482 Test: -build, flash, boot -atest TetheringTests -atest CtsTetheringTest Change-Id: I0399917e7cefa1547d617e688225544c4fc1a231 --- .../src/android/net/TetheringManager.java | 36 +++++- .../android/net/TetheringRequestParcel.aidl | 1 + Tethering/src/android/net/ip/IpServer.java | 28 ++++- .../src/android/net/util/TetheringUtils.java | 16 +++ .../connectivity/tethering/Tethering.java | 73 ++++++++---- .../android/net/util/TetheringUtilsTest.java | 87 ++++++++++++++ .../connectivity/tethering/TetheringTest.java | 107 ++++++++++++++++-- 7 files changed, 310 insertions(+), 38 deletions(-) create mode 100644 Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 5d680b0a60..f8f89e703b 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -512,19 +512,36 @@ public class TetheringManager { mBuilderParcel = new TetheringRequestParcel(); mBuilderParcel.tetheringType = type; mBuilderParcel.localIPv4Address = null; + mBuilderParcel.staticClientAddress = null; mBuilderParcel.exemptFromEntitlementCheck = false; mBuilderParcel.showProvisioningUi = true; } /** - * Configure tethering with static IPv4 assignment (with DHCP disabled). + * Configure tethering with static IPv4 assignment. * - * @param localIPv4Address The preferred local IPv4 address to use. + * The clientAddress must be in the localIPv4Address prefix. A DHCP server will be + * started, but will only be able to offer the client address. The two addresses must + * be in the same prefix. + * + * @param localIPv4Address The preferred local IPv4 link address to use. + * @param clientAddress The static client address. */ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) @NonNull - public Builder useStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address) { + public Builder setStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address, + @NonNull final LinkAddress clientAddress) { + Objects.requireNonNull(localIPv4Address); + Objects.requireNonNull(clientAddress); + if (localIPv4Address.getPrefixLength() != clientAddress.getPrefixLength() + || !localIPv4Address.isIpv4() || !clientAddress.isIpv4() + || !new IpPrefix(localIPv4Address.toString()).equals( + new IpPrefix(clientAddress.toString()))) { + throw new IllegalArgumentException("Invalid server or client addresses"); + } + mBuilderParcel.localIPv4Address = localIPv4Address; + mBuilderParcel.staticClientAddress = clientAddress; return this; } @@ -549,6 +566,18 @@ public class TetheringManager { public TetheringRequest build() { return new TetheringRequest(mBuilderParcel); } + + /** Get static server address. */ + @Nullable + public LinkAddress getLocalIpv4Address() { + return mBuilderParcel.localIPv4Address; + } + + /** Get static client address. */ + @Nullable + public LinkAddress getClientStaticIpv4Address() { + return mBuilderParcel.staticClientAddress; + } } /** @@ -563,6 +592,7 @@ public class TetheringManager { public String toString() { return "TetheringRequest [ type= " + mRequestParcel.tetheringType + ", localIPv4Address= " + mRequestParcel.localIPv4Address + + ", staticClientAddress= " + mRequestParcel.staticClientAddress + ", exemptFromEntitlementCheck= " + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= " + mRequestParcel.showProvisioningUi + " ]"; diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl index bf19d85f6a..c0280d3dbf 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl +++ b/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl @@ -25,6 +25,7 @@ import android.net.LinkAddress; parcelable TetheringRequestParcel { int tetheringType; LinkAddress localIPv4Address; + LinkAddress staticClientAddress; boolean exemptFromEntitlementCheck; boolean showProvisioningUi; } diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 38f8609e21..5f5de9ea6b 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -34,6 +34,7 @@ import android.net.MacAddress; import android.net.RouteInfo; import android.net.TetheredClient; import android.net.TetheringManager; +import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpLeaseParcelable; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; @@ -242,6 +243,10 @@ public class IpServer extends StateMachine { private IDhcpServer mDhcpServer; private RaParams mLastRaParams; private LinkAddress mIpv4Address; + + private LinkAddress mStaticIpv4ServerAddr; + private LinkAddress mStaticIpv4ClientAddr; + @NonNull private List mDhcpLeases = Collections.emptyList(); @@ -544,6 +549,8 @@ public class IpServer extends StateMachine { // into calls to InterfaceController, shared with startIPv4(). mInterfaceCtrl.clearIPv4Address(); mIpv4Address = null; + mStaticIpv4ServerAddr = null; + mStaticIpv4ClientAddr = null; } private boolean configureIPv4(boolean enabled) { @@ -554,7 +561,10 @@ public class IpServer extends StateMachine { final Inet4Address srvAddr; int prefixLen = 0; try { - if (mInterfaceType == TetheringManager.TETHERING_USB + if (mStaticIpv4ServerAddr != null) { + srvAddr = (Inet4Address) mStaticIpv4ServerAddr.getAddress(); + prefixLen = mStaticIpv4ServerAddr.getPrefixLength(); + } else if (mInterfaceType == TetheringManager.TETHERING_USB || mInterfaceType == TetheringManager.TETHERING_NCM) { srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR); prefixLen = USB_PREFIX_LENGTH; @@ -599,10 +609,6 @@ public class IpServer extends StateMachine { return false; } - if (!configureDhcp(enabled, srvAddr, prefixLen)) { - return false; - } - // Directly-connected route. final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), mIpv4Address.getPrefixLength()); @@ -614,7 +620,8 @@ public class IpServer extends StateMachine { mLinkProperties.removeLinkAddress(mIpv4Address); mLinkProperties.removeRoute(route); } - return true; + + return configureDhcp(enabled, srvAddr, prefixLen); } private String getRandomWifiIPv4Address() { @@ -934,6 +941,13 @@ public class IpServer extends StateMachine { mLinkProperties.setInterfaceName(mIfaceName); } + private void maybeConfigureStaticIp(final TetheringRequestParcel request) { + if (request == null) return; + + mStaticIpv4ServerAddr = request.localIPv4Address; + mStaticIpv4ClientAddr = request.staticClientAddress; + } + class InitialState extends State { @Override public void enter() { @@ -948,9 +962,11 @@ public class IpServer extends StateMachine { mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; switch (message.arg1) { case STATE_LOCAL_ONLY: + maybeConfigureStaticIp((TetheringRequestParcel) message.obj); transitionTo(mLocalHotspotState); break; case STATE_TETHERED: + maybeConfigureStaticIp((TetheringRequestParcel) message.obj); transitionTo(mTetheredState); break; default: diff --git a/Tethering/src/android/net/util/TetheringUtils.java b/Tethering/src/android/net/util/TetheringUtils.java index 5a6d5c1cbf..dd67dddae1 100644 --- a/Tethering/src/android/net/util/TetheringUtils.java +++ b/Tethering/src/android/net/util/TetheringUtils.java @@ -15,8 +15,11 @@ */ package android.net.util; +import android.net.TetheringRequestParcel; + import java.io.FileDescriptor; import java.net.SocketException; +import java.util.Objects; /** * Native methods for tethering utilization. @@ -38,4 +41,17 @@ public class TetheringUtils { public static int uint16(short s) { return s & 0xffff; } + + /** Check whether two TetheringRequestParcels are the same. */ + public static boolean isTetheringRequestEquals(final TetheringRequestParcel request, + final TetheringRequestParcel otherRequest) { + if (request == otherRequest) return true; + + return request != null && otherRequest != null + && request.tetheringType == otherRequest.tetheringType + && Objects.equals(request.localIPv4Address, otherRequest.localIPv4Address) + && Objects.equals(request.staticClientAddress, otherRequest.staticClientAddress) + && request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck + && request.showProvisioningUi == otherRequest.showProvisioningUi; + } } diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 5539017573..a9e9a752fc 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -92,6 +92,7 @@ import android.net.util.BaseNetdUnsolicitedEventListener; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; import android.net.util.SharedLog; +import android.net.util.TetheringUtils; import android.net.util.VersionedBroadcastListener; import android.net.wifi.WifiClient; import android.net.wifi.WifiManager; @@ -196,6 +197,11 @@ public class Tethering { private final SharedLog mLog = new SharedLog(TAG); private final RemoteCallbackList mTetheringEventCallbacks = new RemoteCallbackList<>(); + // Currently active tethering requests per tethering type. Only one of each type can be + // requested at a time. After a tethering type is requested, the map keeps tethering parameters + // to be used after the interface comes up asynchronously. + private final SparseArray mActiveTetheringRequests = + new SparseArray<>(); // used to synchronize public access to members private final Object mPublicSync; @@ -487,14 +493,31 @@ public class Tethering { } void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) { - mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType, - request.showProvisioningUi); - enableTetheringInternal(request.tetheringType, true /* enabled */, listener); + mHandler.post(() -> { + final TetheringRequestParcel unfinishedRequest = mActiveTetheringRequests.get( + request.tetheringType); + // If tethering is already enabled with a different request, + // disable before re-enabling. + if (unfinishedRequest != null + && !TetheringUtils.isTetheringRequestEquals(unfinishedRequest, request)) { + enableTetheringInternal(request.tetheringType, false /* disabled */, null); + mEntitlementMgr.stopProvisioningIfNeeded(request.tetheringType); + } + mActiveTetheringRequests.put(request.tetheringType, request); + + mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType, + request.showProvisioningUi); + enableTetheringInternal(request.tetheringType, true /* enabled */, listener); + }); } void stopTethering(int type) { - enableTetheringInternal(type, false /* disabled */, null); - mEntitlementMgr.stopProvisioningIfNeeded(type); + mHandler.post(() -> { + mActiveTetheringRequests.remove(type); + + enableTetheringInternal(type, false /* disabled */, null); + mEntitlementMgr.stopProvisioningIfNeeded(type); + }); } /** @@ -503,39 +526,45 @@ public class Tethering { */ private void enableTetheringInternal(int type, boolean enable, final IIntResultListener listener) { - int result; + int result = TETHER_ERROR_NO_ERROR; switch (type) { case TETHERING_WIFI: result = setWifiTethering(enable); - sendTetherResult(listener, result); break; case TETHERING_USB: result = setUsbTethering(enable); - sendTetherResult(listener, result); break; case TETHERING_BLUETOOTH: setBluetoothTethering(enable, listener); break; case TETHERING_NCM: result = setNcmTethering(enable); - sendTetherResult(listener, result); break; case TETHERING_ETHERNET: result = setEthernetTethering(enable); - sendTetherResult(listener, result); break; default: Log.w(TAG, "Invalid tether type."); - sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE); + result = TETHER_ERROR_UNKNOWN_IFACE; + } + + // The result of Bluetooth tethering will be sent by #setBluetoothTethering. + if (type != TETHERING_BLUETOOTH) { + sendTetherResult(listener, result, type); } } - private void sendTetherResult(final IIntResultListener listener, int result) { + private void sendTetherResult(final IIntResultListener listener, final int result, + final int type) { if (listener != null) { try { listener.onResult(result); } catch (RemoteException e) { } } + + // If changing tethering fail, remove corresponding request + // no matter who trigger the start/stop. + if (result != TETHER_ERROR_NO_ERROR) mActiveTetheringRequests.remove(type); } private int setWifiTethering(final boolean enable) { @@ -565,7 +594,7 @@ public class Tethering { if (adapter == null || !adapter.isEnabled()) { Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " + (adapter == null)); - sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL); + sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL, TETHERING_BLUETOOTH); return; } @@ -594,7 +623,7 @@ public class Tethering { final int result = (((BluetoothPan) proxy).isTetheringOn() == enable) ? TETHER_ERROR_NO_ERROR : TETHER_ERROR_MASTER_ERROR; - sendTetherResult(listener, result); + sendTetherResult(listener, result, TETHERING_BLUETOOTH); adapter.closeProfileProxy(BluetoothProfile.PAN, proxy); } }, BluetoothProfile.PAN); @@ -672,12 +701,18 @@ public class Tethering { Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring"); return TETHER_ERROR_UNAVAIL_IFACE; } - // NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's - // queue but not yet processed, this will be a no-op and it will not - // return an error. + // NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's queue but not yet + // processed, this will be a no-op and it will not return an error. // - // TODO: reexamine the threading and messaging model. - tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState); + // This code cannot race with untether() because they both synchronize on mPublicSync. + // TODO: reexamine the threading and messaging model to totally remove mPublicSync. + final int type = tetherState.ipServer.interfaceType(); + final TetheringRequestParcel request = mActiveTetheringRequests.get(type, null); + if (request != null) { + mActiveTetheringRequests.delete(type); + } + tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState, 0, + request); return TETHER_ERROR_NO_ERROR; } } diff --git a/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java b/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java new file mode 100644 index 0000000000..1499f3be22 --- /dev/null +++ b/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2019 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.util; + +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import android.net.LinkAddress; +import android.net.TetheringRequestParcel; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.MiscAssertsKt; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class TetheringUtilsTest { + private static final LinkAddress TEST_SERVER_ADDR = new LinkAddress("192.168.43.1/24"); + private static final LinkAddress TEST_CLIENT_ADDR = new LinkAddress("192.168.43.5/24"); + private TetheringRequestParcel mTetheringRequest; + + @Before + public void setUp() { + mTetheringRequest = makeTetheringRequestParcel(); + } + + public TetheringRequestParcel makeTetheringRequestParcel() { + final TetheringRequestParcel request = new TetheringRequestParcel(); + request.tetheringType = TETHERING_WIFI; + request.localIPv4Address = TEST_SERVER_ADDR; + request.staticClientAddress = TEST_CLIENT_ADDR; + request.exemptFromEntitlementCheck = false; + request.showProvisioningUi = true; + return request; + } + + @Test + public void testIsTetheringRequestEquals() throws Exception { + TetheringRequestParcel request = makeTetheringRequestParcel(); + + assertTrue(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, mTetheringRequest)); + assertTrue(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); + assertTrue(TetheringUtils.isTetheringRequestEquals(null, null)); + assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, null)); + assertFalse(TetheringUtils.isTetheringRequestEquals(null, mTetheringRequest)); + + request = makeTetheringRequestParcel(); + request.tetheringType = TETHERING_USB; + assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); + + request = makeTetheringRequestParcel(); + request.localIPv4Address = null; + request.staticClientAddress = null; + assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); + + request = makeTetheringRequestParcel(); + request.exemptFromEntitlementCheck = true; + assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); + + request = makeTetheringRequestParcel(); + request.showProvisioningUi = false; + assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); + + MiscAssertsKt.assertFieldCountEquals(5, TetheringRequestParcel.class); + } +} diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 2f7c88aec7..d983fae09b 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -82,6 +82,7 @@ import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.EthernetManager; import android.net.EthernetManager.TetheredInterfaceRequest; +import android.net.IIntResultListener; import android.net.INetd; import android.net.ITetheringEventCallback; import android.net.InetAddresses; @@ -499,10 +500,16 @@ public class TetheringTest { return new Tethering(mTetheringDependencies); } - private TetheringRequestParcel createTetheringRquestParcel(final int type) { + private TetheringRequestParcel createTetheringRequestParcel(final int type) { + return createTetheringRequestParcel(type, null, null); + } + + private TetheringRequestParcel createTetheringRequestParcel(final int type, + final LinkAddress serverAddr, final LinkAddress clientAddr) { final TetheringRequestParcel request = new TetheringRequestParcel(); request.tetheringType = type; - request.localIPv4Address = null; + request.localIPv4Address = serverAddr; + request.staticClientAddress = clientAddr; request.exemptFromEntitlementCheck = false; request.showProvisioningUi = false; @@ -616,7 +623,7 @@ public class TetheringTest { private void prepareNcmTethering() { // Emulate startTethering(TETHERING_NCM) called - mTethering.startTethering(createTetheringRquestParcel(TETHERING_NCM), null); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_NCM), null); mLooper.dispatchAll(); verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NCM); @@ -629,7 +636,7 @@ public class TetheringTest { .thenReturn(upstreamState); // Emulate pressing the USB tethering button in Settings UI. - mTethering.startTethering(createTetheringRquestParcel(TETHERING_USB), null); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null); mLooper.dispatchAll(); verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); @@ -903,7 +910,7 @@ public class TetheringTest { when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true); // Emulate pressing the WiFi tethering button. - mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null); mLooper.dispatchAll(); verify(mWifiManager, times(1)).startSoftAp(null); verifyNoMoreInteractions(mWifiManager); @@ -931,7 +938,7 @@ public class TetheringTest { when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true); // Emulate pressing the WiFi tethering button. - mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null); mLooper.dispatchAll(); verify(mWifiManager, times(1)).startSoftAp(null); verifyNoMoreInteractions(mWifiManager); @@ -1008,7 +1015,7 @@ public class TetheringTest { doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME); // Emulate pressing the WiFi tethering button. - mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null); mLooper.dispatchAll(); verify(mWifiManager, times(1)).startSoftAp(null); verifyNoMoreInteractions(mWifiManager); @@ -1303,7 +1310,7 @@ public class TetheringTest { tetherState = callback.pollTetherStatesChanged(); assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME}); - mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null); sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); mLooper.dispatchAll(); tetherState = callback.pollTetherStatesChanged(); @@ -1398,10 +1405,10 @@ public class TetheringTest { public void testNoDuplicatedEthernetRequest() throws Exception { final TetheredInterfaceRequest mockRequest = mock(TetheredInterfaceRequest.class); when(mEm.requestTetheredInterface(any(), any())).thenReturn(mockRequest); - mTethering.startTethering(createTetheringRquestParcel(TETHERING_ETHERNET), null); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_ETHERNET), null); mLooper.dispatchAll(); verify(mEm, times(1)).requestTetheredInterface(any(), any()); - mTethering.startTethering(createTetheringRquestParcel(TETHERING_ETHERNET), null); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_ETHERNET), null); mLooper.dispatchAll(); verifyNoMoreInteractions(mEm); mTethering.stopTethering(TETHERING_ETHERNET); @@ -1580,6 +1587,86 @@ public class TetheringTest { assertTrue(element + " not found in " + collection, collection.contains(element)); } + private class ResultListener extends IIntResultListener.Stub { + private final int mExpectedResult; + private boolean mHasResult = false; + ResultListener(final int expectedResult) { + mExpectedResult = expectedResult; + } + + @Override + public void onResult(final int resultCode) { + mHasResult = true; + if (resultCode != mExpectedResult) { + fail("expected result: " + mExpectedResult + " but actual result: " + resultCode); + } + } + + public void assertHasResult() { + if (!mHasResult) fail("No callback result"); + } + } + + @Test + public void testMultipleStartTethering() throws Exception { + final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24"); + final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24"); + final String serverAddr = "192.168.20.1"; + final ResultListener firstResult = new ResultListener(TETHER_ERROR_NO_ERROR); + final ResultListener secondResult = new ResultListener(TETHER_ERROR_NO_ERROR); + final ResultListener thirdResult = new ResultListener(TETHER_ERROR_NO_ERROR); + + // Enable USB tethering and check that Tethering starts USB. + mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB, + null, null), firstResult); + mLooper.dispatchAll(); + firstResult.assertHasResult(); + verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); + verifyNoMoreInteractions(mUsbManager); + + // Enable USB tethering again with the same request and expect no change to USB. + mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB, + null, null), secondResult); + mLooper.dispatchAll(); + secondResult.assertHasResult(); + verify(mUsbManager, never()).setCurrentFunctions(UsbManager.FUNCTION_NONE); + reset(mUsbManager); + + // Enable USB tethering with a different request and expect that USB is stopped and + // started. + mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB, + serverLinkAddr, clientLinkAddr), thirdResult); + mLooper.dispatchAll(); + thirdResult.assertHasResult(); + verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE); + verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); + + // Expect that when USB comes up, the DHCP server is configured with the requested address. + mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true); + sendUsbBroadcast(true, true, true, TETHERING_USB); + mLooper.dispatchAll(); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( + any(), any()); + verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr))); + } + + @Test + public void testRequestStaticServerIp() throws Exception { + final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24"); + final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24"); + final String serverAddr = "192.168.20.1"; + mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB, + serverLinkAddr, clientLinkAddr), null); + mLooper.dispatchAll(); + verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); + mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true); + sendUsbBroadcast(true, true, true, TETHERING_USB); + mLooper.dispatchAll(); + verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr))); + + // TODO: test static client address. + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } From fbe50c723af71beeebefcf4bcc79ad5d554c73db Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 16 Mar 2020 09:59:47 -0700 Subject: [PATCH 0805/1415] WifiNetworkSpecifierTest: Add tests for enterprise builder methods Bug: 150236894 Test: atest android.net.wifi.cts Change-Id: Ie902dfa2c0fb83505c0b570b77462fcdf4c4ecaf --- .../wifi/cts/WifiNetworkSpecifierTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java index 96cf45ff1f..2065bb025c 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java @@ -31,6 +31,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.NetworkRequestMatchCallback; @@ -506,4 +507,44 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { .build(); testUserRejectionWithSpecifier(specifier); } + + /** + * Tests the builder for WPA2 enterprise networks. + * Note: Can't do end to end tests for such networks in CTS environment. + */ + public void testBuilderForWpa2Enterprise() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() + .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setWpa2EnterpriseConfig(new WifiEnterpriseConfig()) + .build(); + WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() + .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setWpa2EnterpriseConfig(new WifiEnterpriseConfig()) + .build(); + assertThat(specifier1.satisfiedBy(specifier2)).isTrue(); + } + + /** + * Tests the builder for WPA3 enterprise networks. + * Note: Can't do end to end tests for such networks in CTS environment. + */ + public void testBuilderForWpa3Enterprise() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() + .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setWpa3EnterpriseConfig(new WifiEnterpriseConfig()) + .build(); + WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() + .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setWpa3EnterpriseConfig(new WifiEnterpriseConfig()) + .build(); + assertThat(specifier1.satisfiedBy(specifier2)).isTrue(); + } } From 96f9efcb759894a454120436ecdcd7645bce10a4 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 16 Mar 2020 10:05:54 -0700 Subject: [PATCH 0806/1415] WifiNetworkSuggestionTest: Add test for WAPI builder method Bug: 150236894 Test: atest android.net.wifi.cts Change-Id: I294f309ec972c24dfe83d9c40fd33fb591398872 --- .../wifi/cts/WifiNetworkSuggestionTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java index 994b6c907a..e73abb8b54 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java @@ -17,6 +17,7 @@ package android.net.wifi.cts; import static android.net.wifi.WifiEnterpriseConfig.Eap.AKA; +import static android.net.wifi.WifiEnterpriseConfig.Eap.WAPI_CERT; import android.net.MacAddress; import android.net.wifi.WifiEnterpriseConfig; @@ -198,6 +199,28 @@ public class WifiNetworkSuggestionTest extends AndroidTestCase { assertNull(suggestion.getPasspointConfig()); } + /** + * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class. + */ + public void testBuilderWithWapiEnterprise() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); + enterpriseConfig.setEapMethod(WAPI_CERT); + WifiNetworkSuggestion suggestion = + createBuilderWithCommonParams() + .setWapiEnterpriseConfig(enterpriseConfig) + .build(); + validateCommonParams(suggestion); + assertNull(suggestion.getPassphrase()); + assertNotNull(suggestion.getEnterpriseConfig()); + assertEquals(enterpriseConfig.getEapMethod(), + suggestion.getEnterpriseConfig().getEapMethod()); + assertNull(suggestion.getPasspointConfig()); + } + /** * Helper function for creating a {@link PasspointConfiguration} for testing. * From 90d49fbc579f2f769551d91bbae99a540d57a6c6 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 16 Mar 2020 11:08:14 -0700 Subject: [PATCH 0807/1415] WifiManagerTest: Add test for isTdls & isStaApConcurrency supported Bug: 150236894 Test: atest android.net.wifi.cts Change-Id: Id532a189b0d3e6848408e7a798acda13669ffb52 --- .../android/net/wifi/cts/WifiManagerTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 46d4e7f371..2368d1be0a 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -1472,6 +1472,45 @@ public class WifiManagerTest extends AndroidTestCase { mWifiManager.isPreferredNetworkOffloadSupported(); } + /** + * Tests {@link WifiManager#isTdlsSupported()} does not crash. + */ + public void testIsTdlsSupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + mWifiManager.isTdlsSupported(); + } + + /** + * Tests {@link WifiManager#isStaApConcurrencySupported(). + */ + public void testIsStaApConcurrencySupported() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + // check that softap mode is supported by the device + if (!mWifiManager.isPortableHotspotSupported()) { + return; + } + assertTrue(mWifiManager.isWifiEnabled()); + + boolean isStaApConcurrencySupported = mWifiManager.isStaApConcurrencySupported(); + // start local only hotspot. + TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); + if (isStaApConcurrencySupported) { + assertTrue(mWifiManager.isWifiEnabled()); + } else { + // no concurrency, wifi should be disabled. + assertFalse(mWifiManager.isWifiEnabled()); + } + stopLocalOnlyHotspot(callback, true); + + assertTrue(mWifiManager.isWifiEnabled()); + } + private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback { private final Object mLock; public boolean onStateChangedCalled = false; From 74ab41b1cdfde999332a7ff79bec531dfb211208 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 16 Mar 2020 14:07:35 -0700 Subject: [PATCH 0808/1415] WifiMigrationTest: Remove all usage of WifiMigration.loadFromStore In preparation of moving away from this API surface to a different mechanism. Bug: 149418926 Test: atest android.net.wifi.cts Change-Id: I5805d9dc27a248b633d514356f603f63af799429 --- .../net/wifi/cts/WifiMigrationTest.java | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java index 6e19a21217..ea59f00a22 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java @@ -48,41 +48,6 @@ public class WifiMigrationTest extends AndroidTestCase { super.tearDown(); } - /** - * Tests {@link android.net.wifi.WifiMigration.ConfigStoreMigrationData} class. - */ - public void testWifiMigrationConfigStoreDataBuilder() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiConfiguration savedNetwork1 = new WifiConfiguration(); - savedNetwork1.SSID = "\"test1\""; - WifiConfiguration savedNetwork2 = new WifiConfiguration(); - savedNetwork1.SSID = "\"test2\""; - List savedNetworks = Arrays.asList(savedNetwork1, savedNetwork2); - - SoftApConfiguration softApConfiguration = new SoftApConfiguration.Builder() - .setSsid("\"test3\"") - .build(); - - WifiMigration.ConfigStoreMigrationData migrationData = - new WifiMigration.ConfigStoreMigrationData.Builder() - .setUserSavedNetworkConfigurations(savedNetworks) - .setUserSoftApConfiguration(softApConfiguration) - .build(); - - assertNotNull(migrationData); - assertEquals(savedNetworks.size(), - migrationData.getUserSavedNetworkConfigurations().size()); - assertEquals(savedNetwork1.SSID, - migrationData.getUserSavedNetworkConfigurations().get(0).SSID); - assertEquals(savedNetwork2.SSID, - migrationData.getUserSavedNetworkConfigurations().get(1).SSID); - assertEquals(softApConfiguration.getSsid(), - migrationData.getUserSoftApConfiguration().getSsid()); - } - /** * Tests {@link android.net.wifi.WifiMigration.ConfigStoreMigrationData} class. */ From 6a780a7c161eec756da9c8a9a0a64e0bf52126a3 Mon Sep 17 00:00:00 2001 From: David Su Date: Mon, 16 Mar 2020 22:47:20 -0700 Subject: [PATCH 0809/1415] CTS: test WifiNl80211Manager.sendMgmtFrame Link probing is an optional feature gated by an overlay. Unfortunately, there is no public/system API that can be used to check if link probing is supported on the device. `adb shell cmd wifi send-link-probe` requires root, which is not supported by CTS. For devices that do not support link probing, this API could even throw an exception. Thus, this test does not have any expectations. Bug: 150978929 Test: atest android.net.wifi.nl80211.cts.WifiNl80211ManagerTest Change-Id: I13f9be5571c0eb7d64cc86bea5b7fd8addc1db5c --- .../nl80211/cts/WifiNl80211ManagerTest.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java index fa8447d2da..f1f3010ddf 100644 --- a/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java @@ -42,11 +42,13 @@ import java.util.Arrays; @RunWith(AndroidJUnit4.class) public class WifiNl80211ManagerTest { + private Context mContext; + @Before public void setUp() { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); + mContext = InstrumentationRegistry.getInstrumentation().getContext(); // skip tests if Wifi is not supported - assumeTrue(WifiFeature.isWifiSupported(context)); + assumeTrue(WifiFeature.isWifiSupported(mContext)); } @Test @@ -64,4 +66,19 @@ public class WifiNl80211ManagerTest { .isEqualTo(Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP)); assertThat(securityType.groupCipher).isEqualTo(ScanResult.CIPHER_CCMP); } + + @Test + public void testSendMgmtFrame() { + try { + WifiNl80211Manager manager = mContext.getSystemService(WifiNl80211Manager.class); + manager.sendMgmtFrame("wlan0", new byte[]{}, -1, Runnable::run, + new WifiNl80211Manager.SendMgmtFrameCallback() { + @Override + public void onAck(int elapsedTimeMs) {} + + @Override + public void onFailure(int reason) {} + }); + } catch (Exception ignore) {} + } } From 65031e4d9f289260cc55e69e35d96b6471919947 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Tue, 17 Mar 2020 13:38:09 -0700 Subject: [PATCH 0810/1415] [CTS] Add tests for hotspot2.OsuProvider getters Added coverage for below APIs: getFriendlyName() getServerUri() Bug: 150977165 Test: atest WifiHotspot2Test Change-Id: I0abe5ab63dff6793103552870322da6a2f426dba --- .../net/wifi/cts/WifiHotspot2Test.java | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java index 96e1caaebe..a05b81b932 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java @@ -18,23 +18,45 @@ package android.net.wifi.cts; import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE; +import android.net.Uri; +import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.test.AndroidTestCase; +import android.text.TextUtils; +import java.lang.reflect.Constructor; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; public class WifiHotspot2Test extends AndroidTestCase { static final int SIM_CREDENTIAL = 0; static final int USER_CREDENTIAL = 1; static final int CERT_CREDENTIAL = 2; - + private static final String TEST_SSID = "TEST SSID"; + private static final String TEST_FRIENDLY_NAME = "Friendly Name"; + private static final Map TEST_FRIENDLY_NAMES = + new HashMap() { + { + put("en", TEST_FRIENDLY_NAME); + put("kr", TEST_FRIENDLY_NAME + 2); + put("jp", TEST_FRIENDLY_NAME + 3); + } + }; + private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service"; + private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com"); + private static final String TEST_NAI = "test.access.com"; + private static final List TEST_METHOD_LIST = + Arrays.asList(1 /* METHOD_SOAP_XML_SPP */); @Override protected void setUp() throws Exception { super.setUp(); @@ -434,4 +456,33 @@ public class WifiHotspot2Test extends AndroidTestCase { return createCredential(userCred, null, null, null, null, FakeKeys.CA_CERT0); } + + /** + * Tests {@link OsuProvider#getFriendlyName()} and {@link OsuProvider#getServerUri()} methods. + *

    + * Test that getting a set friendly name and server URI produces the same value + */ + public void testOsuProviderGetters() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + // Using Java reflection to construct an OsuProvider instance because its constructor is + // hidden and not available to apps. + Class osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider"); + Constructor osuProviderClassConstructor = osuProviderClass.getConstructor(String.class, + Map.class, String.class, Uri.class, String.class, List.class); + + OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID, + TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, + TEST_METHOD_LIST); + String lang = Locale.getDefault().getLanguage(); + String friendlyName = TEST_FRIENDLY_NAMES.get(lang); + if (TextUtils.isEmpty(friendlyName)) { + friendlyName = TEST_FRIENDLY_NAMES.get("en"); + } + assertEquals(friendlyName, osuProvider.getFriendlyName()); + assertEquals(TEST_SERVER_URI, osuProvider.getServerUri()); + } } From 36a172910e81b412847c23b7924253f4739d23c8 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 16 Mar 2020 13:27:28 +0800 Subject: [PATCH 0811/1415] [SP25] Rename functions that add Entry conditionally Currently, in NetworkStats, there are many methods to manipulate the records. However, some methods are similar and ambiguous, such as addEntry, addValues, setValues, addIfaceValues, combineValues and combineAllValues. Thus, properly grouping and renaming methods are necessary. In this change, for methods that add one record conditionally, name them addEntry. addValues -> addEntry Test: atest FrameworksNetTests ImsPhoneCallTrackerTest TetheringTests Fix: 148895143 Change-Id: I9495a198cf247e6c79100f7ac1edcea370b071de Merged-In: I9495a198cf247e6c79100f7ac1edcea370b071de (cherry picked from ag/10700816) --- .../tethering/OffloadController.java | 2 +- .../tethering/OffloadControllerTest.java | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java index d43c5c682f..15cdb6ad7a 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java @@ -284,7 +284,7 @@ public class OffloadController { final ForwardedStats value = kv.getValue(); final Entry entry = new Entry(kv.getKey(), uid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, value.rxBytes, 0L, value.txBytes, 0L, 0L); - stats = stats.addValues(entry); + stats = stats.addEntry(entry); } return stats; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java index 1d100e6321..fe840864fb 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java @@ -446,12 +446,12 @@ public class OffloadControllerTest { final NetworkStats ifaceStats = mTetherStatsProvider.getTetherStats(STATS_PER_IFACE); final NetworkStats uidStats = mTetherStatsProvider.getTetherStats(STATS_PER_UID); final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) - .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321)); + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) + .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321)); final NetworkStats expectedUidStats = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) - .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321)); + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) + .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321)); assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStats)); assertTrue(orderInsensitiveEquals(expectedUidStats, uidStats)); @@ -485,12 +485,12 @@ public class OffloadControllerTest { final NetworkStats ifaceStatsAccu = mTetherStatsProvider.getTetherStats(STATS_PER_IFACE); final NetworkStats uidStatsAccu = mTetherStatsProvider.getTetherStats(STATS_PER_UID); final NetworkStats expectedIfaceStatsAccu = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) - .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321)); + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) + .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321)); final NetworkStats expectedUidStatsAccu = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) - .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321)); + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) + .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321)); assertTrue(orderInsensitiveEquals(expectedIfaceStatsAccu, ifaceStatsAccu)); assertTrue(orderInsensitiveEquals(expectedUidStatsAccu, uidStatsAccu)); @@ -499,12 +499,12 @@ public class OffloadControllerTest { reset(mTetherStatsProviderCb); mTetherStatsProvider.pushTetherStats(); final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) - .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000)); + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) + .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000)); final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) - .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) + .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); verify(mTetherStatsProviderCb, times(1)) .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue())); From 3355cc4f061b2d05d47ce450210280ae4927b8e4 Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 17 Mar 2020 22:44:46 +0800 Subject: [PATCH 0812/1415] [TNU1.1]Add tethering notification strings Add string for no upstream and cellular roaming notification. Bug: 145629001 Bug: 147818698 Test: atest TetheringTests Change-Id: I30f68d83344f66fb3ef77abf3f8748c3eb1276f0 --- Tethering/res/values-mcc204-mnc04/strings.xml | 26 +++++++++++++++++++ .../res/values-mcc310-mnc004/strings.xml | 26 +++++++++++++++++++ .../res/values-mcc311-mnc480/strings.xml | 26 +++++++++++++++++++ Tethering/res/values/strings.xml | 10 +++++++ 4 files changed, 88 insertions(+) create mode 100644 Tethering/res/values-mcc204-mnc04/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480/strings.xml diff --git a/Tethering/res/values-mcc204-mnc04/strings.xml b/Tethering/res/values-mcc204-mnc04/strings.xml new file mode 100644 index 0000000000..6bc2e2aa92 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04/strings.xml @@ -0,0 +1,26 @@ + + + + + Tethering & Mobile Hotspot has no internet access + + + Roaming + + You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available + + Continue + \ No newline at end of file diff --git a/Tethering/res/values-mcc310-mnc004/strings.xml b/Tethering/res/values-mcc310-mnc004/strings.xml new file mode 100644 index 0000000000..6bc2e2aa92 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004/strings.xml @@ -0,0 +1,26 @@ + + + + + Tethering & Mobile Hotspot has no internet access + + + Roaming + + You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available + + Continue + \ No newline at end of file diff --git a/Tethering/res/values-mcc311-mnc480/strings.xml b/Tethering/res/values-mcc311-mnc480/strings.xml new file mode 100644 index 0000000000..6bc2e2aa92 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480/strings.xml @@ -0,0 +1,26 @@ + + + + + Tethering & Mobile Hotspot has no internet access + + + Roaming + + You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available + + Continue + \ No newline at end of file diff --git a/Tethering/res/values/strings.xml b/Tethering/res/values/strings.xml index ba98a66ff7..d50884b2a7 100644 --- a/Tethering/res/values/strings.xml +++ b/Tethering/res/values/strings.xml @@ -32,4 +32,14 @@ Internet" settings page. That is currently the tether_settings_title_all string. --> Hotspot & tethering status + + + + + + + + + + \ No newline at end of file From a4a48ef75937964487c345c948dcdfcf91e41e0f Mon Sep 17 00:00:00 2001 From: David Su Date: Tue, 17 Mar 2020 17:39:35 -0700 Subject: [PATCH 0813/1415] CTS: Test PNO Scanning Test that PNO scans reconnects us to a saved network when Wifi is disconnected and screen is off. This also adds coverage for WifiNl80211Manager.startPnoScan. Bug: 150978929 Test: atest android.net.wifi.cts.WifiManagerTest Change-Id: Id0487f4df48ea013d67e19faecd96b5a469f09da --- .../android/net/wifi/cts/WifiManagerTest.java | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 51a4f32a64..fc4f2eaaac 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -81,9 +81,11 @@ import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; @@ -1212,8 +1214,12 @@ public class WifiManagerTest extends AndroidTestCase { Thread.sleep(DURATION_SCREEN_TOGGLE); } - private void turnScreenOff() throws Exception { + private void turnScreenOffNoDelay() throws Exception { mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); + } + + private void turnScreenOff() throws Exception { + turnScreenOffNoDelay(); // Since the screen on/off intent is ordered, they will not be sent right now. Thread.sleep(DURATION_SCREEN_TOGGLE); } @@ -1799,6 +1805,59 @@ public class WifiManagerTest extends AndroidTestCase { mWifiManager.isPreferredNetworkOffloadSupported(); } + /** Test that PNO scans reconnects us when the device is disconnected and the screen is off. */ + public void testPnoScan() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + if (!mWifiManager.isPreferredNetworkOffloadSupported()) { + // skip the test if PNO scanning is not supported + return; + } + + // make sure we're connected + waitForConnection(); + + WifiInfo currentNetwork = ShellIdentityUtils.invokeWithShellPermissions( + mWifiManager::getConnectionInfo); + + // disable all networks that aren't already disabled + List savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( + mWifiManager::getConfiguredNetworks); + Set disabledNetworkIds = new HashSet<>(); + for (WifiConfiguration config : savedNetworks) { + if (config.getNetworkSelectionStatus().getNetworkSelectionDisableReason() + == WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE) { + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.disableNetwork(config.networkId)); + disabledNetworkIds.add(config.networkId); + } + } + + try { + // wait for disconnection from current network + waitForDisconnection(); + + // turn screen off + turnScreenOffNoDelay(); + + // re-enable the current network - this will trigger PNO + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.enableNetwork(currentNetwork.getNetworkId(), false)); + disabledNetworkIds.remove(currentNetwork.getNetworkId()); + + // PNO should reconnect us back to the network we disconnected from + waitForConnection(); + } finally { + // re-enable disabled networks + for (int disabledNetworkId : disabledNetworkIds) { + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.enableNetwork(disabledNetworkId, false)); + } + } + } + /** * Tests {@link WifiManager#isTdlsSupported()} does not crash. */ From e7c52c7e3f056af3d766bfbb512d8c2b8897a570 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Fri, 17 Jan 2020 19:03:34 +0000 Subject: [PATCH 0814/1415] Add individual API tracking files for modules This adds metalava api tracking generation to the module stub rules, to make sure we know exactly what API a particular module stub exports. Bug: 147768409 Test: m update-api check-api Exempt-From-Owner-Approval: rebase + m update-api Change-Id: Iaf2ef5b5751eb208d119ddbc74481239366fe581 --- Tethering/common/TetheringLib/api/current.txt | 1 + .../TetheringLib/api/module-lib-current.txt | 128 ++++++++++++++++++ .../TetheringLib/api/module-lib-removed.txt | 1 + Tethering/common/TetheringLib/api/removed.txt | 1 + .../TetheringLib/api/system-current.txt | 106 +++++++++++++++ .../TetheringLib/api/system-removed.txt | 1 + 6 files changed, 238 insertions(+) create mode 100644 Tethering/common/TetheringLib/api/current.txt create mode 100644 Tethering/common/TetheringLib/api/module-lib-current.txt create mode 100644 Tethering/common/TetheringLib/api/module-lib-removed.txt create mode 100644 Tethering/common/TetheringLib/api/removed.txt create mode 100644 Tethering/common/TetheringLib/api/system-current.txt create mode 100644 Tethering/common/TetheringLib/api/system-removed.txt diff --git a/Tethering/common/TetheringLib/api/current.txt b/Tethering/common/TetheringLib/api/current.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Tethering/common/TetheringLib/api/current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Tethering/common/TetheringLib/api/module-lib-current.txt b/Tethering/common/TetheringLib/api/module-lib-current.txt new file mode 100644 index 0000000000..8a7e975051 --- /dev/null +++ b/Tethering/common/TetheringLib/api/module-lib-current.txt @@ -0,0 +1,128 @@ +// Signature format: 2.0 +package android.net { + + public final class TetheredClient implements android.os.Parcelable { + ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection, int); + method public int describeContents(); + method @NonNull public java.util.List getAddresses(); + method @NonNull public android.net.MacAddress getMacAddress(); + method public int getTetheringType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class TetheredClient.AddressInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.LinkAddress getAddress(); + method @Nullable public String getHostname(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public final class TetheringConstants { + field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; + field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback"; + field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType"; + field public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; + field public static final String EXTRA_SET_ALARM = "extraSetAlarm"; + } + + public class TetheringManager { + ctor public TetheringManager(@NonNull android.content.Context, @NonNull java.util.function.Supplier); + method public int getLastTetherError(@NonNull String); + method @NonNull public String[] getTetherableBluetoothRegexs(); + method @NonNull public String[] getTetherableIfaces(); + method @NonNull public String[] getTetherableUsbRegexs(); + method @NonNull public String[] getTetherableWifiRegexs(); + method @NonNull public String[] getTetheredIfaces(); + method @NonNull public String[] getTetheringErroredIfaces(); + method public boolean isTetheringSupported(); + method public boolean isTetheringSupported(@NonNull String); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); + method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean); + method @Deprecated public int setUsbTethering(boolean); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); + method @Deprecated public int tether(@NonNull String); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); + method @Deprecated public int untether(@NonNull String); + field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; + field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY"; + field public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; + field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; + field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_ETHERNET = 5; // 0x5 + field public static final int TETHERING_INVALID = -1; // 0xffffffff + field public static final int TETHERING_NCM = 4; // 0x4 + field public static final int TETHERING_USB = 1; // 0x1 + field public static final int TETHERING_WIFI = 0; // 0x0 + field public static final int TETHERING_WIFI_P2P = 3; // 0x3 + field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc + field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9 + field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8 + field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd + field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa + field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5 + field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf + field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe + field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 + field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2 + field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6 + field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4 + field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1 + field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3 + field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7 + field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2 + field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1 + field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0 + } + + public static interface TetheringManager.OnTetheringEntitlementResultListener { + method public void onTetheringEntitlementResult(int); + } + + public abstract static class TetheringManager.StartTetheringCallback { + ctor public TetheringManager.StartTetheringCallback(); + method public void onTetheringFailed(int); + method public void onTetheringStarted(); + } + + public abstract static class TetheringManager.TetheringEventCallback { + ctor public TetheringManager.TetheringEventCallback(); + method public void onClientsChanged(@NonNull java.util.Collection); + method public void onError(@NonNull String, int); + method public void onOffloadStatusChanged(int); + method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); + method public void onTetherableInterfacesChanged(@NonNull java.util.List); + method public void onTetheredInterfacesChanged(@NonNull java.util.List); + method public void onTetheringSupported(boolean); + method public void onUpstreamChanged(@Nullable android.net.Network); + } + + @Deprecated public static class TetheringManager.TetheringInterfaceRegexps { + ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]); + method @Deprecated @NonNull public java.util.List getTetherableBluetoothRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableUsbRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); + } + + public static class TetheringManager.TetheringRequest { + } + + public static class TetheringManager.TetheringRequest.Builder { + ctor public TetheringManager.TetheringRequest.Builder(int); + method @NonNull public android.net.TetheringManager.TetheringRequest build(); + method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); + method @Nullable public android.net.LinkAddress getLocalIpv4Address(); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); + } + +} + diff --git a/Tethering/common/TetheringLib/api/module-lib-removed.txt b/Tethering/common/TetheringLib/api/module-lib-removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Tethering/common/TetheringLib/api/module-lib-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Tethering/common/TetheringLib/api/removed.txt b/Tethering/common/TetheringLib/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Tethering/common/TetheringLib/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Tethering/common/TetheringLib/api/system-current.txt b/Tethering/common/TetheringLib/api/system-current.txt new file mode 100644 index 0000000000..ac739532a4 --- /dev/null +++ b/Tethering/common/TetheringLib/api/system-current.txt @@ -0,0 +1,106 @@ +// Signature format: 2.0 +package android.net { + + public final class TetheredClient implements android.os.Parcelable { + ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection, int); + method public int describeContents(); + method @NonNull public java.util.List getAddresses(); + method @NonNull public android.net.MacAddress getMacAddress(); + method public int getTetheringType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class TetheredClient.AddressInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.LinkAddress getAddress(); + method @Nullable public String getHostname(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public class TetheringManager { + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); + field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; + field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY"; + field public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; + field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; + field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_ETHERNET = 5; // 0x5 + field public static final int TETHERING_INVALID = -1; // 0xffffffff + field public static final int TETHERING_NCM = 4; // 0x4 + field public static final int TETHERING_USB = 1; // 0x1 + field public static final int TETHERING_WIFI = 0; // 0x0 + field public static final int TETHERING_WIFI_P2P = 3; // 0x3 + field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc + field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9 + field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8 + field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd + field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa + field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5 + field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf + field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe + field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 + field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2 + field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6 + field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4 + field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1 + field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3 + field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7 + field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2 + field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1 + field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0 + } + + public static interface TetheringManager.OnTetheringEntitlementResultListener { + method public void onTetheringEntitlementResult(int); + } + + public abstract static class TetheringManager.StartTetheringCallback { + ctor public TetheringManager.StartTetheringCallback(); + method public void onTetheringFailed(int); + method public void onTetheringStarted(); + } + + public abstract static class TetheringManager.TetheringEventCallback { + ctor public TetheringManager.TetheringEventCallback(); + method public void onClientsChanged(@NonNull java.util.Collection); + method public void onError(@NonNull String, int); + method public void onOffloadStatusChanged(int); + method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); + method public void onTetherableInterfacesChanged(@NonNull java.util.List); + method public void onTetheredInterfacesChanged(@NonNull java.util.List); + method public void onTetheringSupported(boolean); + method public void onUpstreamChanged(@Nullable android.net.Network); + } + + @Deprecated public static class TetheringManager.TetheringInterfaceRegexps { + ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]); + method @Deprecated @NonNull public java.util.List getTetherableBluetoothRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableUsbRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); + } + + public static class TetheringManager.TetheringRequest { + } + + public static class TetheringManager.TetheringRequest.Builder { + ctor public TetheringManager.TetheringRequest.Builder(int); + method @NonNull public android.net.TetheringManager.TetheringRequest build(); + method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); + method @Nullable public android.net.LinkAddress getLocalIpv4Address(); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); + } + +} + diff --git a/Tethering/common/TetheringLib/api/system-removed.txt b/Tethering/common/TetheringLib/api/system-removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Tethering/common/TetheringLib/api/system-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 From a5428687e4f20e25a31a3a38557f2e874689b58d Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Fri, 17 Jan 2020 19:03:34 +0000 Subject: [PATCH 0815/1415] Add individual API tracking files for modules This adds metalava api tracking generation to the module stub rules, to make sure we know exactly what API a particular module stub exports. Bug: 147768409 Test: m update-api Exempt-From-Owner-Approval: Approved in master Change-Id: Iaf2ef5b5751eb208d119ddbc74481239366fe581 Merged-In: Iaf2ef5b5751eb208d119ddbc74481239366fe581 (cherry picked from commit b602b0b2f18d96866a5d7e5d27958af774d1f802) --- Tethering/common/TetheringLib/api/current.txt | 1 + .../TetheringLib/api/module-lib-current.txt | 128 ++++++++++++++++++ .../TetheringLib/api/module-lib-removed.txt | 1 + Tethering/common/TetheringLib/api/removed.txt | 1 + .../TetheringLib/api/system-current.txt | 106 +++++++++++++++ .../TetheringLib/api/system-removed.txt | 1 + 6 files changed, 238 insertions(+) create mode 100644 Tethering/common/TetheringLib/api/current.txt create mode 100644 Tethering/common/TetheringLib/api/module-lib-current.txt create mode 100644 Tethering/common/TetheringLib/api/module-lib-removed.txt create mode 100644 Tethering/common/TetheringLib/api/removed.txt create mode 100644 Tethering/common/TetheringLib/api/system-current.txt create mode 100644 Tethering/common/TetheringLib/api/system-removed.txt diff --git a/Tethering/common/TetheringLib/api/current.txt b/Tethering/common/TetheringLib/api/current.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Tethering/common/TetheringLib/api/current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Tethering/common/TetheringLib/api/module-lib-current.txt b/Tethering/common/TetheringLib/api/module-lib-current.txt new file mode 100644 index 0000000000..8a7e975051 --- /dev/null +++ b/Tethering/common/TetheringLib/api/module-lib-current.txt @@ -0,0 +1,128 @@ +// Signature format: 2.0 +package android.net { + + public final class TetheredClient implements android.os.Parcelable { + ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection, int); + method public int describeContents(); + method @NonNull public java.util.List getAddresses(); + method @NonNull public android.net.MacAddress getMacAddress(); + method public int getTetheringType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class TetheredClient.AddressInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.LinkAddress getAddress(); + method @Nullable public String getHostname(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public final class TetheringConstants { + field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; + field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback"; + field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType"; + field public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; + field public static final String EXTRA_SET_ALARM = "extraSetAlarm"; + } + + public class TetheringManager { + ctor public TetheringManager(@NonNull android.content.Context, @NonNull java.util.function.Supplier); + method public int getLastTetherError(@NonNull String); + method @NonNull public String[] getTetherableBluetoothRegexs(); + method @NonNull public String[] getTetherableIfaces(); + method @NonNull public String[] getTetherableUsbRegexs(); + method @NonNull public String[] getTetherableWifiRegexs(); + method @NonNull public String[] getTetheredIfaces(); + method @NonNull public String[] getTetheringErroredIfaces(); + method public boolean isTetheringSupported(); + method public boolean isTetheringSupported(@NonNull String); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); + method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean); + method @Deprecated public int setUsbTethering(boolean); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); + method @Deprecated public int tether(@NonNull String); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); + method @Deprecated public int untether(@NonNull String); + field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; + field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY"; + field public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; + field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; + field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_ETHERNET = 5; // 0x5 + field public static final int TETHERING_INVALID = -1; // 0xffffffff + field public static final int TETHERING_NCM = 4; // 0x4 + field public static final int TETHERING_USB = 1; // 0x1 + field public static final int TETHERING_WIFI = 0; // 0x0 + field public static final int TETHERING_WIFI_P2P = 3; // 0x3 + field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc + field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9 + field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8 + field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd + field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa + field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5 + field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf + field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe + field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 + field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2 + field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6 + field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4 + field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1 + field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3 + field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7 + field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2 + field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1 + field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0 + } + + public static interface TetheringManager.OnTetheringEntitlementResultListener { + method public void onTetheringEntitlementResult(int); + } + + public abstract static class TetheringManager.StartTetheringCallback { + ctor public TetheringManager.StartTetheringCallback(); + method public void onTetheringFailed(int); + method public void onTetheringStarted(); + } + + public abstract static class TetheringManager.TetheringEventCallback { + ctor public TetheringManager.TetheringEventCallback(); + method public void onClientsChanged(@NonNull java.util.Collection); + method public void onError(@NonNull String, int); + method public void onOffloadStatusChanged(int); + method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); + method public void onTetherableInterfacesChanged(@NonNull java.util.List); + method public void onTetheredInterfacesChanged(@NonNull java.util.List); + method public void onTetheringSupported(boolean); + method public void onUpstreamChanged(@Nullable android.net.Network); + } + + @Deprecated public static class TetheringManager.TetheringInterfaceRegexps { + ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]); + method @Deprecated @NonNull public java.util.List getTetherableBluetoothRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableUsbRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); + } + + public static class TetheringManager.TetheringRequest { + } + + public static class TetheringManager.TetheringRequest.Builder { + ctor public TetheringManager.TetheringRequest.Builder(int); + method @NonNull public android.net.TetheringManager.TetheringRequest build(); + method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); + method @Nullable public android.net.LinkAddress getLocalIpv4Address(); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); + } + +} + diff --git a/Tethering/common/TetheringLib/api/module-lib-removed.txt b/Tethering/common/TetheringLib/api/module-lib-removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Tethering/common/TetheringLib/api/module-lib-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Tethering/common/TetheringLib/api/removed.txt b/Tethering/common/TetheringLib/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Tethering/common/TetheringLib/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Tethering/common/TetheringLib/api/system-current.txt b/Tethering/common/TetheringLib/api/system-current.txt new file mode 100644 index 0000000000..ac739532a4 --- /dev/null +++ b/Tethering/common/TetheringLib/api/system-current.txt @@ -0,0 +1,106 @@ +// Signature format: 2.0 +package android.net { + + public final class TetheredClient implements android.os.Parcelable { + ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection, int); + method public int describeContents(); + method @NonNull public java.util.List getAddresses(); + method @NonNull public android.net.MacAddress getMacAddress(); + method public int getTetheringType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class TetheredClient.AddressInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.LinkAddress getAddress(); + method @Nullable public String getHostname(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public class TetheringManager { + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); + field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; + field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY"; + field public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; + field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; + field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_ETHERNET = 5; // 0x5 + field public static final int TETHERING_INVALID = -1; // 0xffffffff + field public static final int TETHERING_NCM = 4; // 0x4 + field public static final int TETHERING_USB = 1; // 0x1 + field public static final int TETHERING_WIFI = 0; // 0x0 + field public static final int TETHERING_WIFI_P2P = 3; // 0x3 + field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc + field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9 + field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8 + field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd + field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa + field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5 + field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf + field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe + field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 + field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2 + field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6 + field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4 + field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1 + field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3 + field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7 + field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2 + field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1 + field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0 + } + + public static interface TetheringManager.OnTetheringEntitlementResultListener { + method public void onTetheringEntitlementResult(int); + } + + public abstract static class TetheringManager.StartTetheringCallback { + ctor public TetheringManager.StartTetheringCallback(); + method public void onTetheringFailed(int); + method public void onTetheringStarted(); + } + + public abstract static class TetheringManager.TetheringEventCallback { + ctor public TetheringManager.TetheringEventCallback(); + method public void onClientsChanged(@NonNull java.util.Collection); + method public void onError(@NonNull String, int); + method public void onOffloadStatusChanged(int); + method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); + method public void onTetherableInterfacesChanged(@NonNull java.util.List); + method public void onTetheredInterfacesChanged(@NonNull java.util.List); + method public void onTetheringSupported(boolean); + method public void onUpstreamChanged(@Nullable android.net.Network); + } + + @Deprecated public static class TetheringManager.TetheringInterfaceRegexps { + ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]); + method @Deprecated @NonNull public java.util.List getTetherableBluetoothRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableUsbRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); + } + + public static class TetheringManager.TetheringRequest { + } + + public static class TetheringManager.TetheringRequest.Builder { + ctor public TetheringManager.TetheringRequest.Builder(int); + method @NonNull public android.net.TetheringManager.TetheringRequest build(); + method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); + method @Nullable public android.net.LinkAddress getLocalIpv4Address(); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); + } + +} + diff --git a/Tethering/common/TetheringLib/api/system-removed.txt b/Tethering/common/TetheringLib/api/system-removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Tethering/common/TetheringLib/api/system-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 From 245352ed0771ed7bd1f9cf4556c3fa82a3e5c81d Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 27 Feb 2020 20:27:18 +0800 Subject: [PATCH 0816/1415] Assign specific client address to dhcp server Bug: 141256482 Test: manual atest TetheringTests Change-Id: Ief76c98c843ba5420224cbf0f34464f366c891b7 --- .../src/android/net/TetheringManager.java | 23 +++++++++---- .../net/dhcp/DhcpServingParamsParcelExt.java | 15 ++++++++- Tethering/src/android/net/ip/IpServer.java | 32 ++++++++++++++----- .../dhcp/DhcpServingParamsParcelExtTest.java | 8 +++++ .../connectivity/tethering/TetheringTest.java | 20 ++++++++---- 5 files changed, 76 insertions(+), 22 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index f8f89e703b..1febe85850 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -520,9 +520,8 @@ public class TetheringManager { /** * Configure tethering with static IPv4 assignment. * - * The clientAddress must be in the localIPv4Address prefix. A DHCP server will be - * started, but will only be able to offer the client address. The two addresses must - * be in the same prefix. + * A DHCP server will be started, but will only be able to offer the client address. + * The two addresses must be in the same prefix. * * @param localIPv4Address The preferred local IPv4 link address to use. * @param clientAddress The static client address. @@ -533,10 +532,7 @@ public class TetheringManager { @NonNull final LinkAddress clientAddress) { Objects.requireNonNull(localIPv4Address); Objects.requireNonNull(clientAddress); - if (localIPv4Address.getPrefixLength() != clientAddress.getPrefixLength() - || !localIPv4Address.isIpv4() || !clientAddress.isIpv4() - || !new IpPrefix(localIPv4Address.toString()).equals( - new IpPrefix(clientAddress.toString()))) { + if (!checkStaticAddressConfiguration(localIPv4Address, clientAddress)) { throw new IllegalArgumentException("Invalid server or client addresses"); } @@ -580,6 +576,19 @@ public class TetheringManager { } } + /** + * Check whether the two addresses are ipv4 and in the same prefix. + * @hide + */ + public static boolean checkStaticAddressConfiguration( + @NonNull final LinkAddress localIPv4Address, + @NonNull final LinkAddress clientAddress) { + return localIPv4Address.getPrefixLength() == clientAddress.getPrefixLength() + && localIPv4Address.isIpv4() && clientAddress.isIpv4() + && new IpPrefix(localIPv4Address.toString()).equals( + new IpPrefix(clientAddress.toString())); + } + /** * Get a TetheringRequestParcel from the configuration * @hide diff --git a/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java index d6bc063210..82a26beada 100644 --- a/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -18,10 +18,12 @@ package android.net.dhcp; import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; -import android.annotation.NonNull; import android.net.LinkAddress; import android.util.ArraySet; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.net.Inet4Address; import java.util.Collection; import java.util.Collections; @@ -160,6 +162,17 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { return this; } + /** + * Set the client address to tell DHCP server only offer this address. + * The client's prefix length is the same as server's. + * + *

    If not set, the default value is null. + */ + public DhcpServingParamsParcelExt setSingleClientAddr(@Nullable Inet4Address clientAddr) { + this.clientAddr = clientAddr == null ? 0 : inet4AddressToIntHTH(clientAddr); + return this; + } + private static int[] toIntArray(@NonNull Collection addrs) { int[] res = new int[addrs.size()]; int i = 0; diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 433b903ebe..99e2fb14e8 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -18,6 +18,7 @@ package android.net.ip; import static android.net.InetAddresses.parseNumericAddress; import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.util.NetworkConstants.FF; @@ -492,17 +493,24 @@ public class IpServer extends StateMachine { } } - private boolean startDhcp(Inet4Address addr, int prefixLen) { + private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) { if (mUsingLegacyDhcp) { return true; } + + final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress(); + final int prefixLen = serverLinkAddr.getPrefixLength(); + final Inet4Address clientAddr = clientLinkAddr == null ? null : + (Inet4Address) clientLinkAddr.getAddress(); + final DhcpServingParamsParcel params; params = new DhcpServingParamsParcelExt() .setDefaultRouters(addr) .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) .setDnsServers(addr) - .setServerAddr(new LinkAddress(addr, prefixLen)) - .setMetered(true); + .setServerAddr(serverLinkAddr) + .setMetered(true) + .setSingleClientAddr(clientAddr); // TODO: also advertise link MTU mDhcpServerStartIndex++; @@ -537,9 +545,10 @@ public class IpServer extends StateMachine { } } - private boolean configureDhcp(boolean enable, Inet4Address addr, int prefixLen) { + private boolean configureDhcp(boolean enable, final LinkAddress serverAddr, + final LinkAddress clientAddr) { if (enable) { - return startDhcp(addr, prefixLen); + return startDhcp(serverAddr, clientAddr); } else { stopDhcp(); return true; @@ -587,7 +596,7 @@ public class IpServer extends StateMachine { // code that calls into NetworkManagementService directly. srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR); mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); - return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); + return configureDhcp(enabled, mIpv4Address, null /* clientAddress */); } mIpv4Address = new LinkAddress(srvAddr, prefixLen); } catch (IllegalArgumentException e) { @@ -624,7 +633,7 @@ public class IpServer extends StateMachine { mLinkProperties.removeRoute(route); } - return configureDhcp(enabled, srvAddr, prefixLen); + return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } private String getRandomWifiIPv4Address() { @@ -945,7 +954,14 @@ public class IpServer extends StateMachine { } private void maybeConfigureStaticIp(final TetheringRequestParcel request) { - if (request == null) return; + // Ignore static address configuration if they are invalid or null. In theory, static + // addresses should not be invalid here because TetheringManager do not allow caller to + // specify invalid static address configuration. + if (request == null || request.localIPv4Address == null + || request.staticClientAddress == null || !checkStaticAddressConfiguration( + request.localIPv4Address, request.staticClientAddress)) { + return; + } mStaticIpv4ServerAddr = request.localIPv4Address; mStaticIpv4ClientAddr = request.staticClientAddress; diff --git a/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java index e8add9830b..f8eb1476ba 100644 --- a/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java +++ b/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java @@ -42,7 +42,9 @@ import java.util.stream.IntStream; @SmallTest public class DhcpServingParamsParcelExtTest { private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123"); + private static final Inet4Address TEST_CLIENT_ADDRESS = inet4Addr("192.168.0.42"); private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b; + private static final int TEST_CLIENT_ADDRESS_PARCELED = 0xc0a8002a; private static final int TEST_PREFIX_LENGTH = 17; private static final int TEST_LEASE_TIME_SECS = 120; private static final int TEST_MTU = 1000; @@ -105,6 +107,12 @@ public class DhcpServingParamsParcelExtTest { assertFalse(mParcel.metered); } + @Test + public void testSetClientAddr() { + mParcel.setSingleClientAddr(TEST_CLIENT_ADDRESS); + assertEquals(TEST_CLIENT_ADDRESS_PARCELED, mParcel.clientAddr); + } + private static Inet4Address inet4Addr(String addr) { return (Inet4Address) parseNumericAddress(addr); } diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index d983fae09b..82573e7c8a 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -38,6 +38,7 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -1651,10 +1652,13 @@ public class TetheringTest { } @Test - public void testRequestStaticServerIp() throws Exception { - final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24"); - final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24"); - final String serverAddr = "192.168.20.1"; + public void testRequestStaticIp() throws Exception { + final LinkAddress serverLinkAddr = new LinkAddress("192.168.0.123/24"); + final LinkAddress clientLinkAddr = new LinkAddress("192.168.0.42/24"); + final String serverAddr = "192.168.0.123"; + final int clientAddrParceled = 0xc0a8002a; + final ArgumentCaptor dhcpParamsCaptor = + ArgumentCaptor.forClass(DhcpServingParamsParcel.class); mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB, serverLinkAddr, clientLinkAddr), null); mLooper.dispatchAll(); @@ -1663,8 +1667,12 @@ public class TetheringTest { sendUsbBroadcast(true, true, true, TETHERING_USB); mLooper.dispatchAll(); verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr))); - - // TODO: test static client address. + verify(mIpServerDependencies, times(1)).makeDhcpServer(any(), dhcpParamsCaptor.capture(), + any()); + final DhcpServingParamsParcel params = dhcpParamsCaptor.getValue(); + assertEquals(serverAddr, intToInet4AddressHTH(params.serverAddr).getHostAddress()); + assertEquals(24, params.serverAddrPrefixLength); + assertEquals(clientAddrParceled, params.clientAddr); } // TODO: Test that a request for hotspot mode doesn't interfere with an From 1f1a316fb2a62ac219efb07910575d573ade6b3d Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Tue, 17 Mar 2020 15:02:49 -0700 Subject: [PATCH 0817/1415] [CTS] Added tests for hotspot2 provisioning APIs Added coverage for below APIs: ProvisioningCallback() WifiManager#startSubscriptionProvisioning() Bug: 150977584 Test: atest WifiManagerTest Change-Id: Ic810b8a4fdeb22a96900971b355c336670199ed6 --- .../android/net/wifi/cts/WifiManagerTest.java | 127 ++++++++++++++++-- 1 file changed, 113 insertions(+), 14 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index fc4f2eaaac..65d9dea41e 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -32,7 +32,6 @@ import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.net.util.MacAddressUtils; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.MacAddress; @@ -41,6 +40,8 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.TetheringManager; +import android.net.Uri; +import android.net.util.MacAddressUtils; import android.net.wifi.ScanResult; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; @@ -52,9 +53,14 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.net.wifi.WifiNetworkConnectionStatistics; import android.net.wifi.hotspot2.ConfigParser; +import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.hotspot2.ProvisioningCallback; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.HandlerThread; import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; @@ -78,15 +84,18 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.reflect.Constructor; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -130,7 +139,7 @@ public class WifiManagerTest extends AndroidTestCase { private static final int SCAN_TIMEOUT_MSEC = 9000; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; - private static final int DURATION = 10_000; + private static final int TEST_WAIT_DURATION_MS = 10_000; private static final int DURATION_SCREEN_TOGGLE = 2000; private static final int DURATION_SETTINGS_TOGGLE = 1_000; private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000; @@ -190,6 +199,54 @@ public class WifiManagerTest extends AndroidTestCase { } } }; + // Initialize with an invalid status value (0) + private int mProvisioningStatus = 0; + // Initialize with an invalid status value (0) + private int mProvisioningFailureStatus = 0; + private boolean mProvisioningComplete = false; + private ProvisioningCallback mProvisioningCallback = new ProvisioningCallback() { + @Override + public void onProvisioningFailure(int status) { + synchronized (mLock) { + mProvisioningFailureStatus = status; + mLock.notify(); + } + } + + @Override + public void onProvisioningStatus(int status) { + synchronized (mLock) { + mProvisioningStatus = status; + mLock.notify(); + } + } + + @Override + public void onProvisioningComplete() { + mProvisioningComplete = true; + } + }; + private static final String TEST_SSID = "TEST SSID"; + private static final String TEST_FRIENDLY_NAME = "Friendly Name"; + private static final Map TEST_FRIENDLY_NAMES = + new HashMap() { + { + put("en", TEST_FRIENDLY_NAME); + put("kr", TEST_FRIENDLY_NAME + 2); + put("jp", TEST_FRIENDLY_NAME + 3); + } + }; + private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service"; + private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com"); + private static final String TEST_NAI = "test.access.com"; + private static final List TEST_METHOD_LIST = + Arrays.asList(1 /* METHOD_SOAP_XML_SPP */); + private final HandlerThread mHandlerThread = new HandlerThread("WifiManagerTest"); + protected final Executor mExecutor; + { + mHandlerThread.start(); + mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper())); + } @Override protected void setUp() throws Exception { @@ -228,7 +285,7 @@ public class WifiManagerTest extends AndroidTestCase { setWifiEnabled(true); mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); turnScreenOnNoDelay(); - Thread.sleep(DURATION); + Thread.sleep(TEST_WAIT_DURATION_MS); assertTrue(mWifiManager.isWifiEnabled()); synchronized (mMySync) { mMySync.expectedState = STATE_NULL; @@ -259,7 +316,7 @@ public class WifiManagerTest extends AndroidTestCase { // restore original softap config ShellIdentityUtils.invokeWithShellPermissions( () -> mWifiManager.setSoftApConfiguration(mOriginalSoftApConfig)); - Thread.sleep(DURATION); + Thread.sleep(TEST_WAIT_DURATION_MS); super.tearDown(); } @@ -377,7 +434,7 @@ public class WifiManagerTest extends AndroidTestCase { + " empty when location is disabled!"); } setWifiEnabled(false); - Thread.sleep(DURATION); + Thread.sleep(TEST_WAIT_DURATION_MS); startScan(); if (mWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) { // Make sure at least one AP is found. @@ -712,7 +769,7 @@ public class WifiManagerTest extends AndroidTestCase { try { mWifiManager.startLocalOnlyHotspot(callback, null); // now wait for callback - mLock.wait(DURATION); + mLock.wait(TEST_WAIT_DURATION_MS); } catch (InterruptedException e) { } // check if we got the callback @@ -806,7 +863,7 @@ public class WifiManagerTest extends AndroidTestCase { boolean wifiEnabled = mWifiManager.isWifiEnabled(); // now we should fail to toggle wifi state. assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled)); - Thread.sleep(DURATION); + Thread.sleep(TEST_WAIT_DURATION_MS); assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } @@ -1553,7 +1610,7 @@ public class WifiManagerTest extends AndroidTestCase { mWifiManager.connect(savedNetworks.get(0), actionListener); } // now wait for callback - mLock.wait(DURATION); + mLock.wait(TEST_WAIT_DURATION_MS); } catch (InterruptedException e) { } } @@ -1632,7 +1689,7 @@ public class WifiManagerTest extends AndroidTestCase { .build(), networkCallbackListener); // now wait for callback - mLock.wait(DURATION); + mLock.wait(TEST_WAIT_DURATION_MS); } catch (InterruptedException e) { } } @@ -1680,7 +1737,7 @@ public class WifiManagerTest extends AndroidTestCase { modSavedNetwork.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED; mWifiManager.save(modSavedNetwork, actionListener); // now wait for callback - mLock.wait(DURATION); + mLock.wait(TEST_WAIT_DURATION_MS); } catch (InterruptedException e) { } } @@ -1728,7 +1785,7 @@ public class WifiManagerTest extends AndroidTestCase { try { mWifiManager.forget(newNetworkId, actionListener); // now wait for callback - mLock.wait(DURATION); + mLock.wait(TEST_WAIT_DURATION_MS); } catch (InterruptedException e) { } } @@ -1962,7 +2019,7 @@ public class WifiManagerTest extends AndroidTestCase { // Send some traffic to trigger the traffic state change callbacks. sendTraffic(); // now wait for callback - mLock.wait(DURATION); + mLock.wait(TEST_WAIT_DURATION_MS); } catch (InterruptedException e) { } } @@ -2185,7 +2242,7 @@ public class WifiManagerTest extends AndroidTestCase { .build(), networkCallbackListener); // now wait for callback - mLock.wait(DURATION); + mLock.wait(TEST_WAIT_DURATION_MS); } catch (InterruptedException e) { } } @@ -2407,4 +2464,46 @@ public class WifiManagerTest extends AndroidTestCase { // Clean up mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); } + + /** + * Tests that + * {@link WifiManager#startSubscriptionProvisioning(OsuProvider, Executor, ProvisioningCallback)} + * starts a subscription provisioning, and confirm a status callback invoked once. + */ + public void testStartSubscriptionProvisioning() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + + // Using Java reflection to construct an OsuProvider instance because its constructor is + // hidden and not available to apps. + Class osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider"); + Constructor osuProviderClassConstructor = osuProviderClass.getConstructor(String.class, + Map.class, String.class, Uri.class, String.class, List.class); + + OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID, + TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, + TEST_METHOD_LIST); + + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + synchronized (mLock) { + // Start a subscription provisioning for a non-existent Passpoint R2 AP + mWifiManager.startSubscriptionProvisioning(osuProvider, mExecutor, + mProvisioningCallback); + mLock.wait(TEST_WAIT_DURATION_MS); + } + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + + // Expect only a single callback event, connecting. Since AP doesn't exist, it ends here + assertEquals(ProvisioningCallback.OSU_STATUS_AP_CONNECTING, mProvisioningStatus); + // No failure callbacks expected + assertEquals(0, mProvisioningFailureStatus); + // No completion callback expected + assertFalse(mProvisioningComplete); + } } From 6afc73aef6a05a0f9114cd19138848b30c34dff1 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 18 Mar 2020 16:23:28 -0700 Subject: [PATCH 0818/1415] WifiMigrationTest: Add test for WifiMigration.loadFromSettings This assumes that OEM's were using the same AOSP @Settings.Global values to persist the data (which is probably true on all devices). Bug: 150236894 Test: atest android.net.wifi.cts.WifiMigrationTest Change-Id: I7e80730c81e6ed4773cf187e4eb1018528edb158 --- .../net/wifi/cts/WifiMigrationTest.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java index ea59f00a22..7d94ad3ff8 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java @@ -16,16 +16,9 @@ package android.net.wifi.cts; -import static org.junit.Assert.assertNotNull; - -import android.net.wifi.SoftApConfiguration; -import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiMigration; import android.test.AndroidTestCase; -import java.util.Arrays; -import java.util.List; - public class WifiMigrationTest extends AndroidTestCase { private static final String TEST_SSID_UNQUOTED = "testSsid1"; @@ -49,7 +42,7 @@ public class WifiMigrationTest extends AndroidTestCase { } /** - * Tests {@link android.net.wifi.WifiMigration.ConfigStoreMigrationData} class. + * Tests {@link android.net.wifi.WifiMigration.SettingsMigrationData.Builder} class. */ public void testWifiMigrationSettingsDataBuilder() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { @@ -76,4 +69,15 @@ public class WifiMigrationTest extends AndroidTestCase { assertTrue(migrationData.isVerboseLoggingEnabled()); assertEquals(TEST_SSID_UNQUOTED, migrationData.getP2pDeviceName()); } + + /** + * Tests {@link android.net.wifi.WifiMigration.SettingsMigrationData} class. + */ + public void testWifiMigrationSettings() throws Exception { + try { + // ensure that this does not crash. + WifiMigration.loadFromSettings(getContext()); + } catch (Exception ignore) { + } + } } From 938c3858720592e69ae1e071daa39623a3cdff8e Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 17 Mar 2020 13:51:39 +0800 Subject: [PATCH 0819/1415] Clean up for TetheringManager API change Bug: 149858697 Bug: 151243337 Test: atest CtsTetheringTest Change-Id: I817cb62f0f41d72e861952394ac8fbbfdc360f11 --- .../src/android/tethering/cts/TetheringManagerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 98dbe52e41..4d72eae3e4 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -180,15 +180,15 @@ public class TetheringManagerTest { } } - private class StartTetheringCallback extends TetheringManager.StartTetheringCallback { + private class StartTetheringCallback implements TetheringManager.StartTetheringCallback { @Override public void onTetheringStarted() { // Do nothing, TetherChangeReceiver will wait until it receives the broadcast. } @Override - public void onTetheringFailed(final int resultCode) { - fail("startTethering fail: " + resultCode); + public void onTetheringFailed(final int error) { + fail("startTethering fail: " + error); } } From 1957e6a0fbc4738e4728811aa8ea0cdbbed85218 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 19 Mar 2020 15:15:39 +0800 Subject: [PATCH 0820/1415] [TNU1.2] Add string for client number notification Add string for client number notification Bug: 122085773 Test: atest TetheringTests Change-Id: Icc4e59ce3b2d8d4c1c7883c2f9d040d3ce563f09 --- .../res/values-mcc310-mnc120/strings.xml | 22 +++++++++++++++++++ .../res/values-mcc311-mnc490/strings.xml | 22 +++++++++++++++++++ .../res/values-mcc312-mnc530/strings.xml | 22 +++++++++++++++++++ Tethering/res/values/strings.xml | 5 ++++- 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 Tethering/res/values-mcc310-mnc120/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc490/strings.xml create mode 100644 Tethering/res/values-mcc312-mnc530/strings.xml diff --git a/Tethering/res/values-mcc310-mnc120/strings.xml b/Tethering/res/values-mcc310-mnc120/strings.xml new file mode 100644 index 0000000000..618df90c71 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc120/strings.xml @@ -0,0 +1,22 @@ + + + + + + %1$d device connected. + %1$d devices connected. + + \ No newline at end of file diff --git a/Tethering/res/values-mcc311-mnc490/strings.xml b/Tethering/res/values-mcc311-mnc490/strings.xml new file mode 100644 index 0000000000..618df90c71 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc490/strings.xml @@ -0,0 +1,22 @@ + + + + + + %1$d device connected. + %1$d devices connected. + + \ No newline at end of file diff --git a/Tethering/res/values-mcc312-mnc530/strings.xml b/Tethering/res/values-mcc312-mnc530/strings.xml new file mode 100644 index 0000000000..618df90c71 --- /dev/null +++ b/Tethering/res/values-mcc312-mnc530/strings.xml @@ -0,0 +1,22 @@ + + + + + + %1$d device connected. + %1$d devices connected. + + \ No newline at end of file diff --git a/Tethering/res/values/strings.xml b/Tethering/res/values/strings.xml index d50884b2a7..981524e4da 100644 --- a/Tethering/res/values/strings.xml +++ b/Tethering/res/values/strings.xml @@ -13,12 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. --> - + Tethering or hotspot active Tap to set up. + + + - Tethering & Mobile Hotspot has no internet access + Hotspot has no internet + + Devices can\u2019t connect to internet + + Turn off hotspot - Roaming + Hotspot is on - You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available + Additional charges may apply while roaming Continue - \ No newline at end of file + diff --git a/Tethering/res/values-mcc310-mnc004/strings.xml b/Tethering/res/values-mcc310-mnc004/strings.xml index 6bc2e2aa92..a996b4247a 100644 --- a/Tethering/res/values-mcc310-mnc004/strings.xml +++ b/Tethering/res/values-mcc310-mnc004/strings.xml @@ -15,12 +15,16 @@ --> - Tethering & Mobile Hotspot has no internet access + Hotspot has no internet + + Devices can\u2019t connect to internet + + Turn off hotspot - Roaming + Hotspot is on - You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available + Additional charges may apply while roaming Continue - \ No newline at end of file + diff --git a/Tethering/res/values-mcc311-mnc480/strings.xml b/Tethering/res/values-mcc311-mnc480/strings.xml index 6bc2e2aa92..a996b4247a 100644 --- a/Tethering/res/values-mcc311-mnc480/strings.xml +++ b/Tethering/res/values-mcc311-mnc480/strings.xml @@ -15,12 +15,16 @@ --> - Tethering & Mobile Hotspot has no internet access + Hotspot has no internet + + Devices can\u2019t connect to internet + + Turn off hotspot - Roaming + Hotspot is on - You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available + Additional charges may apply while roaming Continue - \ No newline at end of file + diff --git a/Tethering/res/values/strings.xml b/Tethering/res/values/strings.xml index 981524e4da..52a16545c2 100644 --- a/Tethering/res/values/strings.xml +++ b/Tethering/res/values/strings.xml @@ -38,6 +38,10 @@ + + + + @@ -45,4 +49,4 @@ - \ No newline at end of file + From 5dd8299525eb59c205f01bec336148bd57b5daec Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 19 Mar 2020 14:24:05 -0700 Subject: [PATCH 0830/1415] ConnectedNetworkScorerTest: Add tests for wifi usability stats Bug: 150236894 Bug: 150973472 Test: atest android.net.wifi.cts.ConnectedNetworkScorerTest Change-Id: Ic55dbbe672da5492db5382aa6c427976355518ed --- .../wifi/cts/ConnectedNetworkScorerTest.java | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java diff --git a/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java b/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java new file mode 100644 index 0000000000..5869ee8ea4 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java @@ -0,0 +1,236 @@ +/* + * 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.wifi.cts; + +import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE; +import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE; +import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS; +import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.UiAutomation; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiUsabilityStatsEntry; +import android.support.test.uiautomator.UiDevice; +import android.telephony.TelephonyManager; +import android.test.AndroidTestCase; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.compatibility.common.util.PollingCheck; +import com.android.compatibility.common.util.ShellIdentityUtils; +import com.android.compatibility.common.util.SystemUtil; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class ConnectedNetworkScorerTest extends AndroidTestCase { + private WifiManager mWifiManager; + private UiDevice mUiDevice; + private boolean mWasVerboseLoggingEnabled; + + private static final int DURATION = 10_000; + private static final int DURATION_SCREEN_TOGGLE = 2000; + + @Override + protected void setUp() throws Exception { + super.setUp(); + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + mWifiManager = getContext().getSystemService(WifiManager.class); + assertNotNull(mWifiManager); + + // turn on verbose logging for tests + mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.isVerboseLoggingEnabled()); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setVerboseLoggingEnabled(true)); + + if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); + mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + turnScreenOn(); + PollingCheck.check("Wifi not enabled", DURATION, () -> mWifiManager.isWifiEnabled()); + List savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.getConfiguredNetworks()); + assertFalse("Need at least one saved network", savedNetworks.isEmpty()); + // Wait for wifi is to be connected + PollingCheck.check( + "Wifi not connected", + DURATION, + () -> mWifiManager.getConnectionInfo().getNetworkId() != -1); + assertThat(mWifiManager.getConnectionInfo().getNetworkId()).isNotEqualTo(-1); + } + + @Override + protected void tearDown() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + super.tearDown(); + return; + } + if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); + turnScreenOff(); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); + super.tearDown(); + } + + private void setWifiEnabled(boolean enable) throws Exception { + // now trigger the change using shell commands. + SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable")); + } + + private void turnScreenOn() throws Exception { + mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); + mUiDevice.executeShellCommand("wm dismiss-keyguard"); + // Since the screen on/off intent is ordered, they will not be sent right now. + Thread.sleep(DURATION_SCREEN_TOGGLE); + } + + private void turnScreenOff() throws Exception { + mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); + } + + private static class TestUsabilityStatsListener implements + WifiManager.OnWifiUsabilityStatsListener { + private final CountDownLatch mCountDownLatch; + public int seqNum; + public boolean isSameBssidAndFre; + public WifiUsabilityStatsEntry statsEntry; + + TestUsabilityStatsListener(CountDownLatch countDownLatch) { + mCountDownLatch = countDownLatch; + } + + @Override + public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, + WifiUsabilityStatsEntry statsEntry) { + this.seqNum = seqNum; + this.isSameBssidAndFre = isSameBssidAndFreq; + this.statsEntry = statsEntry; + mCountDownLatch.countDown(); + } + } + + /** + * Tests the {@link android.net.wifi.WifiUsabilityStatsEntry} retrieved from + * {@link WifiManager.OnWifiUsabilityStatsListener}. + */ + public void testWifiUsabilityStatsEntry() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + CountDownLatch countDownLatch = new CountDownLatch(1); + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + TestUsabilityStatsListener usabilityStatsListener = + new TestUsabilityStatsListener(countDownLatch); + try { + uiAutomation.adoptShellPermissionIdentity(); + mWifiManager.addOnWifiUsabilityStatsListener( + Executors.newSingleThreadExecutor(), usabilityStatsListener); + // Wait for new usability stats (while connected & screen on this is triggered + // by platform periodically). + assertThat(countDownLatch.await(DURATION, TimeUnit.MILLISECONDS)).isTrue(); + + assertThat(usabilityStatsListener.statsEntry).isNotNull(); + WifiUsabilityStatsEntry statsEntry = usabilityStatsListener.statsEntry; + + assertThat(statsEntry.getTimeStampMillis()).isGreaterThan(0L); + assertThat(statsEntry.getRssi()).isLessThan(0); + assertThat(statsEntry.getLinkSpeedMbps()).isGreaterThan(0); + assertThat(statsEntry.getTotalTxSuccess()).isGreaterThan(0L); + assertThat(statsEntry.getTotalTxRetries()).isAtLeast(0L); + assertThat(statsEntry.getTotalTxBad()).isAtLeast(0L); + assertThat(statsEntry.getTotalRxSuccess()).isAtLeast(0L); + assertThat(statsEntry.getTotalRadioOnTimeMillis()).isGreaterThan(0L); + assertThat(statsEntry.getTotalRadioTxTimeMillis()).isGreaterThan(0L); + assertThat(statsEntry.getTotalRadioRxTimeMillis()).isGreaterThan(0L); + assertThat(statsEntry.getTotalScanTimeMillis()).isGreaterThan(0L); + assertThat(statsEntry.getTotalNanScanTimeMillis()).isAtLeast(0L); + assertThat(statsEntry.getTotalBackgroundScanTimeMillis()).isAtLeast(0L); + assertThat(statsEntry.getTotalRoamScanTimeMillis()).isAtLeast(0L); + assertThat(statsEntry.getTotalPnoScanTimeMillis()).isAtLeast(0L); + assertThat(statsEntry.getTotalHotspot2ScanTimeMillis()).isAtLeast(0L); + assertThat(statsEntry.getTotalCcaBusyFreqTimeMillis()).isAtLeast(0L); + assertThat(statsEntry.getTotalRadioOnTimeMillis()).isGreaterThan(0L); + assertThat(statsEntry.getTotalBeaconRx()).isGreaterThan(0L); + assertThat(statsEntry.getProbeStatusSinceLastUpdate()) + .isAnyOf(PROBE_STATUS_SUCCESS, + PROBE_STATUS_FAILURE, + PROBE_STATUS_NO_PROBE, + PROBE_STATUS_UNKNOWN); + // -1 is default value for some of these fields if they're not available. + assertThat(statsEntry.getProbeElapsedTimeSinceLastUpdateMillis()).isAtLeast(-1); + assertThat(statsEntry.getProbeMcsRateSinceLastUpdate()).isAtLeast(-1); + assertThat(statsEntry.getRxLinkSpeedMbps()).isAtLeast(-1); + // no longer populated, return default value. + assertThat(statsEntry.getCellularDataNetworkType()) + .isAnyOf(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyManager.NETWORK_TYPE_GPRS, + TelephonyManager.NETWORK_TYPE_EDGE, + TelephonyManager.NETWORK_TYPE_UMTS, + TelephonyManager.NETWORK_TYPE_CDMA, + TelephonyManager.NETWORK_TYPE_EVDO_0, + TelephonyManager.NETWORK_TYPE_EVDO_A, + TelephonyManager.NETWORK_TYPE_1xRTT, + TelephonyManager.NETWORK_TYPE_HSDPA, + TelephonyManager.NETWORK_TYPE_HSUPA, + TelephonyManager.NETWORK_TYPE_HSPA, + TelephonyManager.NETWORK_TYPE_IDEN, + TelephonyManager.NETWORK_TYPE_EVDO_B, + TelephonyManager.NETWORK_TYPE_LTE, + TelephonyManager.NETWORK_TYPE_EHRPD, + TelephonyManager.NETWORK_TYPE_HSPAP, + TelephonyManager.NETWORK_TYPE_GSM, + TelephonyManager.NETWORK_TYPE_TD_SCDMA, + TelephonyManager.NETWORK_TYPE_IWLAN, + TelephonyManager.NETWORK_TYPE_NR); + assertThat(statsEntry.getCellularSignalStrengthDbm()).isAtMost(0); + assertThat(statsEntry.getCellularSignalStrengthDb()).isAtMost(0); + assertThat(statsEntry.isSameRegisteredCell()).isFalse(); + } finally { + mWifiManager.removeOnWifiUsabilityStatsListener(usabilityStatsListener); + uiAutomation.dropShellPermissionIdentity(); + } + } + + /** + * Tests the {@link android.net.wifi.WifiManager#updateWifiUsabilityScore(int, int, int)} + */ + public void testUpdateWifiUsabilityScore() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + // update scoring with dummy values. + mWifiManager.updateWifiUsabilityScore(0, 50, 50); + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } + +} From b6b4c49895b700081e021c5b80fbd89748487bd2 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 19 Mar 2020 15:09:28 -0700 Subject: [PATCH 0831/1415] ConnectedNetworkScorerTest: Add test for connected network scorer Bug: 150236894 Bug: 150973472 Test: atest android.net.wifi.cts.ConnectedNetworkScorerTest Change-Id: Id928678bfefe00f66229f4dbd9915c7f41274972 --- .../wifi/cts/ConnectedNetworkScorerTest.java | 110 +++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java b/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java index 5869ee8ea4..ce5bb81d7b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java @@ -58,7 +58,7 @@ public class ConnectedNetworkScorerTest extends AndroidTestCase { return; } mWifiManager = getContext().getSystemService(WifiManager.class); - assertNotNull(mWifiManager); + assertThat(mWifiManager).isNotNull(); // turn on verbose logging for tests mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( @@ -233,4 +233,112 @@ public class ConnectedNetworkScorerTest extends AndroidTestCase { } } + private static class TestConnectedNetworkScorer implements + WifiManager.WifiConnectedNetworkScorer { + private CountDownLatch mCountDownLatch; + public int startSessionId; + public int stopSessionId; + public WifiManager.ScoreUpdateObserver scoreUpdateObserver; + + TestConnectedNetworkScorer(CountDownLatch countDownLatch) { + mCountDownLatch = countDownLatch; + } + + @Override + public void onStart(int sessionId) { + synchronized (mCountDownLatch) { + this.startSessionId = sessionId; + mCountDownLatch.countDown(); + } + } + + @Override + public void onStop(int sessionId) { + synchronized (mCountDownLatch) { + this.stopSessionId = sessionId; + mCountDownLatch.countDown(); + } + } + + @Override + public void onSetScoreUpdateObserver(WifiManager.ScoreUpdateObserver observerImpl) { + this.scoreUpdateObserver = observerImpl; + } + + public void resetCountDownLatch(CountDownLatch countDownLatch) { + synchronized (mCountDownLatch) { + mCountDownLatch = countDownLatch; + } + } + } + + /** + * Tests the {@link android.net.wifi.WifiConnectedNetworkScorer} interface. + * + * Note: We could write more interesting test cases (if the device has a mobile connection), but + * that would make the test flaky. The default network/route selection on the device is not just + * controlled by the wifi scorer input, but also based on params which are controlled by + * other parts of the platform (likely in connectivity service) and hence will behave + * differently on OEM devices. + */ + public void testSetWifiConnectedNetworkScorer() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + CountDownLatch countDownLatchScorer = new CountDownLatch(1); + CountDownLatch countDownLatchUsabilityStats = new CountDownLatch(1); + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + TestConnectedNetworkScorer connectedNetworkScorer = + new TestConnectedNetworkScorer(countDownLatchScorer); + TestUsabilityStatsListener usabilityStatsListener = + new TestUsabilityStatsListener(countDownLatchUsabilityStats); + try { + uiAutomation.adoptShellPermissionIdentity(); + mWifiManager.setWifiConnectedNetworkScorer( + Executors.newSingleThreadExecutor(), connectedNetworkScorer); + // Since we're already connected, wait for onStart to be invoked. + assertThat(countDownLatchScorer.await(DURATION, TimeUnit.MILLISECONDS)).isTrue(); + + assertThat(connectedNetworkScorer.startSessionId).isAtLeast(0); + assertThat(connectedNetworkScorer.scoreUpdateObserver).isNotNull(); + WifiManager.ScoreUpdateObserver scoreUpdateObserver = + connectedNetworkScorer.scoreUpdateObserver; + + // Now trigger a dummy score update. + scoreUpdateObserver.notifyScoreUpdate(connectedNetworkScorer.startSessionId, 50); + + // Register the usability listener + mWifiManager.addOnWifiUsabilityStatsListener( + Executors.newSingleThreadExecutor(), usabilityStatsListener); + // Trigger a usability stats update. + scoreUpdateObserver.triggerUpdateOfWifiUsabilityStats( + connectedNetworkScorer.startSessionId); + // Ensure that we got the stats update callback. + assertThat(countDownLatchUsabilityStats.await(DURATION, TimeUnit.MILLISECONDS)) + .isTrue(); + assertThat(usabilityStatsListener.seqNum).isAtLeast(0); + + // Reset the scorer countdown latch for onStop + countDownLatchScorer = new CountDownLatch(1); + connectedNetworkScorer.resetCountDownLatch(countDownLatchScorer); + // Now disconnect from the network. + mWifiManager.disconnect(); + // Wait for it to be disconnected. + PollingCheck.check( + "Wifi not disconnected", + DURATION, + () -> mWifiManager.getConnectionInfo().getNetworkId() == -1); + assertThat(mWifiManager.getConnectionInfo().getNetworkId()).isEqualTo(-1); + + // Wait for stop to be invoked and ensure that the session id matches. + assertThat(countDownLatchScorer.await(DURATION, TimeUnit.MILLISECONDS)).isTrue(); + assertThat(connectedNetworkScorer.stopSessionId) + .isEqualTo(connectedNetworkScorer.startSessionId); + } finally { + mWifiManager.removeOnWifiUsabilityStatsListener(usabilityStatsListener); + mWifiManager.clearWifiConnectedNetworkScorer(); + uiAutomation.dropShellPermissionIdentity(); + } + } } From 4168cea5e1a8ddb8de527d3cd77a93a51f09685d Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Fri, 20 Mar 2020 13:24:30 +0000 Subject: [PATCH 0832/1415] Update tethering module api files Bug: 147768409 Test: m checkapi Merged-In: Idd041f0fbeca411ea23e49786a50dd7feb77ef45 Change-Id: I3da71661048b1f66522696e9333c2c14a224fe9f --- .../TetheringLib/api/module-lib-current.txt | 49 ++++++++++--------- .../TetheringLib/api/system-current.txt | 46 ++++++++--------- 2 files changed, 45 insertions(+), 50 deletions(-) diff --git a/Tethering/common/TetheringLib/api/module-lib-current.txt b/Tethering/common/TetheringLib/api/module-lib-current.txt index 8a7e975051..e823e17892 100644 --- a/Tethering/common/TetheringLib/api/module-lib-current.txt +++ b/Tethering/common/TetheringLib/api/module-lib-current.txt @@ -62,19 +62,20 @@ package android.net { field public static final int TETHERING_WIFI = 0; // 0x0 field public static final int TETHERING_WIFI_P2P = 3; // 0x3 field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc - field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9 - field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8 + field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9 + field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8 field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa - field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5 + field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5 field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 - field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2 field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6 field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4 field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1 + field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10 field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3 field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7 field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2 @@ -86,29 +87,26 @@ package android.net { method public void onTetheringEntitlementResult(int); } - public abstract static class TetheringManager.StartTetheringCallback { - ctor public TetheringManager.StartTetheringCallback(); - method public void onTetheringFailed(int); - method public void onTetheringStarted(); + public static interface TetheringManager.StartTetheringCallback { + method public default void onTetheringFailed(int); + method public default void onTetheringStarted(); } - public abstract static class TetheringManager.TetheringEventCallback { - ctor public TetheringManager.TetheringEventCallback(); - method public void onClientsChanged(@NonNull java.util.Collection); - method public void onError(@NonNull String, int); - method public void onOffloadStatusChanged(int); - method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); - method public void onTetherableInterfacesChanged(@NonNull java.util.List); - method public void onTetheredInterfacesChanged(@NonNull java.util.List); - method public void onTetheringSupported(boolean); - method public void onUpstreamChanged(@Nullable android.net.Network); + public static interface TetheringManager.TetheringEventCallback { + method public default void onClientsChanged(@NonNull java.util.Collection); + method public default void onError(@NonNull String, int); + method public default void onOffloadStatusChanged(int); + method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); + method public default void onTetherableInterfacesChanged(@NonNull java.util.List); + method public default void onTetheredInterfacesChanged(@NonNull java.util.List); + method public default void onTetheringSupported(boolean); + method public default void onUpstreamChanged(@Nullable android.net.Network); } - @Deprecated public static class TetheringManager.TetheringInterfaceRegexps { - ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]); - method @Deprecated @NonNull public java.util.List getTetherableBluetoothRegexs(); - method @Deprecated @NonNull public java.util.List getTetherableUsbRegexs(); - method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); + public static class TetheringManager.TetheringInterfaceRegexps { + method @NonNull public java.util.List getTetherableBluetoothRegexs(); + method @NonNull public java.util.List getTetherableUsbRegexs(); + method @NonNull public java.util.List getTetherableWifiRegexs(); } public static class TetheringManager.TetheringRequest { @@ -119,8 +117,11 @@ package android.net { method @NonNull public android.net.TetheringManager.TetheringRequest build(); method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); method @Nullable public android.net.LinkAddress getLocalIpv4Address(); + method public boolean getShouldShowEntitlementUi(); + method public int getTetheringType(); + method public boolean isExemptFromEntitlementCheck(); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); - method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); } diff --git a/Tethering/common/TetheringLib/api/system-current.txt b/Tethering/common/TetheringLib/api/system-current.txt index ac739532a4..375113553d 100644 --- a/Tethering/common/TetheringLib/api/system-current.txt +++ b/Tethering/common/TetheringLib/api/system-current.txt @@ -40,19 +40,20 @@ package android.net { field public static final int TETHERING_WIFI = 0; // 0x0 field public static final int TETHERING_WIFI_P2P = 3; // 0x3 field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc - field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9 - field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8 + field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9 + field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8 field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa - field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5 + field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5 field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 - field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2 field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6 field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4 field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1 + field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10 field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3 field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7 field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2 @@ -64,29 +65,19 @@ package android.net { method public void onTetheringEntitlementResult(int); } - public abstract static class TetheringManager.StartTetheringCallback { - ctor public TetheringManager.StartTetheringCallback(); - method public void onTetheringFailed(int); - method public void onTetheringStarted(); + public static interface TetheringManager.StartTetheringCallback { + method public default void onTetheringFailed(int); + method public default void onTetheringStarted(); } - public abstract static class TetheringManager.TetheringEventCallback { - ctor public TetheringManager.TetheringEventCallback(); - method public void onClientsChanged(@NonNull java.util.Collection); - method public void onError(@NonNull String, int); - method public void onOffloadStatusChanged(int); - method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); - method public void onTetherableInterfacesChanged(@NonNull java.util.List); - method public void onTetheredInterfacesChanged(@NonNull java.util.List); - method public void onTetheringSupported(boolean); - method public void onUpstreamChanged(@Nullable android.net.Network); - } - - @Deprecated public static class TetheringManager.TetheringInterfaceRegexps { - ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]); - method @Deprecated @NonNull public java.util.List getTetherableBluetoothRegexs(); - method @Deprecated @NonNull public java.util.List getTetherableUsbRegexs(); - method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); + public static interface TetheringManager.TetheringEventCallback { + method public default void onClientsChanged(@NonNull java.util.Collection); + method public default void onError(@NonNull String, int); + method public default void onOffloadStatusChanged(int); + method public default void onTetherableInterfacesChanged(@NonNull java.util.List); + method public default void onTetheredInterfacesChanged(@NonNull java.util.List); + method public default void onTetheringSupported(boolean); + method public default void onUpstreamChanged(@Nullable android.net.Network); } public static class TetheringManager.TetheringRequest { @@ -97,8 +88,11 @@ package android.net { method @NonNull public android.net.TetheringManager.TetheringRequest build(); method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); method @Nullable public android.net.LinkAddress getLocalIpv4Address(); + method public boolean getShouldShowEntitlementUi(); + method public int getTetheringType(); + method public boolean isExemptFromEntitlementCheck(); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); - method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); } From f25df0d381c27936d75994268f355537e150d927 Mon Sep 17 00:00:00 2001 From: lesl Date: Fri, 20 Mar 2020 17:47:43 +0800 Subject: [PATCH 0833/1415] cts: unregister softap callback after finish the test Bug: 150307166 Test: atest android.net.wifi.cts.WifiManagerTest Change-Id: If189be91217f4f94e358fc0aedd2bfcc36f96c84 --- .../net/src/android/net/wifi/cts/WifiManagerTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index ae5ef75af6..12db0257be 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -1447,11 +1447,11 @@ public class WifiManagerTest extends AndroidTestCase { */ public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception { UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + TestExecutor executor = new TestExecutor(); + TestSoftApCallback callback = new TestSoftApCallback(mLock); try { uiAutomation.adoptShellPermissionIdentity(); turnOffWifiAndTetheredHotspotIfEnabled(); - TestExecutor executor = new TestExecutor(); - TestSoftApCallback callback = new TestSoftApCallback(mLock); verifyRegisterSoftApCallback(executor, callback); SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder() @@ -1490,6 +1490,7 @@ public class WifiManagerTest extends AndroidTestCase { verifySetGetSoftApConfig(softApConfigBuilder.build()); } } finally { + mWifiManager.unregisterSoftApCallback(callback); uiAutomation.dropShellPermissionIdentity(); } } @@ -1501,11 +1502,11 @@ public class WifiManagerTest extends AndroidTestCase { public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback() throws Exception { UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + TestExecutor executor = new TestExecutor(); + TestSoftApCallback callback = new TestSoftApCallback(mLock); try { uiAutomation.adoptShellPermissionIdentity(); turnOffWifiAndTetheredHotspotIfEnabled(); - TestExecutor executor = new TestExecutor(); - TestSoftApCallback callback = new TestSoftApCallback(mLock); verifyRegisterSoftApCallback(executor, callback); SoftApConfiguration testSoftApConfig = new SoftApConfiguration.Builder() @@ -1544,6 +1545,7 @@ public class WifiManagerTest extends AndroidTestCase { 0 == callback.getCurrentSoftApInfo().getFrequency(); }); } finally { + mWifiManager.unregisterSoftApCallback(callback); uiAutomation.dropShellPermissionIdentity(); } } From 29c4a944064d40a76fab571c1cb597bb46d3c05a Mon Sep 17 00:00:00 2001 From: Nate Jiang Date: Thu, 19 Mar 2020 16:57:03 -0700 Subject: [PATCH 0834/1415] Add cts test for ResponderLocation Bug: 150976615 Test: atest WifiRttTest Change-Id: I830c50d2011ef024b2e758d4558379ab12f1ebae --- .../android/net/wifi/rtt/cts/WifiRttTest.java | 157 +++++++++++++++++- 1 file changed, 156 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java index d5361d730d..25a90b55a1 100644 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java +++ b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock; import android.net.wifi.ScanResult; import android.net.wifi.rtt.RangingRequest; import android.net.wifi.rtt.RangingResult; +import android.net.wifi.rtt.ResponderLocation; import android.platform.test.annotations.AppModeFull; import com.android.compatibility.common.util.DeviceReportLog; @@ -163,7 +164,8 @@ public class WifiRttTest extends TestBase { // Analyze results assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures + ", ITERATIONS=" - + NUM_OF_RTT_ITERATIONS + ", AP RSSI=" + testAp.level, + + NUM_OF_RTT_ITERATIONS + ", AP RSSI=" + testAp.level + + ", AP SSID=" + testAp.SSID, numFailures <= NUM_OF_RTT_ITERATIONS * MAX_FAILURE_RATE_PERCENT / 100); if (numFailures != NUM_OF_RTT_ITERATIONS) { double distanceAvg = distanceSum / (NUM_OF_RTT_ITERATIONS - numFailures); @@ -213,4 +215,157 @@ public class WifiRttTest extends TestBase { + "many peers", false); } + + /** + * Verify ResponderLocation API + */ + public void testRangingToTestApWithResponderLocation() throws InterruptedException { + if (!shouldTestWifiRtt(getContext())) { + return; + } + // Scan for IEEE 802.11mc supporting APs + ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); + assertTrue( + "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " + + "your test setup includes them!", + testAp != null); + + // Perform RTT operations + RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build(); + ResultCallback callback = new ResultCallback(); + mWifiRttManager.startRanging(request, mExecutor, callback); + assertTrue("Wi-Fi RTT results: no callback! ", + callback.waitForCallback()); + + RangingResult result = callback.getResults().get(0); + assertEquals("Ranging request not success", + result.getStatus(), RangingResult.STATUS_SUCCESS); + ResponderLocation responderLocation = result.getUnverifiedResponderLocation(); + assertNotNull("ResponderLocation should not be null", responderLocation); + assertTrue("ResponderLocation is not valid", responderLocation.isLciSubelementValid()); + + // Check LCI related APIs + int exceptionCount = 0; + int apiCount = 0; + try { + apiCount++; + responderLocation.getLatitudeUncertainty(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getLatitude(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getLongitudeUncertainty(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getLongitude(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getAltitudeType(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getAltitudeUncertainty(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getAltitude(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getDatum(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getRegisteredLocationAgreementIndication(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + responderLocation.getLciVersion(); + } catch (IllegalStateException e) { + exceptionCount++; + } + try { + apiCount++; + assertNotNull(responderLocation.toLocation()); + } catch (IllegalStateException e) { + exceptionCount++; + } + // If LCI is not valid, all APIs should throw exception, otherwise no exception. + assertEquals("Exception number should equal to API number", + responderLocation.isLciSubelementValid()? 0 : apiCount, exceptionCount); + + // Verify ZaxisSubelement APIs + apiCount = 0; + exceptionCount = 0; + + try { + apiCount++; + responderLocation.getExpectedToMove(); + } catch (IllegalStateException e) { + exceptionCount++; + } + + try { + apiCount++; + responderLocation.getFloorNumber(); + } catch (IllegalStateException e) { + exceptionCount++; + } + + try { + apiCount++; + responderLocation.getHeightAboveFloorMeters(); + } catch (IllegalStateException e) { + exceptionCount++; + } + + try { + apiCount++; + responderLocation.getHeightAboveFloorUncertaintyMeters(); + } catch (IllegalStateException e) { + exceptionCount++; + } + // If Zaxis is not valid, all APIs should throw exception, otherwise no exception. + assertEquals("Exception number should equal to API number", + responderLocation.isZaxisSubelementValid() ? 0 : apiCount, exceptionCount); + // Verify civic location + if (responderLocation.toCivicLocationAddress() == null) { + assertNull(responderLocation.toCivicLocationSparseArray()); + } else { + assertNotNull(responderLocation.toCivicLocationSparseArray()); + } + // Verify map image + if (responderLocation.getMapImageUri() == null) { + assertNull(responderLocation.getMapImageMimeType()); + } else { + assertNotNull(responderLocation.getMapImageMimeType()); + } + boolean extraInfoOnAssociationIndication = + responderLocation.getExtraInfoOnAssociationIndication(); + assertNotNull("ColocatedBSSID list should be nonNull", + responderLocation.getColocatedBssids()); + } } From 1ccef6fefe605899484106e615b38add25da6f5d Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Fri, 20 Mar 2020 11:58:08 -0700 Subject: [PATCH 0835/1415] WifiMigration: Add test for the config store APIs This only tests that the API does exist, there isn't any other feasible tests for this API surface. Bug: 150973073 Test: atest android.net.wifi.cts.WifiMigrationTest Change-Id: I094e716027a6eb0995b6c20ed351ee12b91fce85 --- .../net/wifi/cts/WifiMigrationTest.java | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java index 7d94ad3ff8..c74c177039 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java @@ -16,7 +16,10 @@ package android.net.wifi.cts; +import android.app.ActivityManager; import android.net.wifi.WifiMigration; +import android.os.UserHandle; +import android.os.UserManager; import android.test.AndroidTestCase; public class WifiMigrationTest extends AndroidTestCase { @@ -75,9 +78,61 @@ public class WifiMigrationTest extends AndroidTestCase { */ public void testWifiMigrationSettings() throws Exception { try { - // ensure that this does not crash. WifiMigration.loadFromSettings(getContext()); } catch (Exception ignore) { } } + + /** + * Tests {@link WifiMigration#convertAndRetrieveSharedConfigStoreFile(int)}, + * {@link WifiMigration#convertAndRetrieveUserConfigStoreFile(int, UserHandle)}, + * {@link WifiMigration#removeSharedConfigStoreFile(int)} and + * {@link WifiMigration#removeUserConfigStoreFile(int, UserHandle)}. + */ + public void testWifiMigrationConfigStore() throws Exception { + try { + WifiMigration.convertAndRetrieveSharedConfigStoreFile( + WifiMigration.STORE_FILE_SHARED_GENERAL); + } catch (Exception ignore) { + } + try { + WifiMigration.convertAndRetrieveSharedConfigStoreFile( + WifiMigration.STORE_FILE_SHARED_SOFTAP); + } catch (Exception ignore) { + } + try { + WifiMigration.convertAndRetrieveUserConfigStoreFile( + WifiMigration.STORE_FILE_USER_GENERAL, + UserHandle.of(ActivityManager.getCurrentUser())); + } catch (Exception ignore) { + } + try { + WifiMigration.convertAndRetrieveUserConfigStoreFile( + WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS, + UserHandle.of(ActivityManager.getCurrentUser())); + } catch (Exception ignore) { + } + try { + WifiMigration.removeSharedConfigStoreFile( + WifiMigration.STORE_FILE_SHARED_GENERAL); + } catch (Exception ignore) { + } + try { + WifiMigration.removeSharedConfigStoreFile( + WifiMigration.STORE_FILE_SHARED_SOFTAP); + } catch (Exception ignore) { + } + try { + WifiMigration.removeUserConfigStoreFile( + WifiMigration.STORE_FILE_USER_GENERAL, + UserHandle.of(ActivityManager.getCurrentUser())); + } catch (Exception ignore) { + } + try { + WifiMigration.removeUserConfigStoreFile( + WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS, + UserHandle.of(ActivityManager.getCurrentUser())); + } catch (Exception ignore) { + } + } } From fd50cff7c6365a0781218552496f92491d881654 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 18 Mar 2020 18:31:39 +0900 Subject: [PATCH 0836/1415] Remove usage of Context.NETWORK_STACK_SERVICE The NetworkStack.getService() API should be used instead. Bug: 151243982 Test: atest FrameworksNetTests TetheringTests Manual tethering test Merged-In: I7855090bffbe895c8349ad4903b8f2eb55515f0b (clean cherry-pick from internal branch) Change-Id: If4af2846a82605e828287a9a4680d5547b76b802 --- .../server/connectivity/tethering/TetheringService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java index 020b32adcf..c5329d8d33 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -33,6 +33,7 @@ import android.net.ITetheringConnector; import android.net.ITetheringEventCallback; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.NetworkStack; import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; @@ -364,8 +365,7 @@ public class TetheringService extends Service { IBinder connector; try { final long before = System.currentTimeMillis(); - while ((connector = (IBinder) mContext.getSystemService( - Context.NETWORK_STACK_SERVICE)) == null) { + while ((connector = NetworkStack.getService()) == null) { if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); return null; From a8b377747b8066594345402dd4e4750a5541acc9 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 23 Mar 2020 10:47:42 +0800 Subject: [PATCH 0837/1415] Address API council review comment about TetheringRequest Test: atest TetheringTests FrameworksNetTests NetworkStackTests Bug: 152055812 Change-Id: I0158d88e364772f9ac258bd18955edcdad266ad8 Merged-In: I0158d88e364772f9ac258bd18955edcdad266ad8 (this is a clean cherry-pick from ag/10796412) Change-Id: I64f1527d79085cc5dfd78c01a6c49c4df87c82e7 --- .../TetheringLib/api/module-lib-current.txt | 10 ++-- .../TetheringLib/api/system-current.txt | 10 ++-- .../src/android/net/TetheringManager.java | 51 +++++++++++-------- 3 files changed, 39 insertions(+), 32 deletions(-) diff --git a/Tethering/common/TetheringLib/api/module-lib-current.txt b/Tethering/common/TetheringLib/api/module-lib-current.txt index e823e17892..754584e70f 100644 --- a/Tethering/common/TetheringLib/api/module-lib-current.txt +++ b/Tethering/common/TetheringLib/api/module-lib-current.txt @@ -110,16 +110,16 @@ package android.net { } public static class TetheringManager.TetheringRequest { - } - - public static class TetheringManager.TetheringRequest.Builder { - ctor public TetheringManager.TetheringRequest.Builder(int); - method @NonNull public android.net.TetheringManager.TetheringRequest build(); method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); method @Nullable public android.net.LinkAddress getLocalIpv4Address(); method public boolean getShouldShowEntitlementUi(); method public int getTetheringType(); method public boolean isExemptFromEntitlementCheck(); + } + + public static class TetheringManager.TetheringRequest.Builder { + ctor public TetheringManager.TetheringRequest.Builder(int); + method @NonNull public android.net.TetheringManager.TetheringRequest build(); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); diff --git a/Tethering/common/TetheringLib/api/system-current.txt b/Tethering/common/TetheringLib/api/system-current.txt index 375113553d..2f5ea6af71 100644 --- a/Tethering/common/TetheringLib/api/system-current.txt +++ b/Tethering/common/TetheringLib/api/system-current.txt @@ -81,16 +81,16 @@ package android.net { } public static class TetheringManager.TetheringRequest { - } - - public static class TetheringManager.TetheringRequest.Builder { - ctor public TetheringManager.TetheringRequest.Builder(int); - method @NonNull public android.net.TetheringManager.TetheringRequest build(); method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); method @Nullable public android.net.LinkAddress getLocalIpv4Address(); method public boolean getShouldShowEntitlementUi(); method public int getTetheringType(); method public boolean isExemptFromEntitlementCheck(); + } + + public static class TetheringManager.TetheringRequest.Builder { + ctor public TetheringManager.TetheringRequest.Builder(int); + method @NonNull public android.net.TetheringManager.TetheringRequest build(); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index cd54c6f14c..b70165ab74 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -620,33 +620,40 @@ public class TetheringManager { public TetheringRequest build() { return new TetheringRequest(mBuilderParcel); } + } - @Nullable - public LinkAddress getLocalIpv4Address() { - return mBuilderParcel.localIPv4Address; - } + /** + * Get the local IPv4 address, if one was configured with + * {@link Builder#setStaticIpv4Addresses}. + */ + @Nullable + public LinkAddress getLocalIpv4Address() { + return mRequestParcel.localIPv4Address; + } - /** Get static client address. */ - @Nullable - public LinkAddress getClientStaticIpv4Address() { - return mBuilderParcel.staticClientAddress; - } + /** + * Get the static IPv4 address of the client, if one was configured with + * {@link Builder#setStaticIpv4Addresses}. + */ + @Nullable + public LinkAddress getClientStaticIpv4Address() { + return mRequestParcel.staticClientAddress; + } - /** Get tethering type. */ - @TetheringType - public int getTetheringType() { - return mBuilderParcel.tetheringType; - } + /** Get tethering type. */ + @TetheringType + public int getTetheringType() { + return mRequestParcel.tetheringType; + } - /** Check if exempt from entitlement check. */ - public boolean isExemptFromEntitlementCheck() { - return mBuilderParcel.exemptFromEntitlementCheck; - } + /** Check if exempt from entitlement check. */ + public boolean isExemptFromEntitlementCheck() { + return mRequestParcel.exemptFromEntitlementCheck; + } - /** Check if show entitlement ui. */ - public boolean getShouldShowEntitlementUi() { - return mBuilderParcel.showProvisioningUi; - } + /** Check if show entitlement ui. */ + public boolean getShouldShowEntitlementUi() { + return mRequestParcel.showProvisioningUi; } /** From 90e7e6cf3fed3a03b3858032a9718270769b4142 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 23 Mar 2020 16:29:46 +0900 Subject: [PATCH 0838/1415] Fix AudioGroupTest on Q The AudioGroup constructor with a Context parameter does not exist on Q devices. Use the previous constructor on older devices. Test: atest CtsNetTestCasesLatestSdk on Q and R devices Bug: 150918852 Change-Id: I24c3e7ab8c7219d6f345943ead3e3b6418fa7f47 --- tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java index fee8621c70..fc78e96e11 100644 --- a/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java +++ b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java @@ -21,9 +21,12 @@ import android.net.rtp.AudioCodec; import android.net.rtp.AudioGroup; import android.net.rtp.AudioStream; import android.net.rtp.RtpStream; +import android.os.Build; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; +import androidx.core.os.BuildCompat; + import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; @@ -62,7 +65,10 @@ public class AudioGroupTest extends AndroidTestCase { mSocketB.connect(mStreamB.getLocalAddress(), mStreamB.getLocalPort()); mStreamB.associate(mSocketB.getLocalAddress(), mSocketB.getLocalPort()); - mGroup = new AudioGroup(mContext); + // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R) + mGroup = Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR() + ? new AudioGroup(mContext) + : new AudioGroup(); // Constructor with context argument was introduced in R } @Override From bbe4af1f08755f6cce59b1a994585b25e62105fa Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Wed, 18 Mar 2020 14:15:42 +0000 Subject: [PATCH 0839/1415] Build tethering against the module SDK Link against the stubs of other modules and the implementation of the tethering module jar. Bug: 146757305 Test: m Tethering Change-Id: I7c93b60654e21a4a27d21cbf0c2a6cb21f813529 Merged-In: I7c93b60654e21a4a27d21cbf0c2a6cb21f813529 (cherry picked from commit aaeaa195b837c27d1f7896ca6c3eb3921c491794) --- Tethering/Android.bp | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 0c37235129..0cfd8843c0 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -16,9 +16,7 @@ java_defaults { name: "TetheringAndroidLibraryDefaults", - // TODO (b/146757305): change to module API once available - // TODO (b/148190005): change to module-libs-api-stubs-current once it is ready. - sdk_version: "core_platform", + sdk_version: "module_current", srcs: [ "src/**/*.java", ":framework-tethering-shared-srcs", @@ -35,15 +33,8 @@ java_defaults { "net-utils-framework-common", ], libs: [ - // Order matters: framework-tethering needs to be before the system stubs, otherwise - // hidden fields in the framework-tethering classes (which are also used to generate stubs) - // will not be found. "framework-tethering", - "android_system_stubs_current", - "framework-res", "unsupportedappusage", - "android_system_stubs_current", - "framework-res", ], plugins: ["java_api_finder"], manifest: "AndroidManifestBase.xml", @@ -91,9 +82,7 @@ cc_library { // Common defaults for compiling the actual APK. java_defaults { name: "TetheringAppDefaults", - // TODO (b/146757305): change to module API once available - // TODO (b/148190005): change to module-libs-api-stubs-current once it is ready. - sdk_version: "core_platform", + sdk_version: "module_current", privileged: true, jni_libs: [ "libtetherutilsjni", @@ -102,12 +91,7 @@ java_defaults { "res", ], libs: [ - // Order matters: framework-tethering needs to be before the system stubs, otherwise - // hidden fields in the framework-tethering classes (which are also used to generate stubs) - // will not be found. "framework-tethering", - "android_system_stubs_current", - "framework-res", ], jarjar_rules: "jarjar-rules.txt", optimize: { From ad92bb63b5eddecf7cdad5e3e43a566143fe86a7 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 23 Mar 2020 08:06:00 -0700 Subject: [PATCH 0840/1415] WifiManagerTest: Use getPrivilegedConfiguredNetworks() in factory reset test Bug: 152048238 Test: atest android.net.wifi.cts.WifiManagerTest Reproduced the original issue (i.e tests after testFactoryReset failing) with a PSK network on the device & verified that this CL fixes the failures. Change-Id: I56947a78142e971c8da6a1c098ebbd0f1e7d370d --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 12db0257be..6613ab9808 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -2166,7 +2166,7 @@ public class WifiManagerTest extends AndroidTestCase { uiAutomation.adoptShellPermissionIdentity(); // These below API's only work with privileged permissions (obtained via shell identity // for test) - savedNetworks = mWifiManager.getConfiguredNetworks(); + savedNetworks = mWifiManager.getPrivilegedConfiguredNetworks(); mWifiManager.factoryReset(); // Ensure all the saved networks are removed. From da85d8b190bfdc745895716410ade45bbf9df07d Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 23 Mar 2020 09:02:45 -0700 Subject: [PATCH 0841/1415] cts(wifi): Disable scan throttling for tests with startScan Scan throttling could lead to flaky tests. Bug: 152048238 Test: atest android.net.wifi.cts Change-Id: Id314da9238c592fcbfde448231bf86f3cf679e62 --- .../android/net/wifi/cts/ScanResultTest.java | 19 +++++++++++++++++++ .../android/net/wifi/cts/WifiManagerTest.java | 8 ++++++++ .../wifi/cts/WifiNetworkSpecifierTest.java | 8 ++++++++ 3 files changed, 35 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java index 161b0b43eb..1977378c1a 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java @@ -34,6 +34,7 @@ import android.net.wifi.WifiManager.WifiLock; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; +import com.android.compatibility.common.util.ShellIdentityUtils; import com.android.compatibility.common.util.SystemUtil; @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @@ -45,6 +46,8 @@ public class ScanResultTest extends AndroidTestCase { private WifiManager mWifiManager; private WifiLock mWifiLock; private static MySync mMySync; + private boolean mWasVerboseLoggingEnabled; + private boolean mWasScanThrottleEnabled; private static final int STATE_NULL = 0; private static final int STATE_WIFI_CHANGING = 1; @@ -113,6 +116,18 @@ public class ScanResultTest extends AndroidTestCase { mContext.registerReceiver(mReceiver, mIntentFilter); mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); assertThat(mWifiManager).isNotNull(); + + // turn on verbose logging for tests + mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.isVerboseLoggingEnabled()); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setVerboseLoggingEnabled(true)); + // Disable scan throttling for tests. + mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.isScanThrottleEnabled()); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setScanThrottleEnabled(false)); + mWifiLock = mWifiManager.createWifiLock(TAG); mWifiLock.acquire(); if (!mWifiManager.isWifiEnabled()) @@ -133,6 +148,10 @@ public class ScanResultTest extends AndroidTestCase { mContext.unregisterReceiver(mReceiver); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled)); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); Thread.sleep(ENABLE_WAIT_MSEC); super.tearDown(); } diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 6613ab9808..9700ca1a6e 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -118,6 +118,7 @@ public class WifiManagerTest extends AndroidTestCase { private final Object mLock = new Object(); private UiDevice mUiDevice; private boolean mWasVerboseLoggingEnabled; + private boolean mWasScanThrottleEnabled; private SoftApConfiguration mOriginalSoftApConfig = null; // Please refer to WifiManager @@ -278,6 +279,11 @@ public class WifiManagerTest extends AndroidTestCase { () -> mWifiManager.isVerboseLoggingEnabled()); ShellIdentityUtils.invokeWithShellPermissions( () -> mWifiManager.setVerboseLoggingEnabled(true)); + // Disable scan throttling for tests. + mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.isScanThrottleEnabled()); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setScanThrottleEnabled(false)); mWifiLock = mWifiManager.createWifiLock(TAG); mWifiLock.acquire(); @@ -311,6 +317,8 @@ public class WifiManagerTest extends AndroidTestCase { setWifiEnabled(true); mWifiLock.release(); mContext.unregisterReceiver(mReceiver); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled)); ShellIdentityUtils.invokeWithShellPermissions( () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); // restore original softap config diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java index 2065bb025c..83018fa1cb 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java @@ -71,6 +71,7 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { private final Object mUiLock = new Object(); private WifiConfiguration mTestNetwork; private boolean mWasVerboseLoggingEnabled; + private boolean mWasScanThrottleEnabled; private static final int DURATION = 10_000; private static final int DURATION_UI_INTERACTION = 15_000; @@ -93,6 +94,11 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { () -> mWifiManager.isVerboseLoggingEnabled()); ShellIdentityUtils.invokeWithShellPermissions( () -> mWifiManager.setVerboseLoggingEnabled(true)); + // Disable scan throttling for tests. + mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.isScanThrottleEnabled()); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setScanThrottleEnabled(false)); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); @@ -126,6 +132,8 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { turnScreenOff(); ShellIdentityUtils.invokeWithShellPermissions( () -> mWifiManager.enableNetwork(mTestNetwork.networkId, false)); + ShellIdentityUtils.invokeWithShellPermissions( + () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled)); ShellIdentityUtils.invokeWithShellPermissions( () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); super.tearDown(); From 67de87eed06bca9b3bf0bf182338f3cf69f84c95 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Thu, 19 Mar 2020 12:07:49 -0700 Subject: [PATCH 0842/1415] Add vts10 suite to existing vts tests This is to prepare renaming vts to vts10. Bug: 151896491 Test: local build Exempt-From-Owner-Approval: This CL adds all tests in vts to a new suite vts10. vts10 will be the new name of existing vts suite. This CL won't change test logic or behavior. Change-Id: Ia9af1fbddc66d3c94976a58c36d274425f1fe461 --- tests/cts/hostside/Android.bp | 1 + tests/cts/hostside/app/Android.bp | 1 + tests/cts/hostside/app2/Android.bp | 1 + tests/cts/net/Android.bp | 1 + tests/cts/net/api23Test/Android.bp | 1 + tests/cts/net/appForApi23/Android.bp | 1 + tests/cts/net/native/qtaguid/Android.bp | 1 + 7 files changed, 7 insertions(+) diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp index b6f514233a..a8cc95ba5f 100644 --- a/tests/cts/hostside/Android.bp +++ b/tests/cts/hostside/Android.bp @@ -25,6 +25,7 @@ java_test_host { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], } diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index e988ea4763..8b6d38b821 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp @@ -36,6 +36,7 @@ android_test_helper_app { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], } diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp index 8a3c8e712a..0bb0d2f631 100644 --- a/tests/cts/hostside/app2/Android.bp +++ b/tests/cts/hostside/app2/Android.bp @@ -24,6 +24,7 @@ android_test_helper_app { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], certificate: ":cts-net-app", diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 624d149776..d77f416557 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -65,6 +65,7 @@ android_test { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], test_config_template: "AndroidTestTemplate.xml", diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index ffe854e2e9..614a5a2a76 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -46,6 +46,7 @@ android_test { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], diff --git a/tests/cts/net/appForApi23/Android.bp b/tests/cts/net/appForApi23/Android.bp index 82e2a08c10..17cfe3821b 100644 --- a/tests/cts/net/appForApi23/Android.bp +++ b/tests/cts/net/appForApi23/Android.bp @@ -27,6 +27,7 @@ android_test { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], diff --git a/tests/cts/net/native/qtaguid/Android.bp b/tests/cts/net/native/qtaguid/Android.bp index c0f0613040..054937b4fa 100644 --- a/tests/cts/net/native/qtaguid/Android.bp +++ b/tests/cts/net/native/qtaguid/Android.bp @@ -43,6 +43,7 @@ cc_test { test_suites: [ "cts", "vts", + "vts10", ], cflags: [ From 01cb32c3321112472f545a1cffccd3c277f70fbb Mon Sep 17 00:00:00 2001 From: Nate Jiang Date: Mon, 23 Mar 2020 11:47:04 -0700 Subject: [PATCH 0843/1415] Add test for aware rtt Bug: 150977837 Test: atest WifiRttTest Change-Id: If19b8708fd76df7f0be3fb5b338b4c58d7279402 --- .../android/net/wifi/rtt/cts/WifiRttTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java index 25a90b55a1..49aa47ec38 100644 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java +++ b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java @@ -18,7 +18,9 @@ package android.net.wifi.rtt.cts; import static org.mockito.Mockito.mock; +import android.net.MacAddress; import android.net.wifi.ScanResult; +import android.net.wifi.aware.PeerHandle; import android.net.wifi.rtt.RangingRequest; import android.net.wifi.rtt.RangingResult; import android.net.wifi.rtt.ResponderLocation; @@ -52,6 +54,9 @@ public class WifiRttTest extends TestBase { // Minimum valid RSSI value private static final int MIN_VALID_RSSI = -100; + // Valid Mac Address + private static final MacAddress MAC = MacAddress.fromString("00:01:02:03:04:05"); + /** * Test Wi-Fi RTT ranging operation: * - Scan for visible APs for the test AP (which is validated to support IEEE 802.11mc) @@ -368,4 +373,36 @@ public class WifiRttTest extends TestBase { assertNotNull("ColocatedBSSID list should be nonNull", responderLocation.getColocatedBssids()); } + + /** + * Verify ranging request with aware peer Mac address and peer handle. + */ + public void testAwareRttWithMacAddress() throws InterruptedException { + RangingRequest request = new RangingRequest.Builder() + .addWifiAwarePeer(MAC).build(); + ResultCallback callback = new ResultCallback(); + mWifiRttManager.startRanging(request, mExecutor, callback); + assertTrue("Wi-Fi RTT results: no callback", + callback.waitForCallback()); + List rangingResults = callback.getResults(); + assertNotNull("Wi-Fi RTT results: null results", rangingResults); + assertEquals(1, rangingResults.size()); + assertEquals(RangingResult.STATUS_FAIL, rangingResults.get(0).getStatus()); + } + + /** + * Verify ranging request with aware peer handle. + */ + public void testAwareRttWithPeerHandle() throws InterruptedException { + PeerHandle peerHandle = mock(PeerHandle.class); + RangingRequest request = new RangingRequest.Builder() + .addWifiAwarePeer(peerHandle).build(); + ResultCallback callback = new ResultCallback(); + mWifiRttManager.startRanging(request, mExecutor, callback); + assertTrue("Wi-Fi RTT results: no callback", + callback.waitForCallback()); + List rangingResults = callback.getResults(); + assertNotNull("Wi-Fi RTT results: null results", rangingResults); + assertEquals("Invalid peerHandle should return 0 result", 0, rangingResults.size()); + } } From 06aec03aba4f3e408f241243db5c6fe6d6e6ad03 Mon Sep 17 00:00:00 2001 From: Nate Jiang Date: Mon, 23 Mar 2020 14:57:59 -0700 Subject: [PATCH 0844/1415] Add test for WifiAwareNetworkSpecifier and ParcelablePeerHandle Test WifiAwareNetworkSpecifier satisfiedBy API Test ParcelablePeerHandle parcel Bug: 150975738 Bug: 150976784 Test: atest SingleDeviceTest Change-Id: I56f775774557b34935b7781f57c0b6f7b7e4e9b4 --- .../net/wifi/aware/cts/SingleDeviceTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java index 29f091b8b4..8f233244e8 100644 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -16,7 +16,9 @@ package android.net.wifi.aware.cts; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.mockito.Mockito.mock; import android.content.BroadcastReceiver; import android.content.Context; @@ -30,17 +32,21 @@ import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.net.wifi.aware.AttachCallback; import android.net.wifi.aware.Characteristics; +import android.net.wifi.aware.DiscoverySession; import android.net.wifi.aware.DiscoverySessionCallback; import android.net.wifi.aware.IdentityChangedListener; +import android.net.wifi.aware.ParcelablePeerHandle; import android.net.wifi.aware.PeerHandle; import android.net.wifi.aware.PublishConfig; import android.net.wifi.aware.PublishDiscoverySession; import android.net.wifi.aware.SubscribeConfig; import android.net.wifi.aware.SubscribeDiscoverySession; import android.net.wifi.aware.WifiAwareManager; +import android.net.wifi.aware.WifiAwareNetworkSpecifier; import android.net.wifi.aware.WifiAwareSession; import android.os.Handler; import android.os.HandlerThread; +import android.os.Parcel; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; @@ -812,6 +818,43 @@ public class SingleDeviceTest extends AndroidTestCase { session.close(); } + /** + * Test WifiAwareNetworkSpecifier. + */ + public void testWifiAwareNetworkSpecifier() { + DiscoverySession session = mock(DiscoverySession.class); + PeerHandle handle = mock(PeerHandle.class); + WifiAwareNetworkSpecifier networkSpecifier = + new WifiAwareNetworkSpecifier.Builder(session, handle).build(); + assertFalse(networkSpecifier.satisfiedBy(null)); + assertTrue(networkSpecifier.satisfiedBy(networkSpecifier)); + + WifiAwareNetworkSpecifier anotherNetworkSpecifier = + new WifiAwareNetworkSpecifier.Builder(session, handle).setPmk(PMK_VALID).build(); + assertFalse(networkSpecifier.satisfiedBy(anotherNetworkSpecifier)); + } + + /** + * Test ParcelablePeerHandle parcel. + */ + public void testParcelablePeerHandle() { + PeerHandle peerHandle = mock(PeerHandle.class); + ParcelablePeerHandle parcelablePeerHandle = new ParcelablePeerHandle(peerHandle); + Parcel parcelW = Parcel.obtain(); + parcelablePeerHandle.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + ParcelablePeerHandle rereadParcelablePeerHandle = + ParcelablePeerHandle.CREATOR.createFromParcel(parcelR); + + assertEquals(parcelablePeerHandle, rereadParcelablePeerHandle); + assertEquals(parcelablePeerHandle.hashCode(), rereadParcelablePeerHandle.hashCode()); + } + // local utilities private WifiAwareSession attachAndGetSession() { From 70b4a2e524b5739c237c4e06eea9fc15914ff44d Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 12 Mar 2020 15:22:01 +0800 Subject: [PATCH 0845/1415] Give tethering bluetooth privilege permission Permisssion of PanService#setBluetoothTethering is change from BLUETOOTH_ADMIN to BLUETOOTH_PRIVILEGED. Tethering service need bluetooth privilege permission to enable bluetooth tethering. Bug: 146045934 Test: on/off bluetooth tethering Merged-In: Ib87a5d5a5bb49390aa55e52713bb3539d4a52348 Change-Id: Ib87a5d5a5bb49390aa55e52713bb3539d4a52348 (cherry picked from commit 1f47e1c22ef82e725575666ddff943c1d560652a) --- Tethering/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index c71d0d7bc5..9328611f5d 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml @@ -27,7 +27,7 @@ added to the privileged permissions whitelist for that package. --> - + From 6b4a05b47485638d85eeec4633468bd4fbc46bf0 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 23 Mar 2020 15:54:29 -0700 Subject: [PATCH 0846/1415] WifiManagerTest: Use addNetwork + enableNetwork instead of save WifiManager.save() is an asynchronous operation. This is sometime causing the tests to be flaky (dropShellIdentity occurs while this is being processed). Use the synchronous legacy API's instead for rewinding the effects of factory reset. Bug: 152048238 Test: atest android.net.wifi.cts.WifiManagerTest Change-Id: Ibb0e04cf931511fcda1b1a81fd6eda4583196c2e --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 9700ca1a6e..3153149629 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -2183,7 +2183,9 @@ public class WifiManagerTest extends AndroidTestCase { // Restore the original saved networks. if (savedNetworks != null) { for (WifiConfiguration network : savedNetworks) { - mWifiManager.save(network, null); + network.networkId = WifiConfiguration.INVALID_NETWORK_ID; + int networkId = mWifiManager.addNetwork(network); + mWifiManager.enableNetwork(networkId, false); } } uiAutomation.dropShellPermissionIdentity(); From 7338a25a99b44d76d431a0e57ca2964bb1ef2098 Mon Sep 17 00:00:00 2001 From: David Su Date: Thu, 12 Mar 2020 22:36:18 -0700 Subject: [PATCH 0847/1415] CTS: Add tests for RssiCurve Bug: 151110495 Test: atest android.net.cts.RssiCurveTest Change-Id: Ife157773f7bdb07d62c5b9a66810328d9fd5ac91 --- .../src/android/net/cts/RssiCurveTest.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/RssiCurveTest.java diff --git a/tests/cts/net/src/android/net/cts/RssiCurveTest.java b/tests/cts/net/src/android/net/cts/RssiCurveTest.java new file mode 100644 index 0000000000..d651b7186b --- /dev/null +++ b/tests/cts/net/src/android/net/cts/RssiCurveTest.java @@ -0,0 +1,102 @@ +/* + * 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 com.google.common.truth.Truth.assertThat; + +import android.net.RssiCurve; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** CTS tests for {@link RssiCurve}. */ +@RunWith(AndroidJUnit4.class) +public class RssiCurveTest { + + @Test + public void lookupScore_constantCurve() { + // One bucket from rssi=-100 to 100 with score 10. + RssiCurve curve = new RssiCurve(-100, 200, new byte[] { 10 }); + assertThat(curve.lookupScore(-200)).isEqualTo(10); + assertThat(curve.lookupScore(-100)).isEqualTo(10); + assertThat(curve.lookupScore(0)).isEqualTo(10); + assertThat(curve.lookupScore(100)).isEqualTo(10); + assertThat(curve.lookupScore(200)).isEqualTo(10); + } + + @Test + public void lookupScore_changingCurve() { + // One bucket from -100 to 0 with score -10, and one bucket from 0 to 100 with score 10. + RssiCurve curve = new RssiCurve(-100, 100, new byte[] { -10, 10 }); + assertThat(curve.lookupScore(-200)).isEqualTo(-10); + assertThat(curve.lookupScore(-100)).isEqualTo(-10); + assertThat(curve.lookupScore(-50)).isEqualTo(-10); + assertThat(curve.lookupScore(0)).isEqualTo(10); + assertThat(curve.lookupScore(50)).isEqualTo(10); + assertThat(curve.lookupScore(100)).isEqualTo(10); + assertThat(curve.lookupScore(200)).isEqualTo(10); + } + + @Test + public void lookupScore_linearCurve() { + // Curve starting at -110, with 15 buckets of width 10 whose scores increases by 10 with + // each bucket. The current active network gets a boost of 15 to its RSSI. + RssiCurve curve = new RssiCurve( + -110, + 10, + new byte[] { -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 }, + 15); + + assertThat(curve.lookupScore(-120)).isEqualTo(-20); + assertThat(curve.lookupScore(-120, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-120, true)).isEqualTo(-20); + + assertThat(curve.lookupScore(-111)).isEqualTo(-20); + assertThat(curve.lookupScore(-111, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-111, true)).isEqualTo(-10); + + assertThat(curve.lookupScore(-110)).isEqualTo(-20); + assertThat(curve.lookupScore(-110, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-110, true)).isEqualTo(-10); + + assertThat(curve.lookupScore(-105)).isEqualTo(-20); + assertThat(curve.lookupScore(-105, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-105, true)).isEqualTo(0); + + assertThat(curve.lookupScore(-100)).isEqualTo(-10); + assertThat(curve.lookupScore(-100, false)).isEqualTo(-10); + assertThat(curve.lookupScore(-100, true)).isEqualTo(0); + + assertThat(curve.lookupScore(-50)).isEqualTo(40); + assertThat(curve.lookupScore(-50, false)).isEqualTo(40); + assertThat(curve.lookupScore(-50, true)).isEqualTo(50); + + assertThat(curve.lookupScore(0)).isEqualTo(90); + assertThat(curve.lookupScore(0, false)).isEqualTo(90); + assertThat(curve.lookupScore(0, true)).isEqualTo(100); + + assertThat(curve.lookupScore(30)).isEqualTo(120); + assertThat(curve.lookupScore(30, false)).isEqualTo(120); + assertThat(curve.lookupScore(30, true)).isEqualTo(120); + + assertThat(curve.lookupScore(40)).isEqualTo(120); + assertThat(curve.lookupScore(40, false)).isEqualTo(120); + assertThat(curve.lookupScore(40, true)).isEqualTo(120); + } +} From 299d3a740fb75bad24f5764f95f5fe7488e50d34 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 12 Mar 2020 15:22:01 +0800 Subject: [PATCH 0848/1415] Give tethering bluetooth privilege permission Permisssion of PanService#setBluetoothTethering is change from BLUETOOTH_ADMIN to BLUETOOTH_PRIVILEGED. Tethering service need bluetooth privilege permission to enable bluetooth tethering. Bug: 146045934 Test: on/off bluetooth tethering Merged-In: Ib87a5d5a5bb49390aa55e52713bb3539d4a52348 Change-Id: Ib87a5d5a5bb49390aa55e52713bb3539d4a52348 (cherry picked from commit 1f47e1c22ef82e725575666ddff943c1d560652a) --- Tethering/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index c71d0d7bc5..9328611f5d 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml @@ -27,7 +27,7 @@ added to the privileged permissions whitelist for that package. --> - + From f79818b88b6385010d3b6916720e7d6a7ab1bde5 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 23 Mar 2020 18:11:35 +0800 Subject: [PATCH 0849/1415] Test IpConfiguration field count and parceling round trip Add test for IpConfiguration and also address review comments from aosp/1171795. Bug: 139268426 Test: CtsNetTestCasesLatestSdk:android.net.cts.IpConfigurationTest Change-Id: Ib30a98e11bdcd9d473b713f7e4c317172b14f000 --- .../android/net/cts/IpConfigurationTest.java | 78 ++++++------------- 1 file changed, 25 insertions(+), 53 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java index 21be35142d..c6bc0770b8 100644 --- a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java +++ b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java @@ -16,6 +16,8 @@ package android.net.cts; +import static com.android.testutils.ParcelUtilsKt.assertParcelSane; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -37,13 +39,6 @@ import java.util.ArrayList; @RunWith(AndroidJUnit4.class) public final class IpConfigurationTest { - private static final int TYPE_IPASSIGNMENT_STATIC = 0; - private static final int TYPE_IPASSIGNMENT_DHCP = 1; - - private static final int TYPE_PROXY_SETTINGS_NONE = 0; - private static final int TYPE_PROXY_SETTINGS_STATIC = 1; - private static final int TYPE_PROXY_SETTINGS_PAC = 2; - private static final LinkAddress LINKADDR = new LinkAddress("192.0.2.2/25"); private static final InetAddress GATEWAY = InetAddressUtils.parseNumericAddress("192.0.2.1"); private static final InetAddress DNS1 = InetAddressUtils.parseNumericAddress("8.8.8.8"); @@ -76,24 +71,31 @@ public final class IpConfigurationTest { assertIpConfigurationEqual(ipConfig, new IpConfiguration()); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_STATIC, - TYPE_PROXY_SETTINGS_PAC); + ipConfig.setStaticIpConfiguration(mStaticIpConfig); + ipConfig.setHttpProxy(mProxy); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_STATIC, - TYPE_PROXY_SETTINGS_STATIC); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, - TYPE_PROXY_SETTINGS_PAC); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, - TYPE_PROXY_SETTINGS_STATIC); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, - TYPE_PROXY_SETTINGS_NONE); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); } @@ -106,46 +108,16 @@ public final class IpConfigurationTest { assertNull(config.getHttpProxy()); } - private IpConfiguration createIpConfiguration(int ipAssignmentType, - int proxySettingType) { - - final IpConfiguration ipConfig = new IpConfiguration(); - - switch (ipAssignmentType) { - case TYPE_IPASSIGNMENT_STATIC: - ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); - break; - case TYPE_IPASSIGNMENT_DHCP: - ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); - break; - default: - throw new IllegalArgumentException("Unknown ip assignment type."); - } - - switch (proxySettingType) { - case TYPE_PROXY_SETTINGS_NONE: - ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE); - break; - case TYPE_PROXY_SETTINGS_STATIC: - ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); - break; - case TYPE_PROXY_SETTINGS_PAC: - ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); - break; - default: - throw new IllegalArgumentException("Unknown proxy setting type."); - } - - ipConfig.setStaticIpConfiguration(mStaticIpConfig); - ipConfig.setHttpProxy(mProxy); - - return ipConfig; - } - private void assertIpConfigurationEqual(IpConfiguration source, IpConfiguration target) { assertEquals(source.getIpAssignment(), target.getIpAssignment()); assertEquals(source.getProxySettings(), target.getProxySettings()); assertEquals(source.getHttpProxy(), target.getHttpProxy()); assertEquals(source.getStaticIpConfiguration(), target.getStaticIpConfiguration()); } + + @Test + public void testParcel() { + final IpConfiguration config = new IpConfiguration(); + assertParcelSane(config, 4); + } } From 7bfbe253d70e31791479f72512031b2161194a80 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 24 Feb 2020 14:50:27 +0800 Subject: [PATCH 0850/1415] [TNU02] Update tethering notification by active data subid Tethering notification can be customized by different subid. Thus update notification when active data subid changed. Bug: 122085773 Bug: 130596698 Test: atest TetheringTests Change-Id: I799d713326cfbf4dc96c712c6b15ed5a4ac18dd2 --- .../connectivity/tethering/Tethering.java | 3 +- .../TetheringNotificationUpdater.java | 42 +++++++++++++++---- .../connectivity/tethering/TetheringTest.java | 2 +- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 3dcc15f92c..882f8d95cb 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -369,9 +369,10 @@ public class Tethering { mActiveDataSubId = subId; updateConfiguration(); + mNotificationUpdater.onActiveDataSubscriptionIdChanged(subId); // To avoid launching unexpected provisioning checks, ignore re-provisioning // when no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() - // ill be triggered again when CarrierConfig is loaded. + // will be triggered again when CarrierConfig is loaded. if (mEntitlementMgr.getCarrierConfig(mConfig) != null) { mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); } else { diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java index b97f75268a..c3fd170a11 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java @@ -29,6 +29,7 @@ import android.content.Intent; import android.content.res.Resources; import android.os.UserHandle; import android.provider.Settings; +import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; @@ -54,6 +55,9 @@ import com.android.networkstack.tethering.R; public class TetheringNotificationUpdater { private static final String TAG = TetheringNotificationUpdater.class.getSimpleName(); private static final String CHANNEL_ID = "TETHERING_STATUS"; + private static final String WIFI_DOWNSTREAM = "WIFI"; + private static final String USB_DOWNSTREAM = "USB"; + private static final String BLUETOOTH_DOWNSTREAM = "BT"; private static final boolean NOTIFY_DONE = true; private static final boolean NO_NOTIFY = false; // Id to update and cancel tethering notification. Must be unique within the tethering app. @@ -65,14 +69,22 @@ public class TetheringNotificationUpdater { private final Context mContext; private final NotificationManager mNotificationManager; private final NotificationChannel mChannel; - // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2. - // This value has to be made 1 2 and 4, and OR'd with the others. + // WARNING : the constructor is called on a different thread. Thread safety therefore // relies on this value being initialized to 0, and not any other value. If you need // to change this, you will need to change the thread where the constructor is invoked, // or to introduce synchronization. + // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2. + // This value has to be made 1 2 and 4, and OR'd with the others. private int mDownstreamTypesMask = DOWNSTREAM_NONE; + // WARNING : this value is not able to being initialized to 0 and must have volatile because + // telephony service is not guaranteed that is up before tethering service starts. If telephony + // is up later than tethering, TetheringNotificationUpdater will use incorrect and valid + // subscription id(0) to query resources. Therefore, initialized subscription id must be + // INVALID_SUBSCRIPTION_ID. + private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + public TetheringNotificationUpdater(@NonNull final Context context) { mContext = context; mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0) @@ -91,6 +103,18 @@ public class TetheringNotificationUpdater { updateNotification(); } + /** Called when active data subscription id changed */ + public void onActiveDataSubscriptionIdChanged(final int subId) { + if (mActiveDataSubId == subId) return; + mActiveDataSubId = subId; + updateNotification(); + } + + @VisibleForTesting + Resources getResourcesForSubId(@NonNull final Context c, final int subId) { + return SubscriptionManager.getResourcesForSubId(c, subId); + } + private void updateNotification() { final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE; @@ -115,11 +139,11 @@ public class TetheringNotificationUpdater { int downstreamTypesMask = DOWNSTREAM_NONE; final String[] downstreams = types.split("\\|"); for (String downstream : downstreams) { - if ("USB".equals(downstream.trim())) { + if (USB_DOWNSTREAM.equals(downstream.trim())) { downstreamTypesMask |= (1 << TETHERING_USB); - } else if ("WIFI".equals(downstream.trim())) { + } else if (WIFI_DOWNSTREAM.equals(downstream.trim())) { downstreamTypesMask |= (1 << TETHERING_WIFI); - } else if ("BT".equals(downstream.trim())) { + } else if (BLUETOOTH_DOWNSTREAM.equals(downstream.trim())) { downstreamTypesMask |= (1 << TETHERING_BLUETOOTH); } } @@ -135,8 +159,7 @@ public class TetheringNotificationUpdater { * @return {@link android.util.SparseArray} with downstream types and icon id info. */ @NonNull - private SparseArray getIcons(@ArrayRes int id) { - final Resources res = mContext.getResources(); + private SparseArray getIcons(@ArrayRes int id, @NonNull Resources res) { final String[] array = res.getStringArray(id); final SparseArray icons = new SparseArray<>(); for (String config : array) { @@ -161,8 +184,9 @@ public class TetheringNotificationUpdater { } private boolean setupNotification() { - final Resources res = mContext.getResources(); - final SparseArray downstreamIcons = getIcons(R.array.tethering_notification_icons); + final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); + final SparseArray downstreamIcons = + getIcons(R.array.tethering_notification_icons, res); final int iconId = downstreamIcons.get(mDownstreamTypesMask, NO_ICON_ID); if (iconId == NO_ICON_ID) return NO_NOTIFY; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index d983fae09b..2aa206c46c 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -210,7 +210,6 @@ public class TetheringTest { private PhoneStateListener mPhoneStateListener; private InterfaceConfigurationParcel mInterfaceConfiguration; - private class TestContext extends BroadcastInterceptingContext { TestContext(Context base) { super(base); @@ -1399,6 +1398,7 @@ public class TetheringTest { mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId); final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration(); assertEquals(fakeSubId, newConfig.activeDataSubId); + verify(mNotificationUpdater, times(1)).onActiveDataSubscriptionIdChanged(eq(fakeSubId)); } @Test From 769e00cad26722bdecb904fa68913ab6ecf71fd7 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 16 Jan 2020 23:47:49 +0800 Subject: [PATCH 0851/1415] [TNU03] Add TetheringNotificationUpdaterTest Add new test for TetheringNotificationUpdater Bug: 122085773 Bug: 130596698 Test: atest TetheringTests Change-Id: I0db3df3e85dd6a8c3989c8bc66a06c50f45a0c15 --- .../TetheringNotificationUpdater.java | 7 +- .../TetheringNotificationUpdaterTest.kt | 227 ++++++++++++++++++ 2 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java index c3fd170a11..b3fff4465c 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java @@ -134,8 +134,9 @@ public class TetheringNotificationUpdater { * * @return downstream types mask value. */ + @VisibleForTesting @IntRange(from = 0, to = 7) - private int getDownstreamTypesMask(@NonNull final String types) { + int getDownstreamTypesMask(@NonNull final String types) { int downstreamTypesMask = DOWNSTREAM_NONE; final String[] downstreams = types.split("\\|"); for (String downstream : downstreams) { @@ -158,8 +159,8 @@ public class TetheringNotificationUpdater { * * @return {@link android.util.SparseArray} with downstream types and icon id info. */ - @NonNull - private SparseArray getIcons(@ArrayRes int id, @NonNull Resources res) { + @VisibleForTesting + SparseArray getIcons(@ArrayRes int id, @NonNull Resources res) { final String[] array = res.getStringArray(id); final SparseArray icons = new SparseArray<>(); for (String config : array) { diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt new file mode 100644 index 0000000000..124f9f4806 --- /dev/null +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt @@ -0,0 +1,227 @@ +/* + * 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 com.android.server.connectivity.tethering + +import android.app.Notification +import android.app.NotificationManager +import android.content.Context +import android.content.res.Resources +import android.net.ConnectivityManager.TETHERING_BLUETOOTH +import android.net.ConnectivityManager.TETHERING_USB +import android.net.ConnectivityManager.TETHERING_WIFI +import android.os.UserHandle +import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID +import androidx.test.InstrumentationRegistry +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.test.BroadcastInterceptingContext +import com.android.networkstack.tethering.R +import com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mock +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.never +import org.mockito.Mockito.reset +import org.mockito.Mockito.times +import org.mockito.Mockito.verifyZeroInteractions +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +const val TEST_SUBID = 1 +const val WIFI_ICON_ID = 1 +const val USB_ICON_ID = 2 +const val BT_ICON_ID = 3 +const val GENERAL_ICON_ID = 4 +const val WIFI_MASK = 1 shl TETHERING_WIFI +const val USB_MASK = 1 shl TETHERING_USB +const val BT_MASK = 1 shl TETHERING_BLUETOOTH +const val TITTLE = "Tethering active" +const val MESSAGE = "Tap here to set up." +const val TEST_TITTLE = "Hotspot active" +const val TEST_MESSAGE = "Tap to set up hotspot." + +@RunWith(AndroidJUnit4::class) +@SmallTest +class TetheringNotificationUpdaterTest { + // lateinit used here for mocks as they need to be reinitialized between each test and the test + // should crash if they are used before being initialized. + @Mock private lateinit var mockContext: Context + @Mock private lateinit var notificationManager: NotificationManager + @Mock private lateinit var defaultResources: Resources + @Mock private lateinit var testResources: Resources + + // lateinit for this class under test, as it should be reset to a different instance for every + // tests but should always be initialized before use (or the test should crash). + private lateinit var notificationUpdater: TetheringNotificationUpdater + + private val ENABLE_ICON_CONFIGS = arrayOf( + "USB;android.test:drawable/usb", "BT;android.test:drawable/bluetooth", + "WIFI|BT;android.test:drawable/general", "WIFI|USB;android.test:drawable/general", + "USB|BT;android.test:drawable/general", "WIFI|USB|BT;android.test:drawable/general") + + private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) { + override fun createContextAsUser(user: UserHandle, flags: Int) = + if (user == UserHandle.ALL) mockContext else this + } + + private inner class WrappedNotificationUpdater(c: Context) : TetheringNotificationUpdater(c) { + override fun getResourcesForSubId(context: Context, subId: Int) = + if (subId == TEST_SUBID) testResources else defaultResources + } + + private fun setupResources() { + doReturn(ENABLE_ICON_CONFIGS).`when`(defaultResources) + .getStringArray(R.array.tethering_notification_icons) + doReturn(arrayOf("WIFI;android.test:drawable/wifi")).`when`(testResources) + .getStringArray(R.array.tethering_notification_icons) + doReturn(TITTLE).`when`(defaultResources).getString(R.string.tethering_notification_title) + doReturn(MESSAGE).`when`(defaultResources) + .getString(R.string.tethering_notification_message) + doReturn(TEST_TITTLE).`when`(testResources).getString(R.string.tethering_notification_title) + doReturn(TEST_MESSAGE).`when`(testResources) + .getString(R.string.tethering_notification_message) + doReturn(USB_ICON_ID).`when`(defaultResources) + .getIdentifier(eq("android.test:drawable/usb"), any(), any()) + doReturn(BT_ICON_ID).`when`(defaultResources) + .getIdentifier(eq("android.test:drawable/bluetooth"), any(), any()) + doReturn(GENERAL_ICON_ID).`when`(defaultResources) + .getIdentifier(eq("android.test:drawable/general"), any(), any()) + doReturn(WIFI_ICON_ID).`when`(testResources) + .getIdentifier(eq("android.test:drawable/wifi"), any(), any()) + } + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + val context = TestContext(InstrumentationRegistry.getContext()) + doReturn(notificationManager).`when`(mockContext) + .getSystemService(Context.NOTIFICATION_SERVICE) + notificationUpdater = WrappedNotificationUpdater(context) + setupResources() + } + + private fun Notification.title() = this.extras.getString(Notification.EXTRA_TITLE) + private fun Notification.text() = this.extras.getString(Notification.EXTRA_TEXT) + + private fun verifyNotification(iconId: Int = 0, title: String = "", text: String = "") { + verify(notificationManager, never()).cancel(any(), anyInt()) + + val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java) + verify(notificationManager, times(1)).notify(any(), anyInt(), notificationCaptor.capture()) + + val notification = notificationCaptor.getValue() + assertEquals(iconId, notification.smallIcon.resId) + assertEquals(title, notification.title()) + assertEquals(text, notification.text()) + + reset(notificationManager) + } + + private fun verifyNoNotification() { + verify(notificationManager, times(1)).cancel(any(), anyInt()) + verify(notificationManager, never()).notify(any(), anyInt(), any()) + + reset(notificationManager) + } + + @Test + fun testNotificationWithDownstreamChanged() { + // Wifi downstream. No notification. + notificationUpdater.onDownstreamChanged(WIFI_MASK) + verifyNoNotification() + + // Same downstream changed. Nothing happened. + notificationUpdater.onDownstreamChanged(WIFI_MASK) + verifyZeroInteractions(notificationManager) + + // Wifi and usb downstreams. Show enable notification + notificationUpdater.onDownstreamChanged(WIFI_MASK or USB_MASK) + verifyNotification(GENERAL_ICON_ID, TITTLE, MESSAGE) + + // Usb downstream. Still show enable notification. + notificationUpdater.onDownstreamChanged(USB_MASK) + verifyNotification(USB_ICON_ID, TITTLE, MESSAGE) + + // No downstream. No notification. + notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) + verifyNoNotification() + } + + @Test + fun testNotificationWithActiveDataSubscriptionIdChanged() { + // Usb downstream. Showed enable notification with default resource. + notificationUpdater.onDownstreamChanged(USB_MASK) + verifyNotification(USB_ICON_ID, TITTLE, MESSAGE) + + // Same subId changed. Nothing happened. + notificationUpdater.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID) + verifyZeroInteractions(notificationManager) + + // Set test sub id. Clear notification with test resource. + notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) + verifyNoNotification() + + // Wifi downstream. Show enable notification with test resource. + notificationUpdater.onDownstreamChanged(WIFI_MASK) + verifyNotification(WIFI_ICON_ID, TEST_TITTLE, TEST_MESSAGE) + + // No downstream. No notification. + notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) + verifyNoNotification() + } + + private fun assertIconNumbers(number: Int, configs: Array) { + doReturn(configs).`when`(defaultResources) + .getStringArray(R.array.tethering_notification_icons) + assertEquals(number, notificationUpdater.getIcons( + R.array.tethering_notification_icons, defaultResources).size()) + } + + @Test + fun testGetIcons() { + assertIconNumbers(0, arrayOfNulls(0)) + assertIconNumbers(0, arrayOf(null, "")) + assertIconNumbers(3, arrayOf( + // These configurations are invalid with wrong strings or symbols. + ";", ",", "|", "|,;", "WIFI", "1;2", " U SB; ", "bt;", "WIFI;USB;BT", "WIFI|USB|BT", + "WIFI,BT,USB", " WIFI| | | USB, test:drawable/test", + // This configuration is valid with two downstream types (USB, BT). + "USB|,,,,,|BT;drawable/test ", + // This configuration is valid with one downstream types (WIFI). + " WIFI ; android.test:drawable/xxx ")) + } + + @Test + fun testGetDownstreamTypesMask() { + assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("")) + assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("1")) + assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("WIFI_P2P")) + assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("usb")) + assertEquals(WIFI_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI ")) + assertEquals(USB_MASK, notificationUpdater.getDownstreamTypesMask("USB | B T")) + assertEquals(BT_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI: | BT")) + assertEquals(WIFI_MASK or USB_MASK, + notificationUpdater.getDownstreamTypesMask("1|2|USB|WIFI|BLUETOOTH||")) + } +} \ No newline at end of file From 972f031fa5d2f9e92f15090a8aa7f1eaf17a8c06 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 16 Mar 2020 17:56:42 +0800 Subject: [PATCH 0852/1415] [TNU04] Add tethering restricted notification If tethering is restricted to the user, show restricted notification to notify the user. Bug: 122085773 Test: atest TetheringTests Change-Id: Ic5baca2d6102886f4c3530ce1e321b5dab6ea9d7 --- .../connectivity/tethering/Tethering.java | 28 +++++++++---- .../TetheringNotificationUpdater.java | 41 ++++++++++++++----- .../TetheringNotificationUpdaterTest.kt | 41 +++++++++++++++++-- .../connectivity/tethering/TetheringTest.java | 10 +++-- 4 files changed, 95 insertions(+), 25 deletions(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 882f8d95cb..54ccc20924 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -303,7 +303,8 @@ public class Tethering { final UserManager userManager = (UserManager) mContext.getSystemService( Context.USER_SERVICE); - mTetheringRestriction = new UserRestrictionActionListener(userManager, this); + mTetheringRestriction = new UserRestrictionActionListener( + userManager, this, mNotificationUpdater); mExecutor = new TetheringThreadExecutor(mHandler); mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor); @@ -997,11 +998,14 @@ public class Tethering { protected static class UserRestrictionActionListener { private final UserManager mUserManager; private final Tethering mWrapper; + private final TetheringNotificationUpdater mNotificationUpdater; public boolean mDisallowTethering; - public UserRestrictionActionListener(UserManager um, Tethering wrapper) { + public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper, + @NonNull TetheringNotificationUpdater updater) { mUserManager = um; mWrapper = wrapper; + mNotificationUpdater = updater; mDisallowTethering = false; } @@ -1020,13 +1024,21 @@ public class Tethering { return; } - // TODO: Add user restrictions notification. - final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0); - - if (newlyDisallowed && isTetheringActiveOnDevice) { - mWrapper.untetherAll(); - // TODO(b/148139325): send tetheringSupported on restriction change + if (!newlyDisallowed) { + // Clear the restricted notification when user is allowed to have tethering + // function. + mNotificationUpdater.tetheringRestrictionLifted(); + return; } + + // Restricted notification is shown when tethering function is disallowed on + // user's device. + mNotificationUpdater.notifyTetheringDisabledByRestriction(); + + // Untether from all downstreams since tethering is disallowed. + mWrapper.untetherAll(); + + // TODO(b/148139325): send tetheringSupported on restriction change } } diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java index b3fff4465c..992cdd8de6 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java @@ -36,6 +36,7 @@ import android.util.SparseArray; import androidx.annotation.ArrayRes; import androidx.annotation.DrawableRes; +import androidx.annotation.IntDef; import androidx.annotation.IntRange; import androidx.annotation.NonNull; @@ -61,7 +62,9 @@ public class TetheringNotificationUpdater { private static final boolean NOTIFY_DONE = true; private static final boolean NO_NOTIFY = false; // Id to update and cancel tethering notification. Must be unique within the tethering app. - private static final int NOTIFY_ID = 20191115; + private static final int ENABLE_NOTIFICATION_ID = 1000; + // Id to update and cancel restricted notification. Must be unique within the tethering app. + private static final int RESTRICTED_NOTIFICATION_ID = 1001; @VisibleForTesting static final int NO_ICON_ID = 0; @VisibleForTesting @@ -85,6 +88,9 @@ public class TetheringNotificationUpdater { // INVALID_SUBSCRIPTION_ID. private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + @IntDef({ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID}) + @interface NotificationId {} + public TetheringNotificationUpdater(@NonNull final Context context) { mContext = context; mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0) @@ -100,14 +106,14 @@ public class TetheringNotificationUpdater { public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) { if (mDownstreamTypesMask == downstreamTypesMask) return; mDownstreamTypesMask = downstreamTypesMask; - updateNotification(); + updateEnableNotification(); } /** Called when active data subscription id changed */ public void onActiveDataSubscriptionIdChanged(final int subId) { if (mActiveDataSubId == subId) return; mActiveDataSubId = subId; - updateNotification(); + updateEnableNotification(); } @VisibleForTesting @@ -115,16 +121,31 @@ public class TetheringNotificationUpdater { return SubscriptionManager.getResourcesForSubId(c, subId); } - private void updateNotification() { + private void updateEnableNotification() { final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE; if (tetheringInactive || setupNotification() == NO_NOTIFY) { - clearNotification(); + clearNotification(ENABLE_NOTIFICATION_ID); } } - private void clearNotification() { - mNotificationManager.cancel(null /* tag */, NOTIFY_ID); + @VisibleForTesting + void tetheringRestrictionLifted() { + clearNotification(RESTRICTED_NOTIFICATION_ID); + } + + private void clearNotification(@NotificationId final int id) { + mNotificationManager.cancel(null /* tag */, id); + } + + @VisibleForTesting + void notifyTetheringDisabledByRestriction() { + final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); + final String title = res.getString(R.string.disable_tether_notification_title); + final String message = res.getString(R.string.disable_tether_notification_message); + + showNotification(R.drawable.stat_sys_tether_general, title, message, + RESTRICTED_NOTIFICATION_ID); } /** @@ -195,12 +216,12 @@ public class TetheringNotificationUpdater { final String title = res.getString(R.string.tethering_notification_title); final String message = res.getString(R.string.tethering_notification_message); - showNotification(iconId, title, message); + showNotification(iconId, title, message, ENABLE_NOTIFICATION_ID); return NOTIFY_DONE; } private void showNotification(@DrawableRes final int iconId, @NonNull final String title, - @NonNull final String message) { + @NonNull final String message, @NotificationId final int id) { final Intent intent = new Intent(Settings.ACTION_TETHER_SETTINGS); final PendingIntent pi = PendingIntent.getActivity( mContext.createContextAsUser(UserHandle.CURRENT, 0), @@ -218,6 +239,6 @@ public class TetheringNotificationUpdater { .setContentIntent(pi) .build(); - mNotificationManager.notify(null /* tag */, NOTIFY_ID, notification); + mNotificationManager.notify(null /* tag */, id, notification); } } diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt index 124f9f4806..b86949185c 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt @@ -25,7 +25,7 @@ import android.net.ConnectivityManager.TETHERING_USB import android.net.ConnectivityManager.TETHERING_WIFI import android.os.UserHandle import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID -import androidx.test.InstrumentationRegistry +import androidx.test.platform.app.InstrumentationRegistry import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.test.BroadcastInterceptingContext @@ -114,7 +114,7 @@ class TetheringNotificationUpdaterTest { @Before fun setUp() { MockitoAnnotations.initMocks(this) - val context = TestContext(InstrumentationRegistry.getContext()) + val context = TestContext(InstrumentationRegistry.getInstrumentation().context) doReturn(notificationManager).`when`(mockContext) .getSystemService(Context.NOTIFICATION_SERVICE) notificationUpdater = WrappedNotificationUpdater(context) @@ -128,7 +128,8 @@ class TetheringNotificationUpdaterTest { verify(notificationManager, never()).cancel(any(), anyInt()) val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java) - verify(notificationManager, times(1)).notify(any(), anyInt(), notificationCaptor.capture()) + verify(notificationManager, times(1)) + .notify(any(), anyInt(), notificationCaptor.capture()) val notification = notificationCaptor.getValue() assertEquals(iconId, notification.smallIcon.resId) @@ -224,4 +225,38 @@ class TetheringNotificationUpdaterTest { assertEquals(WIFI_MASK or USB_MASK, notificationUpdater.getDownstreamTypesMask("1|2|USB|WIFI|BLUETOOTH||")) } + + @Test + fun testSetupRestrictedNotification() { + val title = InstrumentationRegistry.getInstrumentation().context.resources + .getString(R.string.disable_tether_notification_title) + val message = InstrumentationRegistry.getInstrumentation().context.resources + .getString(R.string.disable_tether_notification_message) + val disallowTitle = "Tether function is disallowed" + val disallowMessage = "Please contact your admin" + doReturn(title).`when`(defaultResources) + .getString(R.string.disable_tether_notification_title) + doReturn(message).`when`(defaultResources) + .getString(R.string.disable_tether_notification_message) + doReturn(disallowTitle).`when`(testResources) + .getString(R.string.disable_tether_notification_title) + doReturn(disallowMessage).`when`(testResources) + .getString(R.string.disable_tether_notification_message) + + // User restrictions on. Show restricted notification. + notificationUpdater.notifyTetheringDisabledByRestriction() + verifyNotification(R.drawable.stat_sys_tether_general, title, message) + + // User restrictions off. Clear notification. + notificationUpdater.tetheringRestrictionLifted() + verifyNoNotification() + + // Set test sub id. No notification. + notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) + verifyNoNotification() + + // User restrictions on again. Show restricted notification with test resource. + notificationUpdater.notifyTetheringDisabledByRestriction() + verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage) + } } \ No newline at end of file diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 2aa206c46c..0980514ce2 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -1072,13 +1072,15 @@ public class TetheringTest { when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions); final Tethering.UserRestrictionActionListener ural = - new Tethering.UserRestrictionActionListener(mUserManager, mockTethering); + new Tethering.UserRestrictionActionListener( + mUserManager, mockTethering, mNotificationUpdater); ural.mDisallowTethering = currentDisallow; ural.onUserRestrictionsChanged(); - verify(mockTethering, times(expectedInteractionsWithShowNotification)) - .untetherAll(); + verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification)) + .notifyTetheringDisabledByRestriction(); + verify(mockTethering, times(expectedInteractionsWithShowNotification)).untetherAll(); } @Test @@ -1086,7 +1088,7 @@ public class TetheringTest { final String[] emptyActiveIfacesList = new String[]{}; final boolean currDisallow = false; final boolean nextDisallow = true; - final int expectedInteractionsWithShowNotification = 0; + final int expectedInteractionsWithShowNotification = 1; runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList, expectedInteractionsWithShowNotification); From 58e3896aa8a9bb4c0f8de0a86199f49c37d1db19 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 18 Mar 2020 08:43:07 +0800 Subject: [PATCH 0853/1415] Expose netId by adding getter API Bug: 151156820 Test: m atest TetetheringTests Clean CP from ag/10747732 Change-Id: Ieb1483c146aa2f7d8f251157e6e81d71c44ae899 Merged-In: Ieb1483c146aa2f7d8f251157e6e81d71c44ae899 --- .../com/android/server/connectivity/tethering/Tethering.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 3dcc15f92c..8cf651b777 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -1494,7 +1494,7 @@ public class Tethering { } else { dnsServers = mConfig.defaultIPv4DNS; } - final int netId = (network != null) ? network.netId : NETID_UNSET; + final int netId = (network != null) ? network.getNetId() : NETID_UNSET; try { mNetd.tetherDnsSet(netId, dnsServers); mLog.log(String.format( From 6976fae02e8eea767bd214a428606830d299ccff Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 24 Mar 2020 18:18:44 +0900 Subject: [PATCH 0854/1415] Add a log message if enabling Ethernet tethering if it is already enabled. Test: builds Bug: 150644681 Change-Id: I68123e6dd04ccae5da2ecd7526c11d9f835d1d57 --- .../com/android/server/connectivity/tethering/Tethering.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 3dcc15f92c..167e044642 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -635,7 +635,10 @@ public class Tethering { Context.ETHERNET_SERVICE); synchronized (mPublicSync) { if (enable) { - if (mEthernetCallback != null) return TETHER_ERROR_NO_ERROR; + if (mEthernetCallback != null) { + Log.d(TAG, "Ethernet tethering already started"); + return TETHER_ERROR_NO_ERROR; + } mEthernetCallback = new EthernetCallback(); mEthernetIfaceRequest = em.requestTetheredInterface(mExecutor, mEthernetCallback); From 13694bc4f4e52127ad0e60dc16e576ec4fd93165 Mon Sep 17 00:00:00 2001 From: lesl Date: Tue, 24 Mar 2020 22:52:55 +0800 Subject: [PATCH 0855/1415] cts: setBssid supported for tethered mode hotspot Bug: 152180102 Test: atest android.net.wifi.cts.WifiManagerTest#testSetGetSoftApConfigurationAndSoftApCapabilityCallback Change-Id: I742e8a562046a996d8c69af7c6902ddd75fea72c --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 3153149629..4cbdf62a7e 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -1403,13 +1403,13 @@ public class WifiManagerTest extends AndroidTestCase { mWifiManager.setSoftApConfiguration(targetConfig); // Bssid set dodesn't support for tethered hotspot SoftApConfiguration currentConfig = mWifiManager.getSoftApConfiguration(); - assertNull(currentConfig.getBssid()); compareSoftApConfiguration(targetConfig, currentConfig); } private void compareSoftApConfiguration(SoftApConfiguration currentConfig, SoftApConfiguration testSoftApConfig) { assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid()); + assertEquals(currentConfig.getBssid(), testSoftApConfig.getBssid()); assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType()); assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase()); assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid()); From 53bc7c3a501d41db02a9a2300740d98261934bd4 Mon Sep 17 00:00:00 2001 From: David Su Date: Thu, 19 Mar 2020 21:59:37 -0700 Subject: [PATCH 0856/1415] CTS: Split Wifi tests out of CtsNetTestCases Create CtsWifiTestCases. (dirty cherry-pick from internal branch) Bug: 129133376 Test: atest CtsWifiTestCases Change-Id: Iaa51f7ec86e6b4bfe64dcb26a8d8b818dd356608 Merged-In: Iaa51f7ec86e6b4bfe64dcb26a8d8b818dd356608 --- tests/cts/net/src/android/net/wifi/OWNERS | 5 - .../net/wifi/aware/cts/SingleDeviceTest.java | 787 ------------ .../android/net/wifi/aware/cts/TestUtils.java | 69 -- .../android/net/wifi/cts/ConcurrencyTest.java | 461 ------- .../net/wifi/cts/ConfigParserTest.java | 114 -- .../src/android/net/wifi/cts/FakeKeys.java | 257 ---- .../net/wifi/cts/MulticastLockTest.java | 79 -- .../android/net/wifi/cts/NsdManagerTest.java | 592 --------- .../android/net/wifi/cts/PpsMoParserTest.java | 131 -- .../android/net/wifi/cts/ScanResultTest.java | 233 ---- .../net/wifi/cts/SupplicantStateTest.java | 42 - .../net/wifi/cts/WifiConfigurationTest.java | 51 - .../wifi/cts/WifiEnterpriseConfigTest.java | 796 ------------- .../src/android/net/wifi/cts/WifiFeature.java | 32 - .../android/net/wifi/cts/WifiInfoTest.java | 170 --- .../android/net/wifi/cts/WifiLockTest.java | 90 -- .../android/net/wifi/cts/WifiManagerTest.java | 1056 ----------------- .../net/wifi/p2p/cts/WifiP2pConfigTest.java | 62 - .../android/net/wifi/rtt/cts/TestBase.java | 237 ---- .../android/net/wifi/rtt/cts/WifiRttTest.java | 214 ---- 20 files changed, 5478 deletions(-) delete mode 100644 tests/cts/net/src/android/net/wifi/OWNERS delete mode 100644 tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/FakeKeys.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiFeature.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/rtt/cts/TestBase.java delete mode 100644 tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java diff --git a/tests/cts/net/src/android/net/wifi/OWNERS b/tests/cts/net/src/android/net/wifi/OWNERS deleted file mode 100644 index 4a6001bcfe..0000000000 --- a/tests/cts/net/src/android/net/wifi/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -etancohen@google.com -lorenzo@google.com -mplass@google.com -rpius@google.com -satk@google.com diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java deleted file mode 100644 index 1901f02cdc..0000000000 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ /dev/null @@ -1,787 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.aware.cts; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.location.LocationManager; -import android.net.ConnectivityManager; -import android.net.MacAddress; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.net.wifi.WifiManager; -import android.net.wifi.aware.AttachCallback; -import android.net.wifi.aware.Characteristics; -import android.net.wifi.aware.DiscoverySessionCallback; -import android.net.wifi.aware.IdentityChangedListener; -import android.net.wifi.aware.PeerHandle; -import android.net.wifi.aware.PublishConfig; -import android.net.wifi.aware.PublishDiscoverySession; -import android.net.wifi.aware.SubscribeConfig; -import android.net.wifi.aware.SubscribeDiscoverySession; -import android.net.wifi.aware.WifiAwareManager; -import android.net.wifi.aware.WifiAwareSession; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.SystemClock; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -import com.android.compatibility.common.util.SystemUtil; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Wi-Fi Aware CTS test suite: single device testing. Performs tests on a single - * device to validate Wi-Fi Aware. - */ -@AppModeFull(reason = "Cannot get WifiAwareManager in instant app mode") -public class SingleDeviceTest extends AndroidTestCase { - private static final String TAG = "WifiAwareCtsTests"; - - // wait for Wi-Fi Aware state changes & network requests callbacks - static private final int WAIT_FOR_AWARE_CHANGE_SECS = 10; // 10 seconds - - private final Object mLock = new Object(); - private final HandlerThread mHandlerThread = new HandlerThread("SingleDeviceTest"); - private final Handler mHandler; - { - mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()); - } - - private WifiAwareManager mWifiAwareManager; - private WifiManager mWifiManager; - private WifiManager.WifiLock mWifiLock; - private ConnectivityManager mConnectivityManager; - - // used to store any WifiAwareSession allocated during tests - will clean-up after tests - private List mSessions = new ArrayList<>(); - - private class WifiAwareBroadcastReceiver extends BroadcastReceiver { - private CountDownLatch mBlocker = new CountDownLatch(1); - - @Override - public void onReceive(Context context, Intent intent) { - if (WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED.equals(intent.getAction())) { - mBlocker.countDown(); - } - } - - boolean waitForStateChange() throws InterruptedException { - return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); - } - } - - private class AttachCallbackTest extends AttachCallback { - static final int ATTACHED = 0; - static final int ATTACH_FAILED = 1; - static final int ERROR = 2; // no callback: timeout, interruption - - private CountDownLatch mBlocker = new CountDownLatch(1); - private int mCallbackCalled = ERROR; // garbage init - private WifiAwareSession mSession = null; - - @Override - public void onAttached(WifiAwareSession session) { - mCallbackCalled = ATTACHED; - mSession = session; - synchronized (mLock) { - mSessions.add(session); - } - mBlocker.countDown(); - } - - @Override - public void onAttachFailed() { - mCallbackCalled = ATTACH_FAILED; - mBlocker.countDown(); - } - - /** - * Waits for any of the callbacks to be called - or an error (timeout, interruption). - * Returns one of the ATTACHED, ATTACH_FAILED, or ERROR values. - */ - int waitForAnyCallback() { - try { - boolean noTimeout = mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); - if (noTimeout) { - return mCallbackCalled; - } else { - return ERROR; - } - } catch (InterruptedException e) { - return ERROR; - } - } - - /** - * Access the session created by a callback. Only useful to be called after calling - * waitForAnyCallback() and getting the ATTACHED code back. - */ - WifiAwareSession getSession() { - return mSession; - } - } - - private class IdentityChangedListenerTest extends IdentityChangedListener { - private CountDownLatch mBlocker = new CountDownLatch(1); - private byte[] mMac = null; - - @Override - public void onIdentityChanged(byte[] mac) { - mMac = mac; - mBlocker.countDown(); - } - - /** - * Waits for the listener callback to be called - or an error (timeout, interruption). - * Returns true on callback called, false on error (timeout, interruption). - */ - boolean waitForListener() { - try { - return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - return false; - } - } - - /** - * Returns the MAC address of the discovery interface supplied to the triggered callback. - */ - byte[] getMac() { - return mMac; - } - } - - private class DiscoverySessionCallbackTest extends DiscoverySessionCallback { - static final int ON_PUBLISH_STARTED = 0; - static final int ON_SUBSCRIBE_STARTED = 1; - static final int ON_SESSION_CONFIG_UPDATED = 2; - static final int ON_SESSION_CONFIG_FAILED = 3; - static final int ON_SESSION_TERMINATED = 4; - static final int ON_SERVICE_DISCOVERED = 5; - static final int ON_MESSAGE_SEND_SUCCEEDED = 6; - static final int ON_MESSAGE_SEND_FAILED = 7; - static final int ON_MESSAGE_RECEIVED = 8; - - private final Object mLocalLock = new Object(); - - private CountDownLatch mBlocker; - private int mCurrentWaitForCallback; - private ArrayDeque mCallbackQueue = new ArrayDeque<>(); - - private PublishDiscoverySession mPublishDiscoverySession; - private SubscribeDiscoverySession mSubscribeDiscoverySession; - - private void processCallback(int callback) { - synchronized (mLocalLock) { - if (mBlocker != null && mCurrentWaitForCallback == callback) { - mBlocker.countDown(); - } else { - mCallbackQueue.addLast(callback); - } - } - } - - @Override - public void onPublishStarted(PublishDiscoverySession session) { - mPublishDiscoverySession = session; - processCallback(ON_PUBLISH_STARTED); - } - - @Override - public void onSubscribeStarted(SubscribeDiscoverySession session) { - mSubscribeDiscoverySession = session; - processCallback(ON_SUBSCRIBE_STARTED); - } - - @Override - public void onSessionConfigUpdated() { - processCallback(ON_SESSION_CONFIG_UPDATED); - } - - @Override - public void onSessionConfigFailed() { - processCallback(ON_SESSION_CONFIG_FAILED); - } - - @Override - public void onSessionTerminated() { - processCallback(ON_SESSION_TERMINATED); - } - - @Override - public void onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo, - List matchFilter) { - processCallback(ON_SERVICE_DISCOVERED); - } - - @Override - public void onMessageSendSucceeded(int messageId) { - processCallback(ON_MESSAGE_SEND_SUCCEEDED); - } - - @Override - public void onMessageSendFailed(int messageId) { - processCallback(ON_MESSAGE_SEND_FAILED); - } - - @Override - public void onMessageReceived(PeerHandle peerHandle, byte[] message) { - processCallback(ON_MESSAGE_RECEIVED); - } - - /** - * Wait for the specified callback - any of the ON_* constants. Returns a true - * on success (specified callback triggered) or false on failure (timed-out or - * interrupted while waiting for the requested callback). - * - * Note: other callbacks happening while while waiting for the specified callback will - * be queued. - */ - boolean waitForCallback(int callback) { - return waitForCallback(callback, WAIT_FOR_AWARE_CHANGE_SECS); - } - - /** - * Wait for the specified callback - any of the ON_* constants. Returns a true - * on success (specified callback triggered) or false on failure (timed-out or - * interrupted while waiting for the requested callback). - * - * Same as waitForCallback(int callback) execpt that allows specifying a custom timeout. - * The default timeout is a short value expected to be sufficient for all behaviors which - * should happen relatively quickly. Specifying a custom timeout should only be done for - * those cases which are known to take a specific longer period of time. - * - * Note: other callbacks happening while while waiting for the specified callback will - * be queued. - */ - boolean waitForCallback(int callback, int timeoutSec) { - synchronized (mLocalLock) { - boolean found = mCallbackQueue.remove(callback); - if (found) { - return true; - } - - mCurrentWaitForCallback = callback; - mBlocker = new CountDownLatch(1); - } - - try { - return mBlocker.await(timeoutSec, TimeUnit.SECONDS); - } catch (InterruptedException e) { - return false; - } - } - - /** - * Indicates whether the specified callback (any of the ON_* constants) has already - * happened and in the queue. Useful when the order of events is important. - */ - boolean hasCallbackAlreadyHappened(int callback) { - synchronized (mLocalLock) { - return mCallbackQueue.contains(callback); - } - } - - /** - * Returns the last created publish discovery session. - */ - PublishDiscoverySession getPublishDiscoverySession() { - PublishDiscoverySession session = mPublishDiscoverySession; - mPublishDiscoverySession = null; - return session; - } - - /** - * Returns the last created subscribe discovery session. - */ - SubscribeDiscoverySession getSubscribeDiscoverySession() { - SubscribeDiscoverySession session = mSubscribeDiscoverySession; - mSubscribeDiscoverySession = null; - return session; - } - } - - private class NetworkCallbackTest extends ConnectivityManager.NetworkCallback { - private CountDownLatch mBlocker = new CountDownLatch(1); - - @Override - public void onUnavailable() { - mBlocker.countDown(); - } - - /** - * Wait for the onUnavailable() callback to be triggered. Returns true if triggered, - * otherwise (timed-out, interrupted) returns false. - */ - boolean waitForOnUnavailable() { - try { - return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - return false; - } - } - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - assertTrue("Wi-Fi Aware requires Location to be Enabled", - ((LocationManager) getContext().getSystemService( - Context.LOCATION_SERVICE)).isLocationEnabled()); - - mWifiAwareManager = (WifiAwareManager) getContext().getSystemService( - Context.WIFI_AWARE_SERVICE); - assertNotNull("Wi-Fi Aware Manager", mWifiAwareManager); - - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull("Wi-Fi Manager", mWifiManager); - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) { - SystemUtil.runShellCommand("svc wifi enable"); - } - - mConnectivityManager = (ConnectivityManager) getContext().getSystemService( - Context.CONNECTIVITY_SERVICE); - assertNotNull("Connectivity Manager", mConnectivityManager); - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); - WifiAwareBroadcastReceiver receiver = new WifiAwareBroadcastReceiver(); - mContext.registerReceiver(receiver, intentFilter); - if (!mWifiAwareManager.isAvailable()) { - assertTrue("Timeout waiting for Wi-Fi Aware to change status", - receiver.waitForStateChange()); - assertTrue("Wi-Fi Aware is not available (should be)", mWifiAwareManager.isAvailable()); - } - } - - @Override - protected void tearDown() throws Exception { - if (!TestUtils.shouldTestWifiAware(getContext())) { - super.tearDown(); - return; - } - - synchronized (mLock) { - for (WifiAwareSession session : mSessions) { - // no damage from destroying twice (i.e. ok if test cleaned up after itself already) - session.close(); - } - mSessions.clear(); - } - - super.tearDown(); - } - - /** - * Validate: - * - Characteristics are available - * - Characteristics values are legitimate. Not in the CDD. However, the tested values are - * based on the Wi-Fi Aware protocol. - */ - public void testCharacteristics() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - Characteristics characteristics = mWifiAwareManager.getCharacteristics(); - assertNotNull("Wi-Fi Aware characteristics are null", characteristics); - assertEquals("Service Name Length", characteristics.getMaxServiceNameLength(), 255); - assertEquals("Service Specific Information Length", - characteristics.getMaxServiceSpecificInfoLength(), 255); - assertEquals("Match Filter Length", characteristics.getMaxMatchFilterLength(), 255); - } - - /** - * Validate that on Wi-Fi Aware availability change we get a broadcast + the API returns - * correct status. - */ - public void testAvailabilityStatusChange() throws Exception { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); - - // 1. Disable Wi-Fi - WifiAwareBroadcastReceiver receiver1 = new WifiAwareBroadcastReceiver(); - mContext.registerReceiver(receiver1, intentFilter); - SystemUtil.runShellCommand("svc wifi disable"); - - assertTrue("Timeout waiting for Wi-Fi Aware to change status", - receiver1.waitForStateChange()); - assertFalse("Wi-Fi Aware is available (should not be)", mWifiAwareManager.isAvailable()); - - // 2. Enable Wi-Fi - WifiAwareBroadcastReceiver receiver2 = new WifiAwareBroadcastReceiver(); - mContext.registerReceiver(receiver2, intentFilter); - SystemUtil.runShellCommand("svc wifi enable"); - - assertTrue("Timeout waiting for Wi-Fi Aware to change status", - receiver2.waitForStateChange()); - assertTrue("Wi-Fi Aware is not available (should be)", mWifiAwareManager.isAvailable()); - } - - /** - * Validate that can attach to Wi-Fi Aware. - */ - public void testAttachNoIdentity() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - WifiAwareSession session = attachAndGetSession(); - session.close(); - } - - /** - * Validate that can attach to Wi-Fi Aware and get identity information. Use the identity - * information to validate that MAC address changes on every attach. - * - * Note: relies on no other entity using Wi-Fi Aware during the CTS test. Since if it is used - * then the attach/destroy will not correspond to enable/disable and will not result in a new - * MAC address being generated. - */ - public void testAttachDiscoveryAddressChanges() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final int numIterations = 10; - Set macs = new HashSet<>(); - - for (int i = 0; i < numIterations; ++i) { - AttachCallbackTest attachCb = new AttachCallbackTest(); - IdentityChangedListenerTest identityL = new IdentityChangedListenerTest(); - mWifiAwareManager.attach(attachCb, identityL, mHandler); - assertEquals("Wi-Fi Aware attach: iteration " + i, AttachCallbackTest.ATTACHED, - attachCb.waitForAnyCallback()); - assertTrue("Wi-Fi Aware attach: iteration " + i, identityL.waitForListener()); - - WifiAwareSession session = attachCb.getSession(); - assertNotNull("Wi-Fi Aware session: iteration " + i, session); - - byte[] mac = identityL.getMac(); - assertNotNull("Wi-Fi Aware discovery MAC: iteration " + i, mac); - - session.close(); - - macs.add(new TestUtils.MacWrapper(mac)); - } - - assertEquals("", numIterations, macs.size()); - } - - /** - * Validate a successful publish discovery session lifetime: publish, update publish, destroy. - */ - public void testPublishDiscoverySuccess() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final String serviceName = "ValidName"; - - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - serviceName).build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. publish - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); - assertNotNull("Publish session", discoverySession); - - // 2. update-publish - publishConfig = new PublishConfig.Builder().setServiceName( - serviceName).setServiceSpecificInfo("extras".getBytes()).build(); - discoverySession.updatePublish(publishConfig); - assertTrue("Publish update", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - // 3. destroy - assertFalse("Publish not terminated", discoveryCb.hasCallbackAlreadyHappened( - DiscoverySessionCallbackTest.ON_SESSION_TERMINATED)); - discoverySession.close(); - - // 4. try update post-destroy: should time-out waiting for cb - discoverySession.updatePublish(publishConfig); - assertFalse("Publish update post destroy", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - session.close(); - } - - /** - * Validate that publish with a Time To Live (TTL) setting expires within the specified - * time (and validates that the terminate callback is triggered). - */ - public void testPublishLimitedTtlSuccess() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final String serviceName = "ValidName"; - final int ttlSec = 5; - - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - serviceName).setTtlSec(ttlSec).setTerminateNotificationEnabled(true).build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. publish - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); - assertNotNull("Publish session", discoverySession); - - // 2. wait for terminate within 'ttlSec'. - assertTrue("Publish terminated", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SESSION_TERMINATED, - ttlSec + 5)); - - // 3. try update post-termination: should time-out waiting for cb - publishConfig = new PublishConfig.Builder().setServiceName( - serviceName).setServiceSpecificInfo("extras".getBytes()).build(); - discoverySession.updatePublish(publishConfig); - assertFalse("Publish update post terminate", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - session.close(); - } - - /** - * Validate a successful subscribe discovery session lifetime: subscribe, update subscribe, - * destroy. - */ - public void testSubscribeDiscoverySuccess() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final String serviceName = "ValidName"; - - WifiAwareSession session = attachAndGetSession(); - - SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName( - serviceName).build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. subscribe - session.subscribe(subscribeConfig, discoveryCb, mHandler); - assertTrue("Subscribe started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SUBSCRIBE_STARTED)); - SubscribeDiscoverySession discoverySession = discoveryCb.getSubscribeDiscoverySession(); - assertNotNull("Subscribe session", discoverySession); - - // 2. update-subscribe - subscribeConfig = new SubscribeConfig.Builder().setServiceName( - serviceName).setServiceSpecificInfo("extras".getBytes()).build(); - discoverySession.updateSubscribe(subscribeConfig); - assertTrue("Subscribe update", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - // 3. destroy - assertFalse("Subscribe not terminated", discoveryCb.hasCallbackAlreadyHappened( - DiscoverySessionCallbackTest.ON_SESSION_TERMINATED)); - discoverySession.close(); - - // 4. try update post-destroy: should time-out waiting for cb - discoverySession.updateSubscribe(subscribeConfig); - assertFalse("Subscribe update post destroy", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - session.close(); - } - - /** - * Validate that subscribe with a Time To Live (TTL) setting expires within the specified - * time (and validates that the terminate callback is triggered). - */ - public void testSubscribeLimitedTtlSuccess() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final String serviceName = "ValidName"; - final int ttlSec = 5; - - WifiAwareSession session = attachAndGetSession(); - - SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName( - serviceName).setTtlSec(ttlSec).setTerminateNotificationEnabled(true).build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. subscribe - session.subscribe(subscribeConfig, discoveryCb, mHandler); - assertTrue("Subscribe started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SUBSCRIBE_STARTED)); - SubscribeDiscoverySession discoverySession = discoveryCb.getSubscribeDiscoverySession(); - assertNotNull("Subscribe session", discoverySession); - - // 2. wait for terminate within 'ttlSec'. - assertTrue("Subscribe terminated", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SESSION_TERMINATED, - ttlSec + 5)); - - // 3. try update post-termination: should time-out waiting for cb - subscribeConfig = new SubscribeConfig.Builder().setServiceName( - serviceName).setServiceSpecificInfo("extras".getBytes()).build(); - discoverySession.updateSubscribe(subscribeConfig); - assertFalse("Subscribe update post terminate", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - session.close(); - } - - /** - * Test the send message flow. Since testing single device cannot send to a real peer - - * validate that sending to a bogus peer fails. - */ - public void testSendMessageFail() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - "ValidName").build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. publish - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); - assertNotNull("Publish session", discoverySession); - - // 2. send a message with a null peer-handle - expect exception - try { - discoverySession.sendMessage(null, -1290, "some message".getBytes()); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // empty - } - - discoverySession.close(); - session.close(); - } - - /** - * Request an Aware data-path (open) as a Responder with an arbitrary peer MAC address. Validate - * that receive an onUnavailable() callback. - */ - public void testDataPathOpenOutOfBandFail() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - MacAddress mac = MacAddress.fromString("00:01:02:03:04:05"); - - // 1. initialize Aware: only purpose is to make sure it is available for OOB data-path - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - "ValidName").build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - - // 2. request an AWARE network - NetworkCallbackTest networkCb = new NetworkCallbackTest(); - NetworkRequest nr = new NetworkRequest.Builder().addTransportType( - NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( - session.createNetworkSpecifierOpen( - WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, - mac.toByteArray())).build(); - mConnectivityManager.requestNetwork(nr, networkCb); - assertTrue("OnUnavailable not received", networkCb.waitForOnUnavailable()); - - session.close(); - } - - /** - * Request an Aware data-path (encrypted) as a Responder with an arbitrary peer MAC address. - * Validate that receive an onUnavailable() callback. - */ - public void testDataPathPassphraseOutOfBandFail() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - MacAddress mac = MacAddress.fromString("00:01:02:03:04:05"); - - // 1. initialize Aware: only purpose is to make sure it is available for OOB data-path - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - "ValidName").build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - - // 2. request an AWARE network - NetworkCallbackTest networkCb = new NetworkCallbackTest(); - NetworkRequest nr = new NetworkRequest.Builder().addTransportType( - NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( - session.createNetworkSpecifierPassphrase( - WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, mac.toByteArray(), - "abcdefghihk")).build(); - mConnectivityManager.requestNetwork(nr, networkCb); - assertTrue("OnUnavailable not received", networkCb.waitForOnUnavailable()); - - session.close(); - } - - // local utilities - - private WifiAwareSession attachAndGetSession() { - AttachCallbackTest attachCb = new AttachCallbackTest(); - mWifiAwareManager.attach(attachCb, mHandler); - int cbCalled = attachCb.waitForAnyCallback(); - assertEquals("Wi-Fi Aware attach", AttachCallbackTest.ATTACHED, cbCalled); - - WifiAwareSession session = attachCb.getSession(); - assertNotNull("Wi-Fi Aware session", session); - - return session; - } -} diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java b/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java deleted file mode 100644 index a12c8bb0d2..0000000000 --- a/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.aware.cts; - -import android.content.Context; -import android.content.pm.PackageManager; - -import java.util.Arrays; - -/** - * Test utilities for Wi-Fi Aware CTS test suite. - */ -class TestUtils { - static final String TAG = "WifiAwareCtsTests"; - - /** - * Returns a flag indicating whether or not Wi-Fi Aware should be tested. Wi-Fi Aware - * should be tested if the feature is supported on the current device. - */ - static boolean shouldTestWifiAware(Context context) { - final PackageManager pm = context.getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE); - } - - /** - * Wraps a byte[] (MAC address representation). Intended to provide hash and equality operators - * so that the MAC address can be used in containers. - */ - static class MacWrapper { - private byte[] mMac; - - MacWrapper(byte[] mac) { - mMac = mac; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof MacWrapper)) { - return false; - } - - MacWrapper lhs = (MacWrapper) o; - return Arrays.equals(mMac, lhs.mMac); - } - - @Override - public int hashCode() { - return Arrays.hashCode(mMac); - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java deleted file mode 100644 index ba0832f8b6..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (C) 2012 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.wifi.cts; - -import static org.junit.Assert.assertNotEquals; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkRequest; -import android.net.wifi.WifiManager; -import android.net.wifi.p2p.WifiP2pManager; -import android.provider.Settings; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; -import android.util.Log; - -import com.android.compatibility.common.util.SystemUtil; - -import java.util.Arrays; -import java.util.BitSet; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class ConcurrencyTest extends AndroidTestCase { - private class MySync { - static final int WIFI_STATE = 0; - static final int P2P_STATE = 1; - static final int DISCOVERY_STATE = 2; - static final int NETWORK_INFO = 3; - - public BitSet pendingSync = new BitSet(); - - public int expectedWifiState; - public int expectedP2pState; - public int expectedDiscoveryState; - public NetworkInfo expectedNetworkInfo; - } - - private class MyResponse { - public boolean valid = false; - - public boolean success; - public int p2pState; - public int discoveryState; - public NetworkInfo networkInfo; - } - - private WifiManager mWifiManager; - private WifiP2pManager mWifiP2pManager; - private WifiP2pManager.Channel mWifiP2pChannel; - private MySync mMySync = new MySync(); - private MyResponse mMyResponse = new MyResponse(); - - private static final String TAG = "ConcurrencyTest"; - private static final int TIMEOUT_MSEC = 6000; - private static final int WAIT_MSEC = 60; - private static final int DURATION = 10000; - private IntentFilter mIntentFilter; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.pendingSync.set(MySync.WIFI_STATE); - mMySync.expectedWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_DISABLED); - mMySync.notify(); - } - } else if(action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.pendingSync.set(MySync.P2P_STATE); - mMySync.expectedP2pState = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, - WifiP2pManager.WIFI_P2P_STATE_DISABLED); - mMySync.notify(); - } - } else if (action.equals(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.pendingSync.set(MySync.DISCOVERY_STATE); - mMySync.expectedDiscoveryState = intent.getIntExtra( - WifiP2pManager.EXTRA_DISCOVERY_STATE, - WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); - mMySync.notify(); - } - } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.pendingSync.set(MySync.NETWORK_INFO); - mMySync.expectedNetworkInfo = (NetworkInfo) intent.getExtra( - WifiP2pManager.EXTRA_NETWORK_INFO, null); - mMySync.notify(); - } - } - } - }; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext()) && - !WifiFeature.isP2pSupported(getContext())) { - // skip the test if WiFi && p2p are not supported - return; - } - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); - mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); - - mContext.registerReceiver(mReceiver, mIntentFilter); - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull(mWifiManager); - if (mWifiManager.isWifiEnabled()) { - SystemUtil.runShellCommand("svc wifi disable"); - Thread.sleep(DURATION); - } - assertTrue(!mWifiManager.isWifiEnabled()); - mMySync.expectedWifiState = WifiManager.WIFI_STATE_DISABLED; - mMySync.expectedP2pState = WifiP2pManager.WIFI_P2P_STATE_DISABLED; - mMySync.expectedDiscoveryState = WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED; - mMySync.expectedNetworkInfo = null; - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext()) && - !WifiFeature.isP2pSupported(getContext())) { - // skip the test if WiFi and p2p are not supported - super.tearDown(); - return; - } - mContext.unregisterReceiver(mReceiver); - - enableWifi(); - super.tearDown(); - } - - private boolean waitForBroadcasts(List waitSyncList) { - synchronized (mMySync) { - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout) { - List handledSyncList = waitSyncList.stream() - .filter(w -> mMySync.pendingSync.get(w)) - .collect(Collectors.toList()); - handledSyncList.forEach(w -> mMySync.pendingSync.clear(w)); - waitSyncList.removeAll(handledSyncList); - if (waitSyncList.isEmpty()) { - break; - } - try { - mMySync.wait(WAIT_MSEC); - } catch (InterruptedException e) { } - } - if (!waitSyncList.isEmpty()) { - Log.i(TAG, "Missing broadcast: " + waitSyncList); - } - return waitSyncList.isEmpty(); - } - } - - private boolean waitForBroadcasts(int waitSingleSync) { - return waitForBroadcasts( - new LinkedList(Arrays.asList(waitSingleSync))); - } - - private boolean waitForServiceResponse(MyResponse waitResponse) { - synchronized (waitResponse) { - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout) { - try { - waitResponse.wait(WAIT_MSEC); - } catch (InterruptedException e) { } - - if (waitResponse.valid) { - return true; - } - } - return false; - } - } - - // Return true if location is enabled. - private boolean isLocationEnabled() { - return Settings.Secure.getInt(getContext().getContentResolver(), - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) - != Settings.Secure.LOCATION_MODE_OFF; - } - - // Returns true if the device has location feature. - private boolean hasLocationFeature() { - return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); - } - - private void resetResponse(MyResponse responseObj) { - synchronized (responseObj) { - responseObj.valid = false; - responseObj.networkInfo = null; - } - } - - /* - * Enables Wifi and block until connection is established. - */ - private void enableWifi() throws InterruptedException { - if (!mWifiManager.isWifiEnabled()) { - SystemUtil.runShellCommand("svc wifi enable"); - } - - ConnectivityManager cm = - (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkRequest request = - new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - final CountDownLatch latch = new CountDownLatch(1); - NetworkCallback networkCallback = new NetworkCallback() { - @Override - public void onAvailable(Network network) { - latch.countDown(); - } - }; - cm.registerNetworkCallback(request, networkCallback); - latch.await(DURATION, TimeUnit.MILLISECONDS); - - cm.unregisterNetworkCallback(networkCallback); - } - - private boolean setupWifiP2p() { - // Cannot support p2p alone - if (!WifiFeature.isWifiSupported(getContext())) { - assertTrue(!WifiFeature.isP2pSupported(getContext())); - return false; - } - - if (!WifiFeature.isP2pSupported(getContext())) { - // skip the test if p2p is not supported - return false; - } - - if (!hasLocationFeature()) { - Log.d(TAG, "Skipping test as location is not supported"); - return false; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since P-release WiFi Direct" - + " needs Location enabled."); - } - - mWifiP2pManager = - (WifiP2pManager) getContext().getSystemService(Context.WIFI_P2P_SERVICE); - mWifiP2pChannel = mWifiP2pManager.initialize( - getContext(), getContext().getMainLooper(), null); - - assertNotNull(mWifiP2pManager); - assertNotNull(mWifiP2pChannel); - - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (!mWifiManager.isWifiEnabled() && System.currentTimeMillis() < timeout) { - try { - enableWifi(); - } catch (InterruptedException e) { } - } - - assertTrue(mWifiManager.isWifiEnabled()); - - assertTrue(waitForBroadcasts( - new LinkedList( - Arrays.asList(MySync.WIFI_STATE, MySync.P2P_STATE)))); - - assertEquals(WifiManager.WIFI_STATE_ENABLED, mMySync.expectedWifiState); - assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMySync.expectedP2pState); - - assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); - // wait for changing to EnabledState - assertNotNull(mMySync.expectedNetworkInfo); - - return true; - } - - public void testConcurrency() { - if (!setupWifiP2p()) { - return; - } - - resetResponse(mMyResponse); - mWifiP2pManager.requestP2pState(mWifiP2pChannel, new WifiP2pManager.P2pStateListener() { - @Override - public void onP2pStateAvailable(int state) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.p2pState = state; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMyResponse.p2pState); - } - - public void testRequestDiscoveryState() { - if (!setupWifiP2p()) { - return; - } - - resetResponse(mMyResponse); - mWifiP2pManager.requestDiscoveryState( - mWifiP2pChannel, new WifiP2pManager.DiscoveryStateListener() { - @Override - public void onDiscoveryStateAvailable(int state) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.discoveryState = state; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED, mMyResponse.discoveryState); - - resetResponse(mMyResponse); - mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() { - @Override - public void onSuccess() { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.success = true; - mMyResponse.notify(); - } - } - - @Override - public void onFailure(int reason) { - synchronized (mMyResponse) { - Log.d(TAG, "discoveryPeers failure reason: " + reason); - mMyResponse.valid = true; - mMyResponse.success = false; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - assertTrue(waitForBroadcasts(MySync.DISCOVERY_STATE)); - - resetResponse(mMyResponse); - mWifiP2pManager.requestDiscoveryState(mWifiP2pChannel, - new WifiP2pManager.DiscoveryStateListener() { - @Override - public void onDiscoveryStateAvailable(int state) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.discoveryState = state; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED, mMyResponse.discoveryState); - - mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, null); - } - - public void testRequestNetworkInfo() { - if (!setupWifiP2p()) { - return; - } - - resetResponse(mMyResponse); - mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel, - new WifiP2pManager.NetworkInfoListener() { - @Override - public void onNetworkInfoAvailable(NetworkInfo info) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.networkInfo = info; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertNotNull(mMyResponse.networkInfo); - // The state might be IDLE, DISCONNECTED, FAILED before a connection establishment. - // Just ensure the state is NOT CONNECTED. - assertNotEquals(NetworkInfo.DetailedState.CONNECTED, - mMySync.expectedNetworkInfo.getDetailedState()); - - resetResponse(mMyResponse); - mWifiP2pManager.createGroup(mWifiP2pChannel, new WifiP2pManager.ActionListener() { - @Override - public void onSuccess() { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.success = true; - mMyResponse.notify(); - } - } - - @Override - public void onFailure(int reason) { - synchronized (mMyResponse) { - Log.d(TAG, "createGroup failure reason: " + reason); - mMyResponse.valid = true; - mMyResponse.success = false; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); - assertNotNull(mMySync.expectedNetworkInfo); - assertEquals(NetworkInfo.DetailedState.CONNECTED, - mMySync.expectedNetworkInfo.getDetailedState()); - - resetResponse(mMyResponse); - mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel, - new WifiP2pManager.NetworkInfoListener() { - @Override - public void onNetworkInfoAvailable(NetworkInfo info) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.networkInfo = info; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertNotNull(mMyResponse.networkInfo); - assertEquals(NetworkInfo.DetailedState.CONNECTED, - mMyResponse.networkInfo.getDetailedState()); - - mWifiP2pManager.removeGroup(mWifiP2pChannel, null); - } - -} diff --git a/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java b/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java deleted file mode 100644 index 52ed2a6d73..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.cts; - -import android.net.wifi.hotspot2.ConfigParser; -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.pps.Credential; -import android.net.wifi.hotspot2.pps.HomeSp; -import android.test.AndroidTestCase; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Arrays; - -/** - * CTS tests for Hotspot 2.0 Release 1 installation file parsing API. - */ -public class ConfigParserTest extends AndroidTestCase { - /** - * Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a - * CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}. - */ - private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT = - "assets/HSR1ProfileWithCACert.base64"; - - /** - * Read the content of the given resource file into a String. - * - * @param filename String name of the file - * @return String - * @throws IOException - */ - private String loadResourceFile(String filename) throws IOException { - InputStream in = getClass().getClassLoader().getResourceAsStream(filename); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - StringBuilder builder = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - builder.append(line).append("\n"); - } - - return builder.toString(); - } - - /** - * Generate a {@link PasspointConfiguration} that matches the configuration specified in the - * XML file {@link #PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT}. - * - * @return {@link PasspointConfiguration} - */ - private PasspointConfiguration generateConfigurationFromProfile() { - PasspointConfiguration config = new PasspointConfiguration(); - - // HomeSP configuration. - HomeSp homeSp = new HomeSp(); - homeSp.setFriendlyName("Century House"); - homeSp.setFqdn("mi6.co.uk"); - homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L}); - config.setHomeSp(homeSp); - - // Credential configuration. - Credential credential = new Credential(); - credential.setRealm("shaken.stirred.com"); - Credential.UserCredential userCredential = new Credential.UserCredential(); - userCredential.setUsername("james"); - userCredential.setPassword("Ym9uZDAwNw=="); - userCredential.setEapType(21); - userCredential.setNonEapInnerMethod("MS-CHAP-V2"); - credential.setUserCredential(userCredential); - Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); - certCredential.setCertType("x509v3"); - byte[] certSha256Fingerprint = new byte[32]; - Arrays.fill(certSha256Fingerprint, (byte)0x1f); - certCredential.setCertSha256Fingerprint(certSha256Fingerprint); - credential.setCertCredential(certCredential); - Credential.SimCredential simCredential = new Credential.SimCredential(); - simCredential.setImsi("imsi"); - simCredential.setEapType(24); - credential.setSimCredential(simCredential); - credential.setCaCertificate(FakeKeys.CA_CERT0); - config.setCredential(credential); - return config; - } - - /** - * Verify a valid installation file is parsed successfully with the matching contents. - * - * @throws Exception - */ - public void testParseConfigFile() throws Exception { - String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT); - PasspointConfiguration expectedConfig = generateConfigurationFromProfile(); - PasspointConfiguration actualConfig = - ConfigParser.parsePasspointConfig( - "application/x-wifi-config", configStr.getBytes()); - assertTrue(actualConfig.equals(expectedConfig)); - } -} \ No newline at end of file diff --git a/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java b/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java deleted file mode 100644 index f8753017db..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2016 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.wifi.cts; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; - -/** - * A class containing test certificates and private keys. - */ -public class FakeKeys { - private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" + - "MIIDKDCCAhCgAwIBAgIJAILlFdwzLVurMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" + - "BAMTB0VBUCBDQTEwHhcNMTYwMTEyMTE1MDE1WhcNMjYwMTA5MTE1MDE1WjASMRAw\n" + - "DgYDVQQDEwdFQVAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" + - "znAPUz26Msae4ws43czR41/J2QtrSIZUKmVUsVumDbYHrPNvTXKSMXAcewORDQYX\n" + - "RqvHvpn8CscB1+oGXZvHwxj4zV0WKoK2zeXkau3vcyl3HIKupJfq2TEACefVjj0t\n" + - "JW+X35PGWp9/H5zIUNVNVjS7Ums84IvKhRB8512PB9UyHagXYVX5GWpAcVpyfrlR\n" + - "FI9Qdhh+Pbk0uyktdbf/CdfgHOoebrTtwRljM0oDtX+2Cv6j0wBK7hD8pPvf1+uy\n" + - "GzczigAU/4Kw7eZqydf9B+5RupR+IZipX41xEiIrKRwqi517WWzXcjaG2cNbf451\n" + - "xpH5PnV3i1tq04jMGQUzFwIDAQABo4GAMH4wHQYDVR0OBBYEFIwX4vs8BiBcScod\n" + - "5noZHRM8E4+iMEIGA1UdIwQ7MDmAFIwX4vs8BiBcScod5noZHRM8E4+ioRakFDAS\n" + - "MRAwDgYDVQQDEwdFQVAgQ0ExggkAguUV3DMtW6swDAYDVR0TBAUwAwEB/zALBgNV\n" + - "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFfQqOTA7Rv7K+luQ7pnas4BYwHE\n" + - "9GEP/uohv6KOy0TGQFbrRTjFoLVNB9BZ1ymMDZ0/TIwIUc7wi7a8t5mEqYH153wW\n" + - "aWooiSjyLLhuI4sNrNCOtisdBq2r2MFXt6h0mAQYOPv8R8K7/fgSxGFqzhyNmmVL\n" + - "1qBJldx34SpwsTALQVPb4hGwJzZfr1PcpEQx6xMnTl8xEWZE3Ms99uaUxbQqIwRu\n" + - "LgAOkNCmY2m89VhzaHJ1uV85AdM/tD+Ysmlnnjt9LRCejbBipjIGjOXrg1JP+lxV\n" + - "muM4vH+P/mlmxsPPz0d65b+EGmJZpoLkO/tdNNvCYzjJpTEWpEsO6NMhKYo=\n" + - "-----END CERTIFICATE-----\n"; - public static final X509Certificate CA_CERT0 = loadCertificate(CA_CERT0_STRING); - - private static final String CA_CERT1_STRING = "-----BEGIN CERTIFICATE-----\n" + - "MIIDKDCCAhCgAwIBAgIJAOM5SzKO2pzCMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" + - "BAMTB0VBUCBDQTAwHhcNMTYwMTEyMDAxMDQ3WhcNMjYwMTA5MDAxMDQ3WjASMRAw\n" + - "DgYDVQQDEwdFQVAgQ0EwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" + - "89ug+IEKVQXnJGKg5g4uVHg6J/8iRUxR5k2eH5o03hrJNMfN2D+cBe/wCiZcnWbI\n" + - "GbGZACWm2nQth2wy9Zgm2LOd3b4ocrHYls3XLq6Qb5Dd7a0JKU7pdGufiNVEkrmF\n" + - "EB+N64wgwH4COTvCiN4erp5kyJwkfqAl2xLkZo0C464c9XoyQOXbmYD9A8v10wZu\n" + - "jyNsEo7Nr2USyw+qhjWSbFbEirP77Tvx+7pJQJwdtk1V9Tn73T2dGF2WHYejei9S\n" + - "mcWpdIUqsu9etYH+zDmtu7I1xlkwiaVsNr2+D+qaCJyOYqrDTKVNK5nmbBPXDWZc\n" + - "NoDbTOoqquX7xONpq9M6jQIDAQABo4GAMH4wHQYDVR0OBBYEFAZ3A2S4qJZZwuNY\n" + - "wkJ6mAdc0gVdMEIGA1UdIwQ7MDmAFAZ3A2S4qJZZwuNYwkJ6mAdc0gVdoRakFDAS\n" + - "MRAwDgYDVQQDEwdFQVAgQ0EwggkA4zlLMo7anMIwDAYDVR0TBAUwAwEB/zALBgNV\n" + - "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHmdMwEhtys4d0E+t7owBmoVR+lU\n" + - "hMCcRtWs8YKX5WIM2kTweT0h/O1xwE1mWmRv/IbDAEb8od4BjAQLhIcolStr2JaO\n" + - "9ZzyxjOnNzqeErh/1DHDbb/moPpqfeJ8YiEz7nH/YU56Q8iCPO7TsgS0sNNE7PfN\n" + - "IUsBW0yHRgpQ4OxWmiZG2YZWiECRzAC0ecPzo59N5iH4vLQIMTMYquiDeMPQnn1e\n" + - "NDGxG8gCtDKIaS6tMg3a28MvWB094pr2ETou8O1C8Ji0Y4hE8QJmSdT7I4+GZjgW\n" + - "g94DZ5RiL7sdp3vC48CXOmeT61YBIvhGUsE1rPhXqkpqQ3Z3C4TFF0jXZZc=\n" + - "-----END CERTIFICATE-----\n"; - public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING); - - private static final String CA_PUBLIC_CERT_STRING = "-----BEGIN CERTIFICATE-----\n" + - "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\n" + - "GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\n" + - "b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\n" + - "BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\n" + - "VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\n" + - "DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\n" + - "THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\n" + - "Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\n" + - "c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\n" + - "gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" + - "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\n" + - "AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\n" + - "Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\n" + - "j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\n" + - "hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\n" + - "X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n" + - "-----END CERTIFICATE-----\n"; - public static final X509Certificate CA_PUBLIC_CERT = loadCertificate(CA_PUBLIC_CERT_STRING); - - private static final String CLIENT_CERT_STR = "-----BEGIN CERTIFICATE-----\n" + - "MIIE/DCCAuQCAQEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxCzAJBgNV\n" + - "BAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdUZXN0aW5n\n" + - "MB4XDTE2MDkzMDIwNTQyOFoXDTE3MDkzMDIwNTQyOFowRDELMAkGA1UEBhMCVVMx\n" + - "CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdU\n" + - "ZXN0aW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnpmcbuaeHfnJ\n" + - "k+2QNvxmdVFTawyFMNk0USCq5sexscwmxbewG/Rb8YnixwJWS44v2XkSujB67z5C\n" + - "s2qudFEhRXKdEuC6idbAuA97KjipHh0AAniWMsyv61fvbgsUC0b0canx3LiDq81p\n" + - "y28NNGmAvoazLZUZ4AhBRiwYZY6FKk723gmZoGbEIeG7J1dlXPusc1662rIjz4eU\n" + - "zlmmlvqyHfNqnNk8L14Vug6Xh+lOEGN85xhu1YHAEKGrS89kZxs5rum/cZU8KH2V\n" + - "v6eKnY03kxjiVLQtnLpm/7VUEoCMGHyruRj+p3my4+DgqMsmsH52RZCBsjyGlpbU\n" + - "NOwOTIX6xh+Rqloduz4AnrMYYIiIw2s8g+2zJM7VbcVKx0fGS26BKdrxgrXWfmNE\n" + - "nR0/REQ5AxDGw0jfTUvtdTkXAf+K4MDjcNLEZ+MA4rHfAfQWZtUR5BkHCQYxNpJk\n" + - "pA0gyk+BpKdC4WdzI14NSWsu5sRCmBCFqH6BTOSEq/V1cNorBxNwLSSTwFFqUDqx\n" + - "Y5nQLXygkJf9WHZWtSKeSjtOYgilz7UKzC2s3CsjmIyGFe+SwpuHJnuE4Uc8Z5Cb\n" + - "bjNGHPzqL6XnmzZHJp7RF8kBdKdjGC7dCUltzOfICZeKlzOOq+Kw42T/nXjuXvpb\n" + - "nkXNxg741Nwd6RecykXJbseFwm3EYxkCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEA\n" + - "Ga1mGwI9aXkL2fTPXO9YkAPzoGeX8aeuVYSQaSkNq+5vnogYCyAt3YDHjRG+ewTT\n" + - "WbnPA991xRAPac+biJeXWmwvgGj0YuT7e79phAiGkTTnbAjFHGfYnBy/tI/v7btO\n" + - "hRNElA5yTJ1m2fVbBEKXzMR83jrT9iyI+YLRN86zUZIaC86xxSbqnrdWN2jOK6MX\n" + - "dS8Arp9tPQjC/4gW+2Ilxv68jiYh+5auWHQZVjppWVY//iu4mAbkq1pTwQEhZ8F8\n" + - "Zrmh9DHh60hLFcfSuhIAwf/NMzppwdkjy1ruKVrpijhGKGp4OWu8nvOUgHSzxc7F\n" + - "PwpVZ5N2Ku4L8MLO6BG2VasRJK7l17TzDXlfLZHJjkuryOFxVaQKt8ZNFgTOaCXS\n" + - "E+gpTLksKU7riYckoiP4+H1sn9qcis0e8s4o/uf1UVc8GSdDw61ReGM5oZEDm1u8\n" + - "H9x20QU6igLqzyBpqvCKv7JNgU1uB2PAODHH78zJiUfnKd1y+o+J1iWzaGj3EFji\n" + - "T8AXksbTP733FeFXfggXju2dyBH+Z1S5BBTEOd1brWgXlHSAZGm97MKZ94r6/tkX\n" + - "qfv3fCos0DKz0oV7qBxYS8wiYhzrRVxG6ITAoH8uuUVVQaZF+G4nJ2jEqNbfuKyX\n" + - "ATQsVNjNNlDA0J33GobPMjT326wa4YAWMx8PI5PJZ3g=\n" + - "-----END CERTIFICATE-----\n"; - public static final X509Certificate CLIENT_CERT = loadCertificate(CLIENT_CERT_STR); - - private static final byte[] FAKE_RSA_KEY_1 = new byte[] { - (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01, - (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82, - (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e, - (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, - (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b, - (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66, - (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a, - (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02, - (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3, - (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d, - (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67, - (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb, - (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2, - (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79, - (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce, - (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08, - (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b, - (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4, - (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d, - (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23, - (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08, - (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1, - (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4, - (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16, - (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e, - (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01, - (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16, - (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98, - (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf, - (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a, - (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2, - (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc, - (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5, - (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a, - (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b, - (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9, - (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12, - (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e, - (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d, - (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2, - (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d, - (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc, - (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98, - (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96, - (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30, - (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e, - (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad, - (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f, - (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89, - (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13, - (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a, - (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e, - (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa, - (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47, - (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44, - (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22, - (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10, - (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45, - (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4, - (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda, - (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1, - (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab, - (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7, - (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc, - (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d, - (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82, - (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3, - (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a, - (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9, - (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6, - (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00, - (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd, - (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb, - (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4, - (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0, - (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2, - (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce, - (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a, - (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21, - (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d, - (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1, - (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41, - (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce, - (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0, - (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40, - (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a, - (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c, - (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90, - (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf, - (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb, - (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14, - (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab, - (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02, - (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67, - (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d, - (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d, - (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b, - (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2, - (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28, - (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd, - (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d, - (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b, - (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1, - (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51 - }; - public static final PrivateKey RSA_KEY1 = loadPrivateRSAKey(FAKE_RSA_KEY_1); - - private static X509Certificate loadCertificate(String blob) { - try { - final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - InputStream stream = new ByteArrayInputStream(blob.getBytes(StandardCharsets.UTF_8)); - - return (X509Certificate) certFactory.generateCertificate(stream); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - private static PrivateKey loadPrivateRSAKey(byte[] fakeKey) { - try { - KeyFactory kf = KeyFactory.getInstance("RSA"); - return kf.generatePrivate(new PKCS8EncodedKeySpec(fakeKey)); - } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { - return null; - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java b/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java deleted file mode 100644 index 71f04a33c1..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 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.wifi.cts; - -import android.content.Context; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.MulticastLock; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class MulticastLockTest extends AndroidTestCase { - - private static final String WIFI_TAG = "MulticastLockTest"; - - /** - * Verify acquire and release of Multicast locks - */ - public void testMulticastLock() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - MulticastLock mcl = wm.createMulticastLock(WIFI_TAG); - - mcl.setReferenceCounted(true); - assertFalse(mcl.isHeld()); - mcl.acquire(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertFalse(mcl.isHeld()); - mcl.acquire(); - mcl.acquire(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertFalse(mcl.isHeld()); - assertNotNull(mcl.toString()); - try { - mcl.release(); - fail("should throw out exception because release is called" - +" a greater number of times than acquire"); - } catch (RuntimeException e) { - // expected - } - - mcl = wm.createMulticastLock(WIFI_TAG); - mcl.setReferenceCounted(false); - assertFalse(mcl.isHeld()); - mcl.acquire(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertFalse(mcl.isHeld()); - mcl.acquire(); - mcl.acquire(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertFalse(mcl.isHeld()); - assertNotNull(mcl.toString()); - // releasing again after release: but ignored for non-referenced locks - mcl.release(); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java deleted file mode 100644 index f2a2b48267..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Copyright (C) 2012 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.wifi.cts; - -import android.content.Context; -import android.net.nsd.NsdManager; -import android.net.nsd.NsdServiceInfo; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; -import android.util.Log; - -import java.io.IOException; -import java.net.ServerSocket; -import java.util.Arrays; -import java.util.Random; -import java.util.List; -import java.util.ArrayList; - -@AppModeFull(reason = "Socket cannot bind in instant app mode") -public class NsdManagerTest extends AndroidTestCase { - - private static final String TAG = "NsdManagerTest"; - private static final String SERVICE_TYPE = "_nmt._tcp"; - private static final int TIMEOUT = 2000; - - private static final boolean DBG = false; - - NsdManager mNsdManager; - - NsdManager.RegistrationListener mRegistrationListener; - NsdManager.DiscoveryListener mDiscoveryListener; - NsdManager.ResolveListener mResolveListener; - private NsdServiceInfo mResolvedService; - - public NsdManagerTest() { - initRegistrationListener(); - initDiscoveryListener(); - initResolveListener(); - } - - private void initRegistrationListener() { - mRegistrationListener = new NsdManager.RegistrationListener() { - @Override - public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { - setEvent("onRegistrationFailed", errorCode); - } - - @Override - public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { - setEvent("onUnregistrationFailed", errorCode); - } - - @Override - public void onServiceRegistered(NsdServiceInfo serviceInfo) { - setEvent("onServiceRegistered", serviceInfo); - } - - @Override - public void onServiceUnregistered(NsdServiceInfo serviceInfo) { - setEvent("onServiceUnregistered", serviceInfo); - } - }; - } - - private void initDiscoveryListener() { - mDiscoveryListener = new NsdManager.DiscoveryListener() { - @Override - public void onStartDiscoveryFailed(String serviceType, int errorCode) { - setEvent("onStartDiscoveryFailed", errorCode); - } - - @Override - public void onStopDiscoveryFailed(String serviceType, int errorCode) { - setEvent("onStopDiscoveryFailed", errorCode); - } - - @Override - public void onDiscoveryStarted(String serviceType) { - NsdServiceInfo info = new NsdServiceInfo(); - info.setServiceType(serviceType); - setEvent("onDiscoveryStarted", info); - } - - @Override - public void onDiscoveryStopped(String serviceType) { - NsdServiceInfo info = new NsdServiceInfo(); - info.setServiceType(serviceType); - setEvent("onDiscoveryStopped", info); - } - - @Override - public void onServiceFound(NsdServiceInfo serviceInfo) { - setEvent("onServiceFound", serviceInfo); - } - - @Override - public void onServiceLost(NsdServiceInfo serviceInfo) { - setEvent("onServiceLost", serviceInfo); - } - }; - } - - private void initResolveListener() { - mResolveListener = new NsdManager.ResolveListener() { - @Override - public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { - setEvent("onResolveFailed", errorCode); - } - - @Override - public void onServiceResolved(NsdServiceInfo serviceInfo) { - mResolvedService = serviceInfo; - setEvent("onServiceResolved", serviceInfo); - } - }; - } - - - - private final class EventData { - EventData(String callbackName, NsdServiceInfo info) { - mCallbackName = callbackName; - mSucceeded = true; - mErrorCode = 0; - mInfo = info; - } - EventData(String callbackName, int errorCode) { - mCallbackName = callbackName; - mSucceeded = false; - mErrorCode = errorCode; - mInfo = null; - } - private final String mCallbackName; - private final boolean mSucceeded; - private final int mErrorCode; - private final NsdServiceInfo mInfo; - } - - private final List mEventCache = new ArrayList(); - - private void setEvent(String callbackName, int errorCode) { - if (DBG) Log.d(TAG, callbackName + " failed with " + String.valueOf(errorCode)); - EventData eventData = new EventData(callbackName, errorCode); - synchronized (mEventCache) { - mEventCache.add(eventData); - mEventCache.notify(); - } - } - - private void setEvent(String callbackName, NsdServiceInfo info) { - if (DBG) Log.d(TAG, "Received event " + callbackName + " for " + info.getServiceName()); - EventData eventData = new EventData(callbackName, info); - synchronized (mEventCache) { - mEventCache.add(eventData); - mEventCache.notify(); - } - } - - void clearEventCache() { - synchronized(mEventCache) { - mEventCache.clear(); - } - } - - int eventCacheSize() { - synchronized(mEventCache) { - return mEventCache.size(); - } - } - - private int mWaitId = 0; - private EventData waitForCallback(String callbackName) { - - synchronized(mEventCache) { - - mWaitId ++; - if (DBG) Log.d(TAG, "Waiting for " + callbackName + ", id=" + String.valueOf(mWaitId)); - - try { - long startTime = android.os.SystemClock.uptimeMillis(); - long elapsedTime = 0; - int index = 0; - while (elapsedTime < TIMEOUT ) { - // first check if we've received that event - for (; index < mEventCache.size(); index++) { - EventData e = mEventCache.get(index); - if (e.mCallbackName.equals(callbackName)) { - if (DBG) Log.d(TAG, "exiting wait id=" + String.valueOf(mWaitId)); - return e; - } - } - - // Not yet received, just wait - mEventCache.wait(TIMEOUT - elapsedTime); - elapsedTime = android.os.SystemClock.uptimeMillis() - startTime; - } - // we exited the loop because of TIMEOUT; fail the call - if (DBG) Log.d(TAG, "timed out waiting id=" + String.valueOf(mWaitId)); - return null; - } catch (InterruptedException e) { - return null; // wait timed out! - } - } - } - - private EventData waitForNewEvents() throws InterruptedException { - if (DBG) Log.d(TAG, "Waiting for a bit, id=" + String.valueOf(mWaitId)); - - long startTime = android.os.SystemClock.uptimeMillis(); - long elapsedTime = 0; - synchronized (mEventCache) { - int index = mEventCache.size(); - while (elapsedTime < TIMEOUT ) { - // first check if we've received that event - for (; index < mEventCache.size(); index++) { - EventData e = mEventCache.get(index); - return e; - } - - // Not yet received, just wait - mEventCache.wait(TIMEOUT - elapsedTime); - elapsedTime = android.os.SystemClock.uptimeMillis() - startTime; - } - } - - return null; - } - - private String mServiceName; - - @Override - public void setUp() { - if (DBG) Log.d(TAG, "Setup test ..."); - mNsdManager = (NsdManager) getContext().getSystemService(Context.NSD_SERVICE); - - Random rand = new Random(); - mServiceName = new String("NsdTest"); - for (int i = 0; i < 4; i++) { - mServiceName = mServiceName + String.valueOf(rand.nextInt(10)); - } - } - - @Override - public void tearDown() { - if (DBG) Log.d(TAG, "Tear down test ..."); - } - - public void testNDSManager() throws Exception { - EventData lastEvent = null; - - if (DBG) Log.d(TAG, "Starting test ..."); - - NsdServiceInfo si = new NsdServiceInfo(); - si.setServiceType(SERVICE_TYPE); - si.setServiceName(mServiceName); - - byte testByteArray[] = new byte[] {-128, 127, 2, 1, 0, 1, 2}; - String String256 = "1_________2_________3_________4_________5_________6_________" + - "7_________8_________9_________10________11________12________13________" + - "14________15________16________17________18________19________20________" + - "21________22________23________24________25________123456"; - - // Illegal attributes - try { - si.setAttribute(null, (String) null); - fail("Could set null key"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute("", (String) null); - fail("Could set empty key"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute(String256, (String) null); - fail("Could set key with 255 characters"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute("key", String256.substring(3)); - fail("Could set key+value combination with more than 255 characters"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute("key", String256.substring(4)); - fail("Could set key+value combination with 255 characters"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute(new String(new byte[]{0x19}), (String) null); - fail("Could set key with invalid character"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute("=", (String) null); - fail("Could set key with invalid character"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute(new String(new byte[]{0x7F}), (String) null); - fail("Could set key with invalid character"); - } catch (IllegalArgumentException e) { - // expected - } - - // Allowed attributes - si.setAttribute("booleanAttr", (String) null); - si.setAttribute("keyValueAttr", "value"); - si.setAttribute("keyEqualsAttr", "="); - si.setAttribute(" whiteSpaceKeyValueAttr ", " value "); - si.setAttribute("binaryDataAttr", testByteArray); - si.setAttribute("nullBinaryDataAttr", (byte[]) null); - si.setAttribute("emptyBinaryDataAttr", new byte[]{}); - si.setAttribute("longkey", String256.substring(9)); - - ServerSocket socket; - int localPort; - - try { - socket = new ServerSocket(0); - localPort = socket.getLocalPort(); - si.setPort(localPort); - } catch (IOException e) { - if (DBG) Log.d(TAG, "Could not open a local socket"); - assertTrue(false); - return; - } - - if (DBG) Log.d(TAG, "Port = " + String.valueOf(localPort)); - - clearEventCache(); - - mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); - lastEvent = waitForCallback("onServiceRegistered"); // id = 1 - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - assertTrue(eventCacheSize() == 1); - - // We may not always get the name that we tried to register; - // This events tells us the name that was registered. - String registeredName = lastEvent.mInfo.getServiceName(); - si.setServiceName(registeredName); - - clearEventCache(); - - mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, - mDiscoveryListener); - - // Expect discovery started - lastEvent = waitForCallback("onDiscoveryStarted"); // id = 2 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - // Remove this event, so accounting becomes easier later - synchronized (mEventCache) { - mEventCache.remove(lastEvent); - } - - // Expect a service record to be discovered (and filter the ones - // that are unrelated to this test) - boolean found = false; - for (int i = 0; i < 32; i++) { - - lastEvent = waitForCallback("onServiceFound"); // id = 3 - if (lastEvent == null) { - // no more onServiceFound events are being reported! - break; - } - - assertTrue(lastEvent.mSucceeded); - - if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + - lastEvent.mInfo.getServiceName()); - - if (lastEvent.mInfo.getServiceName().equals(registeredName)) { - // Save it, as it will get overwritten with new serviceFound events - si = lastEvent.mInfo; - found = true; - } - - // Remove this event from the event cache, so it won't be found by subsequent - // calls to waitForCallback - synchronized (mEventCache) { - mEventCache.remove(lastEvent); - } - } - - assertTrue(found); - - // We've removed all serviceFound events, and we've removed the discoveryStarted - // event as well, so now the event cache should be empty! - assertTrue(eventCacheSize() == 0); - - // Resolve the service - clearEventCache(); - mNsdManager.resolveService(si, mResolveListener); - lastEvent = waitForCallback("onServiceResolved"); // id = 4 - - assertNotNull(mResolvedService); - - // Check Txt attributes - assertEquals(8, mResolvedService.getAttributes().size()); - assertTrue(mResolvedService.getAttributes().containsKey("booleanAttr")); - assertNull(mResolvedService.getAttributes().get("booleanAttr")); - assertEquals("value", new String(mResolvedService.getAttributes().get("keyValueAttr"))); - assertEquals("=", new String(mResolvedService.getAttributes().get("keyEqualsAttr"))); - assertEquals(" value ", new String(mResolvedService.getAttributes() - .get(" whiteSpaceKeyValueAttr "))); - assertEquals(String256.substring(9), new String(mResolvedService.getAttributes() - .get("longkey"))); - assertTrue(Arrays.equals(testByteArray, - mResolvedService.getAttributes().get("binaryDataAttr"))); - assertTrue(mResolvedService.getAttributes().containsKey("nullBinaryDataAttr")); - assertNull(mResolvedService.getAttributes().get("nullBinaryDataAttr")); - assertTrue(mResolvedService.getAttributes().containsKey("emptyBinaryDataAttr")); - assertNull(mResolvedService.getAttributes().get("emptyBinaryDataAttr")); - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": Port = " + - String.valueOf(lastEvent.mInfo.getPort())); - - assertTrue(lastEvent.mInfo.getPort() == localPort); - assertTrue(eventCacheSize() == 1); - - checkForAdditionalEvents(); - clearEventCache(); - - // Unregister the service - mNsdManager.unregisterService(mRegistrationListener); - lastEvent = waitForCallback("onServiceUnregistered"); // id = 5 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - // Expect a callback for service lost - lastEvent = waitForCallback("onServiceLost"); // id = 6 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); - - // Register service again to see if we discover it - checkForAdditionalEvents(); - clearEventCache(); - - si = new NsdServiceInfo(); - si.setServiceType(SERVICE_TYPE); - si.setServiceName(mServiceName); - si.setPort(localPort); - - // Create a new registration listener and register same service again - initRegistrationListener(); - - mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); - - lastEvent = waitForCallback("onServiceRegistered"); // id = 7 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - registeredName = lastEvent.mInfo.getServiceName(); - - // Expect a record to be discovered - // Expect a service record to be discovered (and filter the ones - // that are unrelated to this test) - found = false; - for (int i = 0; i < 32; i++) { - - lastEvent = waitForCallback("onServiceFound"); // id = 8 - if (lastEvent == null) { - // no more onServiceFound events are being reported! - break; - } - - assertTrue(lastEvent.mSucceeded); - - if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + - lastEvent.mInfo.getServiceName()); - - if (lastEvent.mInfo.getServiceName().equals(registeredName)) { - // Save it, as it will get overwritten with new serviceFound events - si = lastEvent.mInfo; - found = true; - } - - // Remove this event from the event cache, so it won't be found by subsequent - // calls to waitForCallback - synchronized (mEventCache) { - mEventCache.remove(lastEvent); - } - } - - assertTrue(found); - - // Resolve the service - clearEventCache(); - mNsdManager.resolveService(si, mResolveListener); - lastEvent = waitForCallback("onServiceResolved"); // id = 9 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + - lastEvent.mInfo.getServiceName()); - - assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); - - assertNotNull(mResolvedService); - - // Check that we don't have any TXT records - assertEquals(0, mResolvedService.getAttributes().size()); - - checkForAdditionalEvents(); - clearEventCache(); - - mNsdManager.stopServiceDiscovery(mDiscoveryListener); - lastEvent = waitForCallback("onDiscoveryStopped"); // id = 10 - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - assertTrue(checkCacheSize(1)); - - checkForAdditionalEvents(); - clearEventCache(); - - mNsdManager.unregisterService(mRegistrationListener); - - lastEvent = waitForCallback("onServiceUnregistered"); // id = 11 - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - assertTrue(checkCacheSize(1)); - } - - boolean checkCacheSize(int size) { - synchronized (mEventCache) { - int cacheSize = mEventCache.size(); - if (cacheSize != size) { - Log.d(TAG, "id = " + mWaitId + ": event cache size = " + cacheSize); - for (int i = 0; i < cacheSize; i++) { - EventData e = mEventCache.get(i); - String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : ""; - Log.d(TAG, "eventName is " + e.mCallbackName + sname); - } - } - return (cacheSize == size); - } - } - - boolean checkForAdditionalEvents() { - try { - EventData e = waitForNewEvents(); - if (e != null) { - String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : ""; - Log.d(TAG, "ignoring unexpected event " + e.mCallbackName + sname); - } - return (e == null); - } - catch (InterruptedException ex) { - return false; - } - } -} - diff --git a/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java b/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java deleted file mode 100644 index feafd434a7..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.cts; - -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.omadm.PpsMoParser; -import android.net.wifi.hotspot2.pps.Credential; -import android.net.wifi.hotspot2.pps.HomeSp; -import android.test.AndroidTestCase; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * CTS tests for PPS MO (PerProviderSubscription Management Object) XML string parsing API. - */ -public class PpsMoParserTest extends AndroidTestCase { - private static final String PPS_MO_XML_FILE = "assets/PerProviderSubscription.xml"; - - /** - * Read the content of the given resource file into a String. - * - * @param filename String name of the file - * @return String - * @throws IOException - */ - private String loadResourceFile(String filename) throws IOException { - InputStream in = getClass().getClassLoader().getResourceAsStream(filename); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - StringBuilder builder = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - builder.append(line).append("\n"); - } - return builder.toString(); - } - - /** - * Generate a {@link PasspointConfiguration} that matches the configuration specified in the - * XML file {@link #PPS_MO_XML_FILE}. - * - * @return {@link PasspointConfiguration} - */ - private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception { - DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - byte[] certFingerprint = new byte[32]; - Arrays.fill(certFingerprint, (byte) 0x1f); - - PasspointConfiguration config = new PasspointConfiguration(); - - // HomeSP configuration. - HomeSp homeSp = new HomeSp(); - homeSp.setFriendlyName("Century House"); - assertEquals("Century House", homeSp.getFriendlyName()); - homeSp.setFqdn("mi6.co.uk"); - assertEquals("mi6.co.uk", homeSp.getFqdn()); - homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L}); - assertTrue(Arrays.equals(new long[] {0x112233L, 0x445566L}, - homeSp.getRoamingConsortiumOis())); - config.setHomeSp(homeSp); - assertEquals(homeSp, config.getHomeSp()); - - // Credential configuration. - Credential credential = new Credential(); - credential.setRealm("shaken.stirred.com"); - assertEquals("shaken.stirred.com", credential.getRealm()); - Credential.UserCredential userCredential = new Credential.UserCredential(); - userCredential.setUsername("james"); - assertEquals("james", userCredential.getUsername()); - userCredential.setPassword("Ym9uZDAwNw=="); - assertEquals("Ym9uZDAwNw==", userCredential.getPassword()); - userCredential.setEapType(21); - assertEquals(21, userCredential.getEapType()); - userCredential.setNonEapInnerMethod("MS-CHAP-V2"); - assertEquals("MS-CHAP-V2", userCredential.getNonEapInnerMethod()); - credential.setUserCredential(userCredential); - assertEquals(userCredential, credential.getUserCredential()); - Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); - certCredential.setCertType("x509v3"); - assertEquals("x509v3", certCredential.getCertType()); - certCredential.setCertSha256Fingerprint(certFingerprint); - assertTrue(Arrays.equals(certFingerprint, certCredential.getCertSha256Fingerprint())); - credential.setCertCredential(certCredential); - assertEquals(certCredential, credential.getCertCredential()); - Credential.SimCredential simCredential = new Credential.SimCredential(); - simCredential.setImsi("imsi"); - assertEquals("imsi", simCredential.getImsi()); - simCredential.setEapType(24); - assertEquals(24, simCredential.getEapType()); - credential.setSimCredential(simCredential); - assertEquals(simCredential, credential.getSimCredential()); - config.setCredential(credential); - assertEquals(credential, config.getCredential()); - return config; - } - - /** - * Parse and verify all supported fields under PPS MO tree. - * - * @throws Exception - */ - public void testParsePPSMOTree() throws Exception { - String ppsMoTree = loadResourceFile(PPS_MO_XML_FILE); - PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree(); - PasspointConfiguration actualConfig = PpsMoParser.parseMoText(ppsMoTree); - assertTrue(actualConfig.equals(expectedConfig)); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java deleted file mode 100644 index 9bd1226f52..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import java.util.List; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.WifiLock; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; -import android.util.Log; - -import com.android.compatibility.common.util.SystemUtil; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class ScanResultTest extends AndroidTestCase { - private static class MySync { - int expectedState = STATE_NULL; - } - - private WifiManager mWifiManager; - private WifiLock mWifiLock; - private static MySync mMySync; - - private static final int STATE_NULL = 0; - private static final int STATE_WIFI_CHANGING = 1; - private static final int STATE_WIFI_CHANGED = 2; - private static final int STATE_START_SCAN = 3; - private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; - private static final int STATE_SCAN_FAILURE = 5; - - private static final String TAG = "WifiInfoTest"; - private static final int TIMEOUT_MSEC = 6000; - private static final int WAIT_MSEC = 60; - private static final int ENABLE_WAIT_MSEC = 10000; - private static final int SCAN_WAIT_MSEC = 10000; - private static final int SCAN_MAX_RETRY_COUNT = 6; - private static final int SCAN_FIND_BSSID_MAX_RETRY_COUNT = 5; - private static final long SCAN_FIND_BSSID_WAIT_MSEC = 5_000L; - private IntentFilter mIntentFilter; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGED; - mMySync.notify(); - } - } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - synchronized (mMySync) { - if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) { - mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; - } else { - mMySync.expectedState = STATE_SCAN_FAILURE; - } - mMySync.notify(); - } - } - } - }; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mMySync = new MySync(); - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); - - mContext.registerReceiver(mReceiver, mIntentFilter); - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull(mWifiManager); - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - Thread.sleep(ENABLE_WAIT_MSEC); - assertTrue(mWifiManager.isWifiEnabled()); - mMySync.expectedState = STATE_NULL; - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - mWifiLock.release(); - mContext.unregisterReceiver(mReceiver); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - Thread.sleep(ENABLE_WAIT_MSEC); - super.tearDown(); - } - - private void setWifiEnabled(boolean enable) throws Exception { - synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGING; - if (enable) { - SystemUtil.runShellCommand("svc wifi enable"); - } else { - SystemUtil.runShellCommand("svc wifi disable"); - } - waitForBroadcast(TIMEOUT_MSEC, STATE_WIFI_CHANGED); - } - } - - private boolean waitForBroadcast(long timeout, int expectedState) throws Exception { - long waitTime = System.currentTimeMillis() + timeout; - while (System.currentTimeMillis() < waitTime - && mMySync.expectedState != expectedState) - mMySync.wait(WAIT_MSEC); - return mMySync.expectedState == expectedState; - } - - public void testScanResultProperties() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - List scanResults = mWifiManager.getScanResults(); - // this test case should in Wifi environment - for (int i = 0; i < scanResults.size(); i++) { - ScanResult mScanResult = scanResults.get(i); - assertNotNull(mScanResult.toString()); - } - } - - /* Multiple scans to ensure bssid is updated */ - private void scanAndWait() throws Exception { - synchronized (mMySync) { - for (int retry = 0; retry < SCAN_MAX_RETRY_COUNT; retry++) { - mMySync.expectedState = STATE_START_SCAN; - mWifiManager.startScan(); - if (waitForBroadcast(SCAN_WAIT_MSEC, STATE_SCAN_RESULTS_AVAILABLE)) { - break; - } - } - } - } - - public void testScanResultTimeStamp() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - long timestamp = 0; - String BSSID = null; - - scanAndWait(); - - List scanResults = mWifiManager.getScanResults(); - for (ScanResult result : scanResults) { - BSSID = result.BSSID; - timestamp = result.timestamp; - assertTrue(timestamp != 0); - break; - } - - scanAndWait(); - - scanResults = mWifiManager.getScanResults(); - for (ScanResult result : scanResults) { - if (result.BSSID.equals(BSSID)) { - long timeDiff = (result.timestamp - timestamp) / 1000; - assertTrue (timeDiff > 0); - assertTrue (timeDiff < 6 * SCAN_WAIT_MSEC); - } - } - - } - - public void testScanResultMatchesWifiInfo() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // This test case should run while connected to Wifi - final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - assertNotNull(wifiInfo); - - ScanResult currentNetwork = null; - for (int i = 0; i < SCAN_FIND_BSSID_MAX_RETRY_COUNT; i++) { - scanAndWait(); - final List scanResults = mWifiManager.getScanResults(); - currentNetwork = scanResults.stream().filter(r -> r.BSSID.equals(wifiInfo.getBSSID())) - .findAny().orElse(null); - - if (currentNetwork != null) { - break; - } - Thread.sleep(SCAN_FIND_BSSID_WAIT_MSEC); - } - assertNotNull("Current network not found in scan results", currentNetwork); - - assertEquals(wifiInfo.getWifiSsid(), currentNetwork.wifiSsid); - assertEquals(wifiInfo.getFrequency(), currentNetwork.frequency); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java deleted file mode 100644 index 11edf7395b..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import android.net.wifi.SupplicantState; -import android.test.AndroidTestCase; - -public class SupplicantStateTest extends AndroidTestCase { - - public void testIsValidState() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - assertTrue(SupplicantState.isValidState(SupplicantState.DISCONNECTED)); - assertTrue(SupplicantState.isValidState(SupplicantState.INACTIVE)); - assertTrue(SupplicantState.isValidState(SupplicantState.SCANNING)); - assertTrue(SupplicantState.isValidState(SupplicantState.ASSOCIATING)); - assertTrue(SupplicantState.isValidState(SupplicantState.ASSOCIATED)); - assertTrue(SupplicantState.isValidState(SupplicantState.FOUR_WAY_HANDSHAKE)); - assertTrue(SupplicantState.isValidState(SupplicantState.GROUP_HANDSHAKE)); - assertTrue(SupplicantState.isValidState(SupplicantState.COMPLETED)); - assertTrue(SupplicantState.isValidState(SupplicantState.DORMANT)); - assertFalse(SupplicantState.isValidState(SupplicantState.UNINITIALIZED)); - assertFalse(SupplicantState.isValidState(SupplicantState.INVALID)); - } - -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java deleted file mode 100644 index a59c85e5ab..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import java.util.List; - -import android.content.Context; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiConfigurationTest extends AndroidTestCase { - private WifiManager mWifiManager; - @Override - protected void setUp() throws Exception { - super.setUp(); - mWifiManager = (WifiManager) mContext - .getSystemService(Context.WIFI_SERVICE); - } - - public void testWifiConfiguration() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - List wifiConfigurations = mWifiManager.getConfiguredNetworks(); - if (wifiConfigurations != null) { - for (int i = 0; i < wifiConfigurations.size(); i++) { - WifiConfiguration wifiConfiguration = wifiConfigurations.get(i); - assertNotNull(wifiConfiguration); - assertNotNull(wifiConfiguration.toString()); - } - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java deleted file mode 100644 index e4c4b006dc..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java +++ /dev/null @@ -1,796 +0,0 @@ -/* - * Copyright (C) 2013 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.wifi.cts; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.wifi.WifiEnterpriseConfig; -import android.net.wifi.WifiEnterpriseConfig.Eap; -import android.net.wifi.WifiEnterpriseConfig.Phase2; -import android.net.wifi.WifiManager; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -import com.android.compatibility.common.util.SystemUtil; - -import java.io.ByteArrayInputStream; -import java.security.KeyFactory; -import java.security.PrivateKey; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.spec.PKCS8EncodedKeySpec; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiEnterpriseConfigTest extends AndroidTestCase { - private WifiManager mWifiManager; - - private static final String SSID = "\"TestSSID\""; - private static final String IDENTITY = "identity"; - private static final String PASSWORD = "password"; - private static final String SUBJECT_MATCH = "subjectmatch"; - private static final String ALT_SUBJECT_MATCH = "altsubjectmatch"; - private static final String DOM_SUBJECT_MATCH = "domsubjectmatch"; - private static final String PLMN = "plmn"; - private static final String REALM = "realm"; - private static final String ANON_IDENTITY = "anonidentity"; - private static final int ENABLE_DELAY = 10000; - - /* - * The keys and certificates below are generated with: - * - * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem - * openssl ecparam -name prime256v1 -out ecparam.pem - * openssl req -newkey ec:ecparam.pem -keyout userkey.pem -nodes -days 3650 -out userkey.req - * mkdir -p demoCA/newcerts - * touch demoCA/index.txt - * echo "01" > demoCA/serial - * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650 - */ - - /** - * Generated from above and converted with: - * - * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g' - */ - - private static final byte[] FAKE_EC_1 = { - (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x2f, (byte) 0x30, (byte) 0x82, - (byte) 0x03, (byte) 0x17, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, - (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xa7, (byte) 0xe4, - (byte) 0x70, (byte) 0x50, (byte) 0x9b, (byte) 0xd2, (byte) 0x68, (byte) 0x68, - (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, - (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0xad, - (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, - (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, - (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, - (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x12, - (byte) 0x30, (byte) 0x10, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x07, (byte) 0x0c, (byte) 0x09, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, - (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x69, (byte) 0x74, (byte) 0x79, - (byte) 0x31, (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x53, - (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x6f, - (byte) 0x6d, (byte) 0x70, (byte) 0x61, (byte) 0x6e, (byte) 0x79, (byte) 0x31, - (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x53, (byte) 0x65, - (byte) 0x63, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x31, - (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x18, (byte) 0x57, (byte) 0x69, - (byte) 0x66, (byte) 0x69, (byte) 0x45, (byte) 0x6e, (byte) 0x74, (byte) 0x65, - (byte) 0x72, (byte) 0x70, (byte) 0x72, (byte) 0x69, (byte) 0x73, (byte) 0x65, - (byte) 0x43, (byte) 0x6f, (byte) 0x6e, (byte) 0x66, (byte) 0x69, (byte) 0x67, - (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x31, (byte) 0x29, - (byte) 0x30, (byte) 0x27, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x09, - (byte) 0x01, (byte) 0x16, (byte) 0x1a, (byte) 0x61, (byte) 0x6e, (byte) 0x2d, - (byte) 0x65, (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6c, (byte) 0x2d, - (byte) 0x61, (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73, - (byte) 0x40, (byte) 0x64, (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x69, - (byte) 0x6e, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, - (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x36, (byte) 0x30, - (byte) 0x31, (byte) 0x31, (byte) 0x35, (byte) 0x31, (byte) 0x31, (byte) 0x31, - (byte) 0x38, (byte) 0x35, (byte) 0x31, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, - (byte) 0x32, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x31, (byte) 0x32, - (byte) 0x31, (byte) 0x31, (byte) 0x31, (byte) 0x38, (byte) 0x35, (byte) 0x31, - (byte) 0x5a, (byte) 0x30, (byte) 0x81, (byte) 0xad, (byte) 0x31, (byte) 0x0b, - (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, - (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, - (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, - (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x12, (byte) 0x30, (byte) 0x10, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0c, - (byte) 0x09, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, - (byte) 0x43, (byte) 0x69, (byte) 0x74, (byte) 0x79, (byte) 0x31, (byte) 0x15, - (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, - (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x6f, (byte) 0x6d, (byte) 0x70, - (byte) 0x61, (byte) 0x6e, (byte) 0x79, (byte) 0x31, (byte) 0x10, (byte) 0x30, - (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, - (byte) 0x0c, (byte) 0x07, (byte) 0x53, (byte) 0x65, (byte) 0x63, (byte) 0x74, - (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x31, (byte) 0x21, (byte) 0x30, - (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, - (byte) 0x0c, (byte) 0x18, (byte) 0x57, (byte) 0x69, (byte) 0x66, (byte) 0x69, - (byte) 0x45, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x70, - (byte) 0x72, (byte) 0x69, (byte) 0x73, (byte) 0x65, (byte) 0x43, (byte) 0x6f, - (byte) 0x6e, (byte) 0x66, (byte) 0x69, (byte) 0x67, (byte) 0x54, (byte) 0x65, - (byte) 0x73, (byte) 0x74, (byte) 0x31, (byte) 0x29, (byte) 0x30, (byte) 0x27, - (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, - (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x09, (byte) 0x01, (byte) 0x16, - (byte) 0x1a, (byte) 0x61, (byte) 0x6e, (byte) 0x2d, (byte) 0x65, (byte) 0x6d, - (byte) 0x61, (byte) 0x69, (byte) 0x6c, (byte) 0x2d, (byte) 0x61, (byte) 0x64, - (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x40, (byte) 0x64, - (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x2e, - (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x82, (byte) 0x01, - (byte) 0x22, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, - (byte) 0x01, (byte) 0x0f, (byte) 0x00, (byte) 0x30, (byte) 0x82, (byte) 0x01, - (byte) 0x0a, (byte) 0x02, (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x00, - (byte) 0xb4, (byte) 0x6e, (byte) 0x66, (byte) 0x24, (byte) 0xe7, (byte) 0x5c, - (byte) 0xd8, (byte) 0x6f, (byte) 0x08, (byte) 0xd3, (byte) 0x80, (byte) 0xa3, - (byte) 0xb9, (byte) 0xaf, (byte) 0x90, (byte) 0xef, (byte) 0x1c, (byte) 0x2a, - (byte) 0x5f, (byte) 0x39, (byte) 0x0b, (byte) 0xbd, (byte) 0x75, (byte) 0x0d, - (byte) 0x3e, (byte) 0x19, (byte) 0x2e, (byte) 0x47, (byte) 0x1e, (byte) 0x14, - (byte) 0xc2, (byte) 0x1a, (byte) 0x59, (byte) 0xcc, (byte) 0x1b, (byte) 0xb6, - (byte) 0x9b, (byte) 0x46, (byte) 0x1f, (byte) 0x7f, (byte) 0x71, (byte) 0xdd, - (byte) 0x38, (byte) 0xbe, (byte) 0x89, (byte) 0x30, (byte) 0xba, (byte) 0x88, - (byte) 0xfb, (byte) 0x3f, (byte) 0x57, (byte) 0x35, (byte) 0xe7, (byte) 0xa7, - (byte) 0x2f, (byte) 0x2c, (byte) 0x8d, (byte) 0x7c, (byte) 0xe2, (byte) 0xd8, - (byte) 0x0c, (byte) 0x0a, (byte) 0xe6, (byte) 0x62, (byte) 0x46, (byte) 0x8c, - (byte) 0xf4, (byte) 0x51, (byte) 0xfc, (byte) 0x6a, (byte) 0x79, (byte) 0xdd, - (byte) 0x0a, (byte) 0x41, (byte) 0x23, (byte) 0xd3, (byte) 0xe9, (byte) 0x5e, - (byte) 0x91, (byte) 0xcd, (byte) 0xbd, (byte) 0x55, (byte) 0x28, (byte) 0x71, - (byte) 0xec, (byte) 0x52, (byte) 0x19, (byte) 0x85, (byte) 0x0c, (byte) 0x1b, - (byte) 0xfa, (byte) 0xbf, (byte) 0xfe, (byte) 0xae, (byte) 0x5c, (byte) 0x3b, - (byte) 0x99, (byte) 0x42, (byte) 0xd4, (byte) 0xe7, (byte) 0x17, (byte) 0xec, - (byte) 0x41, (byte) 0x22, (byte) 0x2c, (byte) 0x1e, (byte) 0x7b, (byte) 0x53, - (byte) 0xad, (byte) 0x02, (byte) 0xfd, (byte) 0xf6, (byte) 0x4a, (byte) 0xb1, - (byte) 0x6e, (byte) 0x6c, (byte) 0x87, (byte) 0xf5, (byte) 0x7d, (byte) 0x9b, - (byte) 0x34, (byte) 0x0e, (byte) 0x3b, (byte) 0x0e, (byte) 0xaa, (byte) 0xc5, - (byte) 0xc4, (byte) 0xef, (byte) 0xf2, (byte) 0x5a, (byte) 0xa9, (byte) 0xac, - (byte) 0x19, (byte) 0xce, (byte) 0x5f, (byte) 0xc5, (byte) 0xcc, (byte) 0x0d, - (byte) 0xee, (byte) 0x7f, (byte) 0x32, (byte) 0xb4, (byte) 0xfe, (byte) 0xc1, - (byte) 0xca, (byte) 0x9b, (byte) 0x3f, (byte) 0xad, (byte) 0x2c, (byte) 0x7a, - (byte) 0xc5, (byte) 0x8d, (byte) 0x48, (byte) 0xa1, (byte) 0xc9, (byte) 0x74, - (byte) 0xfe, (byte) 0x8a, (byte) 0xe3, (byte) 0xb0, (byte) 0x92, (byte) 0xee, - (byte) 0x73, (byte) 0x09, (byte) 0x0a, (byte) 0xbc, (byte) 0xc8, (byte) 0x63, - (byte) 0xba, (byte) 0x0e, (byte) 0x26, (byte) 0xab, (byte) 0x1e, (byte) 0xff, - (byte) 0xbc, (byte) 0x24, (byte) 0x12, (byte) 0x26, (byte) 0x11, (byte) 0xe0, - (byte) 0x04, (byte) 0xcb, (byte) 0x96, (byte) 0x7d, (byte) 0x41, (byte) 0xf7, - (byte) 0x79, (byte) 0x32, (byte) 0x05, (byte) 0x33, (byte) 0x19, (byte) 0x6e, - (byte) 0xb9, (byte) 0x75, (byte) 0xf3, (byte) 0x50, (byte) 0xa4, (byte) 0xc3, - (byte) 0x55, (byte) 0x9d, (byte) 0x8f, (byte) 0xb6, (byte) 0xab, (byte) 0x97, - (byte) 0xe7, (byte) 0xe2, (byte) 0xe8, (byte) 0x15, (byte) 0xfc, (byte) 0x35, - (byte) 0xbd, (byte) 0xce, (byte) 0x17, (byte) 0xbe, (byte) 0xe3, (byte) 0x73, - (byte) 0xd4, (byte) 0x88, (byte) 0x39, (byte) 0x27, (byte) 0x7e, (byte) 0x6d, - (byte) 0xa2, (byte) 0x27, (byte) 0xfa, (byte) 0x96, (byte) 0xe3, (byte) 0x38, - (byte) 0xc0, (byte) 0xa1, (byte) 0x55, (byte) 0xc6, (byte) 0xf3, (byte) 0x20, - (byte) 0xea, (byte) 0x50, (byte) 0x8d, (byte) 0x6c, (byte) 0x94, (byte) 0x9a, - (byte) 0x43, (byte) 0x74, (byte) 0xc0, (byte) 0xfa, (byte) 0xef, (byte) 0xe0, - (byte) 0xb1, (byte) 0x1c, (byte) 0x6d, (byte) 0x5e, (byte) 0x44, (byte) 0x08, - (byte) 0xef, (byte) 0xd5, (byte) 0x80, (byte) 0xad, (byte) 0x02, (byte) 0x03, - (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, (byte) 0x50, (byte) 0x30, - (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, - (byte) 0xe9, (byte) 0xd0, (byte) 0x9e, (byte) 0x0e, (byte) 0x62, (byte) 0x31, - (byte) 0x02, (byte) 0x9a, (byte) 0x33, (byte) 0xd7, (byte) 0x4a, (byte) 0x93, - (byte) 0x0d, (byte) 0xf3, (byte) 0xd6, (byte) 0x74, (byte) 0xce, (byte) 0x69, - (byte) 0xe1, (byte) 0xef, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18, (byte) 0x30, - (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0xe9, (byte) 0xd0, (byte) 0x9e, - (byte) 0x0e, (byte) 0x62, (byte) 0x31, (byte) 0x02, (byte) 0x9a, (byte) 0x33, - (byte) 0xd7, (byte) 0x4a, (byte) 0x93, (byte) 0x0d, (byte) 0xf3, (byte) 0xd6, - (byte) 0x74, (byte) 0xce, (byte) 0x69, (byte) 0xe1, (byte) 0xef, (byte) 0x30, - (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, - (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, - (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, - (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x52, (byte) 0x70, (byte) 0xb6, - (byte) 0x10, (byte) 0x7f, (byte) 0xaa, (byte) 0x86, (byte) 0x8f, (byte) 0x02, - (byte) 0xb0, (byte) 0x97, (byte) 0x89, (byte) 0xb9, (byte) 0x04, (byte) 0x1d, - (byte) 0x79, (byte) 0xa3, (byte) 0x74, (byte) 0x7c, (byte) 0xdf, (byte) 0xad, - (byte) 0x87, (byte) 0xe4, (byte) 0x00, (byte) 0xd3, (byte) 0x3a, (byte) 0x5c, - (byte) 0x48, (byte) 0x3b, (byte) 0xfe, (byte) 0x77, (byte) 0xfd, (byte) 0xbe, - (byte) 0xce, (byte) 0x5b, (byte) 0xd2, (byte) 0xea, (byte) 0x3e, (byte) 0x7f, - (byte) 0xef, (byte) 0x20, (byte) 0x0d, (byte) 0x0b, (byte) 0xc7, (byte) 0xc4, - (byte) 0x25, (byte) 0x20, (byte) 0xe1, (byte) 0x8f, (byte) 0xc5, (byte) 0x19, - (byte) 0x37, (byte) 0x9c, (byte) 0xa0, (byte) 0x9d, (byte) 0x02, (byte) 0x30, - (byte) 0x5f, (byte) 0x49, (byte) 0x4e, (byte) 0x56, (byte) 0xc4, (byte) 0xab, - (byte) 0xcb, (byte) 0x5c, (byte) 0xe6, (byte) 0x40, (byte) 0x93, (byte) 0x92, - (byte) 0xee, (byte) 0xa1, (byte) 0x69, (byte) 0x7d, (byte) 0x10, (byte) 0x6b, - (byte) 0xd4, (byte) 0xf7, (byte) 0xec, (byte) 0xd9, (byte) 0xa5, (byte) 0x29, - (byte) 0x63, (byte) 0x29, (byte) 0xd9, (byte) 0x27, (byte) 0x2d, (byte) 0x5e, - (byte) 0x34, (byte) 0x37, (byte) 0xa9, (byte) 0xba, (byte) 0x0a, (byte) 0x7b, - (byte) 0x99, (byte) 0x1a, (byte) 0x7d, (byte) 0xa7, (byte) 0xa7, (byte) 0xf0, - (byte) 0xbf, (byte) 0x40, (byte) 0x29, (byte) 0x5d, (byte) 0x2f, (byte) 0x2e, - (byte) 0x0f, (byte) 0x35, (byte) 0x90, (byte) 0xb5, (byte) 0xc3, (byte) 0xfd, - (byte) 0x1e, (byte) 0xe2, (byte) 0xb3, (byte) 0xae, (byte) 0xf9, (byte) 0xde, - (byte) 0x9d, (byte) 0x76, (byte) 0xe1, (byte) 0x20, (byte) 0xf5, (byte) 0x1c, - (byte) 0x30, (byte) 0x42, (byte) 0x80, (byte) 0x2a, (byte) 0x4f, (byte) 0x85, - (byte) 0x5c, (byte) 0xb4, (byte) 0x49, (byte) 0x68, (byte) 0x6c, (byte) 0x7c, - (byte) 0x2a, (byte) 0xc8, (byte) 0xbc, (byte) 0x15, (byte) 0xed, (byte) 0x88, - (byte) 0xfd, (byte) 0x8a, (byte) 0x63, (byte) 0xe0, (byte) 0x93, (byte) 0xfd, - (byte) 0x86, (byte) 0xab, (byte) 0xa9, (byte) 0xf6, (byte) 0x63, (byte) 0xa5, - (byte) 0x29, (byte) 0xaf, (byte) 0xdc, (byte) 0x8f, (byte) 0xca, (byte) 0xc2, - (byte) 0x28, (byte) 0xe7, (byte) 0x26, (byte) 0x89, (byte) 0x75, (byte) 0xf1, - (byte) 0x3e, (byte) 0x2e, (byte) 0x86, (byte) 0x11, (byte) 0x8b, (byte) 0xfa, - (byte) 0xf5, (byte) 0xb4, (byte) 0xb4, (byte) 0x04, (byte) 0x02, (byte) 0xa3, - (byte) 0x85, (byte) 0x81, (byte) 0xad, (byte) 0xb3, (byte) 0xec, (byte) 0x2d, - (byte) 0x4b, (byte) 0x40, (byte) 0x59, (byte) 0x61, (byte) 0x0d, (byte) 0x59, - (byte) 0x09, (byte) 0x09, (byte) 0xee, (byte) 0xc7, (byte) 0x51, (byte) 0xef, - (byte) 0x6f, (byte) 0xd6, (byte) 0x9a, (byte) 0xa5, (byte) 0x45, (byte) 0xa2, - (byte) 0x89, (byte) 0xc2, (byte) 0x97, (byte) 0x93, (byte) 0xbc, (byte) 0x5b, - (byte) 0x37, (byte) 0x55, (byte) 0x73, (byte) 0x55, (byte) 0x0c, (byte) 0x9c, - (byte) 0xcb, (byte) 0x10, (byte) 0xec, (byte) 0x76, (byte) 0xfe, (byte) 0xa7, - (byte) 0x70, (byte) 0x4e, (byte) 0x9a, (byte) 0xa2, (byte) 0xf9, (byte) 0x40, - (byte) 0xdd, (byte) 0x96, (byte) 0x7d, (byte) 0x67, (byte) 0x5c, (byte) 0x8e, - (byte) 0x43, (byte) 0x1a, (byte) 0x26, (byte) 0xaa, (byte) 0xee, (byte) 0x38, - (byte) 0x11, (byte) 0x26, (byte) 0x3d, (byte) 0x69, (byte) 0xc7, (byte) 0x6a, - (byte) 0xe7, (byte) 0xbd, (byte) 0x67, (byte) 0x70, (byte) 0x35, (byte) 0xff, - (byte) 0x72, (byte) 0x2c, (byte) 0x87, (byte) 0x82, (byte) 0x68, (byte) 0x3f, - (byte) 0x8d - }; - - private static final byte[] FAKE_EC_2 = { - (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x4f, (byte) 0x30, (byte) 0x82, - (byte) 0x03, (byte) 0x37, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, - (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xd9, (byte) 0xc4, - (byte) 0xe1, (byte) 0xfc, (byte) 0x3d, (byte) 0x02, (byte) 0x21, (byte) 0x1f, - (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, - (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0xbd, - (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, - (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, - (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, - (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x12, - (byte) 0x30, (byte) 0x10, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x07, (byte) 0x0c, (byte) 0x09, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, - (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x69, (byte) 0x74, (byte) 0x79, - (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x12, (byte) 0x53, - (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x4f, (byte) 0x74, - (byte) 0x68, (byte) 0x65, (byte) 0x72, (byte) 0x2d, (byte) 0x43, (byte) 0x6f, - (byte) 0x6d, (byte) 0x70, (byte) 0x61, (byte) 0x6e, (byte) 0x79, (byte) 0x31, - (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x0c, (byte) 0x53, (byte) 0x6f, - (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x65, (byte) 0x63, - (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x31, (byte) 0x21, - (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x03, (byte) 0x0c, (byte) 0x18, (byte) 0x57, (byte) 0x69, (byte) 0x66, - (byte) 0x69, (byte) 0x45, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72, - (byte) 0x70, (byte) 0x72, (byte) 0x69, (byte) 0x73, (byte) 0x65, (byte) 0x43, - (byte) 0x6f, (byte) 0x6e, (byte) 0x66, (byte) 0x69, (byte) 0x67, (byte) 0x54, - (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x31, (byte) 0x2e, (byte) 0x30, - (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, - (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x09, (byte) 0x01, - (byte) 0x16, (byte) 0x1f, (byte) 0x61, (byte) 0x6e, (byte) 0x2d, (byte) 0x65, - (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6c, (byte) 0x2d, (byte) 0x61, - (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x40, - (byte) 0x73, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x64, - (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x2e, - (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x1e, (byte) 0x17, - (byte) 0x0d, (byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x31, - (byte) 0x35, (byte) 0x31, (byte) 0x31, (byte) 0x33, (byte) 0x32, (byte) 0x34, - (byte) 0x36, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x36, - (byte) 0x30, (byte) 0x31, (byte) 0x31, (byte) 0x32, (byte) 0x31, (byte) 0x31, - (byte) 0x33, (byte) 0x32, (byte) 0x34, (byte) 0x36, (byte) 0x5a, (byte) 0x30, - (byte) 0x81, (byte) 0xbd, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, - (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, - (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, - (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, - (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, - (byte) 0x31, (byte) 0x12, (byte) 0x30, (byte) 0x10, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0c, (byte) 0x09, (byte) 0x53, - (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x69, - (byte) 0x74, (byte) 0x79, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, - (byte) 0x12, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, - (byte) 0x4f, (byte) 0x74, (byte) 0x68, (byte) 0x65, (byte) 0x72, (byte) 0x2d, - (byte) 0x43, (byte) 0x6f, (byte) 0x6d, (byte) 0x70, (byte) 0x61, (byte) 0x6e, - (byte) 0x79, (byte) 0x31, (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x0c, - (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, - (byte) 0x65, (byte) 0x63, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, - (byte) 0x31, (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x18, (byte) 0x57, - (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x45, (byte) 0x6e, (byte) 0x74, - (byte) 0x65, (byte) 0x72, (byte) 0x70, (byte) 0x72, (byte) 0x69, (byte) 0x73, - (byte) 0x65, (byte) 0x43, (byte) 0x6f, (byte) 0x6e, (byte) 0x66, (byte) 0x69, - (byte) 0x67, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x31, - (byte) 0x2e, (byte) 0x30, (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x09, (byte) 0x01, (byte) 0x16, (byte) 0x1f, (byte) 0x61, (byte) 0x6e, - (byte) 0x2d, (byte) 0x65, (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6c, - (byte) 0x2d, (byte) 0x61, (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, - (byte) 0x73, (byte) 0x40, (byte) 0x73, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, - (byte) 0x2d, (byte) 0x64, (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x69, - (byte) 0x6e, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, - (byte) 0x82, (byte) 0x01, (byte) 0x22, (byte) 0x30, (byte) 0x0d, (byte) 0x06, - (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, - (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, - (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x0f, (byte) 0x00, (byte) 0x30, - (byte) 0x82, (byte) 0x01, (byte) 0x0a, (byte) 0x02, (byte) 0x82, (byte) 0x01, - (byte) 0x01, (byte) 0x00, (byte) 0xa9, (byte) 0xa3, (byte) 0x21, (byte) 0xfd, - (byte) 0xa6, (byte) 0xc1, (byte) 0x04, (byte) 0x48, (byte) 0xc2, (byte) 0xc8, - (byte) 0x44, (byte) 0x50, (byte) 0xc4, (byte) 0x6d, (byte) 0x35, (byte) 0x24, - (byte) 0xf0, (byte) 0x6d, (byte) 0x69, (byte) 0xfb, (byte) 0xd1, (byte) 0xfc, - (byte) 0xde, (byte) 0xe9, (byte) 0xdb, (byte) 0xca, (byte) 0xee, (byte) 0x24, - (byte) 0x3d, (byte) 0x85, (byte) 0x8d, (byte) 0x84, (byte) 0xb4, (byte) 0x73, - (byte) 0xd1, (byte) 0x09, (byte) 0x37, (byte) 0x16, (byte) 0x80, (byte) 0x70, - (byte) 0x6b, (byte) 0x61, (byte) 0xcc, (byte) 0xf2, (byte) 0x98, (byte) 0xbd, - (byte) 0x53, (byte) 0x3a, (byte) 0x68, (byte) 0x60, (byte) 0x02, (byte) 0xba, - (byte) 0x0c, (byte) 0x53, (byte) 0x96, (byte) 0xfb, (byte) 0x80, (byte) 0xd1, - (byte) 0x5b, (byte) 0xc3, (byte) 0xcb, (byte) 0x7a, (byte) 0x81, (byte) 0x00, - (byte) 0x5d, (byte) 0x20, (byte) 0x72, (byte) 0xc0, (byte) 0xe4, (byte) 0x48, - (byte) 0x0e, (byte) 0xa2, (byte) 0xcd, (byte) 0xa2, (byte) 0x63, (byte) 0x8c, - (byte) 0x05, (byte) 0x7c, (byte) 0x63, (byte) 0x5b, (byte) 0xda, (byte) 0x0e, - (byte) 0xa7, (byte) 0x05, (byte) 0x09, (byte) 0x6d, (byte) 0xd5, (byte) 0xe4, - (byte) 0x3a, (byte) 0x4e, (byte) 0xa1, (byte) 0xf5, (byte) 0xfd, (byte) 0x47, - (byte) 0xee, (byte) 0x7b, (byte) 0xa3, (byte) 0x4c, (byte) 0x8c, (byte) 0xd3, - (byte) 0xbb, (byte) 0x58, (byte) 0x0f, (byte) 0x1c, (byte) 0x56, (byte) 0x80, - (byte) 0x80, (byte) 0xb5, (byte) 0xf9, (byte) 0x80, (byte) 0xc2, (byte) 0xd1, - (byte) 0x1d, (byte) 0x3f, (byte) 0xe8, (byte) 0x2a, (byte) 0x63, (byte) 0x0b, - (byte) 0x54, (byte) 0x5f, (byte) 0xd4, (byte) 0xcb, (byte) 0xb7, (byte) 0x94, - (byte) 0xe2, (byte) 0x35, (byte) 0x65, (byte) 0x59, (byte) 0xd1, (byte) 0x72, - (byte) 0xa4, (byte) 0xb8, (byte) 0xee, (byte) 0x82, (byte) 0x11, (byte) 0x7a, - (byte) 0x4c, (byte) 0x26, (byte) 0x66, (byte) 0x9b, (byte) 0x27, (byte) 0x3d, - (byte) 0x14, (byte) 0x4b, (byte) 0x4b, (byte) 0xc8, (byte) 0xf0, (byte) 0x6e, - (byte) 0x43, (byte) 0x8f, (byte) 0xee, (byte) 0x1f, (byte) 0xeb, (byte) 0x20, - (byte) 0xe2, (byte) 0x4c, (byte) 0x79, (byte) 0xbf, (byte) 0x21, (byte) 0x0d, - (byte) 0x36, (byte) 0xed, (byte) 0x5f, (byte) 0xcc, (byte) 0x70, (byte) 0x68, - (byte) 0x8a, (byte) 0x05, (byte) 0x7c, (byte) 0x2f, (byte) 0x1b, (byte) 0xe9, - (byte) 0xec, (byte) 0x83, (byte) 0x6e, (byte) 0x9a, (byte) 0x78, (byte) 0x31, - (byte) 0x3d, (byte) 0xf4, (byte) 0xde, (byte) 0x1b, (byte) 0xd2, (byte) 0x76, - (byte) 0x32, (byte) 0x6c, (byte) 0x1e, (byte) 0xc9, (byte) 0x90, (byte) 0x7f, - (byte) 0xc4, (byte) 0x30, (byte) 0xc0, (byte) 0xae, (byte) 0xab, (byte) 0x70, - (byte) 0x08, (byte) 0x78, (byte) 0xbf, (byte) 0x2e, (byte) 0x8b, (byte) 0x07, - (byte) 0xab, (byte) 0x8f, (byte) 0x03, (byte) 0xc5, (byte) 0xd3, (byte) 0xeb, - (byte) 0x98, (byte) 0x19, (byte) 0x50, (byte) 0x83, (byte) 0x52, (byte) 0xf7, - (byte) 0xff, (byte) 0xf5, (byte) 0x89, (byte) 0xe6, (byte) 0xe7, (byte) 0xa7, - (byte) 0xcb, (byte) 0xdf, (byte) 0x96, (byte) 0x9d, (byte) 0x14, (byte) 0x04, - (byte) 0x5e, (byte) 0x45, (byte) 0x82, (byte) 0xf7, (byte) 0x23, (byte) 0x1a, - (byte) 0xb6, (byte) 0x64, (byte) 0x57, (byte) 0xe8, (byte) 0x7e, (byte) 0xa1, - (byte) 0xaf, (byte) 0x58, (byte) 0x68, (byte) 0x70, (byte) 0xc5, (byte) 0x0f, - (byte) 0x8d, (byte) 0x54, (byte) 0xf3, (byte) 0x49, (byte) 0xa3, (byte) 0x97, - (byte) 0x32, (byte) 0xa7, (byte) 0x2a, (byte) 0x79, (byte) 0xbe, (byte) 0xcd, - (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, - (byte) 0x50, (byte) 0x30, (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, - (byte) 0x04, (byte) 0x14, (byte) 0xac, (byte) 0xf3, (byte) 0x73, (byte) 0x9a, - (byte) 0x25, (byte) 0x08, (byte) 0x01, (byte) 0x07, (byte) 0x86, (byte) 0x8b, - (byte) 0xc4, (byte) 0xed, (byte) 0xb1, (byte) 0x6b, (byte) 0x53, (byte) 0xa3, - (byte) 0x21, (byte) 0xb4, (byte) 0xb4, (byte) 0x46, (byte) 0x30, (byte) 0x1f, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, - (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0xac, - (byte) 0xf3, (byte) 0x73, (byte) 0x9a, (byte) 0x25, (byte) 0x08, (byte) 0x01, - (byte) 0x07, (byte) 0x86, (byte) 0x8b, (byte) 0xc4, (byte) 0xed, (byte) 0xb1, - (byte) 0x6b, (byte) 0x53, (byte) 0xa3, (byte) 0x21, (byte) 0xb4, (byte) 0xb4, - (byte) 0x46, (byte) 0x30, (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, - (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06, - (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, - (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05, (byte) 0x00, - (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x16, - (byte) 0xf6, (byte) 0xd0, (byte) 0xe1, (byte) 0x14, (byte) 0x2d, (byte) 0x52, - (byte) 0x47, (byte) 0xa2, (byte) 0x89, (byte) 0xe6, (byte) 0x7f, (byte) 0xac, - (byte) 0x88, (byte) 0x04, (byte) 0x15, (byte) 0x21, (byte) 0x00, (byte) 0x72, - (byte) 0xf9, (byte) 0xee, (byte) 0xb2, (byte) 0x1b, (byte) 0x8e, (byte) 0x46, - (byte) 0x8b, (byte) 0x90, (byte) 0x20, (byte) 0x4f, (byte) 0xa7, (byte) 0xae, - (byte) 0x30, (byte) 0xb6, (byte) 0x24, (byte) 0xc5, (byte) 0x54, (byte) 0xaf, - (byte) 0x6c, (byte) 0x1e, (byte) 0xd6, (byte) 0x73, (byte) 0x22, (byte) 0x48, - (byte) 0x07, (byte) 0xb5, (byte) 0x13, (byte) 0x35, (byte) 0xbb, (byte) 0x9e, - (byte) 0xd9, (byte) 0x19, (byte) 0x79, (byte) 0xda, (byte) 0x76, (byte) 0x7f, - (byte) 0xf7, (byte) 0x87, (byte) 0xc9, (byte) 0xc3, (byte) 0x0b, (byte) 0x38, - (byte) 0x20, (byte) 0x26, (byte) 0xfc, (byte) 0x7f, (byte) 0x32, (byte) 0x2a, - (byte) 0xd5, (byte) 0x09, (byte) 0x87, (byte) 0xda, (byte) 0x23, (byte) 0x1f, - (byte) 0x71, (byte) 0x83, (byte) 0x00, (byte) 0x17, (byte) 0xf6, (byte) 0xb9, - (byte) 0x57, (byte) 0x21, (byte) 0xdf, (byte) 0x29, (byte) 0xcc, (byte) 0xdb, - (byte) 0xe9, (byte) 0x2c, (byte) 0xba, (byte) 0x86, (byte) 0x34, (byte) 0x53, - (byte) 0x29, (byte) 0x09, (byte) 0xc7, (byte) 0x3c, (byte) 0x8e, (byte) 0xa3, - (byte) 0x86, (byte) 0x81, (byte) 0x26, (byte) 0x7b, (byte) 0xa1, (byte) 0xbe, - (byte) 0xbc, (byte) 0xc9, (byte) 0x83, (byte) 0xb5, (byte) 0x36, (byte) 0x65, - (byte) 0x51, (byte) 0xb4, (byte) 0x41, (byte) 0xf0, (byte) 0x05, (byte) 0x78, - (byte) 0x3a, (byte) 0xa6, (byte) 0xad, (byte) 0x4b, (byte) 0x08, (byte) 0xd1, - (byte) 0xe4, (byte) 0xf1, (byte) 0x2e, (byte) 0xc7, (byte) 0x23, (byte) 0x6d, - (byte) 0xf0, (byte) 0x9d, (byte) 0x60, (byte) 0x6d, (byte) 0xe7, (byte) 0x11, - (byte) 0xaf, (byte) 0x41, (byte) 0x68, (byte) 0xee, (byte) 0x06, (byte) 0x76, - (byte) 0x82, (byte) 0x48, (byte) 0xee, (byte) 0x41, (byte) 0xc4, (byte) 0xf8, - (byte) 0xe1, (byte) 0x83, (byte) 0xbc, (byte) 0xa8, (byte) 0xbd, (byte) 0x9c, - (byte) 0x17, (byte) 0x45, (byte) 0xf4, (byte) 0x36, (byte) 0x67, (byte) 0x47, - (byte) 0x0e, (byte) 0x32, (byte) 0x13, (byte) 0x6e, (byte) 0xc1, (byte) 0x1e, - (byte) 0x08, (byte) 0xef, (byte) 0x10, (byte) 0xdf, (byte) 0x45, (byte) 0xbf, - (byte) 0x5a, (byte) 0xc4, (byte) 0x44, (byte) 0x4c, (byte) 0xd0, (byte) 0xd5, - (byte) 0x23, (byte) 0xde, (byte) 0xd7, (byte) 0x83, (byte) 0x1e, (byte) 0xb0, - (byte) 0x27, (byte) 0x4d, (byte) 0x57, (byte) 0xa3, (byte) 0xe8, (byte) 0x36, - (byte) 0x52, (byte) 0x1c, (byte) 0x48, (byte) 0x0a, (byte) 0xc4, (byte) 0xd8, - (byte) 0x32, (byte) 0xfc, (byte) 0xd0, (byte) 0x26, (byte) 0x6f, (byte) 0xa4, - (byte) 0x61, (byte) 0x2c, (byte) 0x3a, (byte) 0xa9, (byte) 0xfe, (byte) 0xa4, - (byte) 0x7a, (byte) 0x58, (byte) 0x54, (byte) 0x58, (byte) 0x96, (byte) 0x2b, - (byte) 0x6e, (byte) 0x9c, (byte) 0xc9, (byte) 0x00, (byte) 0xda, (byte) 0xc6, - (byte) 0xbb, (byte) 0x97, (byte) 0xc4, (byte) 0x95, (byte) 0x32, (byte) 0x6b, - (byte) 0x03, (byte) 0x6f, (byte) 0x33, (byte) 0x59, (byte) 0xd4, (byte) 0xa4, - (byte) 0x4a, (byte) 0x29, (byte) 0x29, (byte) 0x9a, (byte) 0xf4, (byte) 0x87, - (byte) 0x26, (byte) 0xe6, (byte) 0xee, (byte) 0x5c, (byte) 0x0b, (byte) 0xe9, - (byte) 0x98, (byte) 0x5d, (byte) 0xab, (byte) 0x31, (byte) 0xa1, (byte) 0x63, - (byte) 0xaa, (byte) 0x1a, (byte) 0xea, (byte) 0x61, (byte) 0x27, (byte) 0x5e, - (byte) 0x9e, (byte) 0x34, (byte) 0x73 - }; - - /** - * Client certificate generated from above and converted with: - * - * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g' - */ - private static final byte[] FAKE_EC_3 = { - (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xdf, (byte) 0x30, (byte) 0x82, - (byte) 0x01, (byte) 0xc7, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, - (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d, - (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, - (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05, - (byte) 0x00, (byte) 0x30, (byte) 0x64, (byte) 0x31, (byte) 0x0b, (byte) 0x30, - (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, - (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b, - (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x08, (byte) 0x0c, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31, - (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x07, (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f, - (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, - (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, - (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06, (byte) 0x47, (byte) 0x6f, - (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x31, (byte) 0x10, - (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, - (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x0d, - (byte) 0x30, (byte) 0x0b, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x03, (byte) 0x0c, (byte) 0x04, (byte) 0x54, (byte) 0x45, (byte) 0x53, - (byte) 0x54, (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, - (byte) 0x37, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x37, (byte) 0x31, - (byte) 0x37, (byte) 0x35, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x5a, - (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x37, (byte) 0x30, (byte) 0x31, - (byte) 0x32, (byte) 0x35, (byte) 0x31, (byte) 0x37, (byte) 0x35, (byte) 0x38, - (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x50, (byte) 0x31, - (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, - (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x02, (byte) 0x43, - (byte) 0x41, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06, - (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, - (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, - (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, - (byte) 0x31, (byte) 0x11, (byte) 0x30, (byte) 0x0f, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x08, (byte) 0x54, - (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2d, (byte) 0x55, (byte) 0x53, - (byte) 0x52, (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, - (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, - (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, - (byte) 0x03, (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0x4a, (byte) 0xb8, - (byte) 0x60, (byte) 0x17, (byte) 0x40, (byte) 0x91, (byte) 0x30, (byte) 0xf7, - (byte) 0xdf, (byte) 0x36, (byte) 0x83, (byte) 0x31, (byte) 0xb5, (byte) 0x3a, - (byte) 0xf4, (byte) 0xd4, (byte) 0xa1, (byte) 0xce, (byte) 0xd5, (byte) 0x54, - (byte) 0x97, (byte) 0x93, (byte) 0x7e, (byte) 0x7b, (byte) 0x08, (byte) 0x63, - (byte) 0x37, (byte) 0x62, (byte) 0xf1, (byte) 0x4e, (byte) 0x6a, (byte) 0x2e, - (byte) 0x35, (byte) 0x4e, (byte) 0x9f, (byte) 0x48, (byte) 0xcd, (byte) 0x09, - (byte) 0x17, (byte) 0xb3, (byte) 0xc1, (byte) 0x58, (byte) 0x02, (byte) 0x49, - (byte) 0x7b, (byte) 0x4c, (byte) 0xf7, (byte) 0x9b, (byte) 0xbb, (byte) 0x1b, - (byte) 0x2b, (byte) 0x9c, (byte) 0xe9, (byte) 0x36, (byte) 0xc4, (byte) 0x00, - (byte) 0x81, (byte) 0x2c, (byte) 0x28, (byte) 0xd9, (byte) 0x6b, (byte) 0xad, - (byte) 0xe3, (byte) 0xe8, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, - (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, - (byte) 0x13, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, - (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, - (byte) 0x01, (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, - (byte) 0x04, (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, - (byte) 0x65, (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, - (byte) 0x47, (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, - (byte) 0x74, (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, - (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, - (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, - (byte) 0x04, (byte) 0x14, (byte) 0xef, (byte) 0xf0, (byte) 0x15, (byte) 0xd7, - (byte) 0xc9, (byte) 0x3e, (byte) 0x9a, (byte) 0x73, (byte) 0xfa, (byte) 0x38, - (byte) 0xc5, (byte) 0x81, (byte) 0x84, (byte) 0x74, (byte) 0xd3, (byte) 0x83, - (byte) 0x74, (byte) 0x26, (byte) 0xf1, (byte) 0x0b, (byte) 0x30, (byte) 0x1f, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, - (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x38, - (byte) 0x6a, (byte) 0x9b, (byte) 0xf8, (byte) 0x3c, (byte) 0x0d, (byte) 0x54, - (byte) 0x9f, (byte) 0xdf, (byte) 0xf8, (byte) 0x53, (byte) 0x32, (byte) 0xa8, - (byte) 0xf7, (byte) 0x09, (byte) 0x15, (byte) 0x08, (byte) 0x76, (byte) 0xab, - (byte) 0x8d, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, - (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0xa6, (byte) 0x6c, (byte) 0x18, - (byte) 0xa9, (byte) 0x67, (byte) 0x16, (byte) 0x6a, (byte) 0x9e, (byte) 0x23, - (byte) 0xb3, (byte) 0x2a, (byte) 0xb8, (byte) 0x16, (byte) 0x7b, (byte) 0xb4, - (byte) 0xc8, (byte) 0xbc, (byte) 0x51, (byte) 0xe0, (byte) 0x6f, (byte) 0x05, - (byte) 0x66, (byte) 0xa1, (byte) 0x6f, (byte) 0x96, (byte) 0xde, (byte) 0x5b, - (byte) 0x41, (byte) 0x60, (byte) 0xe5, (byte) 0x29, (byte) 0x99, (byte) 0x12, - (byte) 0xfc, (byte) 0xa9, (byte) 0x91, (byte) 0x23, (byte) 0xb7, (byte) 0x9e, - (byte) 0x00, (byte) 0x5f, (byte) 0x93, (byte) 0xd4, (byte) 0xf7, (byte) 0x27, - (byte) 0x29, (byte) 0x77, (byte) 0xfb, (byte) 0x53, (byte) 0x09, (byte) 0xdc, - (byte) 0xe9, (byte) 0xd0, (byte) 0x5c, (byte) 0x92, (byte) 0x6d, (byte) 0xb7, - (byte) 0xcf, (byte) 0x04, (byte) 0xab, (byte) 0xf1, (byte) 0x39, (byte) 0xb9, - (byte) 0x49, (byte) 0x23, (byte) 0x7c, (byte) 0x0f, (byte) 0x15, (byte) 0x27, - (byte) 0xcd, (byte) 0x65, (byte) 0x3c, (byte) 0x6b, (byte) 0x91, (byte) 0x42, - (byte) 0x5a, (byte) 0xfe, (byte) 0xbe, (byte) 0xb8, (byte) 0xa2, (byte) 0xfd, - (byte) 0x67, (byte) 0x43, (byte) 0x4b, (byte) 0xc9, (byte) 0x28, (byte) 0x65, - (byte) 0x1b, (byte) 0x82, (byte) 0x5b, (byte) 0x25, (byte) 0x20, (byte) 0x9b, - (byte) 0xea, (byte) 0x99, (byte) 0xbb, (byte) 0x66, (byte) 0xc1, (byte) 0x8e, - (byte) 0x46, (byte) 0x0b, (byte) 0x4e, (byte) 0x06, (byte) 0xdd, (byte) 0x50, - (byte) 0x51, (byte) 0x64, (byte) 0xe8, (byte) 0x83, (byte) 0x99, (byte) 0x8e, - (byte) 0x53, (byte) 0xe9, (byte) 0x48, (byte) 0x47, (byte) 0x0e, (byte) 0x08, - (byte) 0x5e, (byte) 0x0d, (byte) 0x4a, (byte) 0x54, (byte) 0x17, (byte) 0xc1, - (byte) 0xf8, (byte) 0xcf, (byte) 0xba, (byte) 0x5c, (byte) 0x38, (byte) 0x70, - (byte) 0x33, (byte) 0x31, (byte) 0x22, (byte) 0x03, (byte) 0x6f, (byte) 0x54, - (byte) 0x3c, (byte) 0x41, (byte) 0xf0, (byte) 0x89, (byte) 0x85, (byte) 0xbc, - (byte) 0x77, (byte) 0x3c, (byte) 0xe8, (byte) 0xec, (byte) 0xb4, (byte) 0x35, - (byte) 0x7a, (byte) 0xcc, (byte) 0x8c, (byte) 0x5f, (byte) 0xa1, (byte) 0xed, - (byte) 0xa6, (byte) 0x28, (byte) 0x14, (byte) 0xc7, (byte) 0x8a, (byte) 0xef, - (byte) 0x56, (byte) 0x26, (byte) 0x35, (byte) 0x46, (byte) 0xab, (byte) 0xb0, - (byte) 0x97, (byte) 0xd2, (byte) 0xbd, (byte) 0xa9, (byte) 0x6a, (byte) 0xe4, - (byte) 0x3e, (byte) 0x87, (byte) 0xfb, (byte) 0xe1, (byte) 0x09, (byte) 0x8d, - (byte) 0x33, (byte) 0x12, (byte) 0xcf, (byte) 0xf0, (byte) 0xc0, (byte) 0xb8, - (byte) 0x9b, (byte) 0x9f, (byte) 0xb1, (byte) 0xcb, (byte) 0xac, (byte) 0x76, - (byte) 0xa8, (byte) 0x05, (byte) 0x6b, (byte) 0xcc, (byte) 0x41, (byte) 0xd2, - (byte) 0x26, (byte) 0x73, (byte) 0xfa, (byte) 0x69, (byte) 0xd3, (byte) 0x1f, - (byte) 0xa9, (byte) 0x0c, (byte) 0x6a, (byte) 0xd6, (byte) 0xc9, (byte) 0x35, - (byte) 0xc5, (byte) 0xad, (byte) 0xa1, (byte) 0x98, (byte) 0xc9, (byte) 0x78, - (byte) 0xa0, (byte) 0xe8, (byte) 0x02, (byte) 0x69, (byte) 0x80, (byte) 0x44, - (byte) 0xd9, (byte) 0xe6, (byte) 0xe5, (byte) 0x26, (byte) 0x4f, (byte) 0xcf, - (byte) 0x38, (byte) 0xcb, (byte) 0x55, (byte) 0x8c, (byte) 0x7d, (byte) 0x3c, - (byte) 0xa8, (byte) 0x82, (byte) 0x69, (byte) 0xa3, (byte) 0xdf, (byte) 0x0a, - (byte) 0x79, (byte) 0x7b, (byte) 0xdd, (byte) 0x24, (byte) 0x6a, (byte) 0x21, - (byte) 0x7b, (byte) 0x20, (byte) 0x94, (byte) 0xcd, (byte) 0x15, (byte) 0x92, - (byte) 0xad, (byte) 0x4a, (byte) 0x72, (byte) 0x0b, (byte) 0x0e, (byte) 0xb2, - (byte) 0xc9 - }; - - private static final byte[] FAKE_KEY_3 = { - (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01, - (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82, - (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e, - (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, - (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b, - (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66, - (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a, - (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02, - (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3, - (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d, - (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67, - (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb, - (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2, - (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79, - (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce, - (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08, - (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b, - (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4, - (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d, - (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23, - (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08, - (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1, - (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4, - (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16, - (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e, - (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01, - (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16, - (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98, - (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf, - (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a, - (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2, - (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc, - (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5, - (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a, - (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b, - (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9, - (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12, - (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e, - (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d, - (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2, - (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d, - (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc, - (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98, - (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96, - (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30, - (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e, - (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad, - (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f, - (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89, - (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13, - (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a, - (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e, - (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa, - (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47, - (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44, - (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22, - (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10, - (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45, - (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4, - (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda, - (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1, - (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab, - (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7, - (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc, - (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d, - (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82, - (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3, - (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a, - (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9, - (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6, - (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00, - (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd, - (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb, - (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4, - (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0, - (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2, - (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce, - (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a, - (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21, - (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d, - (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1, - (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41, - (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce, - (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0, - (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40, - (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a, - (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c, - (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90, - (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf, - (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb, - (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14, - (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab, - (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02, - (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67, - (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d, - (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d, - (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b, - (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2, - (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28, - (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd, - (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d, - (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b, - (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1, - (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51 - }; - - private boolean hasWifi() { - return getContext().getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - if(!hasWifi()) { - return; - } - mWifiManager = (WifiManager) mContext - .getSystemService(Context.WIFI_SERVICE); - assertNotNull(mWifiManager); - SystemUtil.runShellCommand("svc wifi enable"); - Thread.sleep(ENABLE_DELAY); - if (hasWifi()) { - assertTrue(mWifiManager.isWifiEnabled()); - } - } - - public void testSettersAndGetters() throws Exception { - if (!hasWifi()) { - return; - } - - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - assertTrue(config.getEapMethod() == Eap.NONE); - config.setEapMethod(Eap.PEAP); - assertTrue(config.getEapMethod() == Eap.PEAP); - config.setEapMethod(Eap.PWD); - assertTrue(config.getEapMethod() == Eap.PWD); - config.setEapMethod(Eap.TLS); - assertTrue(config.getEapMethod() == Eap.TLS); - config.setEapMethod(Eap.TTLS); - assertTrue(config.getEapMethod() == Eap.TTLS); - assertTrue(config.getPhase2Method() == Phase2.NONE); - config.setPhase2Method(Phase2.PAP); - assertTrue(config.getPhase2Method() == Phase2.PAP); - config.setPhase2Method(Phase2.MSCHAP); - assertTrue(config.getPhase2Method() == Phase2.MSCHAP); - config.setPhase2Method(Phase2.MSCHAPV2); - assertTrue(config.getPhase2Method() == Phase2.MSCHAPV2); - config.setPhase2Method(Phase2.GTC); - assertTrue(config.getPhase2Method() == Phase2.GTC); - config.setIdentity(IDENTITY); - assertTrue(config.getIdentity().equals(IDENTITY)); - config.setAnonymousIdentity(ANON_IDENTITY); - assertTrue(config.getAnonymousIdentity().equals(ANON_IDENTITY)); - config.setPassword(PASSWORD); - assertTrue(config.getPassword().equals(PASSWORD)); - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - X509Certificate cert1 = (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(FAKE_EC_1)); - X509Certificate cert2 = (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(FAKE_EC_2)); - config.setCaCertificate(cert1); - assertTrue(config.getCaCertificate().getSerialNumber().equals(cert1.getSerialNumber())); - config.setCaCertificates(new X509Certificate[]{cert1, cert2}); - X509Certificate[] certs = config.getCaCertificates(); - assertTrue(cert1.getSerialNumber().equals(certs[0].getSerialNumber())); - assertTrue(cert2.getSerialNumber().equals(certs[1].getSerialNumber())); - - X509Certificate clientCert = (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(FAKE_EC_3)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - PrivateKey clientKey = kf.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_3)); - - config.setClientKeyEntry(clientKey, clientCert); - X509Certificate testClientCert = config.getClientCertificate(); - X509Certificate[] testClientCertChain = config.getClientCertificateChain(); - assertTrue(clientCert.getSerialNumber().equals(testClientCert.getSerialNumber())); - assertTrue(testClientCertChain.length == 1); - assertTrue(testClientCertChain[0] == testClientCert); - - config.setClientKeyEntry(null, null); - assertTrue(config.getClientCertificate() == null); - assertTrue(config.getClientCertificateChain() == null); - - config.setClientKeyEntryWithCertificateChain(clientKey, - new X509Certificate[]{clientCert, cert1}); - testClientCert = config.getClientCertificate(); - testClientCertChain = config.getClientCertificateChain(); - assertTrue(clientCert.getSerialNumber().equals(testClientCert.getSerialNumber())); - assertTrue(testClientCertChain.length == 2); - assertTrue(testClientCertChain[0] == testClientCert); - assertTrue(testClientCertChain[1] == cert1); - - config.setSubjectMatch(SUBJECT_MATCH); - assertTrue(config.getSubjectMatch().equals(SUBJECT_MATCH)); - // Hotspot 2.0 related attributes - config.setPlmn(PLMN); - assertTrue(config.getPlmn().equals(PLMN)); - config.setRealm(REALM); - assertTrue(config.getRealm().equals(REALM)); - config.setAltSubjectMatch(ALT_SUBJECT_MATCH); - assertTrue(config.getAltSubjectMatch().equals(ALT_SUBJECT_MATCH)); - config.setDomainSuffixMatch(DOM_SUBJECT_MATCH); - assertTrue(config.getDomainSuffixMatch().equals(DOM_SUBJECT_MATCH)); - } - - public void testEnterpriseConfigDoesNotPrintPassword() { - if(!hasWifi()) { - return; - } - WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); - final String identity = "IdentityIsOkayToBeDisplayedHere"; - final String password = "PasswordIsNotOkayToBeDisplayedHere"; - enterpriseConfig.setIdentity(identity); - enterpriseConfig.setPassword(password); - final String stringRepresentation = enterpriseConfig.toString(); - assertTrue(stringRepresentation.contains(identity)); - assertFalse(stringRepresentation.contains(password)); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java deleted file mode 100644 index 63fa1dd94c..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2012 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.wifi.cts; - -import android.content.Context; -import android.content.pm.PackageManager; - -public class WifiFeature { - static boolean isWifiSupported(Context context) { - PackageManager packageManager = context.getPackageManager(); - return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI); - } - - static boolean isP2pSupported(Context context) { - PackageManager packageManager = context.getPackageManager(); - return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java deleted file mode 100644 index 9d9b2a3902..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.wifi.SupplicantState; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.WifiLock; -import android.net.wifi.WifiSsid; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -import com.android.compatibility.common.util.PollingCheck; -import com.android.compatibility.common.util.SystemUtil; - -import java.util.concurrent.Callable; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiInfoTest extends AndroidTestCase { - private static class MySync { - int expectedState = STATE_NULL; - } - - private WifiManager mWifiManager; - private WifiLock mWifiLock; - private static MySync mMySync; - - private static final int STATE_NULL = 0; - private static final int STATE_WIFI_CHANGING = 1; - private static final int STATE_WIFI_CHANGED = 2; - - private static final String TAG = "WifiInfoTest"; - private static final int TIMEOUT_MSEC = 6000; - private static final int WAIT_MSEC = 60; - private static final int DURATION = 10000; - private IntentFilter mIntentFilter; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGED; - mMySync.notify(); - } - } - } - }; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mMySync = new MySync(); - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - - mContext.registerReceiver(mReceiver, mIntentFilter); - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull(mWifiManager); - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - Thread.sleep(DURATION); - assertTrue(mWifiManager.isWifiEnabled()); - mMySync.expectedState = STATE_NULL; - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - mWifiLock.release(); - mContext.unregisterReceiver(mReceiver); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - Thread.sleep(DURATION); - super.tearDown(); - } - - private void setWifiEnabled(boolean enable) throws Exception { - synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGING; - if (enable) { - SystemUtil.runShellCommand("svc wifi enable"); - } else { - SystemUtil.runShellCommand("svc wifi disable"); - } - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && mMySync.expectedState == STATE_WIFI_CHANGING) - mMySync.wait(WAIT_MSEC); - } - } - - public void testWifiInfoProperties() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // this test case should in Wifi environment - WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - - assertNotNull(wifiInfo); - assertNotNull(wifiInfo.toString()); - SupplicantState.isValidState(wifiInfo.getSupplicantState()); - WifiInfo.getDetailedStateOf(SupplicantState.DISCONNECTED); - String ssid = wifiInfo.getSSID(); - if (!ssid.startsWith("0x") && !ssid.equals(WifiSsid.NONE)) { - // Non-hex string should be quoted - assertTrue(ssid.charAt(0) == '"'); - assertTrue(ssid.charAt(ssid.length() - 1) == '"'); - } - - wifiInfo.getBSSID(); - wifiInfo.getFrequency(); - wifiInfo.getIpAddress(); - wifiInfo.getLinkSpeed(); - wifiInfo.getPasspointFqdn(); - wifiInfo.getPasspointProviderFriendlyName(); - wifiInfo.getTxLinkSpeedMbps(); - wifiInfo.getRxLinkSpeedMbps(); - wifiInfo.getRssi(); - wifiInfo.getHiddenSSID(); - wifiInfo.getMacAddress(); - setWifiEnabled(false); - - PollingCheck.check("getNetworkId not -1", 20000, new Callable() { - @Override - public Boolean call() throws Exception { - WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - return wifiInfo.getNetworkId() == -1; - } - }); - - PollingCheck.check("getWifiState not disabled", 20000, new Callable() { - @Override - public Boolean call() throws Exception { - return mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED; - } - }); - } - -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java deleted file mode 100644 index 6ac92d409c..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import android.content.Context; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.WifiLock; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiLockTest extends AndroidTestCase { - - private static final String WIFI_TAG = "WifiLockTest"; - - /** - * Verify acquire and release of High Performance wifi locks - */ - public void testHiPerfWifiLock() { - testWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF); - } - - /** - * Verify acquire and release of Low latency wifi locks - */ - public void testLowLatencyWifiLock() { - testWifiLock(WifiManager.WIFI_MODE_FULL_LOW_LATENCY); - } - - private void testWifiLock(int lockType) { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - WifiLock wl = wm.createWifiLock(lockType, WIFI_TAG); - - wl.setReferenceCounted(true); - assertFalse(wl.isHeld()); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - wl.acquire(); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - assertNotNull(wl.toString()); - try { - wl.release(); - fail("should throw out exception because release is called" - +" a greater number of times than acquire"); - } catch (RuntimeException e) { - // expected - } - - wl = wm.createWifiLock(lockType, WIFI_TAG); - wl.setReferenceCounted(false); - assertFalse(wl.isHeld()); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - wl.acquire(); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - assertNotNull(wl.toString()); - // releasing again after release: but ignored for non-referenced locks - wl.release(); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java deleted file mode 100644 index 5b8a8d5cc4..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ /dev/null @@ -1,1056 +0,0 @@ -/* - * Copyright (C) 2009 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.wifi.cts; - - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.TxPacketCountListener; -import android.net.wifi.WifiManager.WifiLock; -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.pps.Credential; -import android.net.wifi.hotspot2.pps.HomeSp; -import android.os.Process; -import android.os.SystemClock; -import android.os.UserHandle; -import android.platform.test.annotations.AppModeFull; -import android.provider.Settings; -import android.support.test.uiautomator.UiDevice; -import android.test.AndroidTestCase; -import android.text.TextUtils; -import android.util.ArraySet; -import android.util.Log; - -import androidx.test.InstrumentationRegistry; - -import com.android.compatibility.common.util.SystemUtil; - -import java.lang.StringBuilder; -import java.net.HttpURLConnection; -import java.net.URL; -import java.security.MessageDigest; -import java.security.cert.X509Certificate; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiManagerTest extends AndroidTestCase { - private static class MySync { - int expectedState = STATE_NULL; - } - - private WifiManager mWifiManager; - private WifiLock mWifiLock; - private static MySync mMySync; - private List mScanResults = null; - private NetworkInfo mNetworkInfo; - private Object mLOHSLock = new Object(); - private UiDevice mUiDevice; - - // Please refer to WifiManager - private static final int MIN_RSSI = -100; - private static final int MAX_RSSI = -55; - - private static final int STATE_NULL = 0; - private static final int STATE_WIFI_CHANGING = 1; - private static final int STATE_WIFI_ENABLED = 2; - private static final int STATE_WIFI_DISABLED = 3; - private static final int STATE_SCANNING = 4; - private static final int STATE_SCAN_DONE = 5; - - private static final String TAG = "WifiManagerTest"; - private static final String SSID1 = "\"WifiManagerTest\""; - // A full single scan duration is about 6-7 seconds if country code is set - // to US. If country code is set to world mode (00), we would expect a scan - // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here. - private static final int SCAN_TIMEOUT_MSEC = 9000; - private static final int TIMEOUT_MSEC = 6000; - private static final int WAIT_MSEC = 60; - private static final int DURATION = 10000; - private static final int DURATION_SCREEN_TOGGLE = 2000; - private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000; - private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; - private static final int WIFI_SCAN_TEST_ITERATIONS = 5; - - private static final int ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP = 50; - - private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; - private static final String MANAGED_PROVISIONING_PACKAGE_NAME - = "com.android.managedprovisioning"; - - private IntentFilter mIntentFilter; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - - synchronized (mMySync) { - if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) { - mScanResults = mWifiManager.getScanResults(); - } else { - mScanResults = null; - } - mMySync.expectedState = STATE_SCAN_DONE; - mMySync.notifyAll(); - } - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN); - synchronized (mMySync) { - if (newState == WifiManager.WIFI_STATE_ENABLED) { - Log.d(TAG, "*** New WiFi state is ENABLED ***"); - mMySync.expectedState = STATE_WIFI_ENABLED; - mMySync.notifyAll(); - } else if (newState == WifiManager.WIFI_STATE_DISABLED) { - Log.d(TAG, "*** New WiFi state is DISABLED ***"); - mMySync.expectedState = STATE_WIFI_DISABLED; - mMySync.notifyAll(); - } - } - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mNetworkInfo = - (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) - mMySync.notifyAll(); - } - } - } - }; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mMySync = new MySync(); - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); - - mContext.registerReceiver(mReceiver, mIntentFilter); - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull(mWifiManager); - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - turnScreenOnNoDelay(); - Thread.sleep(DURATION); - assertTrue(mWifiManager.isWifiEnabled()); - synchronized (mMySync) { - mMySync.expectedState = STATE_NULL; - } - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - mWifiLock.release(); - mContext.unregisterReceiver(mReceiver); - Thread.sleep(DURATION); - super.tearDown(); - } - - private void setWifiEnabled(boolean enable) throws Exception { - synchronized (mMySync) { - if (mWifiManager.isWifiEnabled() != enable) { - // the new state is different, we expect it to change - mMySync.expectedState = STATE_WIFI_CHANGING; - } else { - mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); - } - // now trigger the change using shell commands. - SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable")); - waitForExpectedWifiState(enable); - } - } - - private void waitForExpectedWifiState(boolean enabled) throws InterruptedException { - synchronized (mMySync) { - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); - while (System.currentTimeMillis() < timeout - && mMySync.expectedState != expected) { - mMySync.wait(WAIT_MSEC); - } - } - } - - // Get the current scan status from sticky broadcast. - private boolean isScanCurrentlyAvailable() { - boolean isAvailable = false; - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiManager.WIFI_SCAN_AVAILABLE); - Intent intent = mContext.registerReceiver(null, intentFilter); - assertNotNull(intent); - if (intent.getAction().equals(WifiManager.WIFI_SCAN_AVAILABLE)) { - int state = intent.getIntExtra( - WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_UNKNOWN); - if (state == WifiManager.WIFI_STATE_ENABLED) { - isAvailable = true; - } else if (state == WifiManager.WIFI_STATE_DISABLED) { - isAvailable = false; - } - } - return isAvailable; - } - - private void startScan() throws Exception { - synchronized (mMySync) { - mMySync.expectedState = STATE_SCANNING; - mScanResults = null; - assertTrue(mWifiManager.startScan()); - long timeout = System.currentTimeMillis() + SCAN_TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANNING) - mMySync.wait(WAIT_MSEC); - } - } - - private void connectWifi() throws Exception { - synchronized (mMySync) { - if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) return; - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && mNetworkInfo.getState() != NetworkInfo.State.CONNECTED) - mMySync.wait(WAIT_MSEC); - assertTrue(mNetworkInfo.getState() == NetworkInfo.State.CONNECTED); - } - } - - private boolean existSSID(String ssid) { - for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { - if (w.SSID.equals(ssid)) - return true; - } - return false; - } - - private int findConfiguredNetworks(String SSID, List networks) { - for (final WifiConfiguration w : networks) { - if (w.SSID.equals(SSID)) - return networks.indexOf(w); - } - return -1; - } - - /** - * Test creation of WifiManager Lock. - */ - public void testWifiManagerLock() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - final String TAG = "Test"; - assertNotNull(mWifiManager.createWifiLock(TAG)); - assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); - } - - /** - * Test wifi scanning when location scan is turned off. - */ - public void testWifiManagerScanWhenWifiOffLocationTurnedOn() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - if (!hasLocationFeature()) { - Log.d(TAG, "Skipping test as location is not supported"); - return; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since Marshmallow WiFi scan results are" - + " empty when location is disabled!"); - } - setWifiEnabled(false); - Thread.sleep(DURATION); - startScan(); - if (mWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) { - // Make sure at least one AP is found. - assertNotNull("mScanResult should not be null!", mScanResults); - assertFalse("empty scan results!", mScanResults.isEmpty()); - } else { - // Make sure no scan results are available. - assertNull("mScanResult should be null!", mScanResults); - } - final String TAG = "Test"; - assertNotNull(mWifiManager.createWifiLock(TAG)); - assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); - } - - /** - * test point of wifiManager properties: - * 1.enable properties - * 2.DhcpInfo properties - * 3.wifi state - * 4.ConnectionInfo - */ - public void testWifiManagerProperties() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - setWifiEnabled(true); - assertTrue(mWifiManager.isWifiEnabled()); - assertNotNull(mWifiManager.getDhcpInfo()); - assertEquals(WifiManager.WIFI_STATE_ENABLED, mWifiManager.getWifiState()); - mWifiManager.getConnectionInfo(); - setWifiEnabled(false); - assertFalse(mWifiManager.isWifiEnabled()); - } - - /** - * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with - * {@link SystemClock#elapsedRealtime()} on device.

    - * To run this test in cts-tradefed: - * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp - */ - public void testWifiScanTimestamp() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - Log.d(TAG, "Skipping test as WiFi is not supported"); - return; - } - if (!hasLocationFeature()) { - Log.d(TAG, "Skipping test as location is not supported"); - return; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since Marshmallow WiFi scan results are" - + " empty when location is disabled!"); - } - if (!mWifiManager.isWifiEnabled()) { - setWifiEnabled(true); - } - // Scan multiple times to make sure scan timestamps increase with device timestamp. - for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) { - startScan(); - // Make sure at least one AP is found. - assertTrue("mScanResult should not be null. This may be due to a scan timeout", - mScanResults != null); - assertFalse("empty scan results!", mScanResults.isEmpty()); - long nowMillis = SystemClock.elapsedRealtime(); - // Keep track of how many APs are fresh in one scan. - int numFreshAps = 0; - for (ScanResult result : mScanResults) { - long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp); - if (Math.abs(nowMillis - scanTimeMillis) < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) { - numFreshAps++; - } - } - // At least half of the APs in the scan should be fresh. - int numTotalAps = mScanResults.size(); - String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: " - + numFreshAps; - assertTrue(msg, numFreshAps * 2 >= mScanResults.size()); - if (i < WIFI_SCAN_TEST_ITERATIONS - 1) { - // Wait before running next iteration. - Thread.sleep(WIFI_SCAN_TEST_INTERVAL_MILLIS); - } - } - } - - // Return true if location is enabled. - private boolean isLocationEnabled() { - return Settings.Secure.getInt(getContext().getContentResolver(), - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) != - Settings.Secure.LOCATION_MODE_OFF; - } - - // Returns true if the device has location feature. - private boolean hasLocationFeature() { - return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); - } - - private boolean hasAutomotiveFeature() { - return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); - } - - public void testSignal() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - final int numLevels = 9; - int expectLevel = 0; - assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels)); - assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels)); - expectLevel = 4; - assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2, - numLevels)); - int rssiA = 4; - int rssiB = 5; - assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0); - rssiB = 4; - assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0); - rssiA = 5; - rssiB = 4; - assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0); - } - - private int getTxPacketCount() throws Exception { - final AtomicInteger ret = new AtomicInteger(-1); - - mWifiManager.getTxPacketCount(new TxPacketCountListener() { - @Override - public void onSuccess(int count) { - ret.set(count); - } - @Override - public void onFailure(int reason) { - ret.set(0); - } - }); - - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (ret.get() < 0 && System.currentTimeMillis() < timeout) - Thread.sleep(WAIT_MSEC); - assertTrue(ret.get() >= 0); - return ret.get(); - } - - /** - * The new WiFi watchdog requires kernel/driver to export some packet loss - * counters. This CTS tests whether those counters are correctly exported. - * To pass this CTS test, a connected WiFi link is required. - */ - public void testWifiWatchdog() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // Make sure WiFi is enabled - if (!mWifiManager.isWifiEnabled()) { - setWifiEnabled(true); - Thread.sleep(DURATION); - } - assertTrue(mWifiManager.isWifiEnabled()); - - // give the test a chance to autoconnect - Thread.sleep(DURATION); - if (mNetworkInfo.getState() != NetworkInfo.State.CONNECTED) { - // this test requires a connectable network be configured - fail("This test requires a wifi network connection."); - } - - // This will generate a distinct stack trace if the initial connection fails. - connectWifi(); - - int i = 0; - for (; i < 15; i++) { - // Wait for a WiFi connection - connectWifi(); - - // Read TX packet counter - int txcount1 = getTxPacketCount(); - - // Do some network operations - HttpURLConnection connection = null; - try { - URL url = new URL("http://www.google.com/"); - connection = (HttpURLConnection) url.openConnection(); - connection.setInstanceFollowRedirects(false); - connection.setConnectTimeout(TIMEOUT_MSEC); - connection.setReadTimeout(TIMEOUT_MSEC); - connection.setUseCaches(false); - connection.getInputStream(); - } catch (Exception e) { - // ignore - } finally { - if (connection != null) connection.disconnect(); - } - - // Read TX packet counter again and make sure it increases - int txcount2 = getTxPacketCount(); - - if (txcount2 > txcount1) { - break; - } else { - Thread.sleep(DURATION); - } - } - assertTrue(i < 15); - } - - public class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback { - Object hotspotLock; - WifiManager.LocalOnlyHotspotReservation reservation = null; - boolean onStartedCalled = false; - boolean onStoppedCalled = false; - boolean onFailedCalled = false; - int failureReason = -1; - - TestLocalOnlyHotspotCallback(Object lock) { - hotspotLock = lock; - } - - @Override - public void onStarted(WifiManager.LocalOnlyHotspotReservation r) { - synchronized (hotspotLock) { - reservation = r; - onStartedCalled = true; - hotspotLock.notify(); - } - } - - @Override - public void onStopped() { - synchronized (hotspotLock) { - onStoppedCalled = true; - hotspotLock.notify(); - } - } - - @Override - public void onFailed(int reason) { - synchronized (hotspotLock) { - onFailedCalled = true; - failureReason = reason; - hotspotLock.notify(); - } - } - } - - private TestLocalOnlyHotspotCallback startLocalOnlyHotspot() { - // Location mode must be enabled for this test - if (!isLocationEnabled()) { - fail("Please enable location for this test"); - } - - TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLOHSLock); - synchronized (mLOHSLock) { - try { - mWifiManager.startLocalOnlyHotspot(callback, null); - // now wait for callback - mLOHSLock.wait(DURATION); - } catch (InterruptedException e) { - } - // check if we got the callback - assertTrue(callback.onStartedCalled); - assertNotNull(callback.reservation.getWifiConfiguration()); - if (!hasAutomotiveFeature()) { - assertEquals( - WifiConfiguration.AP_BAND_2GHZ, - callback.reservation.getWifiConfiguration().apBand); - } - assertFalse(callback.onFailedCalled); - assertFalse(callback.onStoppedCalled); - } - return callback; - } - - private void stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled) { - synchronized (mMySync) { - // we are expecting a new state - mMySync.expectedState = STATE_WIFI_CHANGING; - - // now shut down LocalOnlyHotspot - callback.reservation.close(); - - try { - waitForExpectedWifiState(wifiEnabled); - } catch (InterruptedException e) {} - } - } - - /** - * Verify that calls to startLocalOnlyHotspot succeed with proper permissions. - * - * Note: Location mode must be enabled for this test. - */ - public void testStartLocalOnlyHotspotSuccess() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // check that softap mode is supported by the device - if (!mWifiManager.isPortableHotspotSupported()) { - return; - } - - boolean wifiEnabled = mWifiManager.isWifiEnabled(); - - TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - - // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. - // TODO: remove this sleep as soon as b/124330089 is fixed. - try { - Log.d(TAG, "Sleep for 2 seconds"); - Thread.sleep(2000); - } catch (InterruptedException e) { - Log.d(TAG, "Thread InterruptedException!"); - } - - stopLocalOnlyHotspot(callback, wifiEnabled); - - // wifi should either stay on, or come back on - assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); - } - - /** - * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK. - */ - public void testDeprecatedApis() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - setWifiEnabled(true); - connectWifi(); // ensures that there is at-least 1 saved network on the device. - - WifiConfiguration wifiConfiguration = new WifiConfiguration(); - wifiConfiguration.SSID = SSID1; - wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - - assertEquals(WifiConfiguration.INVALID_NETWORK_ID, - mWifiManager.addNetwork(wifiConfiguration)); - assertEquals(WifiConfiguration.INVALID_NETWORK_ID, - mWifiManager.updateNetwork(wifiConfiguration)); - assertFalse(mWifiManager.enableNetwork(0, true)); - assertFalse(mWifiManager.disableNetwork(0)); - assertFalse(mWifiManager.removeNetwork(0)); - assertFalse(mWifiManager.disconnect()); - assertFalse(mWifiManager.reconnect()); - assertFalse(mWifiManager.reassociate()); - assertTrue(mWifiManager.getConfiguredNetworks().isEmpty()); - - boolean wifiEnabled = mWifiManager.isWifiEnabled(); - // now we should fail to toggle wifi state. - assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled)); - Thread.sleep(DURATION); - assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); - } - - /** - * Verify that applications can only have one registered LocalOnlyHotspot request at a time. - * - * Note: Location mode must be enabled for this test. - */ - public void testStartLocalOnlyHotspotSingleRequestByApps() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // check that softap mode is supported by the device - if (!mWifiManager.isPortableHotspotSupported()) { - return; - } - - boolean caughtException = false; - - boolean wifiEnabled = mWifiManager.isWifiEnabled(); - - TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - - // now make a second request - this should fail. - TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLOHSLock); - try { - mWifiManager.startLocalOnlyHotspot(callback2, null); - } catch (IllegalStateException e) { - Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice"); - caughtException = true; - } - if (!caughtException) { - // second start did not fail, should clean up the hotspot. - stopLocalOnlyHotspot(callback2, wifiEnabled); - } - assertTrue(caughtException); - - // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. - // TODO: remove this sleep as soon as b/124330089 is fixed. - try { - Log.d(TAG, "Sleep for 2 seconds"); - Thread.sleep(2000); - } catch (InterruptedException e) { - Log.d(TAG, "Thread InterruptedException!"); - } - - stopLocalOnlyHotspot(callback, wifiEnabled); - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_STACK} permission is never held by - * any package. - *

    - * No apps should ever attempt to acquire this permission, since it would give those - * apps extremely broad access to connectivity functionality. - */ - public void testNetworkStackPermission() { - final PackageManager pm = getContext().getPackageManager(); - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.NETWORK_STACK - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - for (PackageInfo pi : holding) { - fail("The NETWORK_STACK permission must not be held by " + pi.packageName - + " and must be revoked for security reasons"); - } - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_SETTINGS} permission is - * never held by any package. - *

    - * Only Settings, SysUi, NetworkStack and shell apps should ever attempt to acquire - * this permission, since it would give those apps extremely broad access to connectivity - * functionality. The permission is intended to be granted to only those apps with direct user - * access and no others. - */ - public void testNetworkSettingsPermission() { - final PackageManager pm = getContext().getPackageManager(); - - final ArraySet allowedPackages = new ArraySet(); - final ArraySet allowedUIDs = new ArraySet(); - // explicitly add allowed UIDs - allowedUIDs.add(Process.SYSTEM_UID); - allowedUIDs.add(Process.SHELL_UID); - allowedUIDs.add(Process.PHONE_UID); - allowedUIDs.add(Process.NETWORK_STACK_UID); - allowedUIDs.add(Process.NFC_UID); - - // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using - // this fact to determined allowed package name for sysui. This is a signature permission, - // so allow any package with this permission. - final List sysuiPackages = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.BIND_QUICK_SETTINGS_TILE - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - for (PackageInfo info : sysuiPackages) { - allowedPackages.add(info.packageName); - } - - // the captive portal flow also currently holds the NETWORK_SETTINGS permission - final Intent intent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); - final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); - if (ri != null) { - allowedPackages.add(ri.activityInfo.packageName); - } - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.NETWORK_SETTINGS - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - StringBuilder stringBuilder = new StringBuilder(); - for (PackageInfo pi : holding) { - String packageName = pi.packageName; - - // this is an explicitly allowed package - if (allowedPackages.contains(packageName)) continue; - - // now check if the packages are from allowed UIDs - int uid = -1; - try { - uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM); - } catch (PackageManager.NameNotFoundException e) { - continue; - } - if (!allowedUIDs.contains(uid)) { - stringBuilder.append("The NETWORK_SETTINGS permission must not be held by " - + packageName + ":" + uid + " and must be revoked for security reasons\n"); - } - } - if (stringBuilder.length() > 0) { - fail(stringBuilder.toString()); - } - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} permission is - * only held by the device setup wizard application. - *

    - * Only the SetupWizard app should ever attempt to acquire this - * permission, since it would give those apps extremely broad access to connectivity - * functionality. The permission is intended to be granted to only the device setup wizard. - */ - public void testNetworkSetupWizardPermission() { - final ArraySet allowedPackages = new ArraySet(); - - final PackageManager pm = getContext().getPackageManager(); - - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_SETUP_WIZARD); - final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); - String validPkg = ""; - if (ri != null) { - allowedPackages.add(ri.activityInfo.packageName); - validPkg = ri.activityInfo.packageName; - } - - final Intent preIntent = new Intent("com.android.setupwizard.OEM_PRE_SETUP"); - preIntent.addCategory(Intent.CATEGORY_DEFAULT); - final ResolveInfo preRi = pm - .resolveActivity(preIntent, PackageManager.MATCH_DISABLED_COMPONENTS); - String prePackageName = ""; - if (null != preRi) { - prePackageName = preRi.activityInfo.packageName; - } - - final Intent postIntent = new Intent("com.android.setupwizard.OEM_POST_SETUP"); - postIntent.addCategory(Intent.CATEGORY_DEFAULT); - final ResolveInfo postRi = pm - .resolveActivity(postIntent, PackageManager.MATCH_DISABLED_COMPONENTS); - String postPackageName = ""; - if (null != postRi) { - postPackageName = postRi.activityInfo.packageName; - } - if (!TextUtils.isEmpty(prePackageName) && !TextUtils.isEmpty(postPackageName) - && prePackageName.equals(postPackageName)) { - allowedPackages.add(prePackageName); - } - - final List holding = pm.getPackagesHoldingPermissions(new String[]{ - android.Manifest.permission.NETWORK_SETUP_WIZARD - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - for (PackageInfo pi : holding) { - if (!allowedPackages.contains(pi.packageName)) { - fail("The NETWORK_SETUP_WIZARD permission must not be held by " + pi.packageName - + " and must be revoked for security reasons [" + validPkg + "]"); - } - } - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_MANAGED_PROVISIONING} permission - * is only held by the device managed provisioning application. - *

    - * Only the ManagedProvisioning app should ever attempt to acquire this - * permission, since it would give those apps extremely broad access to connectivity - * functionality. The permission is intended to be granted to only the device managed - * provisioning. - */ - public void testNetworkManagedProvisioningPermission() { - final PackageManager pm = getContext().getPackageManager(); - - // TODO(b/115980767): Using hardcoded package name. Need a better mechanism to find the - // managed provisioning app. - // Ensure that the package exists. - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setPackage(MANAGED_PROVISIONING_PACKAGE_NAME); - final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); - String validPkg = ""; - if (ri != null) { - validPkg = ri.activityInfo.packageName; - } - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.NETWORK_MANAGED_PROVISIONING - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - for (PackageInfo pi : holding) { - if (!Objects.equals(pi.packageName, validPkg)) { - fail("The NETWORK_MANAGED_PROVISIONING permission must not be held by " - + pi.packageName + " and must be revoked for security reasons [" - + validPkg +"]"); - } - } - } - - /** - * Verify that the {@link android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE} permission - * is held by at most one application. - */ - public void testWifiSetDeviceMobilityStatePermission() { - final PackageManager pm = getContext().getPackageManager(); - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - - List uniquePackageNames = holding - .stream() - .map(pi -> pi.packageName) - .distinct() - .collect(Collectors.toList()); - - if (uniquePackageNames.size() > 1) { - fail("The WIFI_SET_DEVICE_MOBILITY_STATE permission must not be held by more than one " - + "application, but is held by " + uniquePackageNames.size() + " applications: " - + String.join(", ", uniquePackageNames)); - } - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission - * is held by at most one application. - */ - public void testNetworkCarrierProvisioningPermission() { - final PackageManager pm = getContext().getPackageManager(); - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.NETWORK_CARRIER_PROVISIONING - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - - List uniquePackageNames = holding - .stream() - .map(pi -> pi.packageName) - .distinct() - .collect(Collectors.toList()); - - if (uniquePackageNames.size() > 2) { - fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than two " - + "applications, but is held by " + uniquePackageNames.size() + " applications: " - + String.join(", ", uniquePackageNames)); - } - } - - /** - * Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE} - * permission is held by at most one application. - */ - public void testUpdateWifiUsabilityStatsScorePermission() { - final PackageManager pm = getContext().getPackageManager(); - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - - List uniquePackageNames = holding - .stream() - .map(pi -> pi.packageName) - .distinct() - .collect(Collectors.toList()); - - if (uniquePackageNames.size() > 1) { - fail("The WIFI_UPDATE_USABILITY_STATS_SCORE permission must not be held by more than " - + "one application, but is held by " + uniquePackageNames.size() + " applications: " - + String.join(", ", uniquePackageNames)); - } - } - - private void turnScreenOnNoDelay() throws Exception { - mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); - mUiDevice.executeShellCommand("wm dismiss-keyguard"); - } - - private void turnScreenOn() throws Exception { - turnScreenOnNoDelay(); - // Since the screen on/off intent is ordered, they will not be sent right now. - Thread.sleep(DURATION_SCREEN_TOGGLE); - } - - private void turnScreenOff() throws Exception { - mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); - // Since the screen on/off intent is ordered, they will not be sent right now. - Thread.sleep(DURATION_SCREEN_TOGGLE); - } - - /** - * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled - * but location is on. - * @throws Exception - */ - public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - if (!hasLocationFeature()) { - // skip the test if location is not supported - return; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since Marshmallow WiFi scan results are" - + " empty when location is disabled!"); - } - if(!mWifiManager.isScanAlwaysAvailable()) { - fail("Please enable Wi-Fi scanning for this test!"); - } - setWifiEnabled(false); - turnScreenOn(); - assertWifiScanningIsOn(); - // Toggle screen and verify Wi-Fi scanning is still on. - turnScreenOff(); - assertWifiScanningIsOn(); - turnScreenOn(); - assertWifiScanningIsOn(); - } - - /** - * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is enabled. - * @throws Exception - */ - public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - if (!hasLocationFeature()) { - // skip the test if location is not supported - return; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since Marshmallow WiFi scan results are" - + " empty when location is disabled!"); - } - if(!mWifiManager.isScanAlwaysAvailable()) { - fail("Please enable Wi-Fi scanning for this test!"); - } - setWifiEnabled(true); - turnScreenOn(); - assertWifiScanningIsOn(); - // Toggle screen and verify Wi-Fi scanning is still on. - turnScreenOff(); - assertWifiScanningIsOn(); - turnScreenOn(); - assertWifiScanningIsOn(); - } - - /** - * Verify that the platform supports a reasonable number of suggestions per app. - * @throws Exception - */ - public void testMaxNumberOfNetworkSuggestionsPerApp() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - assertTrue(mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp() - > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP); - } - - private void assertWifiScanningIsOn() { - if(!mWifiManager.isScanAlwaysAvailable()) { - fail("Wi-Fi scanning should be on."); - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java deleted file mode 100644 index 639db8a7c3..0000000000 --- a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 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.wifi.p2p.cts; - -import android.net.MacAddress; -import android.net.wifi.p2p.WifiP2pConfig; -import android.net.wifi.p2p.WifiP2pGroup; -import android.test.AndroidTestCase; - -public class WifiP2pConfigTest extends AndroidTestCase { - static final String TEST_NETWORK_NAME = "DIRECT-xy-Hello"; - static final String TEST_PASSPHRASE = "8etterW0r1d"; - static final int TEST_OWNER_BAND = WifiP2pConfig.GROUP_OWNER_BAND_5GHZ; - static final int TEST_OWNER_FREQ = 2447; - static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff"; - - public void testWifiP2pConfigBuilderForPersist() { - WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder(); - builder.setNetworkName(TEST_NETWORK_NAME) - .setPassphrase(TEST_PASSPHRASE) - .setGroupOperatingBand(TEST_OWNER_BAND) - .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) - .enablePersistentMode(true); - WifiP2pConfig config = builder.build(); - - assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS)); - assertTrue(config.networkName.equals(TEST_NETWORK_NAME)); - assertTrue(config.passphrase.equals(TEST_PASSPHRASE)); - assertEquals(config.groupOwnerBand, TEST_OWNER_BAND); - assertEquals(config.netId, WifiP2pGroup.PERSISTENT_NET_ID); - } - - public void testWifiP2pConfigBuilderForNonPersist() { - WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder(); - builder.setNetworkName(TEST_NETWORK_NAME) - .setPassphrase(TEST_PASSPHRASE) - .setGroupOperatingFrequency(TEST_OWNER_FREQ) - .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) - .enablePersistentMode(false); - WifiP2pConfig config = builder.build(); - - assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS)); - assertTrue(config.networkName.equals(TEST_NETWORK_NAME)); - assertTrue(config.passphrase.equals(TEST_PASSPHRASE)); - assertEquals(config.groupOwnerBand, TEST_OWNER_FREQ); - assertEquals(config.netId, WifiP2pGroup.TEMPORARY_NET_ID); - } -} diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/TestBase.java b/tests/cts/net/src/android/net/wifi/rtt/cts/TestBase.java deleted file mode 100644 index 07d5718044..0000000000 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/TestBase.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2018 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.wifi.rtt.cts; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.location.LocationManager; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiManager; -import android.net.wifi.rtt.RangingResult; -import android.net.wifi.rtt.RangingResultCallback; -import android.net.wifi.rtt.WifiRttManager; -import android.os.Handler; -import android.os.HandlerExecutor; -import android.os.HandlerThread; -import android.test.AndroidTestCase; - -import com.android.compatibility.common.util.SystemUtil; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; - -/** - * Base class for Wi-Fi RTT CTS test cases. Provides a uniform configuration and event management - * facility. - */ -public class TestBase extends AndroidTestCase { - protected static final String TAG = "WifiRttCtsTests"; - - // wait for Wi-Fi RTT to become available - private static final int WAIT_FOR_RTT_CHANGE_SECS = 10; - - // wait for Wi-Fi scan results to become available - private static final int WAIT_FOR_SCAN_RESULTS_SECS = 20; - - protected WifiRttManager mWifiRttManager; - protected WifiManager mWifiManager; - private LocationManager mLocationManager; - private WifiManager.WifiLock mWifiLock; - - private final HandlerThread mHandlerThread = new HandlerThread("SingleDeviceTest"); - protected final Executor mExecutor; - { - mHandlerThread.start(); - mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper())); - } - - /** - * Returns a flag indicating whether or not Wi-Fi RTT should be tested. Wi-Fi RTT - * should be tested if the feature is supported on the current device. - */ - static boolean shouldTestWifiRtt(Context context) { - final PackageManager pm = context.getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - if (!shouldTestWifiRtt(getContext())) { - return; - } - - mLocationManager = (LocationManager) getContext().getSystemService( - Context.LOCATION_SERVICE); - assertTrue("RTT testing requires Location to be enabled", - mLocationManager.isLocationEnabled()); - - mWifiRttManager = (WifiRttManager) getContext().getSystemService( - Context.WIFI_RTT_RANGING_SERVICE); - assertNotNull("Wi-Fi RTT Manager", mWifiRttManager); - - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull("Wi-Fi Manager", mWifiManager); - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) { - SystemUtil.runShellCommand("svc wifi enable"); - } - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED); - WifiRttBroadcastReceiver receiver = new WifiRttBroadcastReceiver(); - mContext.registerReceiver(receiver, intentFilter); - if (!mWifiRttManager.isAvailable()) { - assertTrue("Timeout waiting for Wi-Fi RTT to change status", - receiver.waitForStateChange()); - assertTrue("Wi-Fi RTT is not available (should be)", mWifiRttManager.isAvailable()); - } - } - - @Override - protected void tearDown() throws Exception { - if (!shouldTestWifiRtt(getContext())) { - super.tearDown(); - return; - } - - super.tearDown(); - } - - class WifiRttBroadcastReceiver extends BroadcastReceiver { - private CountDownLatch mBlocker = new CountDownLatch(1); - - @Override - public void onReceive(Context context, Intent intent) { - if (WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED.equals(intent.getAction())) { - mBlocker.countDown(); - } - } - - boolean waitForStateChange() throws InterruptedException { - return mBlocker.await(WAIT_FOR_RTT_CHANGE_SECS, TimeUnit.SECONDS); - } - } - - class WifiScansBroadcastReceiver extends BroadcastReceiver { - private CountDownLatch mBlocker = new CountDownLatch(1); - - @Override - public void onReceive(Context context, Intent intent) { - if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) { - mBlocker.countDown(); - } - } - - boolean waitForStateChange() throws InterruptedException { - return mBlocker.await(WAIT_FOR_SCAN_RESULTS_SECS, TimeUnit.SECONDS); - } - } - - class ResultCallback extends RangingResultCallback { - private CountDownLatch mBlocker = new CountDownLatch(1); - private int mCode; // 0: success, otherwise RangingResultCallback STATUS_CODE_*. - private List mResults; - - @Override - public void onRangingFailure(int code) { - mCode = code; - mResults = null; // not necessary since intialized to null - but for completeness - mBlocker.countDown(); - } - - @Override - public void onRangingResults(List results) { - mCode = 0; // not necessary since initialized to 0 - but for completeness - mResults = results; - mBlocker.countDown(); - } - - /** - * Waits for the listener callback to be called - or an error (timeout, interruption). - * Returns true on callback called, false on error (timeout, interruption). - */ - boolean waitForCallback() throws InterruptedException { - return mBlocker.await(WAIT_FOR_RTT_CHANGE_SECS, TimeUnit.SECONDS); - } - - /** - * Returns the code of the callback operation. Will be 0 for success (onRangingResults - * called), else (if onRangingFailure called) will be one of the STATUS_CODE_* values. - */ - int getCode() { - return mCode; - } - - /** - * Returns the list of ranging results. In cases of error (getCode() != 0) will return null. - */ - List getResults() { - return mResults; - } - } - - /** - * Start a scan and return a list of observed ScanResults (APs). - */ - protected List scanAps() throws InterruptedException { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - WifiScansBroadcastReceiver receiver = new WifiScansBroadcastReceiver(); - mContext.registerReceiver(receiver, intentFilter); - - mWifiManager.startScan(); - receiver.waitForStateChange(); - mContext.unregisterReceiver(receiver); - return mWifiManager.getScanResults(); - } - - /** - * Start a scan and return a test AP which supports IEEE 802.11mc and which has the highest - * RSSI. Will perform N (parameterized) scans and get the best AP across both scans. - * - * Returns null if test AP is not found in the specified number of scans. - * - * @param numScanRetries Maximum number of scans retries (in addition to first scan). - */ - protected ScanResult scanForTestAp(int numScanRetries) - throws InterruptedException { - int scanCount = 0; - ScanResult bestTestAp = null; - while (scanCount <= numScanRetries) { - for (ScanResult scanResult : scanAps()) { - if (!scanResult.is80211mcResponder()) { - continue; - } - if (bestTestAp == null || scanResult.level > bestTestAp.level) { - bestTestAp = scanResult; - } - } - - scanCount++; - } - - return bestTestAp; - } -} diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java deleted file mode 100644 index f71cadba7e..0000000000 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2018 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.wifi.rtt.cts; - -import android.net.wifi.ScanResult; -import android.net.wifi.rtt.RangingRequest; -import android.net.wifi.rtt.RangingResult; -import android.platform.test.annotations.AppModeFull; - -import com.android.compatibility.common.util.DeviceReportLog; -import com.android.compatibility.common.util.ResultType; -import com.android.compatibility.common.util.ResultUnit; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Wi-Fi RTT CTS test: range to all available Access Points which support IEEE 802.11mc. - */ -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiRttTest extends TestBase { - // Number of scans to do while searching for APs supporting IEEE 802.11mc - private static final int NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP = 2; - - // Number of RTT measurements per AP - private static final int NUM_OF_RTT_ITERATIONS = 10; - - // Maximum failure rate of RTT measurements (percentage) - private static final int MAX_FAILURE_RATE_PERCENT = 10; - - // Maximum variation from the average measurement (measures consistency) - private static final int MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM = 1000; - - // Minimum valid RSSI value - private static final int MIN_VALID_RSSI = -100; - - /** - * Test Wi-Fi RTT ranging operation: - * - Scan for visible APs for the test AP (which is validated to support IEEE 802.11mc) - * - Perform N (constant) RTT operations - * - Validate: - * - Failure ratio < threshold (constant) - * - Result margin < threshold (constant) - */ - public void testRangingToTestAp() throws InterruptedException { - if (!shouldTestWifiRtt(getContext())) { - return; - } - - // Scan for IEEE 802.11mc supporting APs - ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); - assertTrue( - "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " - + "your test setup includes them!", - testAp != null); - - // Perform RTT operations - RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build(); - List allResults = new ArrayList<>(); - int numFailures = 0; - int distanceSum = 0; - int distanceMin = 0; - int distanceMax = 0; - int[] statuses = new int[NUM_OF_RTT_ITERATIONS]; - int[] distanceMms = new int[NUM_OF_RTT_ITERATIONS]; - int[] distanceStdDevMms = new int[NUM_OF_RTT_ITERATIONS]; - int[] rssis = new int[NUM_OF_RTT_ITERATIONS]; - int[] numAttempted = new int[NUM_OF_RTT_ITERATIONS]; - int[] numSuccessful = new int[NUM_OF_RTT_ITERATIONS]; - long[] timestampsMs = new long[NUM_OF_RTT_ITERATIONS]; - byte[] lastLci = null; - byte[] lastLcr = null; - for (int i = 0; i < NUM_OF_RTT_ITERATIONS; ++i) { - ResultCallback callback = new ResultCallback(); - mWifiRttManager.startRanging(request, mExecutor, callback); - assertTrue("Wi-Fi RTT results: no callback on iteration " + i, - callback.waitForCallback()); - - List currentResults = callback.getResults(); - assertTrue("Wi-Fi RTT results: null results (onRangingFailure) on iteration " + i, - currentResults != null); - assertTrue("Wi-Fi RTT results: unexpected # of results (expect 1) on iteration " + i, - currentResults.size() == 1); - RangingResult result = currentResults.get(0); - assertTrue("Wi-Fi RTT results: invalid result (wrong BSSID) entry on iteration " + i, - result.getMacAddress().toString().equals(testAp.BSSID)); - assertEquals( - "Wi-Fi RTT results: invalid result (non-null PeerHandle) entry on iteration " - + i, null, result.getPeerHandle()); - - allResults.add(result); - int status = result.getStatus(); - statuses[i] = status; - if (status == RangingResult.STATUS_SUCCESS) { - distanceSum += result.getDistanceMm(); - if (i == 0) { - distanceMin = result.getDistanceMm(); - distanceMax = result.getDistanceMm(); - } else { - distanceMin = Math.min(distanceMin, result.getDistanceMm()); - distanceMax = Math.max(distanceMax, result.getDistanceMm()); - } - - assertTrue("Wi-Fi RTT results: invalid RSSI on iteration " + i, - result.getRssi() >= MIN_VALID_RSSI); - - distanceMms[i - numFailures] = result.getDistanceMm(); - distanceStdDevMms[i - numFailures] = result.getDistanceStdDevMm(); - rssis[i - numFailures] = result.getRssi(); - numAttempted[i - numFailures] = result.getNumAttemptedMeasurements(); - numSuccessful[i - numFailures] = result.getNumSuccessfulMeasurements(); - timestampsMs[i - numFailures] = result.getRangingTimestampMillis(); - - byte[] currentLci = result.getLci(); - byte[] currentLcr = result.getLcr(); - if (i - numFailures > 0) { - assertTrue("Wi-Fi RTT results: invalid result (LCI mismatch) on iteration " + i, - Arrays.equals(currentLci, lastLci)); - assertTrue("Wi-Fi RTT results: invalid result (LCR mismatch) on iteration " + i, - Arrays.equals(currentLcr, lastLcr)); - } - lastLci = currentLci; - lastLcr = currentLcr; - } else { - numFailures++; - } - } - - // Save results to log - int numGoodResults = NUM_OF_RTT_ITERATIONS - numFailures; - DeviceReportLog reportLog = new DeviceReportLog(TAG, "testRangingToTestAp"); - reportLog.addValues("status_codes", statuses, ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("distance_mm", Arrays.copyOf(distanceMms, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("distance_stddev_mm", Arrays.copyOf(distanceStdDevMms, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("rssi_dbm", Arrays.copyOf(rssis, numGoodResults), ResultType.NEUTRAL, - ResultUnit.NONE); - reportLog.addValues("num_attempted", Arrays.copyOf(numAttempted, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("num_successful", Arrays.copyOf(numSuccessful, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("timestamps", Arrays.copyOf(timestampsMs, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.submit(); - - // Analyze results - assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures + ", ITERATIONS=" - + NUM_OF_RTT_ITERATIONS, - numFailures <= NUM_OF_RTT_ITERATIONS * MAX_FAILURE_RATE_PERCENT / 100); - if (numFailures != NUM_OF_RTT_ITERATIONS) { - double distanceAvg = distanceSum / (NUM_OF_RTT_ITERATIONS - numFailures); - assertTrue("Wi-Fi RTT: Variation (max direction) exceeds threshold", - (distanceMax - distanceAvg) <= MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM); - assertTrue("Wi-Fi RTT: Variation (min direction) exceeds threshold", - (distanceAvg - distanceMin) <= MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM); - for (int i = 0; i < numGoodResults; ++i) { - assertNotSame("Number of attempted measurements is 0", 0, numAttempted[i]); - assertNotSame("Number of successful measurements is 0", 0, numSuccessful[i]); - } - } - } - - /** - * Validate that when a request contains more range operations than allowed (by API) that we - * get an exception. - */ - public void testRequestTooLarge() { - if (!shouldTestWifiRtt(getContext())) { - return; - } - - ScanResult dummy = new ScanResult(); - dummy.BSSID = "00:01:02:03:04:05"; - - RangingRequest.Builder builder = new RangingRequest.Builder(); - for (int i = 0; i < RangingRequest.getMaxPeers() - 2; ++i) { - builder.addAccessPoint(dummy); - } - - List scanResults = new ArrayList<>(); - scanResults.add(dummy); - scanResults.add(dummy); - scanResults.add(dummy); - - builder.addAccessPoints(scanResults); - - try { - mWifiRttManager.startRanging(builder.build(), mExecutor, new ResultCallback()); - } catch (IllegalArgumentException e) { - return; - } - - assertTrue( - "Did not receive expected IllegalArgumentException when tried to range to too " - + "many peers", - false); - } -} From aa5d56647644856ea768d7b162c0211bd2da5345 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 24 Mar 2020 16:12:48 -0700 Subject: [PATCH 0857/1415] WifiNetworkSpecifierTest: Remove double quotes from preSharedKey Legacy WifiConfiguration.preSharedKey is double quoted (similar to SSID). Bug: 152264590 Test: atest android.net.wifi.cts.WifiNetworkSpecifierTest --rerun-until-failure Change-Id: Id139537f07efec4e1b49cda29b2ed9e9f40fb22f --- .../wifi/cts/WifiNetworkSpecifierTest.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java index 83018fa1cb..eb6d6843eb 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java @@ -363,13 +363,17 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { testConnectionFlowWithSpecifier(specifier, true); } + private static String removeDoubleQuotes(String string) { + return WifiInfo.sanitizeSsid(string); + } + private WifiNetworkSpecifier.Builder createSpecifierBuilderWithCredentialFromSavedNetwork() { WifiNetworkSpecifier.Builder specifierBuilder = new WifiNetworkSpecifier.Builder(); if (mTestNetwork.preSharedKey != null) { if (mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { - specifierBuilder.setWpa2Passphrase(mTestNetwork.preSharedKey); + specifierBuilder.setWpa2Passphrase(removeDoubleQuotes(mTestNetwork.preSharedKey)); } else if (mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE)) { - specifierBuilder.setWpa3Passphrase(mTestNetwork.preSharedKey); + specifierBuilder.setWpa3Passphrase(removeDoubleQuotes(mTestNetwork.preSharedKey)); } else { fail("Unsupported security type found in saved networks"); } @@ -391,7 +395,7 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { return; } WifiNetworkSpecifier specifier = createSpecifierBuilderWithCredentialFromSavedNetwork() - .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) .build(); testSuccessfulConnectionWithSpecifier(specifier); } @@ -406,7 +410,7 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { } // Creates a ssid pattern by dropping the last char in the saved network & pass that // as a prefix match pattern in the request. - String ssidUnquoted = WifiInfo.sanitizeSsid(mTestNetwork.SSID); + String ssidUnquoted = removeDoubleQuotes(mTestNetwork.SSID); assertThat(ssidUnquoted.length()).isAtLeast(2); String ssidPrefix = ssidUnquoted.substring(0, ssidUnquoted.length() - 1); // Note: The match may return more than 1 network in this case since we use a prefix match, @@ -460,7 +464,7 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { List scanResults = mWifiManager.getScanResults(); if (scanResults == null || scanResults.isEmpty()) fail("No scan results available"); for (ScanResult scanResult : scanResults) { - if (TextUtils.equals(scanResult.SSID, WifiInfo.sanitizeSsid(mTestNetwork.SSID))) { + if (TextUtils.equals(scanResult.SSID, removeDoubleQuotes(mTestNetwork.SSID))) { return scanResult; } } @@ -511,7 +515,7 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { return; } WifiNetworkSpecifier specifier = createSpecifierBuilderWithCredentialFromSavedNetwork() - .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) .build(); testUserRejectionWithSpecifier(specifier); } @@ -526,11 +530,11 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { return; } WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() - .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) .setWpa2EnterpriseConfig(new WifiEnterpriseConfig()) .build(); WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() - .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) .setWpa2EnterpriseConfig(new WifiEnterpriseConfig()) .build(); assertThat(specifier1.satisfiedBy(specifier2)).isTrue(); @@ -546,11 +550,11 @@ public class WifiNetworkSpecifierTest extends AndroidTestCase { return; } WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() - .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) .setWpa3EnterpriseConfig(new WifiEnterpriseConfig()) .build(); WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() - .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID)) + .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) .setWpa3EnterpriseConfig(new WifiEnterpriseConfig()) .build(); assertThat(specifier1.satisfiedBy(specifier2)).isTrue(); From 69286a3791e95933bf13beef1747e1741a1f4dfd Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 18 Mar 2020 15:58:50 +0900 Subject: [PATCH 0858/1415] Create a builder for NetworkCapabilities. Bug: 151322799 Test: FrameworksWifiTests Change-Id: I69c00c9e3963950e55d7105d8825f7d3a3ec9b2f Merged-In: I06eb97e50d5583579b3c26d1365d2dbaec8bfc99 (cherry picked from commit 9771f34dae9cdeb857636cac2b3c2d473713914e) --- .../tethering/UpstreamNetworkMonitor.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index 7ac7f5f06e..45bb4ab6e5 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -586,21 +586,21 @@ public class UpstreamNetworkMonitor { */ @VisibleForTesting public static NetworkCapabilities networkCapabilitiesForType(int type) { - final NetworkCapabilities nc = new NetworkCapabilities(); + final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); // Map from type to transports. final int notFound = -1; final int transport = sLegacyTypeToTransport.get(type, notFound); Preconditions.checkArgument(transport != notFound, "unknown legacy type: " + type); - nc.addTransportType(transport); + builder.addTransportType(transport); if (type == TYPE_MOBILE_DUN) { - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); // DUN is restricted network, see NetworkCapabilities#FORCE_RESTRICTED_CAPABILITIES. - nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } else { - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } - return nc; + return builder.build(); } } From 04bf92fcceca2ae2b2b1a7bb764739822d3fc5bc Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 12 Mar 2020 22:18:30 +0800 Subject: [PATCH 0859/1415] Rewrite NetworkInfo CTS tests to Kotlin Bug: 152356365 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkInfoTest on both Q and R devices Change-Id: I44ffdc4b4a9ba8fcc1fda895b9d7f8f551fd6bb3 --- .../src/android/net/cts/NetworkInfoTest.java | 71 ------------------ .../src/android/net/cts/NetworkInfoTest.kt | 73 +++++++++++++++++++ 2 files changed, 73 insertions(+), 71 deletions(-) delete mode 100644 tests/cts/net/src/android/net/cts/NetworkInfoTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfoTest.kt diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java deleted file mode 100644 index 4a7b4e7e82..0000000000 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2009 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 android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkInfo.State; -import android.test.AndroidTestCase; - -public class NetworkInfoTest extends AndroidTestCase { - - public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; - public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; - public static final String MOBILE_TYPE_NAME = "mobile"; - public static final String WIFI_TYPE_NAME = "WIFI"; - - public void testAccessNetworkInfoProperties() { - ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( - Context.CONNECTIVITY_SERVICE); - NetworkInfo[] ni = cm.getAllNetworkInfo(); - assertTrue(ni.length >= 1); - - for (NetworkInfo netInfo: ni) { - switch (netInfo.getType()) { - case TYPE_MOBILE: - assertNetworkInfo(netInfo, MOBILE_TYPE_NAME); - break; - case TYPE_WIFI: - assertNetworkInfo(netInfo, WIFI_TYPE_NAME); - break; - // TODO: Add BLUETOOTH_TETHER testing - default: - break; - } - } - } - - private void assertNetworkInfo(NetworkInfo netInfo, String expectedTypeName) { - assertEquals(expectedTypeName.compareToIgnoreCase(netInfo.getTypeName()), 0); - if(netInfo.isConnectedOrConnecting()) { - assertTrue(netInfo.isAvailable()); - if (State.CONNECTED == netInfo.getState()) { - assertTrue(netInfo.isConnected()); - } - assertTrue(State.CONNECTING == netInfo.getState() - || State.CONNECTED == netInfo.getState()); - assertTrue(DetailedState.SCANNING == netInfo.getDetailedState() - || DetailedState.CONNECTING == netInfo.getDetailedState() - || DetailedState.AUTHENTICATING == netInfo.getDetailedState() - || DetailedState.CONNECTED == netInfo.getDetailedState()); - } - assertNotNull(netInfo.toString()); - } -} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt new file mode 100644 index 0000000000..e1dca53620 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt @@ -0,0 +1,73 @@ +/* + * 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 android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkInfo +import android.net.NetworkInfo.DetailedState +import android.net.NetworkInfo.State +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue +import org.junit.runner.RunWith +import org.junit.Test + +const val TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE +const val TYPE_WIFI = ConnectivityManager.TYPE_WIFI +const val MOBILE_TYPE_NAME = "mobile" +const val WIFI_TYPE_NAME = "WIFI" + +@SmallTest +@RunWith(AndroidJUnit4::class) +class NetworkInfoTest { + @Test + fun testAccessNetworkInfoProperties() { + val cm = InstrumentationRegistry.getInstrumentation().context + .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val ni = cm.getAllNetworkInfo() + assertTrue(ni.isNotEmpty()) + + for (netInfo in ni) { + when (netInfo.getType()) { + TYPE_MOBILE -> assertNetworkInfo(netInfo, MOBILE_TYPE_NAME) + TYPE_WIFI -> assertNetworkInfo(netInfo, WIFI_TYPE_NAME) + // TODO: Add BLUETOOTH_TETHER testing + } + } + } + + private fun assertNetworkInfo(netInfo: NetworkInfo, expectedTypeName: String) { + assertTrue(expectedTypeName.equals(netInfo.getTypeName(), ignoreCase = true)) + assertNotNull(netInfo.toString()) + + if (!netInfo.isConnectedOrConnecting()) return + + assertTrue(netInfo.isAvailable()) + if (State.CONNECTED == netInfo.getState()) { + assertTrue(netInfo.isConnected()) + } + assertTrue(State.CONNECTING == netInfo.getState() || + State.CONNECTED == netInfo.getState()) + assertTrue(DetailedState.SCANNING == netInfo.getDetailedState() || + DetailedState.CONNECTING == netInfo.getDetailedState() || + DetailedState.AUTHENTICATING == netInfo.getDetailedState() || + DetailedState.CONNECTED == netInfo.getDetailedState()) + } +} From 2725f6e267fac567e1de3a21906fb2e59a3f08ab Mon Sep 17 00:00:00 2001 From: paulhu Date: Wed, 25 Mar 2020 13:57:05 +0800 Subject: [PATCH 0860/1415] Add NetworkInfo CTS tests Test APIs below: NetworkInfo(int, int, String, String) setDetailedState(android.net.NetworkInfo.DetailedState, String, String) Bug: 152356365 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkInfoTest on both Q and R devices Change-Id: Idada858b1d5cd4c0907998b289aca4d6e6d04f56 --- .../src/android/net/cts/NetworkInfoTest.kt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt index e1dca53620..fa15e8f82c 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt @@ -16,16 +16,24 @@ package android.net.cts +import android.os.Build import android.content.Context import android.net.ConnectivityManager import android.net.NetworkInfo import android.net.NetworkInfo.DetailedState import android.net.NetworkInfo.State +import android.telephony.TelephonyManager import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Rule import org.junit.runner.RunWith import org.junit.Test @@ -33,10 +41,14 @@ const val TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE const val TYPE_WIFI = ConnectivityManager.TYPE_WIFI const val MOBILE_TYPE_NAME = "mobile" const val WIFI_TYPE_NAME = "WIFI" +const val LTE_SUBTYPE_NAME = "LTE" @SmallTest @RunWith(AndroidJUnit4::class) class NetworkInfoTest { + @Rule @JvmField + val ignoreRule = DevSdkIgnoreRule() + @Test fun testAccessNetworkInfoProperties() { val cm = InstrumentationRegistry.getInstrumentation().context @@ -70,4 +82,41 @@ class NetworkInfoTest { DetailedState.AUTHENTICATING == netInfo.getDetailedState() || DetailedState.CONNECTED == netInfo.getDetailedState()) } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testConstructor() { + val networkInfo = NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, + MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + + assertEquals(TYPE_MOBILE, networkInfo.type) + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, networkInfo.subtype) + assertEquals(MOBILE_TYPE_NAME, networkInfo.typeName) + assertEquals(LTE_SUBTYPE_NAME, networkInfo.subtypeName) + assertEquals(DetailedState.IDLE, networkInfo.detailedState) + assertEquals(State.UNKNOWN, networkInfo.state) + assertNull(networkInfo.reason) + assertNull(networkInfo.extraInfo) + + try { + NetworkInfo(ConnectivityManager.MAX_NETWORK_TYPE + 1, + TelephonyManager.NETWORK_TYPE_LTE, MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + fail("Unexpected behavior. Network type is invalid.") + } catch (e: IllegalArgumentException) { + // Expected behavior. + } + } + + @Test + fun testSetDetailedState() { + val networkInfo = NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, + MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + val reason = "TestNetworkInfo" + val extraReason = "setDetailedState test" + + networkInfo.setDetailedState(DetailedState.CONNECTED, reason, extraReason) + assertEquals(DetailedState.CONNECTED, networkInfo.detailedState) + assertEquals(State.CONNECTED, networkInfo.state) + assertEquals(reason, networkInfo.reason) + assertEquals(extraReason, networkInfo.extraInfo) + } } From 7a3387b15ed7a3eb3863b00d5e8a7540a93b75fc Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 25 Mar 2020 05:14:52 +0000 Subject: [PATCH 0861/1415] Test IpConfiguration field count and parceling round trip Add test for IpConfiguration and also address review comments from aosp/1171795. Bug: 139268426 Test: CtsNetTestCasesLatestSdk:android.net.cts.IpConfigurationTest Change-Id: Ib30a98e11bdcd9d473b713f7e4c317172b14f000 Merged-In: Ib30a98e11bdcd9d473b713f7e4c317172b14f000 (cherry picked from commit 8e208eb353263bddca4d93a7a67a5f978316b0cc) --- .../android/net/cts/IpConfigurationTest.java | 78 ++++++------------- 1 file changed, 25 insertions(+), 53 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java index 21be35142d..c6bc0770b8 100644 --- a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java +++ b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java @@ -16,6 +16,8 @@ package android.net.cts; +import static com.android.testutils.ParcelUtilsKt.assertParcelSane; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -37,13 +39,6 @@ import java.util.ArrayList; @RunWith(AndroidJUnit4.class) public final class IpConfigurationTest { - private static final int TYPE_IPASSIGNMENT_STATIC = 0; - private static final int TYPE_IPASSIGNMENT_DHCP = 1; - - private static final int TYPE_PROXY_SETTINGS_NONE = 0; - private static final int TYPE_PROXY_SETTINGS_STATIC = 1; - private static final int TYPE_PROXY_SETTINGS_PAC = 2; - private static final LinkAddress LINKADDR = new LinkAddress("192.0.2.2/25"); private static final InetAddress GATEWAY = InetAddressUtils.parseNumericAddress("192.0.2.1"); private static final InetAddress DNS1 = InetAddressUtils.parseNumericAddress("8.8.8.8"); @@ -76,24 +71,31 @@ public final class IpConfigurationTest { assertIpConfigurationEqual(ipConfig, new IpConfiguration()); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_STATIC, - TYPE_PROXY_SETTINGS_PAC); + ipConfig.setStaticIpConfiguration(mStaticIpConfig); + ipConfig.setHttpProxy(mProxy); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_STATIC, - TYPE_PROXY_SETTINGS_STATIC); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, - TYPE_PROXY_SETTINGS_PAC); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, - TYPE_PROXY_SETTINGS_STATIC); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); - ipConfig = createIpConfiguration(TYPE_IPASSIGNMENT_DHCP, - TYPE_PROXY_SETTINGS_NONE); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE); assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); } @@ -106,46 +108,16 @@ public final class IpConfigurationTest { assertNull(config.getHttpProxy()); } - private IpConfiguration createIpConfiguration(int ipAssignmentType, - int proxySettingType) { - - final IpConfiguration ipConfig = new IpConfiguration(); - - switch (ipAssignmentType) { - case TYPE_IPASSIGNMENT_STATIC: - ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); - break; - case TYPE_IPASSIGNMENT_DHCP: - ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); - break; - default: - throw new IllegalArgumentException("Unknown ip assignment type."); - } - - switch (proxySettingType) { - case TYPE_PROXY_SETTINGS_NONE: - ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE); - break; - case TYPE_PROXY_SETTINGS_STATIC: - ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); - break; - case TYPE_PROXY_SETTINGS_PAC: - ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); - break; - default: - throw new IllegalArgumentException("Unknown proxy setting type."); - } - - ipConfig.setStaticIpConfiguration(mStaticIpConfig); - ipConfig.setHttpProxy(mProxy); - - return ipConfig; - } - private void assertIpConfigurationEqual(IpConfiguration source, IpConfiguration target) { assertEquals(source.getIpAssignment(), target.getIpAssignment()); assertEquals(source.getProxySettings(), target.getProxySettings()); assertEquals(source.getHttpProxy(), target.getHttpProxy()); assertEquals(source.getStaticIpConfiguration(), target.getStaticIpConfiguration()); } + + @Test + public void testParcel() { + final IpConfiguration config = new IpConfiguration(); + assertParcelSane(config, 4); + } } From 1d0aebc7130f725f04c2caa7a3e9913c46691b47 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 19 Mar 2020 21:04:04 +0800 Subject: [PATCH 0862/1415] Hide startTethering with type function to module-lib only Bug: 151918384 Test: m Change-Id: Icef8b363aae97dd020d618bcb397f661aa6c4750 Merged-In: Icef8b363aae97dd020d618bcb397f661aa6c4750 --- Tethering/common/TetheringLib/api/system-current.txt | 1 - .../common/TetheringLib/src/android/net/TetheringManager.java | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Tethering/common/TetheringLib/api/system-current.txt b/Tethering/common/TetheringLib/api/system-current.txt index 2f5ea6af71..edd1ebb5f7 100644 --- a/Tethering/common/TetheringLib/api/system-current.txt +++ b/Tethering/common/TetheringLib/api/system-current.txt @@ -23,7 +23,6 @@ package android.net { method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); - method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index b70165ab74..096f4fefa8 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -739,11 +739,13 @@ public class TetheringManager { * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants. * @param executor {@link Executor} to specify the thread upon which the callback of * TetheringRequest will be invoked. + * @hide */ @RequiresPermission(anyOf = { android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS }) + @SystemApi(client = MODULE_LIBRARIES) public void startTethering(int type, @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) { startTethering(new TetheringRequest.Builder(type).build(), executor, callback); From ca071b79cd106f73c0780c8aa2e460fede914bd5 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 24 Mar 2020 18:13:46 +0900 Subject: [PATCH 0863/1415] Update connected clients when a downstream disappears. Otherwise, if another downstream of the same type reappears, the code would fire a callback with the previous list of clients. Bug: 150644681 Test: atest TetheringIntegrationTests:EthernetTetheringTest --rerun-until-failure 100 Change-Id: I6b34ea747ae1831001077f44879bb6828dcecc96 --- .../server/connectivity/tethering/Tethering.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 1cfc04b481..0be162cbdf 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -430,9 +430,7 @@ public class Tethering { // Called by wifi when the number of soft AP clients changed. @Override public void onConnectedClientsChanged(final List clients) { - if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, clients)) { - reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients()); - } + updateConnectedClients(clients); } } @@ -1558,6 +1556,7 @@ public class Tethering { mIPv6TetheringCoordinator.removeActiveDownstream(who); mOffload.excludeDownstreamInterface(who.interfaceName()); mForwardedDownstreams.remove(who); + updateConnectedClients(null /* wifiClients */); // If this is a Wi-Fi interface, tell WifiManager of any errors // or the inactive serving state. @@ -2140,6 +2139,12 @@ public class Tethering { return false; } + private void updateConnectedClients(final List wifiClients) { + if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, wifiClients)) { + reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients()); + } + } + private IpServer.Callback makeControlCallback() { return new IpServer.Callback() { @Override @@ -2154,10 +2159,7 @@ public class Tethering { @Override public void dhcpLeasesChanged() { - if (mConnectedClientsTracker.updateConnectedClients( - mForwardedDownstreams, null /* wifiClients */)) { - reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients()); - } + updateConnectedClients(null /* wifiClients */); } }; } From eae43d4fcc8405e6564ecc5d610c07ce26ba973e Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Wed, 25 Mar 2020 11:19:36 +0000 Subject: [PATCH 0864/1415] Add permitted_packages to framework-tethering. (cherry picked from commit 577707e09b2e39a019368c8be3383b2c580c2d92) Test: m out/soong/.intermediates/frameworks/base/packages/Tethering/common/TetheringLib/framework-tethering/android_common/package-check.stamp Bug: 151314205 Merged-In: I248c36b2cf2f5776978c4fd2322d3b73ade309ff Change-Id: Iddeeb6648f1ed2a31eebf04eb465ea675fb610ae --- Tethering/common/TetheringLib/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 2fbba68f1e..00d0d9c428 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -60,6 +60,7 @@ java_library { hostdex: true, // for hiddenapi check visibility: ["//frameworks/base/packages/Tethering:__subpackages__"], apex_available: ["com.android.tethering"], + permitted_packages: ["android.net"], } stubs_defaults { From c3fbce9459979ad45e7d128af7ef21b8bd61d6c4 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Wed, 25 Mar 2020 09:20:47 +0000 Subject: [PATCH 0865/1415] Rewrite NetworkInfo CTS tests to Kotlin Bug: 152356365 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkInfoTest on both Q and R devices Change-Id: I44ffdc4b4a9ba8fcc1fda895b9d7f8f551fd6bb3 Merged-In: I44ffdc4b4a9ba8fcc1fda895b9d7f8f551fd6bb3 (cherry picked from aosp/1256248) --- .../src/android/net/cts/NetworkInfoTest.java | 71 ------------------ .../src/android/net/cts/NetworkInfoTest.kt | 73 +++++++++++++++++++ 2 files changed, 73 insertions(+), 71 deletions(-) delete mode 100644 tests/cts/net/src/android/net/cts/NetworkInfoTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfoTest.kt diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java b/tests/cts/net/src/android/net/cts/NetworkInfoTest.java deleted file mode 100644 index 4a7b4e7e82..0000000000 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2009 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 android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkInfo.State; -import android.test.AndroidTestCase; - -public class NetworkInfoTest extends AndroidTestCase { - - public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; - public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; - public static final String MOBILE_TYPE_NAME = "mobile"; - public static final String WIFI_TYPE_NAME = "WIFI"; - - public void testAccessNetworkInfoProperties() { - ConnectivityManager cm = (ConnectivityManager) getContext().getSystemService( - Context.CONNECTIVITY_SERVICE); - NetworkInfo[] ni = cm.getAllNetworkInfo(); - assertTrue(ni.length >= 1); - - for (NetworkInfo netInfo: ni) { - switch (netInfo.getType()) { - case TYPE_MOBILE: - assertNetworkInfo(netInfo, MOBILE_TYPE_NAME); - break; - case TYPE_WIFI: - assertNetworkInfo(netInfo, WIFI_TYPE_NAME); - break; - // TODO: Add BLUETOOTH_TETHER testing - default: - break; - } - } - } - - private void assertNetworkInfo(NetworkInfo netInfo, String expectedTypeName) { - assertEquals(expectedTypeName.compareToIgnoreCase(netInfo.getTypeName()), 0); - if(netInfo.isConnectedOrConnecting()) { - assertTrue(netInfo.isAvailable()); - if (State.CONNECTED == netInfo.getState()) { - assertTrue(netInfo.isConnected()); - } - assertTrue(State.CONNECTING == netInfo.getState() - || State.CONNECTED == netInfo.getState()); - assertTrue(DetailedState.SCANNING == netInfo.getDetailedState() - || DetailedState.CONNECTING == netInfo.getDetailedState() - || DetailedState.AUTHENTICATING == netInfo.getDetailedState() - || DetailedState.CONNECTED == netInfo.getDetailedState()); - } - assertNotNull(netInfo.toString()); - } -} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt new file mode 100644 index 0000000000..e1dca53620 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt @@ -0,0 +1,73 @@ +/* + * 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 android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkInfo +import android.net.NetworkInfo.DetailedState +import android.net.NetworkInfo.State +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue +import org.junit.runner.RunWith +import org.junit.Test + +const val TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE +const val TYPE_WIFI = ConnectivityManager.TYPE_WIFI +const val MOBILE_TYPE_NAME = "mobile" +const val WIFI_TYPE_NAME = "WIFI" + +@SmallTest +@RunWith(AndroidJUnit4::class) +class NetworkInfoTest { + @Test + fun testAccessNetworkInfoProperties() { + val cm = InstrumentationRegistry.getInstrumentation().context + .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val ni = cm.getAllNetworkInfo() + assertTrue(ni.isNotEmpty()) + + for (netInfo in ni) { + when (netInfo.getType()) { + TYPE_MOBILE -> assertNetworkInfo(netInfo, MOBILE_TYPE_NAME) + TYPE_WIFI -> assertNetworkInfo(netInfo, WIFI_TYPE_NAME) + // TODO: Add BLUETOOTH_TETHER testing + } + } + } + + private fun assertNetworkInfo(netInfo: NetworkInfo, expectedTypeName: String) { + assertTrue(expectedTypeName.equals(netInfo.getTypeName(), ignoreCase = true)) + assertNotNull(netInfo.toString()) + + if (!netInfo.isConnectedOrConnecting()) return + + assertTrue(netInfo.isAvailable()) + if (State.CONNECTED == netInfo.getState()) { + assertTrue(netInfo.isConnected()) + } + assertTrue(State.CONNECTING == netInfo.getState() || + State.CONNECTED == netInfo.getState()) + assertTrue(DetailedState.SCANNING == netInfo.getDetailedState() || + DetailedState.CONNECTING == netInfo.getDetailedState() || + DetailedState.AUTHENTICATING == netInfo.getDetailedState() || + DetailedState.CONNECTED == netInfo.getDetailedState()) + } +} From d1818df99dfabdcd8a95ebc7539a71e77bf33b6c Mon Sep 17 00:00:00 2001 From: David Su Date: Thu, 12 Mar 2020 22:36:18 -0700 Subject: [PATCH 0866/1415] CTS: Add tests for RssiCurve (clean cherry-pick from AOSP) Bug: 151110495 Test: atest android.net.cts.RssiCurveTest Change-Id: Ife157773f7bdb07d62c5b9a66810328d9fd5ac91 Merged-In: Ife157773f7bdb07d62c5b9a66810328d9fd5ac91 --- .../src/android/net/cts/RssiCurveTest.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/RssiCurveTest.java diff --git a/tests/cts/net/src/android/net/cts/RssiCurveTest.java b/tests/cts/net/src/android/net/cts/RssiCurveTest.java new file mode 100644 index 0000000000..d651b7186b --- /dev/null +++ b/tests/cts/net/src/android/net/cts/RssiCurveTest.java @@ -0,0 +1,102 @@ +/* + * 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 com.google.common.truth.Truth.assertThat; + +import android.net.RssiCurve; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** CTS tests for {@link RssiCurve}. */ +@RunWith(AndroidJUnit4.class) +public class RssiCurveTest { + + @Test + public void lookupScore_constantCurve() { + // One bucket from rssi=-100 to 100 with score 10. + RssiCurve curve = new RssiCurve(-100, 200, new byte[] { 10 }); + assertThat(curve.lookupScore(-200)).isEqualTo(10); + assertThat(curve.lookupScore(-100)).isEqualTo(10); + assertThat(curve.lookupScore(0)).isEqualTo(10); + assertThat(curve.lookupScore(100)).isEqualTo(10); + assertThat(curve.lookupScore(200)).isEqualTo(10); + } + + @Test + public void lookupScore_changingCurve() { + // One bucket from -100 to 0 with score -10, and one bucket from 0 to 100 with score 10. + RssiCurve curve = new RssiCurve(-100, 100, new byte[] { -10, 10 }); + assertThat(curve.lookupScore(-200)).isEqualTo(-10); + assertThat(curve.lookupScore(-100)).isEqualTo(-10); + assertThat(curve.lookupScore(-50)).isEqualTo(-10); + assertThat(curve.lookupScore(0)).isEqualTo(10); + assertThat(curve.lookupScore(50)).isEqualTo(10); + assertThat(curve.lookupScore(100)).isEqualTo(10); + assertThat(curve.lookupScore(200)).isEqualTo(10); + } + + @Test + public void lookupScore_linearCurve() { + // Curve starting at -110, with 15 buckets of width 10 whose scores increases by 10 with + // each bucket. The current active network gets a boost of 15 to its RSSI. + RssiCurve curve = new RssiCurve( + -110, + 10, + new byte[] { -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 }, + 15); + + assertThat(curve.lookupScore(-120)).isEqualTo(-20); + assertThat(curve.lookupScore(-120, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-120, true)).isEqualTo(-20); + + assertThat(curve.lookupScore(-111)).isEqualTo(-20); + assertThat(curve.lookupScore(-111, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-111, true)).isEqualTo(-10); + + assertThat(curve.lookupScore(-110)).isEqualTo(-20); + assertThat(curve.lookupScore(-110, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-110, true)).isEqualTo(-10); + + assertThat(curve.lookupScore(-105)).isEqualTo(-20); + assertThat(curve.lookupScore(-105, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-105, true)).isEqualTo(0); + + assertThat(curve.lookupScore(-100)).isEqualTo(-10); + assertThat(curve.lookupScore(-100, false)).isEqualTo(-10); + assertThat(curve.lookupScore(-100, true)).isEqualTo(0); + + assertThat(curve.lookupScore(-50)).isEqualTo(40); + assertThat(curve.lookupScore(-50, false)).isEqualTo(40); + assertThat(curve.lookupScore(-50, true)).isEqualTo(50); + + assertThat(curve.lookupScore(0)).isEqualTo(90); + assertThat(curve.lookupScore(0, false)).isEqualTo(90); + assertThat(curve.lookupScore(0, true)).isEqualTo(100); + + assertThat(curve.lookupScore(30)).isEqualTo(120); + assertThat(curve.lookupScore(30, false)).isEqualTo(120); + assertThat(curve.lookupScore(30, true)).isEqualTo(120); + + assertThat(curve.lookupScore(40)).isEqualTo(120); + assertThat(curve.lookupScore(40, false)).isEqualTo(120); + assertThat(curve.lookupScore(40, true)).isEqualTo(120); + } +} From 8de7c96417adc1d0b31244d7e99344701072c32d Mon Sep 17 00:00:00 2001 From: Nate Jiang Date: Wed, 25 Mar 2020 14:19:54 -0700 Subject: [PATCH 0867/1415] Replace mock ScanResult with real one ScanResult is now a final class, mock will not work. Use real one instead. Bug: 152434349 Test: atest WifiRttTest Change-Id: I25daf0c2596a5a1a24726e68a79191ad4199b142 --- .../android/net/wifi/rtt/cts/WifiRttTest.java | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java index 49aa47ec38..9cbaf3953e 100644 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java +++ b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java @@ -72,10 +72,9 @@ public class WifiRttTest extends TestBase { // Scan for IEEE 802.11mc supporting APs ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); - assertTrue( + assertNotNull( "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " - + "your test setup includes them!", - testAp != null); + + "your test setup includes them!", testAp); // Perform RTT operations RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build(); @@ -100,16 +99,15 @@ public class WifiRttTest extends TestBase { callback.waitForCallback()); List currentResults = callback.getResults(); - assertTrue("Wi-Fi RTT results: null results (onRangingFailure) on iteration " + i, - currentResults != null); - assertTrue("Wi-Fi RTT results: unexpected # of results (expect 1) on iteration " + i, - currentResults.size() == 1); + assertNotNull("Wi-Fi RTT results: null results (onRangingFailure) on iteration " + i, + currentResults); + assertEquals("Wi-Fi RTT results: unexpected # of results (expect 1) on iteration " + i, + 1, currentResults.size()); RangingResult result = currentResults.get(0); - assertTrue("Wi-Fi RTT results: invalid result (wrong BSSID) entry on iteration " + i, - result.getMacAddress().toString().equals(testAp.BSSID)); - assertEquals( - "Wi-Fi RTT results: invalid result (non-null PeerHandle) entry on iteration " - + i, null, result.getPeerHandle()); + assertEquals("Wi-Fi RTT results: invalid result (wrong BSSID) entry on iteration " + i, + result.getMacAddress().toString(), testAp.BSSID); + assertNull("Wi-Fi RTT results: invalid result (non-null PeerHandle) entry on iteration " + + i, result.getPeerHandle()); allResults.add(result); int status = result.getStatus(); @@ -189,23 +187,24 @@ public class WifiRttTest extends TestBase { * Validate that when a request contains more range operations than allowed (by API) that we * get an exception. */ - public void testRequestTooLarge() { + public void testRequestTooLarge() throws InterruptedException { if (!shouldTestWifiRtt(getContext())) { return; } - - ScanResult dummy = mock(ScanResult.class); - dummy.BSSID = "00:01:02:03:04:05"; + ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); + assertNotNull( + "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " + + "your test setup includes them!", testAp); RangingRequest.Builder builder = new RangingRequest.Builder(); for (int i = 0; i < RangingRequest.getMaxPeers() - 2; ++i) { - builder.addAccessPoint(dummy); + builder.addAccessPoint(testAp); } List scanResults = new ArrayList<>(); - scanResults.add(dummy); - scanResults.add(dummy); - scanResults.add(dummy); + scanResults.add(testAp); + scanResults.add(testAp); + scanResults.add(testAp); builder.addAccessPoints(scanResults); @@ -215,10 +214,8 @@ public class WifiRttTest extends TestBase { return; } - assertTrue( - "Did not receive expected IllegalArgumentException when tried to range to too " - + "many peers", - false); + fail("Did not receive expected IllegalArgumentException when tried to range to too " + + "many peers"); } /** @@ -230,10 +227,9 @@ public class WifiRttTest extends TestBase { } // Scan for IEEE 802.11mc supporting APs ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); - assertTrue( + assertNotNull( "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " - + "your test setup includes them!", - testAp != null); + + "your test setup includes them!", testAp); // Perform RTT operations RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build(); From 932336bb81624b3882a23c827663df6d2d42c72f Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 25 Mar 2020 16:57:00 -0700 Subject: [PATCH 0868/1415] ConnectedNetworkScorerTest: Test for a getter in WifiUsabilityStatsEntry Missed in the initial check-in. Bug: 150236894 Test: atest android.net.wifi.cts.ConnectedNetworkScorerTest Change-Id: I081e6840083f5b6115c143cc57fc8f3132bdbe47 --- .../net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java b/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java index ce5bb81d7b..9624dd7c4d 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java @@ -174,6 +174,7 @@ public class ConnectedNetworkScorerTest extends AndroidTestCase { assertThat(statsEntry.getTotalHotspot2ScanTimeMillis()).isAtLeast(0L); assertThat(statsEntry.getTotalCcaBusyFreqTimeMillis()).isAtLeast(0L); assertThat(statsEntry.getTotalRadioOnTimeMillis()).isGreaterThan(0L); + assertThat(statsEntry.getTotalRadioOnFreqTimeMillis()).isGreaterThan(0L); assertThat(statsEntry.getTotalBeaconRx()).isGreaterThan(0L); assertThat(statsEntry.getProbeStatusSinceLastUpdate()) .isAnyOf(PROBE_STATUS_SUCCESS, From 6254c4a809a30b95bc227c9b41b24d2870e5e2a0 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Wed, 25 Mar 2020 09:21:17 +0000 Subject: [PATCH 0869/1415] Add NetworkInfo CTS tests Test APIs below: NetworkInfo(int, int, String, String) setDetailedState(android.net.NetworkInfo.DetailedState, String, String) Bug: 152356365 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkInfoTest on both Q and R devices Change-Id: Idada858b1d5cd4c0907998b289aca4d6e6d04f56 Merged-In: Idada858b1d5cd4c0907998b289aca4d6e6d04f56 (cherry picked from aosp/1267480) --- .../src/android/net/cts/NetworkInfoTest.kt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt index e1dca53620..fa15e8f82c 100644 --- a/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt @@ -16,16 +16,24 @@ package android.net.cts +import android.os.Build import android.content.Context import android.net.ConnectivityManager import android.net.NetworkInfo import android.net.NetworkInfo.DetailedState import android.net.NetworkInfo.State +import android.telephony.TelephonyManager import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Rule import org.junit.runner.RunWith import org.junit.Test @@ -33,10 +41,14 @@ const val TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE const val TYPE_WIFI = ConnectivityManager.TYPE_WIFI const val MOBILE_TYPE_NAME = "mobile" const val WIFI_TYPE_NAME = "WIFI" +const val LTE_SUBTYPE_NAME = "LTE" @SmallTest @RunWith(AndroidJUnit4::class) class NetworkInfoTest { + @Rule @JvmField + val ignoreRule = DevSdkIgnoreRule() + @Test fun testAccessNetworkInfoProperties() { val cm = InstrumentationRegistry.getInstrumentation().context @@ -70,4 +82,41 @@ class NetworkInfoTest { DetailedState.AUTHENTICATING == netInfo.getDetailedState() || DetailedState.CONNECTED == netInfo.getDetailedState()) } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testConstructor() { + val networkInfo = NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, + MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + + assertEquals(TYPE_MOBILE, networkInfo.type) + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, networkInfo.subtype) + assertEquals(MOBILE_TYPE_NAME, networkInfo.typeName) + assertEquals(LTE_SUBTYPE_NAME, networkInfo.subtypeName) + assertEquals(DetailedState.IDLE, networkInfo.detailedState) + assertEquals(State.UNKNOWN, networkInfo.state) + assertNull(networkInfo.reason) + assertNull(networkInfo.extraInfo) + + try { + NetworkInfo(ConnectivityManager.MAX_NETWORK_TYPE + 1, + TelephonyManager.NETWORK_TYPE_LTE, MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + fail("Unexpected behavior. Network type is invalid.") + } catch (e: IllegalArgumentException) { + // Expected behavior. + } + } + + @Test + fun testSetDetailedState() { + val networkInfo = NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, + MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + val reason = "TestNetworkInfo" + val extraReason = "setDetailedState test" + + networkInfo.setDetailedState(DetailedState.CONNECTED, reason, extraReason) + assertEquals(DetailedState.CONNECTED, networkInfo.detailedState) + assertEquals(State.CONNECTED, networkInfo.state) + assertEquals(reason, networkInfo.reason) + assertEquals(extraReason, networkInfo.extraInfo) + } } From 31097ecbb6a134689693f49e67cfa0911f5888e7 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Wed, 25 Mar 2020 10:49:39 +0000 Subject: [PATCH 0870/1415] Fix AudioGroupTest on Q The AudioGroup constructor with a Context parameter does not exist on Q devices. Use the previous constructor on older devices. Test: atest CtsNetTestCasesLatestSdk on Q and R devices Bug: 150918852 Merged-In: I24c3e7ab8c7219d6f345943ead3e3b6418fa7f47 Change-Id: I24c3e7ab8c7219d6f345943ead3e3b6418fa7f47 --- tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java index fee8621c70..fc78e96e11 100644 --- a/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java +++ b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java @@ -21,9 +21,12 @@ import android.net.rtp.AudioCodec; import android.net.rtp.AudioGroup; import android.net.rtp.AudioStream; import android.net.rtp.RtpStream; +import android.os.Build; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; +import androidx.core.os.BuildCompat; + import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; @@ -62,7 +65,10 @@ public class AudioGroupTest extends AndroidTestCase { mSocketB.connect(mStreamB.getLocalAddress(), mStreamB.getLocalPort()); mStreamB.associate(mSocketB.getLocalAddress(), mSocketB.getLocalPort()); - mGroup = new AudioGroup(mContext); + // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R) + mGroup = Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR() + ? new AudioGroup(mContext) + : new AudioGroup(); // Constructor with context argument was introduced in R } @Override From 210a4a7e555d37ac29090bdde8fb65f32f0041f1 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Thu, 19 Mar 2020 14:07:07 -0700 Subject: [PATCH 0871/1415] Add vts10 suite to existing vts tests This is to prepare renaming vts to vts10. Bug: 151896491 Test: local build Exempt-From-Owner-Approval: This CL adds all tests in vts to a new suite vts10. vts10 will be the new name of existing vts suite. This CL won't change test logic or behavior. Change-Id: Ic250f04f0424d0a586c183d571b0ad57c56a03d0 Merged-In: Icfbc0ef0d40b908dc9ef664bedf3ead563ff9855 Merged-In: Ibb8ca5e3b9d1cc7247f57d0d89bd15b9f52fec92 Merged-In: Ia9af1fbddc66d3c94976a58c36d274425f1fe461 --- tests/cts/hostside/Android.bp | 1 + tests/cts/hostside/app/Android.bp | 1 + tests/cts/hostside/app2/Android.bp | 1 + tests/cts/net/Android.bp | 1 + tests/cts/net/api23Test/Android.bp | 1 + tests/cts/net/appForApi23/Android.bp | 1 + tests/cts/net/native/qtaguid/Android.bp | 1 + 7 files changed, 7 insertions(+) diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp index b6f514233a..a8cc95ba5f 100644 --- a/tests/cts/hostside/Android.bp +++ b/tests/cts/hostside/Android.bp @@ -25,6 +25,7 @@ java_test_host { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], } diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index d66b71ba83..49aacd91a9 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp @@ -34,6 +34,7 @@ android_test_helper_app { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], } diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp index 8a3c8e712a..0bb0d2f631 100644 --- a/tests/cts/hostside/app2/Android.bp +++ b/tests/cts/hostside/app2/Android.bp @@ -24,6 +24,7 @@ android_test_helper_app { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], certificate: ":cts-net-app", diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 624d149776..d77f416557 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -65,6 +65,7 @@ android_test { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], test_config_template: "AndroidTestTemplate.xml", diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index ffe854e2e9..614a5a2a76 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -46,6 +46,7 @@ android_test { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], diff --git a/tests/cts/net/appForApi23/Android.bp b/tests/cts/net/appForApi23/Android.bp index 82e2a08c10..17cfe3821b 100644 --- a/tests/cts/net/appForApi23/Android.bp +++ b/tests/cts/net/appForApi23/Android.bp @@ -27,6 +27,7 @@ android_test { test_suites: [ "cts", "vts", + "vts10", "general-tests", ], diff --git a/tests/cts/net/native/qtaguid/Android.bp b/tests/cts/net/native/qtaguid/Android.bp index c0f0613040..054937b4fa 100644 --- a/tests/cts/net/native/qtaguid/Android.bp +++ b/tests/cts/net/native/qtaguid/Android.bp @@ -43,6 +43,7 @@ cc_test { test_suites: [ "cts", "vts", + "vts10", ], cflags: [ From 5fa1704f04b1a27fe2bfc95f7829a2e5240d8f2e Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Tue, 24 Mar 2020 19:52:44 +0000 Subject: [PATCH 0872/1415] Make framework-tethering stubs use the new defaults Makes it convenient to change all stubs from a central place. Bug: 149293194 Test: m framework-tethering-stubs{public,system,module_libs_}api Exempt-From-Owner-Approval: Approved internally Change-Id: I330133824e78b3a8927e3d3ffbbd729bcdcb8822 Merged-In: I330133824e78b3a8927e3d3ffbbd729bcdcb8822 (cherry picked from commit 7939cb0a4a8b7a167e19c64238ebfcbbc2245f9e) --- Tethering/common/TetheringLib/Android.bp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 00d0d9c428..6af5fe54f2 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -126,17 +126,17 @@ droidstubs { java_library { name: "framework-tethering-stubs-publicapi", srcs: [":framework-tethering-stubs-srcs-publicapi"], - sdk_version: "current", + defaults: ["framework-module-stubs-lib-defaults-publicapi"], } java_library { name: "framework-tethering-stubs-systemapi", srcs: [":framework-tethering-stubs-srcs-systemapi"], - sdk_version: "system_current", + defaults: ["framework-module-stubs-lib-defaults-systemapi"], } java_library { name: "framework-tethering-stubs-module_libs_api", srcs: [":framework-tethering-stubs-srcs-module_libs_api"], - sdk_version: "module_current", + defaults: ["framework-module-stubs-lib-defaults-systemapi"], } From 88357725e5d16ccfa2c80ca2c4b7ae700323a8e9 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Thu, 26 Mar 2020 09:07:28 -0700 Subject: [PATCH 0873/1415] [CTS] Fix testAddOrUpdatePasspointConfiguration in WifiManagerTest The API addOrUpdatePasspointConfiguration is deprecated on R and available only for privileged apps. Inherit Shell permissions. Bug: 152373068 Test: atest android.net.wifi.cts.WifiManagerTest#testAddOrUpdatePasspointConfiguration Change-Id: Iaedc1e67ecff116a540d7ac9f2f4e50696e459f8 --- .../android/net/wifi/cts/WifiManagerTest.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 3153149629..98846fa39b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -2471,15 +2471,21 @@ public class WifiManagerTest extends AndroidTestCase { // Create and install a Passpoint configuration PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); - mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); + UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); - // Compare configurations - List configurations = mWifiManager.getPasspointConfigurations(); - assertNotNull(configurations); - assertEquals(passpointConfiguration, configurations.get(0)); + // Compare configurations + List configurations = mWifiManager.getPasspointConfigurations(); + assertNotNull(configurations); + assertEquals(passpointConfiguration, configurations.get(0)); - // Clean up - mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); + // Clean up + mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); + } finally { + uiAutomation.dropShellPermissionIdentity(); + } } /** From 9db13f3b266f4474726194b690a186de90d4b7fa Mon Sep 17 00:00:00 2001 From: David Su Date: Thu, 19 Mar 2020 21:59:37 -0700 Subject: [PATCH 0874/1415] CTS: Split Wifi tests out of CtsNetTestCases Create CtsWifiTestCases. Bug: 129133376 Test: atest CtsWifiTestCases Change-Id: Iaa51f7ec86e6b4bfe64dcb26a8d8b818dd356608 --- tests/cts/net/src/android/net/wifi/OWNERS | 5 - .../net/wifi/aware/cts/SingleDeviceTest.java | 871 ------ .../android/net/wifi/aware/cts/TestUtils.java | 69 - .../android/net/wifi/cts/ConcurrencyTest.java | 704 ----- .../net/wifi/cts/ConfigParserTest.java | 114 - .../wifi/cts/ConnectedNetworkScorerTest.java | 345 --- .../cts/EasyConnectStatusCallbackTest.java | 170 -- .../src/android/net/wifi/cts/FakeKeys.java | 257 -- .../net/wifi/cts/MulticastLockTest.java | 79 - .../android/net/wifi/cts/NsdManagerTest.java | 592 ---- .../android/net/wifi/cts/PpsMoParserTest.java | 131 - .../android/net/wifi/cts/ScanResultTest.java | 331 --- .../net/wifi/cts/SupplicantStateTest.java | 42 - .../net/wifi/cts/WifiConfigurationTest.java | 51 - .../wifi/cts/WifiEnterpriseConfigTest.java | 899 ------ .../src/android/net/wifi/cts/WifiFeature.java | 32 - .../cts/WifiFrameworkInitializerTest.java | 40 - .../net/wifi/cts/WifiHotspot2Test.java | 488 ---- .../android/net/wifi/cts/WifiInfoTest.java | 255 -- .../android/net/wifi/cts/WifiLockTest.java | 92 - .../android/net/wifi/cts/WifiManagerTest.java | 2532 ----------------- .../net/wifi/cts/WifiMigrationTest.java | 138 - .../wifi/cts/WifiNetworkSpecifierTest.java | 562 ---- .../wifi/cts/WifiNetworkSuggestionTest.java | 268 -- .../cts/DeviceWiphyCapabilitiesTest.java | 99 - .../nl80211/cts/NativeWifiClientTest.java | 81 - .../net/wifi/nl80211/cts/PnoNetworkTest.java | 97 - .../net/wifi/nl80211/cts/PnoSettingsTest.java | 124 - .../wifi/nl80211/cts/RadioChainInfoTest.java | 83 - .../nl80211/cts/WifiNl80211ManagerTest.java | 84 - .../net/wifi/p2p/cts/WifiP2pConfigTest.java | 80 - .../net/wifi/p2p/cts/WifiP2pDeviceTest.java | 38 - .../net/wifi/p2p/cts/WifiP2pInfoTest.java | 60 - .../p2p/cts/WifiP2pServiceRequestTest.java | 75 - .../net/wifi/p2p/cts/WifiP2pWfdInfoTest.java | 50 - .../android/net/wifi/rtt/cts/TestBase.java | 237 -- .../android/net/wifi/rtt/cts/WifiRttTest.java | 404 --- 37 files changed, 10579 deletions(-) delete mode 100644 tests/cts/net/src/android/net/wifi/OWNERS delete mode 100644 tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/FakeKeys.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiFeature.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiFrameworkInitializerTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pInfoTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pWfdInfoTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/rtt/cts/TestBase.java delete mode 100644 tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java diff --git a/tests/cts/net/src/android/net/wifi/OWNERS b/tests/cts/net/src/android/net/wifi/OWNERS deleted file mode 100644 index 4a6001bcfe..0000000000 --- a/tests/cts/net/src/android/net/wifi/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -etancohen@google.com -lorenzo@google.com -mplass@google.com -rpius@google.com -satk@google.com diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java deleted file mode 100644 index 8f233244e8..0000000000 --- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ /dev/null @@ -1,871 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.aware.cts; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.mockito.Mockito.mock; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.location.LocationManager; -import android.net.ConnectivityManager; -import android.net.MacAddress; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.net.wifi.WifiManager; -import android.net.wifi.aware.AttachCallback; -import android.net.wifi.aware.Characteristics; -import android.net.wifi.aware.DiscoverySession; -import android.net.wifi.aware.DiscoverySessionCallback; -import android.net.wifi.aware.IdentityChangedListener; -import android.net.wifi.aware.ParcelablePeerHandle; -import android.net.wifi.aware.PeerHandle; -import android.net.wifi.aware.PublishConfig; -import android.net.wifi.aware.PublishDiscoverySession; -import android.net.wifi.aware.SubscribeConfig; -import android.net.wifi.aware.SubscribeDiscoverySession; -import android.net.wifi.aware.WifiAwareManager; -import android.net.wifi.aware.WifiAwareNetworkSpecifier; -import android.net.wifi.aware.WifiAwareSession; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Parcel; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -import com.android.compatibility.common.util.SystemUtil; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Wi-Fi Aware CTS test suite: single device testing. Performs tests on a single - * device to validate Wi-Fi Aware. - */ -@AppModeFull(reason = "Cannot get WifiAwareManager in instant app mode") -public class SingleDeviceTest extends AndroidTestCase { - private static final String TAG = "WifiAwareCtsTests"; - - // wait for Wi-Fi Aware state changes & network requests callbacks - static private final int WAIT_FOR_AWARE_CHANGE_SECS = 10; // 10 seconds - private static final int MIN_DISTANCE_MM = 1 * 1000; - private static final int MAX_DISTANCE_MM = 3 * 1000; - private static final byte[] PMK_VALID = "01234567890123456789012345678901".getBytes(); - - private final Object mLock = new Object(); - private final HandlerThread mHandlerThread = new HandlerThread("SingleDeviceTest"); - private final Handler mHandler; - { - mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()); - } - - private WifiAwareManager mWifiAwareManager; - private WifiManager mWifiManager; - private WifiManager.WifiLock mWifiLock; - private ConnectivityManager mConnectivityManager; - - // used to store any WifiAwareSession allocated during tests - will clean-up after tests - private List mSessions = new ArrayList<>(); - - private class WifiAwareBroadcastReceiver extends BroadcastReceiver { - private CountDownLatch mBlocker = new CountDownLatch(1); - - @Override - public void onReceive(Context context, Intent intent) { - if (WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED.equals(intent.getAction())) { - mBlocker.countDown(); - } - } - - boolean waitForStateChange() throws InterruptedException { - return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); - } - } - - private class AttachCallbackTest extends AttachCallback { - static final int ATTACHED = 0; - static final int ATTACH_FAILED = 1; - static final int ERROR = 2; // no callback: timeout, interruption - - private CountDownLatch mBlocker = new CountDownLatch(1); - private int mCallbackCalled = ERROR; // garbage init - private WifiAwareSession mSession = null; - - @Override - public void onAttached(WifiAwareSession session) { - mCallbackCalled = ATTACHED; - mSession = session; - synchronized (mLock) { - mSessions.add(session); - } - mBlocker.countDown(); - } - - @Override - public void onAttachFailed() { - mCallbackCalled = ATTACH_FAILED; - mBlocker.countDown(); - } - - /** - * Waits for any of the callbacks to be called - or an error (timeout, interruption). - * Returns one of the ATTACHED, ATTACH_FAILED, or ERROR values. - */ - int waitForAnyCallback() { - try { - boolean noTimeout = mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); - if (noTimeout) { - return mCallbackCalled; - } else { - return ERROR; - } - } catch (InterruptedException e) { - return ERROR; - } - } - - /** - * Access the session created by a callback. Only useful to be called after calling - * waitForAnyCallback() and getting the ATTACHED code back. - */ - WifiAwareSession getSession() { - return mSession; - } - } - - private class IdentityChangedListenerTest extends IdentityChangedListener { - private CountDownLatch mBlocker = new CountDownLatch(1); - private byte[] mMac = null; - - @Override - public void onIdentityChanged(byte[] mac) { - mMac = mac; - mBlocker.countDown(); - } - - /** - * Waits for the listener callback to be called - or an error (timeout, interruption). - * Returns true on callback called, false on error (timeout, interruption). - */ - boolean waitForListener() { - try { - return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - return false; - } - } - - /** - * Returns the MAC address of the discovery interface supplied to the triggered callback. - */ - byte[] getMac() { - return mMac; - } - } - - private class DiscoverySessionCallbackTest extends DiscoverySessionCallback { - static final int ON_PUBLISH_STARTED = 0; - static final int ON_SUBSCRIBE_STARTED = 1; - static final int ON_SESSION_CONFIG_UPDATED = 2; - static final int ON_SESSION_CONFIG_FAILED = 3; - static final int ON_SESSION_TERMINATED = 4; - static final int ON_SERVICE_DISCOVERED = 5; - static final int ON_MESSAGE_SEND_SUCCEEDED = 6; - static final int ON_MESSAGE_SEND_FAILED = 7; - static final int ON_MESSAGE_RECEIVED = 8; - - private final Object mLocalLock = new Object(); - - private CountDownLatch mBlocker; - private int mCurrentWaitForCallback; - private ArrayDeque mCallbackQueue = new ArrayDeque<>(); - - private PublishDiscoverySession mPublishDiscoverySession; - private SubscribeDiscoverySession mSubscribeDiscoverySession; - - private void processCallback(int callback) { - synchronized (mLocalLock) { - if (mBlocker != null && mCurrentWaitForCallback == callback) { - mBlocker.countDown(); - } else { - mCallbackQueue.addLast(callback); - } - } - } - - @Override - public void onPublishStarted(PublishDiscoverySession session) { - mPublishDiscoverySession = session; - processCallback(ON_PUBLISH_STARTED); - } - - @Override - public void onSubscribeStarted(SubscribeDiscoverySession session) { - mSubscribeDiscoverySession = session; - processCallback(ON_SUBSCRIBE_STARTED); - } - - @Override - public void onSessionConfigUpdated() { - processCallback(ON_SESSION_CONFIG_UPDATED); - } - - @Override - public void onSessionConfigFailed() { - processCallback(ON_SESSION_CONFIG_FAILED); - } - - @Override - public void onSessionTerminated() { - processCallback(ON_SESSION_TERMINATED); - } - - @Override - public void onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo, - List matchFilter) { - processCallback(ON_SERVICE_DISCOVERED); - } - - @Override - public void onMessageSendSucceeded(int messageId) { - processCallback(ON_MESSAGE_SEND_SUCCEEDED); - } - - @Override - public void onMessageSendFailed(int messageId) { - processCallback(ON_MESSAGE_SEND_FAILED); - } - - @Override - public void onMessageReceived(PeerHandle peerHandle, byte[] message) { - processCallback(ON_MESSAGE_RECEIVED); - } - - /** - * Wait for the specified callback - any of the ON_* constants. Returns a true - * on success (specified callback triggered) or false on failure (timed-out or - * interrupted while waiting for the requested callback). - * - * Note: other callbacks happening while while waiting for the specified callback will - * be queued. - */ - boolean waitForCallback(int callback) { - return waitForCallback(callback, WAIT_FOR_AWARE_CHANGE_SECS); - } - - /** - * Wait for the specified callback - any of the ON_* constants. Returns a true - * on success (specified callback triggered) or false on failure (timed-out or - * interrupted while waiting for the requested callback). - * - * Same as waitForCallback(int callback) execpt that allows specifying a custom timeout. - * The default timeout is a short value expected to be sufficient for all behaviors which - * should happen relatively quickly. Specifying a custom timeout should only be done for - * those cases which are known to take a specific longer period of time. - * - * Note: other callbacks happening while while waiting for the specified callback will - * be queued. - */ - boolean waitForCallback(int callback, int timeoutSec) { - synchronized (mLocalLock) { - boolean found = mCallbackQueue.remove(callback); - if (found) { - return true; - } - - mCurrentWaitForCallback = callback; - mBlocker = new CountDownLatch(1); - } - - try { - return mBlocker.await(timeoutSec, TimeUnit.SECONDS); - } catch (InterruptedException e) { - return false; - } - } - - /** - * Indicates whether the specified callback (any of the ON_* constants) has already - * happened and in the queue. Useful when the order of events is important. - */ - boolean hasCallbackAlreadyHappened(int callback) { - synchronized (mLocalLock) { - return mCallbackQueue.contains(callback); - } - } - - /** - * Returns the last created publish discovery session. - */ - PublishDiscoverySession getPublishDiscoverySession() { - PublishDiscoverySession session = mPublishDiscoverySession; - mPublishDiscoverySession = null; - return session; - } - - /** - * Returns the last created subscribe discovery session. - */ - SubscribeDiscoverySession getSubscribeDiscoverySession() { - SubscribeDiscoverySession session = mSubscribeDiscoverySession; - mSubscribeDiscoverySession = null; - return session; - } - } - - private class NetworkCallbackTest extends ConnectivityManager.NetworkCallback { - private CountDownLatch mBlocker = new CountDownLatch(1); - - @Override - public void onUnavailable() { - mBlocker.countDown(); - } - - /** - * Wait for the onUnavailable() callback to be triggered. Returns true if triggered, - * otherwise (timed-out, interrupted) returns false. - */ - boolean waitForOnUnavailable() { - try { - return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - return false; - } - } - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - assertTrue("Wi-Fi Aware requires Location to be Enabled", - ((LocationManager) getContext().getSystemService( - Context.LOCATION_SERVICE)).isLocationEnabled()); - - mWifiAwareManager = (WifiAwareManager) getContext().getSystemService( - Context.WIFI_AWARE_SERVICE); - assertNotNull("Wi-Fi Aware Manager", mWifiAwareManager); - - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull("Wi-Fi Manager", mWifiManager); - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) { - SystemUtil.runShellCommand("svc wifi enable"); - } - - mConnectivityManager = (ConnectivityManager) getContext().getSystemService( - Context.CONNECTIVITY_SERVICE); - assertNotNull("Connectivity Manager", mConnectivityManager); - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); - WifiAwareBroadcastReceiver receiver = new WifiAwareBroadcastReceiver(); - mContext.registerReceiver(receiver, intentFilter); - if (!mWifiAwareManager.isAvailable()) { - assertTrue("Timeout waiting for Wi-Fi Aware to change status", - receiver.waitForStateChange()); - assertTrue("Wi-Fi Aware is not available (should be)", mWifiAwareManager.isAvailable()); - } - } - - @Override - protected void tearDown() throws Exception { - if (!TestUtils.shouldTestWifiAware(getContext())) { - super.tearDown(); - return; - } - - synchronized (mLock) { - for (WifiAwareSession session : mSessions) { - // no damage from destroying twice (i.e. ok if test cleaned up after itself already) - session.close(); - } - mSessions.clear(); - } - - super.tearDown(); - } - - /** - * Validate: - * - Characteristics are available - * - Characteristics values are legitimate. Not in the CDD. However, the tested values are - * based on the Wi-Fi Aware protocol. - */ - public void testCharacteristics() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - Characteristics characteristics = mWifiAwareManager.getCharacteristics(); - assertNotNull("Wi-Fi Aware characteristics are null", characteristics); - assertEquals("Service Name Length", characteristics.getMaxServiceNameLength(), 255); - assertEquals("Service Specific Information Length", - characteristics.getMaxServiceSpecificInfoLength(), 255); - assertEquals("Match Filter Length", characteristics.getMaxMatchFilterLength(), 255); - assertNotEquals("Cipher suites", characteristics.getSupportedCipherSuites(), 0); - } - - /** - * Validate that on Wi-Fi Aware availability change we get a broadcast + the API returns - * correct status. - */ - public void testAvailabilityStatusChange() throws Exception { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); - - // 1. Disable Wi-Fi - WifiAwareBroadcastReceiver receiver1 = new WifiAwareBroadcastReceiver(); - mContext.registerReceiver(receiver1, intentFilter); - SystemUtil.runShellCommand("svc wifi disable"); - - assertTrue("Timeout waiting for Wi-Fi Aware to change status", - receiver1.waitForStateChange()); - assertFalse("Wi-Fi Aware is available (should not be)", mWifiAwareManager.isAvailable()); - - // 2. Enable Wi-Fi - WifiAwareBroadcastReceiver receiver2 = new WifiAwareBroadcastReceiver(); - mContext.registerReceiver(receiver2, intentFilter); - SystemUtil.runShellCommand("svc wifi enable"); - - assertTrue("Timeout waiting for Wi-Fi Aware to change status", - receiver2.waitForStateChange()); - assertTrue("Wi-Fi Aware is not available (should be)", mWifiAwareManager.isAvailable()); - } - - /** - * Validate that can attach to Wi-Fi Aware. - */ - public void testAttachNoIdentity() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - WifiAwareSession session = attachAndGetSession(); - session.close(); - } - - /** - * Validate that can attach to Wi-Fi Aware and get identity information. Use the identity - * information to validate that MAC address changes on every attach. - * - * Note: relies on no other entity using Wi-Fi Aware during the CTS test. Since if it is used - * then the attach/destroy will not correspond to enable/disable and will not result in a new - * MAC address being generated. - */ - public void testAttachDiscoveryAddressChanges() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final int numIterations = 10; - Set macs = new HashSet<>(); - - for (int i = 0; i < numIterations; ++i) { - AttachCallbackTest attachCb = new AttachCallbackTest(); - IdentityChangedListenerTest identityL = new IdentityChangedListenerTest(); - mWifiAwareManager.attach(attachCb, identityL, mHandler); - assertEquals("Wi-Fi Aware attach: iteration " + i, AttachCallbackTest.ATTACHED, - attachCb.waitForAnyCallback()); - assertTrue("Wi-Fi Aware attach: iteration " + i, identityL.waitForListener()); - - WifiAwareSession session = attachCb.getSession(); - assertNotNull("Wi-Fi Aware session: iteration " + i, session); - - byte[] mac = identityL.getMac(); - assertNotNull("Wi-Fi Aware discovery MAC: iteration " + i, mac); - - session.close(); - - macs.add(new TestUtils.MacWrapper(mac)); - } - - assertEquals("", numIterations, macs.size()); - } - - /** - * Validate a successful publish discovery session lifetime: publish, update publish, destroy. - */ - public void testPublishDiscoverySuccess() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final String serviceName = "ValidName"; - - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - serviceName).build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. publish - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); - assertNotNull("Publish session", discoverySession); - - // 2. update-publish - publishConfig = new PublishConfig.Builder().setServiceName( - serviceName).setServiceSpecificInfo("extras".getBytes()).build(); - discoverySession.updatePublish(publishConfig); - assertTrue("Publish update", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - // 3. destroy - assertFalse("Publish not terminated", discoveryCb.hasCallbackAlreadyHappened( - DiscoverySessionCallbackTest.ON_SESSION_TERMINATED)); - discoverySession.close(); - - // 4. try update post-destroy: should time-out waiting for cb - discoverySession.updatePublish(publishConfig); - assertFalse("Publish update post destroy", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - session.close(); - } - - /** - * Validate that publish with a Time To Live (TTL) setting expires within the specified - * time (and validates that the terminate callback is triggered). - */ - public void testPublishLimitedTtlSuccess() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final String serviceName = "ValidName"; - final int ttlSec = 5; - - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - serviceName).setTtlSec(ttlSec).setTerminateNotificationEnabled(true).build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. publish - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); - assertNotNull("Publish session", discoverySession); - - // 2. wait for terminate within 'ttlSec'. - assertTrue("Publish terminated", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SESSION_TERMINATED, - ttlSec + 5)); - - // 3. try update post-termination: should time-out waiting for cb - publishConfig = new PublishConfig.Builder().setServiceName( - serviceName).setServiceSpecificInfo("extras".getBytes()).build(); - discoverySession.updatePublish(publishConfig); - assertFalse("Publish update post terminate", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - session.close(); - } - - /** - * Validate a successful subscribe discovery session lifetime: subscribe, update subscribe, - * destroy. - */ - public void testSubscribeDiscoverySuccess() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final String serviceName = "ValidName"; - - WifiAwareSession session = attachAndGetSession(); - - SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName( - serviceName).build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. subscribe - session.subscribe(subscribeConfig, discoveryCb, mHandler); - assertTrue("Subscribe started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SUBSCRIBE_STARTED)); - SubscribeDiscoverySession discoverySession = discoveryCb.getSubscribeDiscoverySession(); - assertNotNull("Subscribe session", discoverySession); - - // 2. update-subscribe - subscribeConfig = new SubscribeConfig.Builder().setServiceName( - serviceName).setServiceSpecificInfo("extras".getBytes()) - .setMinDistanceMm(MIN_DISTANCE_MM).build(); - discoverySession.updateSubscribe(subscribeConfig); - assertTrue("Subscribe update", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - // 3. destroy - assertFalse("Subscribe not terminated", discoveryCb.hasCallbackAlreadyHappened( - DiscoverySessionCallbackTest.ON_SESSION_TERMINATED)); - discoverySession.close(); - - // 4. try update post-destroy: should time-out waiting for cb - discoverySession.updateSubscribe(subscribeConfig); - assertFalse("Subscribe update post destroy", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - session.close(); - } - - /** - * Validate that subscribe with a Time To Live (TTL) setting expires within the specified - * time (and validates that the terminate callback is triggered). - */ - public void testSubscribeLimitedTtlSuccess() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - final String serviceName = "ValidName"; - final int ttlSec = 5; - - WifiAwareSession session = attachAndGetSession(); - - SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName( - serviceName).setTtlSec(ttlSec).setTerminateNotificationEnabled(true).build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. subscribe - session.subscribe(subscribeConfig, discoveryCb, mHandler); - assertTrue("Subscribe started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SUBSCRIBE_STARTED)); - SubscribeDiscoverySession discoverySession = discoveryCb.getSubscribeDiscoverySession(); - assertNotNull("Subscribe session", discoverySession); - - // 2. wait for terminate within 'ttlSec'. - assertTrue("Subscribe terminated", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SESSION_TERMINATED, - ttlSec + 5)); - - // 3. try update post-termination: should time-out waiting for cb - subscribeConfig = new SubscribeConfig.Builder().setServiceName( - serviceName).setServiceSpecificInfo("extras".getBytes()).build(); - discoverySession.updateSubscribe(subscribeConfig); - assertFalse("Subscribe update post terminate", discoveryCb.waitForCallback( - DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED)); - - session.close(); - } - - /** - * Test the send message flow. Since testing single device cannot send to a real peer - - * validate that sending to a bogus peer fails. - */ - public void testSendMessageFail() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - "ValidName").build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - - // 1. publish - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession(); - assertNotNull("Publish session", discoverySession); - - // 2. send a message with a null peer-handle - expect exception - try { - discoverySession.sendMessage(null, -1290, "some message".getBytes()); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // empty - } - - discoverySession.close(); - session.close(); - } - - /** - * Request an Aware data-path (open) as a Responder with an arbitrary peer MAC address. Validate - * that receive an onUnavailable() callback. - */ - public void testDataPathOpenOutOfBandFail() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - MacAddress mac = MacAddress.fromString("00:01:02:03:04:05"); - - // 1. initialize Aware: only purpose is to make sure it is available for OOB data-path - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - "ValidName").build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - - // 2. request an AWARE network - NetworkCallbackTest networkCb = new NetworkCallbackTest(); - NetworkRequest nr = new NetworkRequest.Builder().addTransportType( - NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( - session.createNetworkSpecifierOpen( - WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, - mac.toByteArray())).build(); - mConnectivityManager.requestNetwork(nr, networkCb); - assertTrue("OnUnavailable not received", networkCb.waitForOnUnavailable()); - - session.close(); - } - - /** - * Request an Aware data-path (encrypted with Passphrase) as a Responder with an arbitrary peer - * MAC address. - * Validate that receive an onUnavailable() callback. - */ - public void testDataPathPassphraseOutOfBandFail() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - MacAddress mac = MacAddress.fromString("00:01:02:03:04:05"); - - // 1. initialize Aware: only purpose is to make sure it is available for OOB data-path - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - "ValidName").build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - - // 2. request an AWARE network - NetworkCallbackTest networkCb = new NetworkCallbackTest(); - NetworkRequest nr = new NetworkRequest.Builder().addTransportType( - NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( - session.createNetworkSpecifierPassphrase( - WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, mac.toByteArray(), - "abcdefghihk")).build(); - mConnectivityManager.requestNetwork(nr, networkCb); - assertTrue("OnUnavailable not received", networkCb.waitForOnUnavailable()); - - session.close(); - } - - /** - * Request an Aware data-path (encrypted with PMK) as a Responder with an arbitrary peer MAC - * address. - * Validate that receive an onUnavailable() callback. - */ - public void testDataPathPmkOutOfBandFail() { - if (!TestUtils.shouldTestWifiAware(getContext())) { - return; - } - MacAddress mac = MacAddress.fromString("00:01:02:03:04:05"); - - // 1. initialize Aware: only purpose is to make sure it is available for OOB data-path - WifiAwareSession session = attachAndGetSession(); - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( - "ValidName").build(); - DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest(); - session.publish(publishConfig, discoveryCb, mHandler); - assertTrue("Publish started", - discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED)); - - // 2. request an AWARE network - NetworkCallbackTest networkCb = new NetworkCallbackTest(); - NetworkRequest nr = new NetworkRequest.Builder().addTransportType( - NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( - session.createNetworkSpecifierPmk( - WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, mac.toByteArray(), - PMK_VALID)).build(); - mConnectivityManager.requestNetwork(nr, networkCb); - assertTrue("OnUnavailable not received", networkCb.waitForOnUnavailable()); - - session.close(); - } - - /** - * Test WifiAwareNetworkSpecifier. - */ - public void testWifiAwareNetworkSpecifier() { - DiscoverySession session = mock(DiscoverySession.class); - PeerHandle handle = mock(PeerHandle.class); - WifiAwareNetworkSpecifier networkSpecifier = - new WifiAwareNetworkSpecifier.Builder(session, handle).build(); - assertFalse(networkSpecifier.satisfiedBy(null)); - assertTrue(networkSpecifier.satisfiedBy(networkSpecifier)); - - WifiAwareNetworkSpecifier anotherNetworkSpecifier = - new WifiAwareNetworkSpecifier.Builder(session, handle).setPmk(PMK_VALID).build(); - assertFalse(networkSpecifier.satisfiedBy(anotherNetworkSpecifier)); - } - - /** - * Test ParcelablePeerHandle parcel. - */ - public void testParcelablePeerHandle() { - PeerHandle peerHandle = mock(PeerHandle.class); - ParcelablePeerHandle parcelablePeerHandle = new ParcelablePeerHandle(peerHandle); - Parcel parcelW = Parcel.obtain(); - parcelablePeerHandle.writeToParcel(parcelW, 0); - byte[] bytes = parcelW.marshall(); - parcelW.recycle(); - - Parcel parcelR = Parcel.obtain(); - parcelR.unmarshall(bytes, 0, bytes.length); - parcelR.setDataPosition(0); - ParcelablePeerHandle rereadParcelablePeerHandle = - ParcelablePeerHandle.CREATOR.createFromParcel(parcelR); - - assertEquals(parcelablePeerHandle, rereadParcelablePeerHandle); - assertEquals(parcelablePeerHandle.hashCode(), rereadParcelablePeerHandle.hashCode()); - } - - // local utilities - - private WifiAwareSession attachAndGetSession() { - AttachCallbackTest attachCb = new AttachCallbackTest(); - mWifiAwareManager.attach(attachCb, mHandler); - int cbCalled = attachCb.waitForAnyCallback(); - assertEquals("Wi-Fi Aware attach", AttachCallbackTest.ATTACHED, cbCalled); - - WifiAwareSession session = attachCb.getSession(); - assertNotNull("Wi-Fi Aware session", session); - - return session; - } -} diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java b/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java deleted file mode 100644 index a12c8bb0d2..0000000000 --- a/tests/cts/net/src/android/net/wifi/aware/cts/TestUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.aware.cts; - -import android.content.Context; -import android.content.pm.PackageManager; - -import java.util.Arrays; - -/** - * Test utilities for Wi-Fi Aware CTS test suite. - */ -class TestUtils { - static final String TAG = "WifiAwareCtsTests"; - - /** - * Returns a flag indicating whether or not Wi-Fi Aware should be tested. Wi-Fi Aware - * should be tested if the feature is supported on the current device. - */ - static boolean shouldTestWifiAware(Context context) { - final PackageManager pm = context.getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE); - } - - /** - * Wraps a byte[] (MAC address representation). Intended to provide hash and equality operators - * so that the MAC address can be used in containers. - */ - static class MacWrapper { - private byte[] mMac; - - MacWrapper(byte[] mac) { - mMac = mac; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof MacWrapper)) { - return false; - } - - MacWrapper lhs = (MacWrapper) o; - return Arrays.equals(mMac, lhs.mMac); - } - - @Override - public int hashCode() { - return Arrays.hashCode(mMac); - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java deleted file mode 100644 index d91bce8319..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java +++ /dev/null @@ -1,704 +0,0 @@ -/* - * Copyright (C) 2012 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.wifi.cts; - -import static org.junit.Assert.assertNotEquals; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkRequest; -import android.net.wifi.WifiManager; -import android.net.wifi.p2p.WifiP2pDevice; -import android.net.wifi.p2p.WifiP2pGroup; -import android.net.wifi.p2p.WifiP2pGroupList; -import android.net.wifi.p2p.WifiP2pInfo; -import android.net.wifi.p2p.WifiP2pManager; -import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; -import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo; -import android.provider.Settings; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; -import android.util.Log; - -import com.android.compatibility.common.util.ShellIdentityUtils; -import com.android.compatibility.common.util.SystemUtil; - -import java.util.Arrays; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class ConcurrencyTest extends AndroidTestCase { - private class MySync { - static final int WIFI_STATE = 0; - static final int P2P_STATE = 1; - static final int DISCOVERY_STATE = 2; - static final int NETWORK_INFO = 3; - - public BitSet pendingSync = new BitSet(); - - public int expectedWifiState; - public int expectedP2pState; - public int expectedDiscoveryState; - public NetworkInfo expectedNetworkInfo; - } - - private class MyResponse { - public boolean valid = false; - - public boolean success; - public int p2pState; - public int discoveryState; - public NetworkInfo networkInfo; - public WifiP2pInfo p2pInfo; - public String deviceName; - public WifiP2pGroupList persistentGroups; - public WifiP2pGroup group = new WifiP2pGroup(); - } - - private WifiManager mWifiManager; - private WifiP2pManager mWifiP2pManager; - private WifiP2pManager.Channel mWifiP2pChannel; - private MySync mMySync = new MySync(); - private MyResponse mMyResponse = new MyResponse(); - private boolean mWasVerboseLoggingEnabled; - - private static final String TAG = "ConcurrencyTest"; - private static final int TIMEOUT_MSEC = 6000; - private static final int WAIT_MSEC = 60; - private static final int DURATION = 10000; - private IntentFilter mIntentFilter; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.pendingSync.set(MySync.WIFI_STATE); - mMySync.expectedWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_DISABLED); - mMySync.notify(); - } - } else if(action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.pendingSync.set(MySync.P2P_STATE); - mMySync.expectedP2pState = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, - WifiP2pManager.WIFI_P2P_STATE_DISABLED); - mMySync.notify(); - } - } else if (action.equals(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.pendingSync.set(MySync.DISCOVERY_STATE); - mMySync.expectedDiscoveryState = intent.getIntExtra( - WifiP2pManager.EXTRA_DISCOVERY_STATE, - WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); - mMySync.notify(); - } - } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.pendingSync.set(MySync.NETWORK_INFO); - mMySync.expectedNetworkInfo = (NetworkInfo) intent.getExtra( - WifiP2pManager.EXTRA_NETWORK_INFO, null); - mMySync.notify(); - } - } - } - }; - - private WifiP2pManager.ActionListener mActionListener = new WifiP2pManager.ActionListener() { - @Override - public void onSuccess() { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.success = true; - mMyResponse.notify(); - } - } - - @Override - public void onFailure(int reason) { - synchronized (mMyResponse) { - Log.d(TAG, "failure reason: " + reason); - mMyResponse.valid = true; - mMyResponse.success = false; - mMyResponse.notify(); - } - } - }; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext()) && - !WifiFeature.isP2pSupported(getContext())) { - // skip the test if WiFi && p2p are not supported - return; - } - - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); - mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); - - mContext.registerReceiver(mReceiver, mIntentFilter); - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull(mWifiManager); - if (mWifiManager.isWifiEnabled()) { - SystemUtil.runShellCommand("svc wifi disable"); - Thread.sleep(DURATION); - } - - // turn on verbose logging for tests - mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.isVerboseLoggingEnabled()); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(true)); - - assertTrue(!mWifiManager.isWifiEnabled()); - mMySync.expectedWifiState = WifiManager.WIFI_STATE_DISABLED; - mMySync.expectedP2pState = WifiP2pManager.WIFI_P2P_STATE_DISABLED; - mMySync.expectedDiscoveryState = WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED; - mMySync.expectedNetworkInfo = null; - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext()) && - !WifiFeature.isP2pSupported(getContext())) { - // skip the test if WiFi and p2p are not supported - super.tearDown(); - return; - } - mContext.unregisterReceiver(mReceiver); - - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); - - enableWifi(); - super.tearDown(); - } - - private boolean waitForBroadcasts(List waitSyncList) { - synchronized (mMySync) { - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout) { - List handledSyncList = waitSyncList.stream() - .filter(w -> mMySync.pendingSync.get(w)) - .collect(Collectors.toList()); - handledSyncList.forEach(w -> mMySync.pendingSync.clear(w)); - waitSyncList.removeAll(handledSyncList); - if (waitSyncList.isEmpty()) { - break; - } - try { - mMySync.wait(WAIT_MSEC); - } catch (InterruptedException e) { } - } - if (!waitSyncList.isEmpty()) { - Log.i(TAG, "Missing broadcast: " + waitSyncList); - } - return waitSyncList.isEmpty(); - } - } - - private boolean waitForBroadcasts(int waitSingleSync) { - return waitForBroadcasts( - new LinkedList(Arrays.asList(waitSingleSync))); - } - - private boolean waitForServiceResponse(MyResponse waitResponse) { - synchronized (waitResponse) { - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout) { - try { - waitResponse.wait(WAIT_MSEC); - } catch (InterruptedException e) { } - - if (waitResponse.valid) { - return true; - } - } - return false; - } - } - - // Return true if location is enabled. - private boolean isLocationEnabled() { - return Settings.Secure.getInt(getContext().getContentResolver(), - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) - != Settings.Secure.LOCATION_MODE_OFF; - } - - // Returns true if the device has location feature. - private boolean hasLocationFeature() { - return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); - } - - private void resetResponse(MyResponse responseObj) { - synchronized (responseObj) { - responseObj.valid = false; - responseObj.networkInfo = null; - responseObj.p2pInfo = null; - responseObj.deviceName = null; - responseObj.persistentGroups = null; - responseObj.group = null; - } - } - - /* - * Enables Wifi and block until connection is established. - */ - private void enableWifi() throws InterruptedException { - if (!mWifiManager.isWifiEnabled()) { - SystemUtil.runShellCommand("svc wifi enable"); - } - - ConnectivityManager cm = - (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkRequest request = - new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - final CountDownLatch latch = new CountDownLatch(1); - NetworkCallback networkCallback = new NetworkCallback() { - @Override - public void onAvailable(Network network) { - latch.countDown(); - } - }; - cm.registerNetworkCallback(request, networkCallback); - latch.await(DURATION, TimeUnit.MILLISECONDS); - - cm.unregisterNetworkCallback(networkCallback); - } - - private boolean setupWifiP2p() { - // Cannot support p2p alone - if (!WifiFeature.isWifiSupported(getContext())) { - assertTrue(!WifiFeature.isP2pSupported(getContext())); - return false; - } - - if (!WifiFeature.isP2pSupported(getContext())) { - // skip the test if p2p is not supported - return false; - } - - if (!hasLocationFeature()) { - Log.d(TAG, "Skipping test as location is not supported"); - return false; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since P-release WiFi Direct" - + " needs Location enabled."); - } - - mWifiP2pManager = - (WifiP2pManager) getContext().getSystemService(Context.WIFI_P2P_SERVICE); - mWifiP2pChannel = mWifiP2pManager.initialize( - getContext(), getContext().getMainLooper(), null); - - assertNotNull(mWifiP2pManager); - assertNotNull(mWifiP2pChannel); - - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (!mWifiManager.isWifiEnabled() && System.currentTimeMillis() < timeout) { - try { - enableWifi(); - } catch (InterruptedException e) { } - } - - assertTrue(mWifiManager.isWifiEnabled()); - - assertTrue(waitForBroadcasts( - new LinkedList( - Arrays.asList(MySync.WIFI_STATE, MySync.P2P_STATE)))); - - assertEquals(WifiManager.WIFI_STATE_ENABLED, mMySync.expectedWifiState); - assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMySync.expectedP2pState); - - assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); - // wait for changing to EnabledState - assertNotNull(mMySync.expectedNetworkInfo); - - return true; - } - - public void testConcurrency() { - if (!setupWifiP2p()) { - return; - } - - resetResponse(mMyResponse); - mWifiP2pManager.requestP2pState(mWifiP2pChannel, new WifiP2pManager.P2pStateListener() { - @Override - public void onP2pStateAvailable(int state) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.p2pState = state; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMyResponse.p2pState); - } - - public void testRequestDiscoveryState() { - if (!setupWifiP2p()) { - return; - } - - resetResponse(mMyResponse); - mWifiP2pManager.requestDiscoveryState( - mWifiP2pChannel, new WifiP2pManager.DiscoveryStateListener() { - @Override - public void onDiscoveryStateAvailable(int state) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.discoveryState = state; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED, mMyResponse.discoveryState); - - resetResponse(mMyResponse); - mWifiP2pManager.discoverPeers(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - assertTrue(waitForBroadcasts(MySync.DISCOVERY_STATE)); - - resetResponse(mMyResponse); - mWifiP2pManager.requestDiscoveryState(mWifiP2pChannel, - new WifiP2pManager.DiscoveryStateListener() { - @Override - public void onDiscoveryStateAvailable(int state) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.discoveryState = state; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED, mMyResponse.discoveryState); - - mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, null); - } - - public void testRequestNetworkInfo() { - if (!setupWifiP2p()) { - return; - } - - resetResponse(mMyResponse); - mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel, - new WifiP2pManager.NetworkInfoListener() { - @Override - public void onNetworkInfoAvailable(NetworkInfo info) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.networkInfo = info; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertNotNull(mMyResponse.networkInfo); - // The state might be IDLE, DISCONNECTED, FAILED before a connection establishment. - // Just ensure the state is NOT CONNECTED. - assertNotEquals(NetworkInfo.DetailedState.CONNECTED, - mMySync.expectedNetworkInfo.getDetailedState()); - - resetResponse(mMyResponse); - mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); - assertNotNull(mMySync.expectedNetworkInfo); - assertEquals(NetworkInfo.DetailedState.CONNECTED, - mMySync.expectedNetworkInfo.getDetailedState()); - - resetResponse(mMyResponse); - mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel, - new WifiP2pManager.NetworkInfoListener() { - @Override - public void onNetworkInfoAvailable(NetworkInfo info) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.networkInfo = info; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertNotNull(mMyResponse.networkInfo); - assertEquals(NetworkInfo.DetailedState.CONNECTED, - mMyResponse.networkInfo.getDetailedState()); - - resetResponse(mMyResponse); - mWifiP2pManager.requestConnectionInfo(mWifiP2pChannel, - new WifiP2pManager.ConnectionInfoListener() { - @Override - public void onConnectionInfoAvailable(WifiP2pInfo info) { - synchronized (mMyResponse) { - mMyResponse.valid = true; - mMyResponse.p2pInfo = new WifiP2pInfo(info); - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertNotNull(mMyResponse.p2pInfo); - assertTrue(mMyResponse.p2pInfo.groupFormed); - assertTrue(mMyResponse.p2pInfo.isGroupOwner); - - resetResponse(mMyResponse); - mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, - new WifiP2pManager.GroupInfoListener() { - @Override - public void onGroupInfoAvailable(WifiP2pGroup group) { - synchronized (mMyResponse) { - mMyResponse.group = new WifiP2pGroup(group); - mMyResponse.valid = true; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - assertNotNull(mMyResponse.group); - assertNotEquals(0, mMyResponse.group.getFrequency()); - assertTrue(mMyResponse.group.getNetworkId() >= 0); - - resetResponse(mMyResponse); - mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - } - - private String getDeviceName() { - resetResponse(mMyResponse); - mWifiP2pManager.requestDeviceInfo(mWifiP2pChannel, - new WifiP2pManager.DeviceInfoListener() { - @Override - public void onDeviceInfoAvailable(WifiP2pDevice wifiP2pDevice) { - synchronized (mMyResponse) { - mMyResponse.deviceName = wifiP2pDevice.deviceName; - mMyResponse.valid = true; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - return mMyResponse.deviceName; - } - - public void testSetDeviceName() { - if (!setupWifiP2p()) { - return; - } - - String testDeviceName = "test"; - String originalDeviceName = getDeviceName(); - assertNotNull(originalDeviceName); - - ShellIdentityUtils.invokeWithShellPermissions(() -> { - mWifiP2pManager.setDeviceName( - mWifiP2pChannel, testDeviceName, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - }); - - String currentDeviceName = getDeviceName(); - assertEquals(testDeviceName, currentDeviceName); - - // restore the device name at the end - ShellIdentityUtils.invokeWithShellPermissions(() -> { - mWifiP2pManager.setDeviceName( - mWifiP2pChannel, originalDeviceName, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - }); - } - - private WifiP2pGroupList getPersistentGroups() { - resetResponse(mMyResponse); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - mWifiP2pManager.requestPersistentGroupInfo(mWifiP2pChannel, - new WifiP2pManager.PersistentGroupInfoListener() { - @Override - public void onPersistentGroupInfoAvailable(WifiP2pGroupList groups) { - synchronized (mMyResponse) { - mMyResponse.persistentGroups = groups; - mMyResponse.valid = true; - mMyResponse.notify(); - } - } - }); - assertTrue(waitForServiceResponse(mMyResponse)); - }); - return mMyResponse.persistentGroups; - } - - public void testPersistentGroupOperation() { - if (!setupWifiP2p()) { - return; - } - - resetResponse(mMyResponse); - mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); - assertNotNull(mMySync.expectedNetworkInfo); - assertEquals(NetworkInfo.DetailedState.CONNECTED, - mMySync.expectedNetworkInfo.getDetailedState()); - - resetResponse(mMyResponse); - mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - - WifiP2pGroupList persistentGroups = getPersistentGroups(); - assertNotNull(persistentGroups); - assertEquals(1, persistentGroups.getGroupList().size()); - - resetResponse(mMyResponse); - final int firstNetworkId = persistentGroups.getGroupList().get(0).getNetworkId(); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - mWifiP2pManager.deletePersistentGroup(mWifiP2pChannel, - firstNetworkId, - mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - }); - - persistentGroups = getPersistentGroups(); - assertNotNull(persistentGroups); - assertEquals(0, persistentGroups.getGroupList().size()); - - resetResponse(mMyResponse); - mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); - assertNotNull(mMySync.expectedNetworkInfo); - assertEquals(NetworkInfo.DetailedState.CONNECTED, - mMySync.expectedNetworkInfo.getDetailedState()); - - resetResponse(mMyResponse); - mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - - resetResponse(mMyResponse); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - mWifiP2pManager.factoryReset(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - }); - - persistentGroups = getPersistentGroups(); - assertNotNull(persistentGroups); - assertEquals(0, persistentGroups.getGroupList().size()); - } - - public void testP2pListening() { - if (!setupWifiP2p()) { - return; - } - - resetResponse(mMyResponse); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - mWifiP2pManager.setWifiP2pChannels(mWifiP2pChannel, 6, 11, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - }); - - resetResponse(mMyResponse); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - mWifiP2pManager.startListening(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - }); - - resetResponse(mMyResponse); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - mWifiP2pManager.stopListening(mWifiP2pChannel, mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - }); - } - - public void testP2pService() { - if (!setupWifiP2p()) { - return; - } - - // This only store the listener to the WifiP2pManager internal variable, nothing to fail. - mWifiP2pManager.setServiceResponseListener(mWifiP2pChannel, - new WifiP2pManager.ServiceResponseListener() { - @Override - public void onServiceAvailable( - int protocolType, byte[] responseData, WifiP2pDevice srcDevice) { - } - }); - - resetResponse(mMyResponse); - List services = new ArrayList(); - services.add("urn:schemas-upnp-org:service:AVTransport:1"); - services.add("urn:schemas-upnp-org:service:ConnectionManager:1"); - WifiP2pServiceInfo rendererService = WifiP2pUpnpServiceInfo.newInstance( - "6859dede-8574-59ab-9332-123456789011", - "urn:schemas-upnp-org:device:MediaRenderer:1", - services); - mWifiP2pManager.addLocalService(mWifiP2pChannel, - rendererService, - mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - - resetResponse(mMyResponse); - mWifiP2pManager.removeLocalService(mWifiP2pChannel, - rendererService, - mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - - resetResponse(mMyResponse); - mWifiP2pManager.clearLocalServices(mWifiP2pChannel, - mActionListener); - assertTrue(waitForServiceResponse(mMyResponse)); - assertTrue(mMyResponse.success); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java b/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java deleted file mode 100644 index 52ed2a6d73..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/ConfigParserTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.cts; - -import android.net.wifi.hotspot2.ConfigParser; -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.pps.Credential; -import android.net.wifi.hotspot2.pps.HomeSp; -import android.test.AndroidTestCase; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Arrays; - -/** - * CTS tests for Hotspot 2.0 Release 1 installation file parsing API. - */ -public class ConfigParserTest extends AndroidTestCase { - /** - * Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a - * CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}. - */ - private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT = - "assets/HSR1ProfileWithCACert.base64"; - - /** - * Read the content of the given resource file into a String. - * - * @param filename String name of the file - * @return String - * @throws IOException - */ - private String loadResourceFile(String filename) throws IOException { - InputStream in = getClass().getClassLoader().getResourceAsStream(filename); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - StringBuilder builder = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - builder.append(line).append("\n"); - } - - return builder.toString(); - } - - /** - * Generate a {@link PasspointConfiguration} that matches the configuration specified in the - * XML file {@link #PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT}. - * - * @return {@link PasspointConfiguration} - */ - private PasspointConfiguration generateConfigurationFromProfile() { - PasspointConfiguration config = new PasspointConfiguration(); - - // HomeSP configuration. - HomeSp homeSp = new HomeSp(); - homeSp.setFriendlyName("Century House"); - homeSp.setFqdn("mi6.co.uk"); - homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L}); - config.setHomeSp(homeSp); - - // Credential configuration. - Credential credential = new Credential(); - credential.setRealm("shaken.stirred.com"); - Credential.UserCredential userCredential = new Credential.UserCredential(); - userCredential.setUsername("james"); - userCredential.setPassword("Ym9uZDAwNw=="); - userCredential.setEapType(21); - userCredential.setNonEapInnerMethod("MS-CHAP-V2"); - credential.setUserCredential(userCredential); - Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); - certCredential.setCertType("x509v3"); - byte[] certSha256Fingerprint = new byte[32]; - Arrays.fill(certSha256Fingerprint, (byte)0x1f); - certCredential.setCertSha256Fingerprint(certSha256Fingerprint); - credential.setCertCredential(certCredential); - Credential.SimCredential simCredential = new Credential.SimCredential(); - simCredential.setImsi("imsi"); - simCredential.setEapType(24); - credential.setSimCredential(simCredential); - credential.setCaCertificate(FakeKeys.CA_CERT0); - config.setCredential(credential); - return config; - } - - /** - * Verify a valid installation file is parsed successfully with the matching contents. - * - * @throws Exception - */ - public void testParseConfigFile() throws Exception { - String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT); - PasspointConfiguration expectedConfig = generateConfigurationFromProfile(); - PasspointConfiguration actualConfig = - ConfigParser.parsePasspointConfig( - "application/x-wifi-config", configStr.getBytes()); - assertTrue(actualConfig.equals(expectedConfig)); - } -} \ No newline at end of file diff --git a/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java b/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java deleted file mode 100644 index 9624dd7c4d..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * 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.wifi.cts; - -import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE; -import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE; -import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS; -import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.UiAutomation; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiUsabilityStatsEntry; -import android.support.test.uiautomator.UiDevice; -import android.telephony.TelephonyManager; -import android.test.AndroidTestCase; - -import androidx.test.platform.app.InstrumentationRegistry; - -import com.android.compatibility.common.util.PollingCheck; -import com.android.compatibility.common.util.ShellIdentityUtils; -import com.android.compatibility.common.util.SystemUtil; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -public class ConnectedNetworkScorerTest extends AndroidTestCase { - private WifiManager mWifiManager; - private UiDevice mUiDevice; - private boolean mWasVerboseLoggingEnabled; - - private static final int DURATION = 10_000; - private static final int DURATION_SCREEN_TOGGLE = 2000; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager = getContext().getSystemService(WifiManager.class); - assertThat(mWifiManager).isNotNull(); - - // turn on verbose logging for tests - mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.isVerboseLoggingEnabled()); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(true)); - - if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - turnScreenOn(); - PollingCheck.check("Wifi not enabled", DURATION, () -> mWifiManager.isWifiEnabled()); - List savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.getConfiguredNetworks()); - assertFalse("Need at least one saved network", savedNetworks.isEmpty()); - // Wait for wifi is to be connected - PollingCheck.check( - "Wifi not connected", - DURATION, - () -> mWifiManager.getConnectionInfo().getNetworkId() != -1); - assertThat(mWifiManager.getConnectionInfo().getNetworkId()).isNotEqualTo(-1); - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - turnScreenOff(); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); - super.tearDown(); - } - - private void setWifiEnabled(boolean enable) throws Exception { - // now trigger the change using shell commands. - SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable")); - } - - private void turnScreenOn() throws Exception { - mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); - mUiDevice.executeShellCommand("wm dismiss-keyguard"); - // Since the screen on/off intent is ordered, they will not be sent right now. - Thread.sleep(DURATION_SCREEN_TOGGLE); - } - - private void turnScreenOff() throws Exception { - mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); - } - - private static class TestUsabilityStatsListener implements - WifiManager.OnWifiUsabilityStatsListener { - private final CountDownLatch mCountDownLatch; - public int seqNum; - public boolean isSameBssidAndFre; - public WifiUsabilityStatsEntry statsEntry; - - TestUsabilityStatsListener(CountDownLatch countDownLatch) { - mCountDownLatch = countDownLatch; - } - - @Override - public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, - WifiUsabilityStatsEntry statsEntry) { - this.seqNum = seqNum; - this.isSameBssidAndFre = isSameBssidAndFreq; - this.statsEntry = statsEntry; - mCountDownLatch.countDown(); - } - } - - /** - * Tests the {@link android.net.wifi.WifiUsabilityStatsEntry} retrieved from - * {@link WifiManager.OnWifiUsabilityStatsListener}. - */ - public void testWifiUsabilityStatsEntry() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - CountDownLatch countDownLatch = new CountDownLatch(1); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - TestUsabilityStatsListener usabilityStatsListener = - new TestUsabilityStatsListener(countDownLatch); - try { - uiAutomation.adoptShellPermissionIdentity(); - mWifiManager.addOnWifiUsabilityStatsListener( - Executors.newSingleThreadExecutor(), usabilityStatsListener); - // Wait for new usability stats (while connected & screen on this is triggered - // by platform periodically). - assertThat(countDownLatch.await(DURATION, TimeUnit.MILLISECONDS)).isTrue(); - - assertThat(usabilityStatsListener.statsEntry).isNotNull(); - WifiUsabilityStatsEntry statsEntry = usabilityStatsListener.statsEntry; - - assertThat(statsEntry.getTimeStampMillis()).isGreaterThan(0L); - assertThat(statsEntry.getRssi()).isLessThan(0); - assertThat(statsEntry.getLinkSpeedMbps()).isGreaterThan(0); - assertThat(statsEntry.getTotalTxSuccess()).isGreaterThan(0L); - assertThat(statsEntry.getTotalTxRetries()).isAtLeast(0L); - assertThat(statsEntry.getTotalTxBad()).isAtLeast(0L); - assertThat(statsEntry.getTotalRxSuccess()).isAtLeast(0L); - assertThat(statsEntry.getTotalRadioOnTimeMillis()).isGreaterThan(0L); - assertThat(statsEntry.getTotalRadioTxTimeMillis()).isGreaterThan(0L); - assertThat(statsEntry.getTotalRadioRxTimeMillis()).isGreaterThan(0L); - assertThat(statsEntry.getTotalScanTimeMillis()).isGreaterThan(0L); - assertThat(statsEntry.getTotalNanScanTimeMillis()).isAtLeast(0L); - assertThat(statsEntry.getTotalBackgroundScanTimeMillis()).isAtLeast(0L); - assertThat(statsEntry.getTotalRoamScanTimeMillis()).isAtLeast(0L); - assertThat(statsEntry.getTotalPnoScanTimeMillis()).isAtLeast(0L); - assertThat(statsEntry.getTotalHotspot2ScanTimeMillis()).isAtLeast(0L); - assertThat(statsEntry.getTotalCcaBusyFreqTimeMillis()).isAtLeast(0L); - assertThat(statsEntry.getTotalRadioOnTimeMillis()).isGreaterThan(0L); - assertThat(statsEntry.getTotalRadioOnFreqTimeMillis()).isGreaterThan(0L); - assertThat(statsEntry.getTotalBeaconRx()).isGreaterThan(0L); - assertThat(statsEntry.getProbeStatusSinceLastUpdate()) - .isAnyOf(PROBE_STATUS_SUCCESS, - PROBE_STATUS_FAILURE, - PROBE_STATUS_NO_PROBE, - PROBE_STATUS_UNKNOWN); - // -1 is default value for some of these fields if they're not available. - assertThat(statsEntry.getProbeElapsedTimeSinceLastUpdateMillis()).isAtLeast(-1); - assertThat(statsEntry.getProbeMcsRateSinceLastUpdate()).isAtLeast(-1); - assertThat(statsEntry.getRxLinkSpeedMbps()).isAtLeast(-1); - // no longer populated, return default value. - assertThat(statsEntry.getCellularDataNetworkType()) - .isAnyOf(TelephonyManager.NETWORK_TYPE_UNKNOWN, - TelephonyManager.NETWORK_TYPE_GPRS, - TelephonyManager.NETWORK_TYPE_EDGE, - TelephonyManager.NETWORK_TYPE_UMTS, - TelephonyManager.NETWORK_TYPE_CDMA, - TelephonyManager.NETWORK_TYPE_EVDO_0, - TelephonyManager.NETWORK_TYPE_EVDO_A, - TelephonyManager.NETWORK_TYPE_1xRTT, - TelephonyManager.NETWORK_TYPE_HSDPA, - TelephonyManager.NETWORK_TYPE_HSUPA, - TelephonyManager.NETWORK_TYPE_HSPA, - TelephonyManager.NETWORK_TYPE_IDEN, - TelephonyManager.NETWORK_TYPE_EVDO_B, - TelephonyManager.NETWORK_TYPE_LTE, - TelephonyManager.NETWORK_TYPE_EHRPD, - TelephonyManager.NETWORK_TYPE_HSPAP, - TelephonyManager.NETWORK_TYPE_GSM, - TelephonyManager.NETWORK_TYPE_TD_SCDMA, - TelephonyManager.NETWORK_TYPE_IWLAN, - TelephonyManager.NETWORK_TYPE_NR); - assertThat(statsEntry.getCellularSignalStrengthDbm()).isAtMost(0); - assertThat(statsEntry.getCellularSignalStrengthDb()).isAtMost(0); - assertThat(statsEntry.isSameRegisteredCell()).isFalse(); - } finally { - mWifiManager.removeOnWifiUsabilityStatsListener(usabilityStatsListener); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests the {@link android.net.wifi.WifiManager#updateWifiUsabilityScore(int, int, int)} - */ - public void testUpdateWifiUsabilityScore() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - try { - uiAutomation.adoptShellPermissionIdentity(); - // update scoring with dummy values. - mWifiManager.updateWifiUsabilityScore(0, 50, 50); - } finally { - uiAutomation.dropShellPermissionIdentity(); - } - } - - private static class TestConnectedNetworkScorer implements - WifiManager.WifiConnectedNetworkScorer { - private CountDownLatch mCountDownLatch; - public int startSessionId; - public int stopSessionId; - public WifiManager.ScoreUpdateObserver scoreUpdateObserver; - - TestConnectedNetworkScorer(CountDownLatch countDownLatch) { - mCountDownLatch = countDownLatch; - } - - @Override - public void onStart(int sessionId) { - synchronized (mCountDownLatch) { - this.startSessionId = sessionId; - mCountDownLatch.countDown(); - } - } - - @Override - public void onStop(int sessionId) { - synchronized (mCountDownLatch) { - this.stopSessionId = sessionId; - mCountDownLatch.countDown(); - } - } - - @Override - public void onSetScoreUpdateObserver(WifiManager.ScoreUpdateObserver observerImpl) { - this.scoreUpdateObserver = observerImpl; - } - - public void resetCountDownLatch(CountDownLatch countDownLatch) { - synchronized (mCountDownLatch) { - mCountDownLatch = countDownLatch; - } - } - } - - /** - * Tests the {@link android.net.wifi.WifiConnectedNetworkScorer} interface. - * - * Note: We could write more interesting test cases (if the device has a mobile connection), but - * that would make the test flaky. The default network/route selection on the device is not just - * controlled by the wifi scorer input, but also based on params which are controlled by - * other parts of the platform (likely in connectivity service) and hence will behave - * differently on OEM devices. - */ - public void testSetWifiConnectedNetworkScorer() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - CountDownLatch countDownLatchScorer = new CountDownLatch(1); - CountDownLatch countDownLatchUsabilityStats = new CountDownLatch(1); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - TestConnectedNetworkScorer connectedNetworkScorer = - new TestConnectedNetworkScorer(countDownLatchScorer); - TestUsabilityStatsListener usabilityStatsListener = - new TestUsabilityStatsListener(countDownLatchUsabilityStats); - try { - uiAutomation.adoptShellPermissionIdentity(); - mWifiManager.setWifiConnectedNetworkScorer( - Executors.newSingleThreadExecutor(), connectedNetworkScorer); - // Since we're already connected, wait for onStart to be invoked. - assertThat(countDownLatchScorer.await(DURATION, TimeUnit.MILLISECONDS)).isTrue(); - - assertThat(connectedNetworkScorer.startSessionId).isAtLeast(0); - assertThat(connectedNetworkScorer.scoreUpdateObserver).isNotNull(); - WifiManager.ScoreUpdateObserver scoreUpdateObserver = - connectedNetworkScorer.scoreUpdateObserver; - - // Now trigger a dummy score update. - scoreUpdateObserver.notifyScoreUpdate(connectedNetworkScorer.startSessionId, 50); - - // Register the usability listener - mWifiManager.addOnWifiUsabilityStatsListener( - Executors.newSingleThreadExecutor(), usabilityStatsListener); - // Trigger a usability stats update. - scoreUpdateObserver.triggerUpdateOfWifiUsabilityStats( - connectedNetworkScorer.startSessionId); - // Ensure that we got the stats update callback. - assertThat(countDownLatchUsabilityStats.await(DURATION, TimeUnit.MILLISECONDS)) - .isTrue(); - assertThat(usabilityStatsListener.seqNum).isAtLeast(0); - - // Reset the scorer countdown latch for onStop - countDownLatchScorer = new CountDownLatch(1); - connectedNetworkScorer.resetCountDownLatch(countDownLatchScorer); - // Now disconnect from the network. - mWifiManager.disconnect(); - // Wait for it to be disconnected. - PollingCheck.check( - "Wifi not disconnected", - DURATION, - () -> mWifiManager.getConnectionInfo().getNetworkId() == -1); - assertThat(mWifiManager.getConnectionInfo().getNetworkId()).isEqualTo(-1); - - // Wait for stop to be invoked and ensure that the session id matches. - assertThat(countDownLatchScorer.await(DURATION, TimeUnit.MILLISECONDS)).isTrue(); - assertThat(connectedNetworkScorer.stopSessionId) - .isEqualTo(connectedNetworkScorer.startSessionId); - } finally { - mWifiManager.removeOnWifiUsabilityStatsListener(usabilityStatsListener); - mWifiManager.clearWifiConnectedNetworkScorer(); - uiAutomation.dropShellPermissionIdentity(); - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java b/tests/cts/net/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java deleted file mode 100644 index eef50a0059..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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.wifi.cts; - -import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_TIMEOUT; -import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK; -import static android.net.wifi.WifiManager.EASY_CONNECT_NETWORK_ROLE_STA; - -import android.app.UiAutomation; -import android.content.Context; -import android.net.wifi.EasyConnectStatusCallback; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; -import android.os.Handler; -import android.os.HandlerExecutor; -import android.os.HandlerThread; -import android.test.AndroidTestCase; -import android.util.SparseArray; -import androidx.test.platform.app.InstrumentationRegistry; - -import java.util.concurrent.Executor; - -public class EasyConnectStatusCallbackTest extends AndroidTestCase { - private static final String TEST_SSID = "\"testSsid\""; - private static final String TEST_PASSPHRASE = "\"testPassword\""; - private static final int TEST_WAIT_DURATION_MS = 12_000; // Long delay is necessary, see below - private WifiManager mWifiManager; - private static final String TEST_DPP_URI = - "DPP:C:81/1;I:Easy_Connect_Demo;M:000102030405;" - + "K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACDmtXD1Sz6/5B4YRdmTkbkkFLDwk8f0yRnfm1Go" - + "kpx/0=;;"; - private final HandlerThread mHandlerThread = new HandlerThread("EasyConnectTest"); - protected final Executor mExecutor; - { - mHandlerThread.start(); - mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper())); - } - private final Object mLock = new Object(); - private boolean mOnFailureCallback = false; - private int mErrorCode; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - private EasyConnectStatusCallback mEasyConnectStatusCallback = new EasyConnectStatusCallback() { - @Override - public void onEnrolleeSuccess(int newNetworkId) { - - } - - @Override - public void onConfiguratorSuccess(int code) { - - } - - @Override - public void onProgress(int code) { - - } - - @Override - public void onFailure(int code) { - synchronized (mLock) { - mOnFailureCallback = true; - mErrorCode = code; - mLock.notify(); - } - } - - public void onFailure(int code, String ssid, SparseArray channelListArray, - int[] operatingClassArray) { - synchronized (mLock) { - mOnFailureCallback = true; - mErrorCode = code; - mLock.notify(); - } - } - }; - - /** - * Tests {@link android.net.wifi.EasyConnectStatusCallback} class. - * - * Since Easy Connect requires 2 devices, start Easy Connect session and expect an error. - */ - public void testConfiguratorInitiatorOnFailure() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - try { - uiAutomation.adoptShellPermissionIdentity(); - WifiConfiguration config; - config = new WifiConfiguration(); - config.SSID = TEST_SSID; - config.preSharedKey = TEST_PASSPHRASE; - config.setSecurityParams(SECURITY_TYPE_PSK); - int networkId = mWifiManager.addNetwork(config); - assertFalse(networkId == -1); - synchronized (mLock) { - mWifiManager.startEasyConnectAsConfiguratorInitiator(TEST_DPP_URI, networkId, - EASY_CONNECT_NETWORK_ROLE_STA, mExecutor, mEasyConnectStatusCallback); - // Note: A long delay is necessary because there is no enrollee, and the system - // tries to discover it. We will wait for a timeout error to occur. - mLock.wait(TEST_WAIT_DURATION_MS); - } - mWifiManager.removeNetwork(networkId); - assertTrue(mOnFailureCallback); - assertEquals(EASY_CONNECT_EVENT_FAILURE_TIMEOUT, mErrorCode); - mWifiManager.stopEasyConnectSession(); - } finally { - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link android.net.wifi.EasyConnectStatusCallback} class. - * - * Since Easy Connect requires 2 devices, start Easy Connect session and expect an error. - */ - public void testEnrolleeInitiatorOnFailure() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - try { - uiAutomation.adoptShellPermissionIdentity(); - synchronized (mLock) { - mWifiManager.startEasyConnectAsEnrolleeInitiator(TEST_DPP_URI, mExecutor, - mEasyConnectStatusCallback); - // Note: A long delay is necessary because there is no configurator, and the system - // tries to discover it. We will wait for a timeout error to occur. - mLock.wait(TEST_WAIT_DURATION_MS); - } - assertTrue(mOnFailureCallback); - assertEquals(EASY_CONNECT_EVENT_FAILURE_TIMEOUT, mErrorCode); - mWifiManager.stopEasyConnectSession(); - } finally { - uiAutomation.dropShellPermissionIdentity(); - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java b/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java deleted file mode 100644 index f8753017db..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/FakeKeys.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2016 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.wifi.cts; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; - -/** - * A class containing test certificates and private keys. - */ -public class FakeKeys { - private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" + - "MIIDKDCCAhCgAwIBAgIJAILlFdwzLVurMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" + - "BAMTB0VBUCBDQTEwHhcNMTYwMTEyMTE1MDE1WhcNMjYwMTA5MTE1MDE1WjASMRAw\n" + - "DgYDVQQDEwdFQVAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" + - "znAPUz26Msae4ws43czR41/J2QtrSIZUKmVUsVumDbYHrPNvTXKSMXAcewORDQYX\n" + - "RqvHvpn8CscB1+oGXZvHwxj4zV0WKoK2zeXkau3vcyl3HIKupJfq2TEACefVjj0t\n" + - "JW+X35PGWp9/H5zIUNVNVjS7Ums84IvKhRB8512PB9UyHagXYVX5GWpAcVpyfrlR\n" + - "FI9Qdhh+Pbk0uyktdbf/CdfgHOoebrTtwRljM0oDtX+2Cv6j0wBK7hD8pPvf1+uy\n" + - "GzczigAU/4Kw7eZqydf9B+5RupR+IZipX41xEiIrKRwqi517WWzXcjaG2cNbf451\n" + - "xpH5PnV3i1tq04jMGQUzFwIDAQABo4GAMH4wHQYDVR0OBBYEFIwX4vs8BiBcScod\n" + - "5noZHRM8E4+iMEIGA1UdIwQ7MDmAFIwX4vs8BiBcScod5noZHRM8E4+ioRakFDAS\n" + - "MRAwDgYDVQQDEwdFQVAgQ0ExggkAguUV3DMtW6swDAYDVR0TBAUwAwEB/zALBgNV\n" + - "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFfQqOTA7Rv7K+luQ7pnas4BYwHE\n" + - "9GEP/uohv6KOy0TGQFbrRTjFoLVNB9BZ1ymMDZ0/TIwIUc7wi7a8t5mEqYH153wW\n" + - "aWooiSjyLLhuI4sNrNCOtisdBq2r2MFXt6h0mAQYOPv8R8K7/fgSxGFqzhyNmmVL\n" + - "1qBJldx34SpwsTALQVPb4hGwJzZfr1PcpEQx6xMnTl8xEWZE3Ms99uaUxbQqIwRu\n" + - "LgAOkNCmY2m89VhzaHJ1uV85AdM/tD+Ysmlnnjt9LRCejbBipjIGjOXrg1JP+lxV\n" + - "muM4vH+P/mlmxsPPz0d65b+EGmJZpoLkO/tdNNvCYzjJpTEWpEsO6NMhKYo=\n" + - "-----END CERTIFICATE-----\n"; - public static final X509Certificate CA_CERT0 = loadCertificate(CA_CERT0_STRING); - - private static final String CA_CERT1_STRING = "-----BEGIN CERTIFICATE-----\n" + - "MIIDKDCCAhCgAwIBAgIJAOM5SzKO2pzCMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" + - "BAMTB0VBUCBDQTAwHhcNMTYwMTEyMDAxMDQ3WhcNMjYwMTA5MDAxMDQ3WjASMRAw\n" + - "DgYDVQQDEwdFQVAgQ0EwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" + - "89ug+IEKVQXnJGKg5g4uVHg6J/8iRUxR5k2eH5o03hrJNMfN2D+cBe/wCiZcnWbI\n" + - "GbGZACWm2nQth2wy9Zgm2LOd3b4ocrHYls3XLq6Qb5Dd7a0JKU7pdGufiNVEkrmF\n" + - "EB+N64wgwH4COTvCiN4erp5kyJwkfqAl2xLkZo0C464c9XoyQOXbmYD9A8v10wZu\n" + - "jyNsEo7Nr2USyw+qhjWSbFbEirP77Tvx+7pJQJwdtk1V9Tn73T2dGF2WHYejei9S\n" + - "mcWpdIUqsu9etYH+zDmtu7I1xlkwiaVsNr2+D+qaCJyOYqrDTKVNK5nmbBPXDWZc\n" + - "NoDbTOoqquX7xONpq9M6jQIDAQABo4GAMH4wHQYDVR0OBBYEFAZ3A2S4qJZZwuNY\n" + - "wkJ6mAdc0gVdMEIGA1UdIwQ7MDmAFAZ3A2S4qJZZwuNYwkJ6mAdc0gVdoRakFDAS\n" + - "MRAwDgYDVQQDEwdFQVAgQ0EwggkA4zlLMo7anMIwDAYDVR0TBAUwAwEB/zALBgNV\n" + - "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHmdMwEhtys4d0E+t7owBmoVR+lU\n" + - "hMCcRtWs8YKX5WIM2kTweT0h/O1xwE1mWmRv/IbDAEb8od4BjAQLhIcolStr2JaO\n" + - "9ZzyxjOnNzqeErh/1DHDbb/moPpqfeJ8YiEz7nH/YU56Q8iCPO7TsgS0sNNE7PfN\n" + - "IUsBW0yHRgpQ4OxWmiZG2YZWiECRzAC0ecPzo59N5iH4vLQIMTMYquiDeMPQnn1e\n" + - "NDGxG8gCtDKIaS6tMg3a28MvWB094pr2ETou8O1C8Ji0Y4hE8QJmSdT7I4+GZjgW\n" + - "g94DZ5RiL7sdp3vC48CXOmeT61YBIvhGUsE1rPhXqkpqQ3Z3C4TFF0jXZZc=\n" + - "-----END CERTIFICATE-----\n"; - public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING); - - private static final String CA_PUBLIC_CERT_STRING = "-----BEGIN CERTIFICATE-----\n" + - "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\n" + - "GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\n" + - "b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\n" + - "BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\n" + - "VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\n" + - "DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\n" + - "THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\n" + - "Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\n" + - "c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\n" + - "gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" + - "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\n" + - "AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\n" + - "Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\n" + - "j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\n" + - "hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\n" + - "X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n" + - "-----END CERTIFICATE-----\n"; - public static final X509Certificate CA_PUBLIC_CERT = loadCertificate(CA_PUBLIC_CERT_STRING); - - private static final String CLIENT_CERT_STR = "-----BEGIN CERTIFICATE-----\n" + - "MIIE/DCCAuQCAQEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxCzAJBgNV\n" + - "BAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdUZXN0aW5n\n" + - "MB4XDTE2MDkzMDIwNTQyOFoXDTE3MDkzMDIwNTQyOFowRDELMAkGA1UEBhMCVVMx\n" + - "CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdU\n" + - "ZXN0aW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnpmcbuaeHfnJ\n" + - "k+2QNvxmdVFTawyFMNk0USCq5sexscwmxbewG/Rb8YnixwJWS44v2XkSujB67z5C\n" + - "s2qudFEhRXKdEuC6idbAuA97KjipHh0AAniWMsyv61fvbgsUC0b0canx3LiDq81p\n" + - "y28NNGmAvoazLZUZ4AhBRiwYZY6FKk723gmZoGbEIeG7J1dlXPusc1662rIjz4eU\n" + - "zlmmlvqyHfNqnNk8L14Vug6Xh+lOEGN85xhu1YHAEKGrS89kZxs5rum/cZU8KH2V\n" + - "v6eKnY03kxjiVLQtnLpm/7VUEoCMGHyruRj+p3my4+DgqMsmsH52RZCBsjyGlpbU\n" + - "NOwOTIX6xh+Rqloduz4AnrMYYIiIw2s8g+2zJM7VbcVKx0fGS26BKdrxgrXWfmNE\n" + - "nR0/REQ5AxDGw0jfTUvtdTkXAf+K4MDjcNLEZ+MA4rHfAfQWZtUR5BkHCQYxNpJk\n" + - "pA0gyk+BpKdC4WdzI14NSWsu5sRCmBCFqH6BTOSEq/V1cNorBxNwLSSTwFFqUDqx\n" + - "Y5nQLXygkJf9WHZWtSKeSjtOYgilz7UKzC2s3CsjmIyGFe+SwpuHJnuE4Uc8Z5Cb\n" + - "bjNGHPzqL6XnmzZHJp7RF8kBdKdjGC7dCUltzOfICZeKlzOOq+Kw42T/nXjuXvpb\n" + - "nkXNxg741Nwd6RecykXJbseFwm3EYxkCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEA\n" + - "Ga1mGwI9aXkL2fTPXO9YkAPzoGeX8aeuVYSQaSkNq+5vnogYCyAt3YDHjRG+ewTT\n" + - "WbnPA991xRAPac+biJeXWmwvgGj0YuT7e79phAiGkTTnbAjFHGfYnBy/tI/v7btO\n" + - "hRNElA5yTJ1m2fVbBEKXzMR83jrT9iyI+YLRN86zUZIaC86xxSbqnrdWN2jOK6MX\n" + - "dS8Arp9tPQjC/4gW+2Ilxv68jiYh+5auWHQZVjppWVY//iu4mAbkq1pTwQEhZ8F8\n" + - "Zrmh9DHh60hLFcfSuhIAwf/NMzppwdkjy1ruKVrpijhGKGp4OWu8nvOUgHSzxc7F\n" + - "PwpVZ5N2Ku4L8MLO6BG2VasRJK7l17TzDXlfLZHJjkuryOFxVaQKt8ZNFgTOaCXS\n" + - "E+gpTLksKU7riYckoiP4+H1sn9qcis0e8s4o/uf1UVc8GSdDw61ReGM5oZEDm1u8\n" + - "H9x20QU6igLqzyBpqvCKv7JNgU1uB2PAODHH78zJiUfnKd1y+o+J1iWzaGj3EFji\n" + - "T8AXksbTP733FeFXfggXju2dyBH+Z1S5BBTEOd1brWgXlHSAZGm97MKZ94r6/tkX\n" + - "qfv3fCos0DKz0oV7qBxYS8wiYhzrRVxG6ITAoH8uuUVVQaZF+G4nJ2jEqNbfuKyX\n" + - "ATQsVNjNNlDA0J33GobPMjT326wa4YAWMx8PI5PJZ3g=\n" + - "-----END CERTIFICATE-----\n"; - public static final X509Certificate CLIENT_CERT = loadCertificate(CLIENT_CERT_STR); - - private static final byte[] FAKE_RSA_KEY_1 = new byte[] { - (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01, - (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82, - (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e, - (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, - (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b, - (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66, - (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a, - (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02, - (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3, - (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d, - (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67, - (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb, - (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2, - (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79, - (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce, - (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08, - (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b, - (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4, - (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d, - (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23, - (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08, - (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1, - (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4, - (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16, - (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e, - (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01, - (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16, - (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98, - (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf, - (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a, - (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2, - (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc, - (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5, - (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a, - (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b, - (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9, - (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12, - (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e, - (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d, - (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2, - (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d, - (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc, - (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98, - (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96, - (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30, - (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e, - (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad, - (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f, - (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89, - (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13, - (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a, - (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e, - (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa, - (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47, - (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44, - (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22, - (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10, - (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45, - (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4, - (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda, - (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1, - (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab, - (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7, - (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc, - (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d, - (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82, - (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3, - (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a, - (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9, - (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6, - (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00, - (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd, - (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb, - (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4, - (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0, - (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2, - (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce, - (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a, - (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21, - (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d, - (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1, - (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41, - (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce, - (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0, - (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40, - (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a, - (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c, - (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90, - (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf, - (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb, - (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14, - (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab, - (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02, - (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67, - (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d, - (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d, - (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b, - (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2, - (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28, - (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd, - (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d, - (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b, - (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1, - (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51 - }; - public static final PrivateKey RSA_KEY1 = loadPrivateRSAKey(FAKE_RSA_KEY_1); - - private static X509Certificate loadCertificate(String blob) { - try { - final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - InputStream stream = new ByteArrayInputStream(blob.getBytes(StandardCharsets.UTF_8)); - - return (X509Certificate) certFactory.generateCertificate(stream); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - private static PrivateKey loadPrivateRSAKey(byte[] fakeKey) { - try { - KeyFactory kf = KeyFactory.getInstance("RSA"); - return kf.generatePrivate(new PKCS8EncodedKeySpec(fakeKey)); - } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { - return null; - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java b/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java deleted file mode 100644 index 71f04a33c1..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 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.wifi.cts; - -import android.content.Context; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.MulticastLock; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class MulticastLockTest extends AndroidTestCase { - - private static final String WIFI_TAG = "MulticastLockTest"; - - /** - * Verify acquire and release of Multicast locks - */ - public void testMulticastLock() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - MulticastLock mcl = wm.createMulticastLock(WIFI_TAG); - - mcl.setReferenceCounted(true); - assertFalse(mcl.isHeld()); - mcl.acquire(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertFalse(mcl.isHeld()); - mcl.acquire(); - mcl.acquire(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertFalse(mcl.isHeld()); - assertNotNull(mcl.toString()); - try { - mcl.release(); - fail("should throw out exception because release is called" - +" a greater number of times than acquire"); - } catch (RuntimeException e) { - // expected - } - - mcl = wm.createMulticastLock(WIFI_TAG); - mcl.setReferenceCounted(false); - assertFalse(mcl.isHeld()); - mcl.acquire(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertFalse(mcl.isHeld()); - mcl.acquire(); - mcl.acquire(); - assertTrue(mcl.isHeld()); - mcl.release(); - assertFalse(mcl.isHeld()); - assertNotNull(mcl.toString()); - // releasing again after release: but ignored for non-referenced locks - mcl.release(); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java deleted file mode 100644 index f2a2b48267..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Copyright (C) 2012 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.wifi.cts; - -import android.content.Context; -import android.net.nsd.NsdManager; -import android.net.nsd.NsdServiceInfo; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; -import android.util.Log; - -import java.io.IOException; -import java.net.ServerSocket; -import java.util.Arrays; -import java.util.Random; -import java.util.List; -import java.util.ArrayList; - -@AppModeFull(reason = "Socket cannot bind in instant app mode") -public class NsdManagerTest extends AndroidTestCase { - - private static final String TAG = "NsdManagerTest"; - private static final String SERVICE_TYPE = "_nmt._tcp"; - private static final int TIMEOUT = 2000; - - private static final boolean DBG = false; - - NsdManager mNsdManager; - - NsdManager.RegistrationListener mRegistrationListener; - NsdManager.DiscoveryListener mDiscoveryListener; - NsdManager.ResolveListener mResolveListener; - private NsdServiceInfo mResolvedService; - - public NsdManagerTest() { - initRegistrationListener(); - initDiscoveryListener(); - initResolveListener(); - } - - private void initRegistrationListener() { - mRegistrationListener = new NsdManager.RegistrationListener() { - @Override - public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { - setEvent("onRegistrationFailed", errorCode); - } - - @Override - public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { - setEvent("onUnregistrationFailed", errorCode); - } - - @Override - public void onServiceRegistered(NsdServiceInfo serviceInfo) { - setEvent("onServiceRegistered", serviceInfo); - } - - @Override - public void onServiceUnregistered(NsdServiceInfo serviceInfo) { - setEvent("onServiceUnregistered", serviceInfo); - } - }; - } - - private void initDiscoveryListener() { - mDiscoveryListener = new NsdManager.DiscoveryListener() { - @Override - public void onStartDiscoveryFailed(String serviceType, int errorCode) { - setEvent("onStartDiscoveryFailed", errorCode); - } - - @Override - public void onStopDiscoveryFailed(String serviceType, int errorCode) { - setEvent("onStopDiscoveryFailed", errorCode); - } - - @Override - public void onDiscoveryStarted(String serviceType) { - NsdServiceInfo info = new NsdServiceInfo(); - info.setServiceType(serviceType); - setEvent("onDiscoveryStarted", info); - } - - @Override - public void onDiscoveryStopped(String serviceType) { - NsdServiceInfo info = new NsdServiceInfo(); - info.setServiceType(serviceType); - setEvent("onDiscoveryStopped", info); - } - - @Override - public void onServiceFound(NsdServiceInfo serviceInfo) { - setEvent("onServiceFound", serviceInfo); - } - - @Override - public void onServiceLost(NsdServiceInfo serviceInfo) { - setEvent("onServiceLost", serviceInfo); - } - }; - } - - private void initResolveListener() { - mResolveListener = new NsdManager.ResolveListener() { - @Override - public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { - setEvent("onResolveFailed", errorCode); - } - - @Override - public void onServiceResolved(NsdServiceInfo serviceInfo) { - mResolvedService = serviceInfo; - setEvent("onServiceResolved", serviceInfo); - } - }; - } - - - - private final class EventData { - EventData(String callbackName, NsdServiceInfo info) { - mCallbackName = callbackName; - mSucceeded = true; - mErrorCode = 0; - mInfo = info; - } - EventData(String callbackName, int errorCode) { - mCallbackName = callbackName; - mSucceeded = false; - mErrorCode = errorCode; - mInfo = null; - } - private final String mCallbackName; - private final boolean mSucceeded; - private final int mErrorCode; - private final NsdServiceInfo mInfo; - } - - private final List mEventCache = new ArrayList(); - - private void setEvent(String callbackName, int errorCode) { - if (DBG) Log.d(TAG, callbackName + " failed with " + String.valueOf(errorCode)); - EventData eventData = new EventData(callbackName, errorCode); - synchronized (mEventCache) { - mEventCache.add(eventData); - mEventCache.notify(); - } - } - - private void setEvent(String callbackName, NsdServiceInfo info) { - if (DBG) Log.d(TAG, "Received event " + callbackName + " for " + info.getServiceName()); - EventData eventData = new EventData(callbackName, info); - synchronized (mEventCache) { - mEventCache.add(eventData); - mEventCache.notify(); - } - } - - void clearEventCache() { - synchronized(mEventCache) { - mEventCache.clear(); - } - } - - int eventCacheSize() { - synchronized(mEventCache) { - return mEventCache.size(); - } - } - - private int mWaitId = 0; - private EventData waitForCallback(String callbackName) { - - synchronized(mEventCache) { - - mWaitId ++; - if (DBG) Log.d(TAG, "Waiting for " + callbackName + ", id=" + String.valueOf(mWaitId)); - - try { - long startTime = android.os.SystemClock.uptimeMillis(); - long elapsedTime = 0; - int index = 0; - while (elapsedTime < TIMEOUT ) { - // first check if we've received that event - for (; index < mEventCache.size(); index++) { - EventData e = mEventCache.get(index); - if (e.mCallbackName.equals(callbackName)) { - if (DBG) Log.d(TAG, "exiting wait id=" + String.valueOf(mWaitId)); - return e; - } - } - - // Not yet received, just wait - mEventCache.wait(TIMEOUT - elapsedTime); - elapsedTime = android.os.SystemClock.uptimeMillis() - startTime; - } - // we exited the loop because of TIMEOUT; fail the call - if (DBG) Log.d(TAG, "timed out waiting id=" + String.valueOf(mWaitId)); - return null; - } catch (InterruptedException e) { - return null; // wait timed out! - } - } - } - - private EventData waitForNewEvents() throws InterruptedException { - if (DBG) Log.d(TAG, "Waiting for a bit, id=" + String.valueOf(mWaitId)); - - long startTime = android.os.SystemClock.uptimeMillis(); - long elapsedTime = 0; - synchronized (mEventCache) { - int index = mEventCache.size(); - while (elapsedTime < TIMEOUT ) { - // first check if we've received that event - for (; index < mEventCache.size(); index++) { - EventData e = mEventCache.get(index); - return e; - } - - // Not yet received, just wait - mEventCache.wait(TIMEOUT - elapsedTime); - elapsedTime = android.os.SystemClock.uptimeMillis() - startTime; - } - } - - return null; - } - - private String mServiceName; - - @Override - public void setUp() { - if (DBG) Log.d(TAG, "Setup test ..."); - mNsdManager = (NsdManager) getContext().getSystemService(Context.NSD_SERVICE); - - Random rand = new Random(); - mServiceName = new String("NsdTest"); - for (int i = 0; i < 4; i++) { - mServiceName = mServiceName + String.valueOf(rand.nextInt(10)); - } - } - - @Override - public void tearDown() { - if (DBG) Log.d(TAG, "Tear down test ..."); - } - - public void testNDSManager() throws Exception { - EventData lastEvent = null; - - if (DBG) Log.d(TAG, "Starting test ..."); - - NsdServiceInfo si = new NsdServiceInfo(); - si.setServiceType(SERVICE_TYPE); - si.setServiceName(mServiceName); - - byte testByteArray[] = new byte[] {-128, 127, 2, 1, 0, 1, 2}; - String String256 = "1_________2_________3_________4_________5_________6_________" + - "7_________8_________9_________10________11________12________13________" + - "14________15________16________17________18________19________20________" + - "21________22________23________24________25________123456"; - - // Illegal attributes - try { - si.setAttribute(null, (String) null); - fail("Could set null key"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute("", (String) null); - fail("Could set empty key"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute(String256, (String) null); - fail("Could set key with 255 characters"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute("key", String256.substring(3)); - fail("Could set key+value combination with more than 255 characters"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute("key", String256.substring(4)); - fail("Could set key+value combination with 255 characters"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute(new String(new byte[]{0x19}), (String) null); - fail("Could set key with invalid character"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute("=", (String) null); - fail("Could set key with invalid character"); - } catch (IllegalArgumentException e) { - // expected - } - - try { - si.setAttribute(new String(new byte[]{0x7F}), (String) null); - fail("Could set key with invalid character"); - } catch (IllegalArgumentException e) { - // expected - } - - // Allowed attributes - si.setAttribute("booleanAttr", (String) null); - si.setAttribute("keyValueAttr", "value"); - si.setAttribute("keyEqualsAttr", "="); - si.setAttribute(" whiteSpaceKeyValueAttr ", " value "); - si.setAttribute("binaryDataAttr", testByteArray); - si.setAttribute("nullBinaryDataAttr", (byte[]) null); - si.setAttribute("emptyBinaryDataAttr", new byte[]{}); - si.setAttribute("longkey", String256.substring(9)); - - ServerSocket socket; - int localPort; - - try { - socket = new ServerSocket(0); - localPort = socket.getLocalPort(); - si.setPort(localPort); - } catch (IOException e) { - if (DBG) Log.d(TAG, "Could not open a local socket"); - assertTrue(false); - return; - } - - if (DBG) Log.d(TAG, "Port = " + String.valueOf(localPort)); - - clearEventCache(); - - mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); - lastEvent = waitForCallback("onServiceRegistered"); // id = 1 - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - assertTrue(eventCacheSize() == 1); - - // We may not always get the name that we tried to register; - // This events tells us the name that was registered. - String registeredName = lastEvent.mInfo.getServiceName(); - si.setServiceName(registeredName); - - clearEventCache(); - - mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, - mDiscoveryListener); - - // Expect discovery started - lastEvent = waitForCallback("onDiscoveryStarted"); // id = 2 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - // Remove this event, so accounting becomes easier later - synchronized (mEventCache) { - mEventCache.remove(lastEvent); - } - - // Expect a service record to be discovered (and filter the ones - // that are unrelated to this test) - boolean found = false; - for (int i = 0; i < 32; i++) { - - lastEvent = waitForCallback("onServiceFound"); // id = 3 - if (lastEvent == null) { - // no more onServiceFound events are being reported! - break; - } - - assertTrue(lastEvent.mSucceeded); - - if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + - lastEvent.mInfo.getServiceName()); - - if (lastEvent.mInfo.getServiceName().equals(registeredName)) { - // Save it, as it will get overwritten with new serviceFound events - si = lastEvent.mInfo; - found = true; - } - - // Remove this event from the event cache, so it won't be found by subsequent - // calls to waitForCallback - synchronized (mEventCache) { - mEventCache.remove(lastEvent); - } - } - - assertTrue(found); - - // We've removed all serviceFound events, and we've removed the discoveryStarted - // event as well, so now the event cache should be empty! - assertTrue(eventCacheSize() == 0); - - // Resolve the service - clearEventCache(); - mNsdManager.resolveService(si, mResolveListener); - lastEvent = waitForCallback("onServiceResolved"); // id = 4 - - assertNotNull(mResolvedService); - - // Check Txt attributes - assertEquals(8, mResolvedService.getAttributes().size()); - assertTrue(mResolvedService.getAttributes().containsKey("booleanAttr")); - assertNull(mResolvedService.getAttributes().get("booleanAttr")); - assertEquals("value", new String(mResolvedService.getAttributes().get("keyValueAttr"))); - assertEquals("=", new String(mResolvedService.getAttributes().get("keyEqualsAttr"))); - assertEquals(" value ", new String(mResolvedService.getAttributes() - .get(" whiteSpaceKeyValueAttr "))); - assertEquals(String256.substring(9), new String(mResolvedService.getAttributes() - .get("longkey"))); - assertTrue(Arrays.equals(testByteArray, - mResolvedService.getAttributes().get("binaryDataAttr"))); - assertTrue(mResolvedService.getAttributes().containsKey("nullBinaryDataAttr")); - assertNull(mResolvedService.getAttributes().get("nullBinaryDataAttr")); - assertTrue(mResolvedService.getAttributes().containsKey("emptyBinaryDataAttr")); - assertNull(mResolvedService.getAttributes().get("emptyBinaryDataAttr")); - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": Port = " + - String.valueOf(lastEvent.mInfo.getPort())); - - assertTrue(lastEvent.mInfo.getPort() == localPort); - assertTrue(eventCacheSize() == 1); - - checkForAdditionalEvents(); - clearEventCache(); - - // Unregister the service - mNsdManager.unregisterService(mRegistrationListener); - lastEvent = waitForCallback("onServiceUnregistered"); // id = 5 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - // Expect a callback for service lost - lastEvent = waitForCallback("onServiceLost"); // id = 6 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); - - // Register service again to see if we discover it - checkForAdditionalEvents(); - clearEventCache(); - - si = new NsdServiceInfo(); - si.setServiceType(SERVICE_TYPE); - si.setServiceName(mServiceName); - si.setPort(localPort); - - // Create a new registration listener and register same service again - initRegistrationListener(); - - mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); - - lastEvent = waitForCallback("onServiceRegistered"); // id = 7 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - registeredName = lastEvent.mInfo.getServiceName(); - - // Expect a record to be discovered - // Expect a service record to be discovered (and filter the ones - // that are unrelated to this test) - found = false; - for (int i = 0; i < 32; i++) { - - lastEvent = waitForCallback("onServiceFound"); // id = 8 - if (lastEvent == null) { - // no more onServiceFound events are being reported! - break; - } - - assertTrue(lastEvent.mSucceeded); - - if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + - lastEvent.mInfo.getServiceName()); - - if (lastEvent.mInfo.getServiceName().equals(registeredName)) { - // Save it, as it will get overwritten with new serviceFound events - si = lastEvent.mInfo; - found = true; - } - - // Remove this event from the event cache, so it won't be found by subsequent - // calls to waitForCallback - synchronized (mEventCache) { - mEventCache.remove(lastEvent); - } - } - - assertTrue(found); - - // Resolve the service - clearEventCache(); - mNsdManager.resolveService(si, mResolveListener); - lastEvent = waitForCallback("onServiceResolved"); // id = 9 - - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - - if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " + - lastEvent.mInfo.getServiceName()); - - assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName)); - - assertNotNull(mResolvedService); - - // Check that we don't have any TXT records - assertEquals(0, mResolvedService.getAttributes().size()); - - checkForAdditionalEvents(); - clearEventCache(); - - mNsdManager.stopServiceDiscovery(mDiscoveryListener); - lastEvent = waitForCallback("onDiscoveryStopped"); // id = 10 - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - assertTrue(checkCacheSize(1)); - - checkForAdditionalEvents(); - clearEventCache(); - - mNsdManager.unregisterService(mRegistrationListener); - - lastEvent = waitForCallback("onServiceUnregistered"); // id = 11 - assertTrue(lastEvent != null); - assertTrue(lastEvent.mSucceeded); - assertTrue(checkCacheSize(1)); - } - - boolean checkCacheSize(int size) { - synchronized (mEventCache) { - int cacheSize = mEventCache.size(); - if (cacheSize != size) { - Log.d(TAG, "id = " + mWaitId + ": event cache size = " + cacheSize); - for (int i = 0; i < cacheSize; i++) { - EventData e = mEventCache.get(i); - String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : ""; - Log.d(TAG, "eventName is " + e.mCallbackName + sname); - } - } - return (cacheSize == size); - } - } - - boolean checkForAdditionalEvents() { - try { - EventData e = waitForNewEvents(); - if (e != null) { - String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : ""; - Log.d(TAG, "ignoring unexpected event " + e.mCallbackName + sname); - } - return (e == null); - } - catch (InterruptedException ex) { - return false; - } - } -} - diff --git a/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java b/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java deleted file mode 100644 index feafd434a7..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/PpsMoParserTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.cts; - -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.omadm.PpsMoParser; -import android.net.wifi.hotspot2.pps.Credential; -import android.net.wifi.hotspot2.pps.HomeSp; -import android.test.AndroidTestCase; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * CTS tests for PPS MO (PerProviderSubscription Management Object) XML string parsing API. - */ -public class PpsMoParserTest extends AndroidTestCase { - private static final String PPS_MO_XML_FILE = "assets/PerProviderSubscription.xml"; - - /** - * Read the content of the given resource file into a String. - * - * @param filename String name of the file - * @return String - * @throws IOException - */ - private String loadResourceFile(String filename) throws IOException { - InputStream in = getClass().getClassLoader().getResourceAsStream(filename); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - StringBuilder builder = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - builder.append(line).append("\n"); - } - return builder.toString(); - } - - /** - * Generate a {@link PasspointConfiguration} that matches the configuration specified in the - * XML file {@link #PPS_MO_XML_FILE}. - * - * @return {@link PasspointConfiguration} - */ - private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception { - DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - byte[] certFingerprint = new byte[32]; - Arrays.fill(certFingerprint, (byte) 0x1f); - - PasspointConfiguration config = new PasspointConfiguration(); - - // HomeSP configuration. - HomeSp homeSp = new HomeSp(); - homeSp.setFriendlyName("Century House"); - assertEquals("Century House", homeSp.getFriendlyName()); - homeSp.setFqdn("mi6.co.uk"); - assertEquals("mi6.co.uk", homeSp.getFqdn()); - homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L}); - assertTrue(Arrays.equals(new long[] {0x112233L, 0x445566L}, - homeSp.getRoamingConsortiumOis())); - config.setHomeSp(homeSp); - assertEquals(homeSp, config.getHomeSp()); - - // Credential configuration. - Credential credential = new Credential(); - credential.setRealm("shaken.stirred.com"); - assertEquals("shaken.stirred.com", credential.getRealm()); - Credential.UserCredential userCredential = new Credential.UserCredential(); - userCredential.setUsername("james"); - assertEquals("james", userCredential.getUsername()); - userCredential.setPassword("Ym9uZDAwNw=="); - assertEquals("Ym9uZDAwNw==", userCredential.getPassword()); - userCredential.setEapType(21); - assertEquals(21, userCredential.getEapType()); - userCredential.setNonEapInnerMethod("MS-CHAP-V2"); - assertEquals("MS-CHAP-V2", userCredential.getNonEapInnerMethod()); - credential.setUserCredential(userCredential); - assertEquals(userCredential, credential.getUserCredential()); - Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); - certCredential.setCertType("x509v3"); - assertEquals("x509v3", certCredential.getCertType()); - certCredential.setCertSha256Fingerprint(certFingerprint); - assertTrue(Arrays.equals(certFingerprint, certCredential.getCertSha256Fingerprint())); - credential.setCertCredential(certCredential); - assertEquals(certCredential, credential.getCertCredential()); - Credential.SimCredential simCredential = new Credential.SimCredential(); - simCredential.setImsi("imsi"); - assertEquals("imsi", simCredential.getImsi()); - simCredential.setEapType(24); - assertEquals(24, simCredential.getEapType()); - credential.setSimCredential(simCredential); - assertEquals(simCredential, credential.getSimCredential()); - config.setCredential(credential); - assertEquals(credential, config.getCredential()); - return config; - } - - /** - * Parse and verify all supported fields under PPS MO tree. - * - * @throws Exception - */ - public void testParsePPSMOTree() throws Exception { - String ppsMoTree = loadResourceFile(PPS_MO_XML_FILE); - PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree(); - PasspointConfiguration actualConfig = PpsMoParser.parseMoText(ppsMoTree); - assertTrue(actualConfig.equals(expectedConfig)); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java deleted file mode 100644 index 1977378c1a..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/ScanResultTest.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import java.nio.ByteBuffer; -import java.util.List; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.wifi.ScanResult; -import android.net.wifi.ScanResult.InformationElement; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.WifiLock; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -import com.android.compatibility.common.util.ShellIdentityUtils; -import com.android.compatibility.common.util.SystemUtil; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class ScanResultTest extends AndroidTestCase { - private static class MySync { - int expectedState = STATE_NULL; - } - - private WifiManager mWifiManager; - private WifiLock mWifiLock; - private static MySync mMySync; - private boolean mWasVerboseLoggingEnabled; - private boolean mWasScanThrottleEnabled; - - private static final int STATE_NULL = 0; - private static final int STATE_WIFI_CHANGING = 1; - private static final int STATE_WIFI_CHANGED = 2; - private static final int STATE_START_SCAN = 3; - private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; - private static final int STATE_SCAN_FAILURE = 5; - - private static final String TAG = "WifiInfoTest"; - private static final int TIMEOUT_MSEC = 6000; - private static final int WAIT_MSEC = 60; - private static final int ENABLE_WAIT_MSEC = 10000; - private static final int SCAN_WAIT_MSEC = 10000; - private static final int SCAN_MAX_RETRY_COUNT = 6; - private static final int SCAN_FIND_BSSID_MAX_RETRY_COUNT = 5; - private static final long SCAN_FIND_BSSID_WAIT_MSEC = 5_000L; - - private static final String TEST_SSID = "TEST_SSID"; - public static final String TEST_BSSID = "04:ac:fe:45:34:10"; - public static final String TEST_CAPS = "CCMP"; - public static final int TEST_LEVEL = -56; - public static final int TEST_FREQUENCY = 2412; - public static final long TEST_TIMESTAMP = 4660L; - - private IntentFilter mIntentFilter; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGED; - mMySync.notify(); - } - } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - synchronized (mMySync) { - if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) { - mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; - } else { - mMySync.expectedState = STATE_SCAN_FAILURE; - } - mMySync.notify(); - } - } - } - }; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mMySync = new MySync(); - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); - - mContext.registerReceiver(mReceiver, mIntentFilter); - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertThat(mWifiManager).isNotNull(); - - // turn on verbose logging for tests - mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.isVerboseLoggingEnabled()); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(true)); - // Disable scan throttling for tests. - mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.isScanThrottleEnabled()); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setScanThrottleEnabled(false)); - - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - Thread.sleep(ENABLE_WAIT_MSEC); - assertThat(mWifiManager.isWifiEnabled()).isTrue(); - mMySync.expectedState = STATE_NULL; - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - mWifiLock.release(); - mContext.unregisterReceiver(mReceiver); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled)); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); - Thread.sleep(ENABLE_WAIT_MSEC); - super.tearDown(); - } - - private void setWifiEnabled(boolean enable) throws Exception { - synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGING; - if (enable) { - SystemUtil.runShellCommand("svc wifi enable"); - } else { - SystemUtil.runShellCommand("svc wifi disable"); - } - waitForBroadcast(TIMEOUT_MSEC, STATE_WIFI_CHANGED); - } - } - - private boolean waitForBroadcast(long timeout, int expectedState) throws Exception { - long waitTime = System.currentTimeMillis() + timeout; - while (System.currentTimeMillis() < waitTime - && mMySync.expectedState != expectedState) - mMySync.wait(WAIT_MSEC); - return mMySync.expectedState == expectedState; - } - - public void testScanResultProperties() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // this test case should in Wifi environment - for (ScanResult scanResult : mWifiManager.getScanResults()) { - assertThat(scanResult.toString()).isNotNull(); - - for (InformationElement ie : scanResult.getInformationElements()) { - testInformationElementCopyConstructor(ie); - testInformationElementFields(ie); - } - - assertThat(scanResult.getWifiStandard()).isAnyOf( - ScanResult.WIFI_STANDARD_UNKNOWN, - ScanResult.WIFI_STANDARD_LEGACY, - ScanResult.WIFI_STANDARD_11N, - ScanResult.WIFI_STANDARD_11AC, - ScanResult.WIFI_STANDARD_11AX - ); - - scanResult.isPasspointNetwork(); - } - } - - private void testInformationElementCopyConstructor(InformationElement ie) { - InformationElement copy = new InformationElement(ie); - - assertThat(copy.getId()).isEqualTo(ie.getId()); - assertThat(copy.getIdExt()).isEqualTo(ie.getIdExt()); - assertThat(copy.getBytes()).isEqualTo(ie.getBytes()); - } - - private void testInformationElementFields(InformationElement ie) { - // id is 1 octet - int id = ie.getId(); - assertThat(id).isAtLeast(0); - assertThat(id).isAtMost(255); - - // idExt is 0 or 1 octet - int idExt = ie.getIdExt(); - assertThat(idExt).isAtLeast(0); - assertThat(idExt).isAtMost(255); - - ByteBuffer bytes = ie.getBytes(); - assertThat(bytes).isNotNull(); - } - - /* Multiple scans to ensure bssid is updated */ - private void scanAndWait() throws Exception { - synchronized (mMySync) { - for (int retry = 0; retry < SCAN_MAX_RETRY_COUNT; retry++) { - mMySync.expectedState = STATE_START_SCAN; - mWifiManager.startScan(); - if (waitForBroadcast(SCAN_WAIT_MSEC, STATE_SCAN_RESULTS_AVAILABLE)) { - break; - } - } - } - } - - public void testScanResultTimeStamp() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - long timestamp = 0; - String BSSID = null; - - scanAndWait(); - - List scanResults = mWifiManager.getScanResults(); - for (ScanResult result : scanResults) { - BSSID = result.BSSID; - timestamp = result.timestamp; - assertThat(timestamp).isNotEqualTo(0); - break; - } - - scanAndWait(); - - scanResults = mWifiManager.getScanResults(); - for (ScanResult result : scanResults) { - if (result.BSSID.equals(BSSID)) { - long timeDiff = (result.timestamp - timestamp) / 1000; - assertThat(timeDiff).isGreaterThan(0L); - assertThat(timeDiff).isLessThan(6L * SCAN_WAIT_MSEC); - } - } - } - - /** Test that the copy constructor copies fields correctly. */ - public void testScanResultConstructors() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - ScanResult scanResult = new ScanResult(); - scanResult.SSID = TEST_SSID; - scanResult.BSSID = TEST_BSSID; - scanResult.capabilities = TEST_CAPS; - scanResult.level = TEST_LEVEL; - scanResult.frequency = TEST_FREQUENCY; - scanResult.timestamp = TEST_TIMESTAMP; - - ScanResult scanResult2 = new ScanResult(scanResult); - assertThat(scanResult2.SSID).isEqualTo(TEST_SSID); - assertThat(scanResult2.BSSID).isEqualTo(TEST_BSSID); - assertThat(scanResult2.capabilities).isEqualTo(TEST_CAPS); - assertThat(scanResult2.level).isEqualTo(TEST_LEVEL); - assertThat(scanResult2.frequency).isEqualTo(TEST_FREQUENCY); - assertThat(scanResult2.timestamp).isEqualTo(TEST_TIMESTAMP); - } - - public void testScanResultMatchesWifiInfo() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // This test case should run while connected to Wifi - final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - assertThat(wifiInfo).isNotNull(); - - ScanResult currentNetwork = null; - for (int i = 0; i < SCAN_FIND_BSSID_MAX_RETRY_COUNT; i++) { - scanAndWait(); - final List scanResults = mWifiManager.getScanResults(); - currentNetwork = scanResults.stream().filter(r -> r.BSSID.equals(wifiInfo.getBSSID())) - .findAny().orElse(null); - - if (currentNetwork != null) { - break; - } - Thread.sleep(SCAN_FIND_BSSID_WAIT_MSEC); - } - assertWithMessage("Current network not found in scan results") - .that(currentNetwork).isNotNull(); - - String wifiInfoSsidQuoted = wifiInfo.getSSID(); - String scanResultSsidUnquoted = currentNetwork.SSID; - - assertWithMessage( - "SSID mismatch: make sure this isn't a hidden network or an SSID containing " - + "non-UTF-8 characters - neither is supported by this CTS test.") - .that("\"" + scanResultSsidUnquoted + "\"") - .isEqualTo(wifiInfoSsidQuoted); - assertThat(currentNetwork.frequency).isEqualTo(wifiInfo.getFrequency()); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java b/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java deleted file mode 100644 index 11edf7395b..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/SupplicantStateTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import android.net.wifi.SupplicantState; -import android.test.AndroidTestCase; - -public class SupplicantStateTest extends AndroidTestCase { - - public void testIsValidState() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - assertTrue(SupplicantState.isValidState(SupplicantState.DISCONNECTED)); - assertTrue(SupplicantState.isValidState(SupplicantState.INACTIVE)); - assertTrue(SupplicantState.isValidState(SupplicantState.SCANNING)); - assertTrue(SupplicantState.isValidState(SupplicantState.ASSOCIATING)); - assertTrue(SupplicantState.isValidState(SupplicantState.ASSOCIATED)); - assertTrue(SupplicantState.isValidState(SupplicantState.FOUR_WAY_HANDSHAKE)); - assertTrue(SupplicantState.isValidState(SupplicantState.GROUP_HANDSHAKE)); - assertTrue(SupplicantState.isValidState(SupplicantState.COMPLETED)); - assertTrue(SupplicantState.isValidState(SupplicantState.DORMANT)); - assertFalse(SupplicantState.isValidState(SupplicantState.UNINITIALIZED)); - assertFalse(SupplicantState.isValidState(SupplicantState.INVALID)); - } - -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java deleted file mode 100644 index a59c85e5ab..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiConfigurationTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import java.util.List; - -import android.content.Context; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiConfigurationTest extends AndroidTestCase { - private WifiManager mWifiManager; - @Override - protected void setUp() throws Exception { - super.setUp(); - mWifiManager = (WifiManager) mContext - .getSystemService(Context.WIFI_SERVICE); - } - - public void testWifiConfiguration() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - List wifiConfigurations = mWifiManager.getConfiguredNetworks(); - if (wifiConfigurations != null) { - for (int i = 0; i < wifiConfigurations.size(); i++) { - WifiConfiguration wifiConfiguration = wifiConfigurations.get(i); - assertNotNull(wifiConfiguration); - assertNotNull(wifiConfiguration.toString()); - } - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java deleted file mode 100644 index 45b9d97843..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java +++ /dev/null @@ -1,899 +0,0 @@ -/* - * Copyright (C) 2013 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.wifi.cts; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.pm.PackageManager; -import android.net.wifi.WifiEnterpriseConfig; -import android.net.wifi.WifiEnterpriseConfig.Eap; -import android.net.wifi.WifiEnterpriseConfig.Phase2; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -import java.io.ByteArrayInputStream; -import java.security.KeyFactory; -import java.security.PrivateKey; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.spec.PKCS8EncodedKeySpec; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiEnterpriseConfigTest extends AndroidTestCase { - - private static final String IDENTITY = "identity"; - private static final String PASSWORD = "password"; - private static final String SUBJECT_MATCH = "subjectmatch"; - private static final String ALT_SUBJECT_MATCH = "altsubjectmatch"; - private static final String DOM_SUBJECT_MATCH = "domsubjectmatch"; - private static final String PLMN = "plmn"; - private static final String REALM = "realm"; - private static final String ANON_IDENTITY = "anonidentity"; - private static final String CERTIFICATE_ALIAS1 = "certificatealias1"; - private static final String CERTIFICATE_ALIAS2 = "certificatealias2"; - private static final String CA_PATH = "capath"; - private static final String CLIENT_CERTIFICATE_ALIAS = "clientcertificatealias"; - private static final String WAPI_CERT_SUITE = "wapicertsuite"; - - /* - * The keys and certificates below are generated with: - * - * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem - * openssl ecparam -name prime256v1 -out ecparam.pem - * openssl req -newkey ec:ecparam.pem -keyout userkey.pem -nodes -days 3650 -out userkey.req - * mkdir -p demoCA/newcerts - * touch demoCA/index.txt - * echo "01" > demoCA/serial - * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650 - */ - - /** - * Generated from above and converted with: - * - * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g' - */ - - private static final byte[] FAKE_EC_1 = { - (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x2f, (byte) 0x30, (byte) 0x82, - (byte) 0x03, (byte) 0x17, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, - (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xa7, (byte) 0xe4, - (byte) 0x70, (byte) 0x50, (byte) 0x9b, (byte) 0xd2, (byte) 0x68, (byte) 0x68, - (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, - (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0xad, - (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, - (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, - (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, - (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x12, - (byte) 0x30, (byte) 0x10, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x07, (byte) 0x0c, (byte) 0x09, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, - (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x69, (byte) 0x74, (byte) 0x79, - (byte) 0x31, (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x53, - (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x6f, - (byte) 0x6d, (byte) 0x70, (byte) 0x61, (byte) 0x6e, (byte) 0x79, (byte) 0x31, - (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x53, (byte) 0x65, - (byte) 0x63, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x31, - (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x18, (byte) 0x57, (byte) 0x69, - (byte) 0x66, (byte) 0x69, (byte) 0x45, (byte) 0x6e, (byte) 0x74, (byte) 0x65, - (byte) 0x72, (byte) 0x70, (byte) 0x72, (byte) 0x69, (byte) 0x73, (byte) 0x65, - (byte) 0x43, (byte) 0x6f, (byte) 0x6e, (byte) 0x66, (byte) 0x69, (byte) 0x67, - (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x31, (byte) 0x29, - (byte) 0x30, (byte) 0x27, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x09, - (byte) 0x01, (byte) 0x16, (byte) 0x1a, (byte) 0x61, (byte) 0x6e, (byte) 0x2d, - (byte) 0x65, (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6c, (byte) 0x2d, - (byte) 0x61, (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73, - (byte) 0x40, (byte) 0x64, (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x69, - (byte) 0x6e, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, - (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x36, (byte) 0x30, - (byte) 0x31, (byte) 0x31, (byte) 0x35, (byte) 0x31, (byte) 0x31, (byte) 0x31, - (byte) 0x38, (byte) 0x35, (byte) 0x31, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, - (byte) 0x32, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x31, (byte) 0x32, - (byte) 0x31, (byte) 0x31, (byte) 0x31, (byte) 0x38, (byte) 0x35, (byte) 0x31, - (byte) 0x5a, (byte) 0x30, (byte) 0x81, (byte) 0xad, (byte) 0x31, (byte) 0x0b, - (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, - (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, - (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, - (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x12, (byte) 0x30, (byte) 0x10, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0c, - (byte) 0x09, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, - (byte) 0x43, (byte) 0x69, (byte) 0x74, (byte) 0x79, (byte) 0x31, (byte) 0x15, - (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, - (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x6f, (byte) 0x6d, (byte) 0x70, - (byte) 0x61, (byte) 0x6e, (byte) 0x79, (byte) 0x31, (byte) 0x10, (byte) 0x30, - (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, - (byte) 0x0c, (byte) 0x07, (byte) 0x53, (byte) 0x65, (byte) 0x63, (byte) 0x74, - (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x31, (byte) 0x21, (byte) 0x30, - (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, - (byte) 0x0c, (byte) 0x18, (byte) 0x57, (byte) 0x69, (byte) 0x66, (byte) 0x69, - (byte) 0x45, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x70, - (byte) 0x72, (byte) 0x69, (byte) 0x73, (byte) 0x65, (byte) 0x43, (byte) 0x6f, - (byte) 0x6e, (byte) 0x66, (byte) 0x69, (byte) 0x67, (byte) 0x54, (byte) 0x65, - (byte) 0x73, (byte) 0x74, (byte) 0x31, (byte) 0x29, (byte) 0x30, (byte) 0x27, - (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, - (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x09, (byte) 0x01, (byte) 0x16, - (byte) 0x1a, (byte) 0x61, (byte) 0x6e, (byte) 0x2d, (byte) 0x65, (byte) 0x6d, - (byte) 0x61, (byte) 0x69, (byte) 0x6c, (byte) 0x2d, (byte) 0x61, (byte) 0x64, - (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x40, (byte) 0x64, - (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x2e, - (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x82, (byte) 0x01, - (byte) 0x22, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, - (byte) 0x01, (byte) 0x0f, (byte) 0x00, (byte) 0x30, (byte) 0x82, (byte) 0x01, - (byte) 0x0a, (byte) 0x02, (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x00, - (byte) 0xb4, (byte) 0x6e, (byte) 0x66, (byte) 0x24, (byte) 0xe7, (byte) 0x5c, - (byte) 0xd8, (byte) 0x6f, (byte) 0x08, (byte) 0xd3, (byte) 0x80, (byte) 0xa3, - (byte) 0xb9, (byte) 0xaf, (byte) 0x90, (byte) 0xef, (byte) 0x1c, (byte) 0x2a, - (byte) 0x5f, (byte) 0x39, (byte) 0x0b, (byte) 0xbd, (byte) 0x75, (byte) 0x0d, - (byte) 0x3e, (byte) 0x19, (byte) 0x2e, (byte) 0x47, (byte) 0x1e, (byte) 0x14, - (byte) 0xc2, (byte) 0x1a, (byte) 0x59, (byte) 0xcc, (byte) 0x1b, (byte) 0xb6, - (byte) 0x9b, (byte) 0x46, (byte) 0x1f, (byte) 0x7f, (byte) 0x71, (byte) 0xdd, - (byte) 0x38, (byte) 0xbe, (byte) 0x89, (byte) 0x30, (byte) 0xba, (byte) 0x88, - (byte) 0xfb, (byte) 0x3f, (byte) 0x57, (byte) 0x35, (byte) 0xe7, (byte) 0xa7, - (byte) 0x2f, (byte) 0x2c, (byte) 0x8d, (byte) 0x7c, (byte) 0xe2, (byte) 0xd8, - (byte) 0x0c, (byte) 0x0a, (byte) 0xe6, (byte) 0x62, (byte) 0x46, (byte) 0x8c, - (byte) 0xf4, (byte) 0x51, (byte) 0xfc, (byte) 0x6a, (byte) 0x79, (byte) 0xdd, - (byte) 0x0a, (byte) 0x41, (byte) 0x23, (byte) 0xd3, (byte) 0xe9, (byte) 0x5e, - (byte) 0x91, (byte) 0xcd, (byte) 0xbd, (byte) 0x55, (byte) 0x28, (byte) 0x71, - (byte) 0xec, (byte) 0x52, (byte) 0x19, (byte) 0x85, (byte) 0x0c, (byte) 0x1b, - (byte) 0xfa, (byte) 0xbf, (byte) 0xfe, (byte) 0xae, (byte) 0x5c, (byte) 0x3b, - (byte) 0x99, (byte) 0x42, (byte) 0xd4, (byte) 0xe7, (byte) 0x17, (byte) 0xec, - (byte) 0x41, (byte) 0x22, (byte) 0x2c, (byte) 0x1e, (byte) 0x7b, (byte) 0x53, - (byte) 0xad, (byte) 0x02, (byte) 0xfd, (byte) 0xf6, (byte) 0x4a, (byte) 0xb1, - (byte) 0x6e, (byte) 0x6c, (byte) 0x87, (byte) 0xf5, (byte) 0x7d, (byte) 0x9b, - (byte) 0x34, (byte) 0x0e, (byte) 0x3b, (byte) 0x0e, (byte) 0xaa, (byte) 0xc5, - (byte) 0xc4, (byte) 0xef, (byte) 0xf2, (byte) 0x5a, (byte) 0xa9, (byte) 0xac, - (byte) 0x19, (byte) 0xce, (byte) 0x5f, (byte) 0xc5, (byte) 0xcc, (byte) 0x0d, - (byte) 0xee, (byte) 0x7f, (byte) 0x32, (byte) 0xb4, (byte) 0xfe, (byte) 0xc1, - (byte) 0xca, (byte) 0x9b, (byte) 0x3f, (byte) 0xad, (byte) 0x2c, (byte) 0x7a, - (byte) 0xc5, (byte) 0x8d, (byte) 0x48, (byte) 0xa1, (byte) 0xc9, (byte) 0x74, - (byte) 0xfe, (byte) 0x8a, (byte) 0xe3, (byte) 0xb0, (byte) 0x92, (byte) 0xee, - (byte) 0x73, (byte) 0x09, (byte) 0x0a, (byte) 0xbc, (byte) 0xc8, (byte) 0x63, - (byte) 0xba, (byte) 0x0e, (byte) 0x26, (byte) 0xab, (byte) 0x1e, (byte) 0xff, - (byte) 0xbc, (byte) 0x24, (byte) 0x12, (byte) 0x26, (byte) 0x11, (byte) 0xe0, - (byte) 0x04, (byte) 0xcb, (byte) 0x96, (byte) 0x7d, (byte) 0x41, (byte) 0xf7, - (byte) 0x79, (byte) 0x32, (byte) 0x05, (byte) 0x33, (byte) 0x19, (byte) 0x6e, - (byte) 0xb9, (byte) 0x75, (byte) 0xf3, (byte) 0x50, (byte) 0xa4, (byte) 0xc3, - (byte) 0x55, (byte) 0x9d, (byte) 0x8f, (byte) 0xb6, (byte) 0xab, (byte) 0x97, - (byte) 0xe7, (byte) 0xe2, (byte) 0xe8, (byte) 0x15, (byte) 0xfc, (byte) 0x35, - (byte) 0xbd, (byte) 0xce, (byte) 0x17, (byte) 0xbe, (byte) 0xe3, (byte) 0x73, - (byte) 0xd4, (byte) 0x88, (byte) 0x39, (byte) 0x27, (byte) 0x7e, (byte) 0x6d, - (byte) 0xa2, (byte) 0x27, (byte) 0xfa, (byte) 0x96, (byte) 0xe3, (byte) 0x38, - (byte) 0xc0, (byte) 0xa1, (byte) 0x55, (byte) 0xc6, (byte) 0xf3, (byte) 0x20, - (byte) 0xea, (byte) 0x50, (byte) 0x8d, (byte) 0x6c, (byte) 0x94, (byte) 0x9a, - (byte) 0x43, (byte) 0x74, (byte) 0xc0, (byte) 0xfa, (byte) 0xef, (byte) 0xe0, - (byte) 0xb1, (byte) 0x1c, (byte) 0x6d, (byte) 0x5e, (byte) 0x44, (byte) 0x08, - (byte) 0xef, (byte) 0xd5, (byte) 0x80, (byte) 0xad, (byte) 0x02, (byte) 0x03, - (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, (byte) 0x50, (byte) 0x30, - (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, - (byte) 0xe9, (byte) 0xd0, (byte) 0x9e, (byte) 0x0e, (byte) 0x62, (byte) 0x31, - (byte) 0x02, (byte) 0x9a, (byte) 0x33, (byte) 0xd7, (byte) 0x4a, (byte) 0x93, - (byte) 0x0d, (byte) 0xf3, (byte) 0xd6, (byte) 0x74, (byte) 0xce, (byte) 0x69, - (byte) 0xe1, (byte) 0xef, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18, (byte) 0x30, - (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0xe9, (byte) 0xd0, (byte) 0x9e, - (byte) 0x0e, (byte) 0x62, (byte) 0x31, (byte) 0x02, (byte) 0x9a, (byte) 0x33, - (byte) 0xd7, (byte) 0x4a, (byte) 0x93, (byte) 0x0d, (byte) 0xf3, (byte) 0xd6, - (byte) 0x74, (byte) 0xce, (byte) 0x69, (byte) 0xe1, (byte) 0xef, (byte) 0x30, - (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, - (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, - (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, - (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x52, (byte) 0x70, (byte) 0xb6, - (byte) 0x10, (byte) 0x7f, (byte) 0xaa, (byte) 0x86, (byte) 0x8f, (byte) 0x02, - (byte) 0xb0, (byte) 0x97, (byte) 0x89, (byte) 0xb9, (byte) 0x04, (byte) 0x1d, - (byte) 0x79, (byte) 0xa3, (byte) 0x74, (byte) 0x7c, (byte) 0xdf, (byte) 0xad, - (byte) 0x87, (byte) 0xe4, (byte) 0x00, (byte) 0xd3, (byte) 0x3a, (byte) 0x5c, - (byte) 0x48, (byte) 0x3b, (byte) 0xfe, (byte) 0x77, (byte) 0xfd, (byte) 0xbe, - (byte) 0xce, (byte) 0x5b, (byte) 0xd2, (byte) 0xea, (byte) 0x3e, (byte) 0x7f, - (byte) 0xef, (byte) 0x20, (byte) 0x0d, (byte) 0x0b, (byte) 0xc7, (byte) 0xc4, - (byte) 0x25, (byte) 0x20, (byte) 0xe1, (byte) 0x8f, (byte) 0xc5, (byte) 0x19, - (byte) 0x37, (byte) 0x9c, (byte) 0xa0, (byte) 0x9d, (byte) 0x02, (byte) 0x30, - (byte) 0x5f, (byte) 0x49, (byte) 0x4e, (byte) 0x56, (byte) 0xc4, (byte) 0xab, - (byte) 0xcb, (byte) 0x5c, (byte) 0xe6, (byte) 0x40, (byte) 0x93, (byte) 0x92, - (byte) 0xee, (byte) 0xa1, (byte) 0x69, (byte) 0x7d, (byte) 0x10, (byte) 0x6b, - (byte) 0xd4, (byte) 0xf7, (byte) 0xec, (byte) 0xd9, (byte) 0xa5, (byte) 0x29, - (byte) 0x63, (byte) 0x29, (byte) 0xd9, (byte) 0x27, (byte) 0x2d, (byte) 0x5e, - (byte) 0x34, (byte) 0x37, (byte) 0xa9, (byte) 0xba, (byte) 0x0a, (byte) 0x7b, - (byte) 0x99, (byte) 0x1a, (byte) 0x7d, (byte) 0xa7, (byte) 0xa7, (byte) 0xf0, - (byte) 0xbf, (byte) 0x40, (byte) 0x29, (byte) 0x5d, (byte) 0x2f, (byte) 0x2e, - (byte) 0x0f, (byte) 0x35, (byte) 0x90, (byte) 0xb5, (byte) 0xc3, (byte) 0xfd, - (byte) 0x1e, (byte) 0xe2, (byte) 0xb3, (byte) 0xae, (byte) 0xf9, (byte) 0xde, - (byte) 0x9d, (byte) 0x76, (byte) 0xe1, (byte) 0x20, (byte) 0xf5, (byte) 0x1c, - (byte) 0x30, (byte) 0x42, (byte) 0x80, (byte) 0x2a, (byte) 0x4f, (byte) 0x85, - (byte) 0x5c, (byte) 0xb4, (byte) 0x49, (byte) 0x68, (byte) 0x6c, (byte) 0x7c, - (byte) 0x2a, (byte) 0xc8, (byte) 0xbc, (byte) 0x15, (byte) 0xed, (byte) 0x88, - (byte) 0xfd, (byte) 0x8a, (byte) 0x63, (byte) 0xe0, (byte) 0x93, (byte) 0xfd, - (byte) 0x86, (byte) 0xab, (byte) 0xa9, (byte) 0xf6, (byte) 0x63, (byte) 0xa5, - (byte) 0x29, (byte) 0xaf, (byte) 0xdc, (byte) 0x8f, (byte) 0xca, (byte) 0xc2, - (byte) 0x28, (byte) 0xe7, (byte) 0x26, (byte) 0x89, (byte) 0x75, (byte) 0xf1, - (byte) 0x3e, (byte) 0x2e, (byte) 0x86, (byte) 0x11, (byte) 0x8b, (byte) 0xfa, - (byte) 0xf5, (byte) 0xb4, (byte) 0xb4, (byte) 0x04, (byte) 0x02, (byte) 0xa3, - (byte) 0x85, (byte) 0x81, (byte) 0xad, (byte) 0xb3, (byte) 0xec, (byte) 0x2d, - (byte) 0x4b, (byte) 0x40, (byte) 0x59, (byte) 0x61, (byte) 0x0d, (byte) 0x59, - (byte) 0x09, (byte) 0x09, (byte) 0xee, (byte) 0xc7, (byte) 0x51, (byte) 0xef, - (byte) 0x6f, (byte) 0xd6, (byte) 0x9a, (byte) 0xa5, (byte) 0x45, (byte) 0xa2, - (byte) 0x89, (byte) 0xc2, (byte) 0x97, (byte) 0x93, (byte) 0xbc, (byte) 0x5b, - (byte) 0x37, (byte) 0x55, (byte) 0x73, (byte) 0x55, (byte) 0x0c, (byte) 0x9c, - (byte) 0xcb, (byte) 0x10, (byte) 0xec, (byte) 0x76, (byte) 0xfe, (byte) 0xa7, - (byte) 0x70, (byte) 0x4e, (byte) 0x9a, (byte) 0xa2, (byte) 0xf9, (byte) 0x40, - (byte) 0xdd, (byte) 0x96, (byte) 0x7d, (byte) 0x67, (byte) 0x5c, (byte) 0x8e, - (byte) 0x43, (byte) 0x1a, (byte) 0x26, (byte) 0xaa, (byte) 0xee, (byte) 0x38, - (byte) 0x11, (byte) 0x26, (byte) 0x3d, (byte) 0x69, (byte) 0xc7, (byte) 0x6a, - (byte) 0xe7, (byte) 0xbd, (byte) 0x67, (byte) 0x70, (byte) 0x35, (byte) 0xff, - (byte) 0x72, (byte) 0x2c, (byte) 0x87, (byte) 0x82, (byte) 0x68, (byte) 0x3f, - (byte) 0x8d - }; - - private static final byte[] FAKE_EC_2 = { - (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x4f, (byte) 0x30, (byte) 0x82, - (byte) 0x03, (byte) 0x37, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, - (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xd9, (byte) 0xc4, - (byte) 0xe1, (byte) 0xfc, (byte) 0x3d, (byte) 0x02, (byte) 0x21, (byte) 0x1f, - (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, - (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0xbd, - (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, - (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, - (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, - (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x12, - (byte) 0x30, (byte) 0x10, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x07, (byte) 0x0c, (byte) 0x09, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, - (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x69, (byte) 0x74, (byte) 0x79, - (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x12, (byte) 0x53, - (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x4f, (byte) 0x74, - (byte) 0x68, (byte) 0x65, (byte) 0x72, (byte) 0x2d, (byte) 0x43, (byte) 0x6f, - (byte) 0x6d, (byte) 0x70, (byte) 0x61, (byte) 0x6e, (byte) 0x79, (byte) 0x31, - (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x0c, (byte) 0x53, (byte) 0x6f, - (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x65, (byte) 0x63, - (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, (byte) 0x31, (byte) 0x21, - (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x03, (byte) 0x0c, (byte) 0x18, (byte) 0x57, (byte) 0x69, (byte) 0x66, - (byte) 0x69, (byte) 0x45, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72, - (byte) 0x70, (byte) 0x72, (byte) 0x69, (byte) 0x73, (byte) 0x65, (byte) 0x43, - (byte) 0x6f, (byte) 0x6e, (byte) 0x66, (byte) 0x69, (byte) 0x67, (byte) 0x54, - (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x31, (byte) 0x2e, (byte) 0x30, - (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, - (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x09, (byte) 0x01, - (byte) 0x16, (byte) 0x1f, (byte) 0x61, (byte) 0x6e, (byte) 0x2d, (byte) 0x65, - (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6c, (byte) 0x2d, (byte) 0x61, - (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x40, - (byte) 0x73, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x64, - (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x2e, - (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x1e, (byte) 0x17, - (byte) 0x0d, (byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x31, - (byte) 0x35, (byte) 0x31, (byte) 0x31, (byte) 0x33, (byte) 0x32, (byte) 0x34, - (byte) 0x36, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x36, - (byte) 0x30, (byte) 0x31, (byte) 0x31, (byte) 0x32, (byte) 0x31, (byte) 0x31, - (byte) 0x33, (byte) 0x32, (byte) 0x34, (byte) 0x36, (byte) 0x5a, (byte) 0x30, - (byte) 0x81, (byte) 0xbd, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, - (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, - (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, - (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, - (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, - (byte) 0x31, (byte) 0x12, (byte) 0x30, (byte) 0x10, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0c, (byte) 0x09, (byte) 0x53, - (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x43, (byte) 0x69, - (byte) 0x74, (byte) 0x79, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, - (byte) 0x12, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, - (byte) 0x4f, (byte) 0x74, (byte) 0x68, (byte) 0x65, (byte) 0x72, (byte) 0x2d, - (byte) 0x43, (byte) 0x6f, (byte) 0x6d, (byte) 0x70, (byte) 0x61, (byte) 0x6e, - (byte) 0x79, (byte) 0x31, (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x0c, - (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, - (byte) 0x65, (byte) 0x63, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, - (byte) 0x31, (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x18, (byte) 0x57, - (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x45, (byte) 0x6e, (byte) 0x74, - (byte) 0x65, (byte) 0x72, (byte) 0x70, (byte) 0x72, (byte) 0x69, (byte) 0x73, - (byte) 0x65, (byte) 0x43, (byte) 0x6f, (byte) 0x6e, (byte) 0x66, (byte) 0x69, - (byte) 0x67, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x31, - (byte) 0x2e, (byte) 0x30, (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x09, (byte) 0x01, (byte) 0x16, (byte) 0x1f, (byte) 0x61, (byte) 0x6e, - (byte) 0x2d, (byte) 0x65, (byte) 0x6d, (byte) 0x61, (byte) 0x69, (byte) 0x6c, - (byte) 0x2d, (byte) 0x61, (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, - (byte) 0x73, (byte) 0x40, (byte) 0x73, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, - (byte) 0x2d, (byte) 0x64, (byte) 0x6f, (byte) 0x6d, (byte) 0x61, (byte) 0x69, - (byte) 0x6e, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, - (byte) 0x82, (byte) 0x01, (byte) 0x22, (byte) 0x30, (byte) 0x0d, (byte) 0x06, - (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, - (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, - (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x0f, (byte) 0x00, (byte) 0x30, - (byte) 0x82, (byte) 0x01, (byte) 0x0a, (byte) 0x02, (byte) 0x82, (byte) 0x01, - (byte) 0x01, (byte) 0x00, (byte) 0xa9, (byte) 0xa3, (byte) 0x21, (byte) 0xfd, - (byte) 0xa6, (byte) 0xc1, (byte) 0x04, (byte) 0x48, (byte) 0xc2, (byte) 0xc8, - (byte) 0x44, (byte) 0x50, (byte) 0xc4, (byte) 0x6d, (byte) 0x35, (byte) 0x24, - (byte) 0xf0, (byte) 0x6d, (byte) 0x69, (byte) 0xfb, (byte) 0xd1, (byte) 0xfc, - (byte) 0xde, (byte) 0xe9, (byte) 0xdb, (byte) 0xca, (byte) 0xee, (byte) 0x24, - (byte) 0x3d, (byte) 0x85, (byte) 0x8d, (byte) 0x84, (byte) 0xb4, (byte) 0x73, - (byte) 0xd1, (byte) 0x09, (byte) 0x37, (byte) 0x16, (byte) 0x80, (byte) 0x70, - (byte) 0x6b, (byte) 0x61, (byte) 0xcc, (byte) 0xf2, (byte) 0x98, (byte) 0xbd, - (byte) 0x53, (byte) 0x3a, (byte) 0x68, (byte) 0x60, (byte) 0x02, (byte) 0xba, - (byte) 0x0c, (byte) 0x53, (byte) 0x96, (byte) 0xfb, (byte) 0x80, (byte) 0xd1, - (byte) 0x5b, (byte) 0xc3, (byte) 0xcb, (byte) 0x7a, (byte) 0x81, (byte) 0x00, - (byte) 0x5d, (byte) 0x20, (byte) 0x72, (byte) 0xc0, (byte) 0xe4, (byte) 0x48, - (byte) 0x0e, (byte) 0xa2, (byte) 0xcd, (byte) 0xa2, (byte) 0x63, (byte) 0x8c, - (byte) 0x05, (byte) 0x7c, (byte) 0x63, (byte) 0x5b, (byte) 0xda, (byte) 0x0e, - (byte) 0xa7, (byte) 0x05, (byte) 0x09, (byte) 0x6d, (byte) 0xd5, (byte) 0xe4, - (byte) 0x3a, (byte) 0x4e, (byte) 0xa1, (byte) 0xf5, (byte) 0xfd, (byte) 0x47, - (byte) 0xee, (byte) 0x7b, (byte) 0xa3, (byte) 0x4c, (byte) 0x8c, (byte) 0xd3, - (byte) 0xbb, (byte) 0x58, (byte) 0x0f, (byte) 0x1c, (byte) 0x56, (byte) 0x80, - (byte) 0x80, (byte) 0xb5, (byte) 0xf9, (byte) 0x80, (byte) 0xc2, (byte) 0xd1, - (byte) 0x1d, (byte) 0x3f, (byte) 0xe8, (byte) 0x2a, (byte) 0x63, (byte) 0x0b, - (byte) 0x54, (byte) 0x5f, (byte) 0xd4, (byte) 0xcb, (byte) 0xb7, (byte) 0x94, - (byte) 0xe2, (byte) 0x35, (byte) 0x65, (byte) 0x59, (byte) 0xd1, (byte) 0x72, - (byte) 0xa4, (byte) 0xb8, (byte) 0xee, (byte) 0x82, (byte) 0x11, (byte) 0x7a, - (byte) 0x4c, (byte) 0x26, (byte) 0x66, (byte) 0x9b, (byte) 0x27, (byte) 0x3d, - (byte) 0x14, (byte) 0x4b, (byte) 0x4b, (byte) 0xc8, (byte) 0xf0, (byte) 0x6e, - (byte) 0x43, (byte) 0x8f, (byte) 0xee, (byte) 0x1f, (byte) 0xeb, (byte) 0x20, - (byte) 0xe2, (byte) 0x4c, (byte) 0x79, (byte) 0xbf, (byte) 0x21, (byte) 0x0d, - (byte) 0x36, (byte) 0xed, (byte) 0x5f, (byte) 0xcc, (byte) 0x70, (byte) 0x68, - (byte) 0x8a, (byte) 0x05, (byte) 0x7c, (byte) 0x2f, (byte) 0x1b, (byte) 0xe9, - (byte) 0xec, (byte) 0x83, (byte) 0x6e, (byte) 0x9a, (byte) 0x78, (byte) 0x31, - (byte) 0x3d, (byte) 0xf4, (byte) 0xde, (byte) 0x1b, (byte) 0xd2, (byte) 0x76, - (byte) 0x32, (byte) 0x6c, (byte) 0x1e, (byte) 0xc9, (byte) 0x90, (byte) 0x7f, - (byte) 0xc4, (byte) 0x30, (byte) 0xc0, (byte) 0xae, (byte) 0xab, (byte) 0x70, - (byte) 0x08, (byte) 0x78, (byte) 0xbf, (byte) 0x2e, (byte) 0x8b, (byte) 0x07, - (byte) 0xab, (byte) 0x8f, (byte) 0x03, (byte) 0xc5, (byte) 0xd3, (byte) 0xeb, - (byte) 0x98, (byte) 0x19, (byte) 0x50, (byte) 0x83, (byte) 0x52, (byte) 0xf7, - (byte) 0xff, (byte) 0xf5, (byte) 0x89, (byte) 0xe6, (byte) 0xe7, (byte) 0xa7, - (byte) 0xcb, (byte) 0xdf, (byte) 0x96, (byte) 0x9d, (byte) 0x14, (byte) 0x04, - (byte) 0x5e, (byte) 0x45, (byte) 0x82, (byte) 0xf7, (byte) 0x23, (byte) 0x1a, - (byte) 0xb6, (byte) 0x64, (byte) 0x57, (byte) 0xe8, (byte) 0x7e, (byte) 0xa1, - (byte) 0xaf, (byte) 0x58, (byte) 0x68, (byte) 0x70, (byte) 0xc5, (byte) 0x0f, - (byte) 0x8d, (byte) 0x54, (byte) 0xf3, (byte) 0x49, (byte) 0xa3, (byte) 0x97, - (byte) 0x32, (byte) 0xa7, (byte) 0x2a, (byte) 0x79, (byte) 0xbe, (byte) 0xcd, - (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, - (byte) 0x50, (byte) 0x30, (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, - (byte) 0x04, (byte) 0x14, (byte) 0xac, (byte) 0xf3, (byte) 0x73, (byte) 0x9a, - (byte) 0x25, (byte) 0x08, (byte) 0x01, (byte) 0x07, (byte) 0x86, (byte) 0x8b, - (byte) 0xc4, (byte) 0xed, (byte) 0xb1, (byte) 0x6b, (byte) 0x53, (byte) 0xa3, - (byte) 0x21, (byte) 0xb4, (byte) 0xb4, (byte) 0x46, (byte) 0x30, (byte) 0x1f, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, - (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0xac, - (byte) 0xf3, (byte) 0x73, (byte) 0x9a, (byte) 0x25, (byte) 0x08, (byte) 0x01, - (byte) 0x07, (byte) 0x86, (byte) 0x8b, (byte) 0xc4, (byte) 0xed, (byte) 0xb1, - (byte) 0x6b, (byte) 0x53, (byte) 0xa3, (byte) 0x21, (byte) 0xb4, (byte) 0xb4, - (byte) 0x46, (byte) 0x30, (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, - (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06, - (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, - (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05, (byte) 0x00, - (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x16, - (byte) 0xf6, (byte) 0xd0, (byte) 0xe1, (byte) 0x14, (byte) 0x2d, (byte) 0x52, - (byte) 0x47, (byte) 0xa2, (byte) 0x89, (byte) 0xe6, (byte) 0x7f, (byte) 0xac, - (byte) 0x88, (byte) 0x04, (byte) 0x15, (byte) 0x21, (byte) 0x00, (byte) 0x72, - (byte) 0xf9, (byte) 0xee, (byte) 0xb2, (byte) 0x1b, (byte) 0x8e, (byte) 0x46, - (byte) 0x8b, (byte) 0x90, (byte) 0x20, (byte) 0x4f, (byte) 0xa7, (byte) 0xae, - (byte) 0x30, (byte) 0xb6, (byte) 0x24, (byte) 0xc5, (byte) 0x54, (byte) 0xaf, - (byte) 0x6c, (byte) 0x1e, (byte) 0xd6, (byte) 0x73, (byte) 0x22, (byte) 0x48, - (byte) 0x07, (byte) 0xb5, (byte) 0x13, (byte) 0x35, (byte) 0xbb, (byte) 0x9e, - (byte) 0xd9, (byte) 0x19, (byte) 0x79, (byte) 0xda, (byte) 0x76, (byte) 0x7f, - (byte) 0xf7, (byte) 0x87, (byte) 0xc9, (byte) 0xc3, (byte) 0x0b, (byte) 0x38, - (byte) 0x20, (byte) 0x26, (byte) 0xfc, (byte) 0x7f, (byte) 0x32, (byte) 0x2a, - (byte) 0xd5, (byte) 0x09, (byte) 0x87, (byte) 0xda, (byte) 0x23, (byte) 0x1f, - (byte) 0x71, (byte) 0x83, (byte) 0x00, (byte) 0x17, (byte) 0xf6, (byte) 0xb9, - (byte) 0x57, (byte) 0x21, (byte) 0xdf, (byte) 0x29, (byte) 0xcc, (byte) 0xdb, - (byte) 0xe9, (byte) 0x2c, (byte) 0xba, (byte) 0x86, (byte) 0x34, (byte) 0x53, - (byte) 0x29, (byte) 0x09, (byte) 0xc7, (byte) 0x3c, (byte) 0x8e, (byte) 0xa3, - (byte) 0x86, (byte) 0x81, (byte) 0x26, (byte) 0x7b, (byte) 0xa1, (byte) 0xbe, - (byte) 0xbc, (byte) 0xc9, (byte) 0x83, (byte) 0xb5, (byte) 0x36, (byte) 0x65, - (byte) 0x51, (byte) 0xb4, (byte) 0x41, (byte) 0xf0, (byte) 0x05, (byte) 0x78, - (byte) 0x3a, (byte) 0xa6, (byte) 0xad, (byte) 0x4b, (byte) 0x08, (byte) 0xd1, - (byte) 0xe4, (byte) 0xf1, (byte) 0x2e, (byte) 0xc7, (byte) 0x23, (byte) 0x6d, - (byte) 0xf0, (byte) 0x9d, (byte) 0x60, (byte) 0x6d, (byte) 0xe7, (byte) 0x11, - (byte) 0xaf, (byte) 0x41, (byte) 0x68, (byte) 0xee, (byte) 0x06, (byte) 0x76, - (byte) 0x82, (byte) 0x48, (byte) 0xee, (byte) 0x41, (byte) 0xc4, (byte) 0xf8, - (byte) 0xe1, (byte) 0x83, (byte) 0xbc, (byte) 0xa8, (byte) 0xbd, (byte) 0x9c, - (byte) 0x17, (byte) 0x45, (byte) 0xf4, (byte) 0x36, (byte) 0x67, (byte) 0x47, - (byte) 0x0e, (byte) 0x32, (byte) 0x13, (byte) 0x6e, (byte) 0xc1, (byte) 0x1e, - (byte) 0x08, (byte) 0xef, (byte) 0x10, (byte) 0xdf, (byte) 0x45, (byte) 0xbf, - (byte) 0x5a, (byte) 0xc4, (byte) 0x44, (byte) 0x4c, (byte) 0xd0, (byte) 0xd5, - (byte) 0x23, (byte) 0xde, (byte) 0xd7, (byte) 0x83, (byte) 0x1e, (byte) 0xb0, - (byte) 0x27, (byte) 0x4d, (byte) 0x57, (byte) 0xa3, (byte) 0xe8, (byte) 0x36, - (byte) 0x52, (byte) 0x1c, (byte) 0x48, (byte) 0x0a, (byte) 0xc4, (byte) 0xd8, - (byte) 0x32, (byte) 0xfc, (byte) 0xd0, (byte) 0x26, (byte) 0x6f, (byte) 0xa4, - (byte) 0x61, (byte) 0x2c, (byte) 0x3a, (byte) 0xa9, (byte) 0xfe, (byte) 0xa4, - (byte) 0x7a, (byte) 0x58, (byte) 0x54, (byte) 0x58, (byte) 0x96, (byte) 0x2b, - (byte) 0x6e, (byte) 0x9c, (byte) 0xc9, (byte) 0x00, (byte) 0xda, (byte) 0xc6, - (byte) 0xbb, (byte) 0x97, (byte) 0xc4, (byte) 0x95, (byte) 0x32, (byte) 0x6b, - (byte) 0x03, (byte) 0x6f, (byte) 0x33, (byte) 0x59, (byte) 0xd4, (byte) 0xa4, - (byte) 0x4a, (byte) 0x29, (byte) 0x29, (byte) 0x9a, (byte) 0xf4, (byte) 0x87, - (byte) 0x26, (byte) 0xe6, (byte) 0xee, (byte) 0x5c, (byte) 0x0b, (byte) 0xe9, - (byte) 0x98, (byte) 0x5d, (byte) 0xab, (byte) 0x31, (byte) 0xa1, (byte) 0x63, - (byte) 0xaa, (byte) 0x1a, (byte) 0xea, (byte) 0x61, (byte) 0x27, (byte) 0x5e, - (byte) 0x9e, (byte) 0x34, (byte) 0x73 - }; - - /** - * Client certificate generated from above and converted with: - * - * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g' - */ - private static final byte[] FAKE_EC_3 = { - (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xdf, (byte) 0x30, (byte) 0x82, - (byte) 0x01, (byte) 0xc7, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, - (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d, - (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, - (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05, - (byte) 0x00, (byte) 0x30, (byte) 0x64, (byte) 0x31, (byte) 0x0b, (byte) 0x30, - (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, - (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b, - (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x08, (byte) 0x0c, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31, - (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x07, (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f, - (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, - (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, - (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06, (byte) 0x47, (byte) 0x6f, - (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x31, (byte) 0x10, - (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, - (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x0d, - (byte) 0x30, (byte) 0x0b, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x03, (byte) 0x0c, (byte) 0x04, (byte) 0x54, (byte) 0x45, (byte) 0x53, - (byte) 0x54, (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, - (byte) 0x37, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x37, (byte) 0x31, - (byte) 0x37, (byte) 0x35, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x5a, - (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x37, (byte) 0x30, (byte) 0x31, - (byte) 0x32, (byte) 0x35, (byte) 0x31, (byte) 0x37, (byte) 0x35, (byte) 0x38, - (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x50, (byte) 0x31, - (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, - (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x02, (byte) 0x43, - (byte) 0x41, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06, - (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, - (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, - (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, - (byte) 0x31, (byte) 0x11, (byte) 0x30, (byte) 0x0f, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x08, (byte) 0x54, - (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2d, (byte) 0x55, (byte) 0x53, - (byte) 0x52, (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, - (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, - (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, - (byte) 0x03, (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0x4a, (byte) 0xb8, - (byte) 0x60, (byte) 0x17, (byte) 0x40, (byte) 0x91, (byte) 0x30, (byte) 0xf7, - (byte) 0xdf, (byte) 0x36, (byte) 0x83, (byte) 0x31, (byte) 0xb5, (byte) 0x3a, - (byte) 0xf4, (byte) 0xd4, (byte) 0xa1, (byte) 0xce, (byte) 0xd5, (byte) 0x54, - (byte) 0x97, (byte) 0x93, (byte) 0x7e, (byte) 0x7b, (byte) 0x08, (byte) 0x63, - (byte) 0x37, (byte) 0x62, (byte) 0xf1, (byte) 0x4e, (byte) 0x6a, (byte) 0x2e, - (byte) 0x35, (byte) 0x4e, (byte) 0x9f, (byte) 0x48, (byte) 0xcd, (byte) 0x09, - (byte) 0x17, (byte) 0xb3, (byte) 0xc1, (byte) 0x58, (byte) 0x02, (byte) 0x49, - (byte) 0x7b, (byte) 0x4c, (byte) 0xf7, (byte) 0x9b, (byte) 0xbb, (byte) 0x1b, - (byte) 0x2b, (byte) 0x9c, (byte) 0xe9, (byte) 0x36, (byte) 0xc4, (byte) 0x00, - (byte) 0x81, (byte) 0x2c, (byte) 0x28, (byte) 0xd9, (byte) 0x6b, (byte) 0xad, - (byte) 0xe3, (byte) 0xe8, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, - (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, - (byte) 0x13, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, - (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, - (byte) 0x01, (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, - (byte) 0x04, (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, - (byte) 0x65, (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, - (byte) 0x47, (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, - (byte) 0x74, (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, - (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, - (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, - (byte) 0x04, (byte) 0x14, (byte) 0xef, (byte) 0xf0, (byte) 0x15, (byte) 0xd7, - (byte) 0xc9, (byte) 0x3e, (byte) 0x9a, (byte) 0x73, (byte) 0xfa, (byte) 0x38, - (byte) 0xc5, (byte) 0x81, (byte) 0x84, (byte) 0x74, (byte) 0xd3, (byte) 0x83, - (byte) 0x74, (byte) 0x26, (byte) 0xf1, (byte) 0x0b, (byte) 0x30, (byte) 0x1f, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, - (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x38, - (byte) 0x6a, (byte) 0x9b, (byte) 0xf8, (byte) 0x3c, (byte) 0x0d, (byte) 0x54, - (byte) 0x9f, (byte) 0xdf, (byte) 0xf8, (byte) 0x53, (byte) 0x32, (byte) 0xa8, - (byte) 0xf7, (byte) 0x09, (byte) 0x15, (byte) 0x08, (byte) 0x76, (byte) 0xab, - (byte) 0x8d, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, - (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0xa6, (byte) 0x6c, (byte) 0x18, - (byte) 0xa9, (byte) 0x67, (byte) 0x16, (byte) 0x6a, (byte) 0x9e, (byte) 0x23, - (byte) 0xb3, (byte) 0x2a, (byte) 0xb8, (byte) 0x16, (byte) 0x7b, (byte) 0xb4, - (byte) 0xc8, (byte) 0xbc, (byte) 0x51, (byte) 0xe0, (byte) 0x6f, (byte) 0x05, - (byte) 0x66, (byte) 0xa1, (byte) 0x6f, (byte) 0x96, (byte) 0xde, (byte) 0x5b, - (byte) 0x41, (byte) 0x60, (byte) 0xe5, (byte) 0x29, (byte) 0x99, (byte) 0x12, - (byte) 0xfc, (byte) 0xa9, (byte) 0x91, (byte) 0x23, (byte) 0xb7, (byte) 0x9e, - (byte) 0x00, (byte) 0x5f, (byte) 0x93, (byte) 0xd4, (byte) 0xf7, (byte) 0x27, - (byte) 0x29, (byte) 0x77, (byte) 0xfb, (byte) 0x53, (byte) 0x09, (byte) 0xdc, - (byte) 0xe9, (byte) 0xd0, (byte) 0x5c, (byte) 0x92, (byte) 0x6d, (byte) 0xb7, - (byte) 0xcf, (byte) 0x04, (byte) 0xab, (byte) 0xf1, (byte) 0x39, (byte) 0xb9, - (byte) 0x49, (byte) 0x23, (byte) 0x7c, (byte) 0x0f, (byte) 0x15, (byte) 0x27, - (byte) 0xcd, (byte) 0x65, (byte) 0x3c, (byte) 0x6b, (byte) 0x91, (byte) 0x42, - (byte) 0x5a, (byte) 0xfe, (byte) 0xbe, (byte) 0xb8, (byte) 0xa2, (byte) 0xfd, - (byte) 0x67, (byte) 0x43, (byte) 0x4b, (byte) 0xc9, (byte) 0x28, (byte) 0x65, - (byte) 0x1b, (byte) 0x82, (byte) 0x5b, (byte) 0x25, (byte) 0x20, (byte) 0x9b, - (byte) 0xea, (byte) 0x99, (byte) 0xbb, (byte) 0x66, (byte) 0xc1, (byte) 0x8e, - (byte) 0x46, (byte) 0x0b, (byte) 0x4e, (byte) 0x06, (byte) 0xdd, (byte) 0x50, - (byte) 0x51, (byte) 0x64, (byte) 0xe8, (byte) 0x83, (byte) 0x99, (byte) 0x8e, - (byte) 0x53, (byte) 0xe9, (byte) 0x48, (byte) 0x47, (byte) 0x0e, (byte) 0x08, - (byte) 0x5e, (byte) 0x0d, (byte) 0x4a, (byte) 0x54, (byte) 0x17, (byte) 0xc1, - (byte) 0xf8, (byte) 0xcf, (byte) 0xba, (byte) 0x5c, (byte) 0x38, (byte) 0x70, - (byte) 0x33, (byte) 0x31, (byte) 0x22, (byte) 0x03, (byte) 0x6f, (byte) 0x54, - (byte) 0x3c, (byte) 0x41, (byte) 0xf0, (byte) 0x89, (byte) 0x85, (byte) 0xbc, - (byte) 0x77, (byte) 0x3c, (byte) 0xe8, (byte) 0xec, (byte) 0xb4, (byte) 0x35, - (byte) 0x7a, (byte) 0xcc, (byte) 0x8c, (byte) 0x5f, (byte) 0xa1, (byte) 0xed, - (byte) 0xa6, (byte) 0x28, (byte) 0x14, (byte) 0xc7, (byte) 0x8a, (byte) 0xef, - (byte) 0x56, (byte) 0x26, (byte) 0x35, (byte) 0x46, (byte) 0xab, (byte) 0xb0, - (byte) 0x97, (byte) 0xd2, (byte) 0xbd, (byte) 0xa9, (byte) 0x6a, (byte) 0xe4, - (byte) 0x3e, (byte) 0x87, (byte) 0xfb, (byte) 0xe1, (byte) 0x09, (byte) 0x8d, - (byte) 0x33, (byte) 0x12, (byte) 0xcf, (byte) 0xf0, (byte) 0xc0, (byte) 0xb8, - (byte) 0x9b, (byte) 0x9f, (byte) 0xb1, (byte) 0xcb, (byte) 0xac, (byte) 0x76, - (byte) 0xa8, (byte) 0x05, (byte) 0x6b, (byte) 0xcc, (byte) 0x41, (byte) 0xd2, - (byte) 0x26, (byte) 0x73, (byte) 0xfa, (byte) 0x69, (byte) 0xd3, (byte) 0x1f, - (byte) 0xa9, (byte) 0x0c, (byte) 0x6a, (byte) 0xd6, (byte) 0xc9, (byte) 0x35, - (byte) 0xc5, (byte) 0xad, (byte) 0xa1, (byte) 0x98, (byte) 0xc9, (byte) 0x78, - (byte) 0xa0, (byte) 0xe8, (byte) 0x02, (byte) 0x69, (byte) 0x80, (byte) 0x44, - (byte) 0xd9, (byte) 0xe6, (byte) 0xe5, (byte) 0x26, (byte) 0x4f, (byte) 0xcf, - (byte) 0x38, (byte) 0xcb, (byte) 0x55, (byte) 0x8c, (byte) 0x7d, (byte) 0x3c, - (byte) 0xa8, (byte) 0x82, (byte) 0x69, (byte) 0xa3, (byte) 0xdf, (byte) 0x0a, - (byte) 0x79, (byte) 0x7b, (byte) 0xdd, (byte) 0x24, (byte) 0x6a, (byte) 0x21, - (byte) 0x7b, (byte) 0x20, (byte) 0x94, (byte) 0xcd, (byte) 0x15, (byte) 0x92, - (byte) 0xad, (byte) 0x4a, (byte) 0x72, (byte) 0x0b, (byte) 0x0e, (byte) 0xb2, - (byte) 0xc9 - }; - - private static final byte[] FAKE_KEY_3 = { - (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01, - (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, - (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82, - (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e, - (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, - (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b, - (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66, - (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a, - (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02, - (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3, - (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d, - (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67, - (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb, - (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2, - (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79, - (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce, - (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08, - (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b, - (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4, - (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d, - (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23, - (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08, - (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1, - (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4, - (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16, - (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e, - (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01, - (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16, - (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98, - (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf, - (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a, - (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2, - (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc, - (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5, - (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a, - (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b, - (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9, - (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12, - (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e, - (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d, - (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2, - (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d, - (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc, - (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98, - (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96, - (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30, - (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e, - (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad, - (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f, - (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89, - (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13, - (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a, - (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e, - (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa, - (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47, - (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44, - (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22, - (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10, - (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45, - (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4, - (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda, - (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1, - (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab, - (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7, - (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc, - (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d, - (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82, - (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3, - (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a, - (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9, - (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6, - (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00, - (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd, - (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb, - (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4, - (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0, - (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2, - (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce, - (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a, - (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21, - (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d, - (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1, - (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41, - (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce, - (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0, - (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40, - (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a, - (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c, - (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90, - (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf, - (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb, - (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14, - (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab, - (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02, - (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67, - (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d, - (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d, - (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b, - (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2, - (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28, - (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd, - (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d, - (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b, - (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1, - (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51 - }; - - private boolean hasWifi() { - return getContext().getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI); - } - - public void testSettersAndGetters() throws Exception { - if (!hasWifi()) { - return; - } - - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - assertTrue(config.getEapMethod() == Eap.NONE); - config.setEapMethod(Eap.PEAP); - assertTrue(config.getEapMethod() == Eap.PEAP); - config.setEapMethod(Eap.PWD); - assertTrue(config.getEapMethod() == Eap.PWD); - config.setEapMethod(Eap.TLS); - assertTrue(config.getEapMethod() == Eap.TLS); - config.setEapMethod(Eap.TTLS); - assertTrue(config.getEapMethod() == Eap.TTLS); - assertTrue(config.getPhase2Method() == Phase2.NONE); - config.setPhase2Method(Phase2.PAP); - assertTrue(config.getPhase2Method() == Phase2.PAP); - config.setPhase2Method(Phase2.MSCHAP); - assertTrue(config.getPhase2Method() == Phase2.MSCHAP); - config.setPhase2Method(Phase2.MSCHAPV2); - assertTrue(config.getPhase2Method() == Phase2.MSCHAPV2); - config.setPhase2Method(Phase2.GTC); - assertTrue(config.getPhase2Method() == Phase2.GTC); - config.setIdentity(IDENTITY); - assertTrue(config.getIdentity().equals(IDENTITY)); - config.setAnonymousIdentity(ANON_IDENTITY); - assertTrue(config.getAnonymousIdentity().equals(ANON_IDENTITY)); - config.setPassword(PASSWORD); - assertTrue(config.getPassword().equals(PASSWORD)); - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - X509Certificate cert1 = (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(FAKE_EC_1)); - X509Certificate cert2 = (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(FAKE_EC_2)); - config.setCaCertificate(cert1); - assertTrue(config.getCaCertificate().getSerialNumber().equals(cert1.getSerialNumber())); - config.setCaCertificates(new X509Certificate[]{cert1, cert2}); - X509Certificate[] certs = config.getCaCertificates(); - assertTrue(cert1.getSerialNumber().equals(certs[0].getSerialNumber())); - assertTrue(cert2.getSerialNumber().equals(certs[1].getSerialNumber())); - - X509Certificate clientCert = (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(FAKE_EC_3)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - PrivateKey clientKey = kf.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_3)); - - config.setClientKeyEntry(clientKey, clientCert); - X509Certificate testClientCert = config.getClientCertificate(); - X509Certificate[] testClientCertChain = config.getClientCertificateChain(); - assertTrue(clientCert.getSerialNumber().equals(testClientCert.getSerialNumber())); - assertTrue(testClientCertChain.length == 1); - assertTrue(testClientCertChain[0] == testClientCert); - - config.setClientKeyEntry(null, null); - assertTrue(config.getClientCertificate() == null); - assertTrue(config.getClientCertificateChain() == null); - - config.setClientKeyEntryWithCertificateChain(clientKey, - new X509Certificate[]{clientCert, cert1}); - testClientCert = config.getClientCertificate(); - testClientCertChain = config.getClientCertificateChain(); - assertTrue(clientCert.getSerialNumber().equals(testClientCert.getSerialNumber())); - assertTrue(testClientCertChain.length == 2); - assertTrue(testClientCertChain[0] == testClientCert); - assertTrue(testClientCertChain[1] == cert1); - assertSame(clientKey, config.getClientPrivateKey()); - - config.setSubjectMatch(SUBJECT_MATCH); - assertTrue(config.getSubjectMatch().equals(SUBJECT_MATCH)); - // Hotspot 2.0 related attributes - config.setPlmn(PLMN); - assertTrue(config.getPlmn().equals(PLMN)); - config.setRealm(REALM); - assertTrue(config.getRealm().equals(REALM)); - config.setAltSubjectMatch(ALT_SUBJECT_MATCH); - assertTrue(config.getAltSubjectMatch().equals(ALT_SUBJECT_MATCH)); - config.setDomainSuffixMatch(DOM_SUBJECT_MATCH); - assertTrue(config.getDomainSuffixMatch().equals(DOM_SUBJECT_MATCH)); - } - - public void testEnterpriseConfigDoesNotPrintPassword() { - if(!hasWifi()) { - return; - } - WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); - final String identity = "IdentityIsOkayToBeDisplayedHere"; - final String password = "PasswordIsNotOkayToBeDisplayedHere"; - enterpriseConfig.setIdentity(identity); - enterpriseConfig.setPassword(password); - final String stringRepresentation = enterpriseConfig.toString(); - assertTrue(stringRepresentation.contains(identity)); - assertFalse(stringRepresentation.contains(password)); - } - - public void testGetSetCaCertificateAliases() { - if (!hasWifi()) { - return; - } - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - - config.setCaCertificateAliases(null); - assertThat(config.getCaCertificateAliases()).isNull(); - - config.setCaCertificateAliases(new String[]{CERTIFICATE_ALIAS1}); - assertThat(config.getCaCertificateAliases()).isEqualTo(new String[]{CERTIFICATE_ALIAS1}); - - config.setCaCertificateAliases(new String[]{CERTIFICATE_ALIAS1, CERTIFICATE_ALIAS2}); - assertThat(config.getCaCertificateAliases()) - .isEqualTo(new String[]{CERTIFICATE_ALIAS1, CERTIFICATE_ALIAS2}); - } - - public void testGetSetCaPath() { - if (!hasWifi()) { - return; - } - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - - config.setCaPath(""); - assertThat(config.getCaPath()).isEmpty(); - - config.setCaPath(CA_PATH); - assertThat(config.getCaPath()).isEqualTo(CA_PATH); - } - - public void testGetSetClientCertificateAlias() { - if (!hasWifi()) { - return; - } - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - - config.setClientCertificateAlias(""); - assertThat(config.getClientCertificateAlias()).isEmpty(); - - config.setClientCertificateAlias(CLIENT_CERTIFICATE_ALIAS); - assertThat(config.getClientCertificateAlias()).isEqualTo(CLIENT_CERTIFICATE_ALIAS); - } - - public void testGetSetOcsp() { - if (!hasWifi()) { - return; - } - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - - config.setOcsp(WifiEnterpriseConfig.OCSP_NONE); - assertThat(config.getOcsp()).isEqualTo(WifiEnterpriseConfig.OCSP_NONE); - - config.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS); - assertThat(config.getOcsp()) - .isEqualTo(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS); - - try { - config.setOcsp(-1); - fail("WifiEnterpriseConfig.setOcsp(-1) did not throw an IllegalArgumentException!"); - } catch (IllegalArgumentException expected) {} - } - - public void testGetSetWapiCertSuite() { - if (!hasWifi()) { - return; - } - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - - config.setWapiCertSuite(""); - assertThat(config.getWapiCertSuite()).isEmpty(); - - config.setWapiCertSuite(WAPI_CERT_SUITE); - assertThat(config.getWapiCertSuite()).isEqualTo(WAPI_CERT_SUITE); - } - - public void testIsAuthenticationSimBased() { - if (!hasWifi()) { - return; - } - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - - config.setEapMethod(Eap.AKA); - assertThat(config.isAuthenticationSimBased()).isTrue(); - - config.setEapMethod(Eap.PWD); - assertThat(config.isAuthenticationSimBased()).isFalse(); - - config.setEapMethod(Eap.PEAP); - config.setPhase2Method(Phase2.SIM); - assertThat(config.isAuthenticationSimBased()).isTrue(); - - config.setEapMethod(Eap.PEAP); - config.setPhase2Method(Phase2.NONE); - assertThat(config.isAuthenticationSimBased()).isFalse(); - } - - public void testCopyConstructor() { - if (!hasWifi()) { - return; - } - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - config.setEapMethod(Eap.WAPI_CERT); - config.setWapiCertSuite(WAPI_CERT_SUITE); - config.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS); - config.setCaPath(CA_PATH); - config.setPassword(PASSWORD); - config.setRealm(REALM); - - WifiEnterpriseConfig copy = new WifiEnterpriseConfig(config); - assertThat(copy.getEapMethod()).isEqualTo(Eap.WAPI_CERT); - assertThat(copy.getWapiCertSuite()).isEqualTo(WAPI_CERT_SUITE); - assertThat(copy.getOcsp()) - .isEqualTo(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS); - assertThat(copy.getCaPath()).isEqualTo(CA_PATH); - assertThat(copy.getPassword()).isEqualTo(PASSWORD); - assertThat(copy.getRealm()).isEqualTo(REALM); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java deleted file mode 100644 index 3e9fef406e..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2012 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.wifi.cts; - -import android.content.Context; -import android.content.pm.PackageManager; - -public class WifiFeature { - public static boolean isWifiSupported(Context context) { - PackageManager packageManager = context.getPackageManager(); - return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI); - } - - public static boolean isP2pSupported(Context context) { - PackageManager packageManager = context.getPackageManager(); - return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiFrameworkInitializerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiFrameworkInitializerTest.java deleted file mode 100644 index d714ed6b35..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiFrameworkInitializerTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.wifi.cts; - -import android.net.wifi.WifiFrameworkInitializer; -import android.test.AndroidTestCase; - -public class WifiFrameworkInitializerTest extends AndroidTestCase { - /** - * WifiFrameworkInitializer.registerServiceWrappers() should only be called by - * SystemServiceRegistry during boot up when Wifi is first initialized. Calling this API at - * any other time should throw an exception. - */ - public void testRegisterServiceWrappers_failsWhenCalledOutsideOfSystemServiceRegistry() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - try { - WifiFrameworkInitializer.registerServiceWrappers(); - fail("Expected exception when calling " - + "WifiFrameworkInitializer.registerServiceWrappers() outside of " - + "SystemServiceRegistry!"); - } catch (IllegalStateException expected) {} - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java deleted file mode 100644 index a05b81b932..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java +++ /dev/null @@ -1,488 +0,0 @@ -/* - * 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.wifi.cts; - -import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE; - -import android.net.Uri; -import android.net.wifi.hotspot2.OsuProvider; -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.pps.Credential; -import android.net.wifi.hotspot2.pps.HomeSp; -import android.test.AndroidTestCase; -import android.text.TextUtils; - -import java.lang.reflect.Constructor; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -public class WifiHotspot2Test extends AndroidTestCase { - static final int SIM_CREDENTIAL = 0; - static final int USER_CREDENTIAL = 1; - static final int CERT_CREDENTIAL = 2; - private static final String TEST_SSID = "TEST SSID"; - private static final String TEST_FRIENDLY_NAME = "Friendly Name"; - private static final Map TEST_FRIENDLY_NAMES = - new HashMap() { - { - put("en", TEST_FRIENDLY_NAME); - put("kr", TEST_FRIENDLY_NAME + 2); - put("jp", TEST_FRIENDLY_NAME + 3); - } - }; - private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service"; - private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com"); - private static final String TEST_NAI = "test.access.com"; - private static final List TEST_METHOD_LIST = - Arrays.asList(1 /* METHOD_SOAP_XML_SPP */); - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - /** - * Tests {@link PasspointConfiguration#getMeteredOverride()} method. - *

    - * Test default value - */ - public void testGetMeteredOverride() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); - assertEquals(METERED_OVERRIDE_NONE, passpointConfiguration.getMeteredOverride()); - } - - /** - * Tests {@link PasspointConfiguration#getSubscriptionExpirationTimeMillis()} method. - *

    - * Test default value - */ - public void testGetSubscriptionExpirationTimeMillis() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); - assertEquals(Long.MIN_VALUE, - passpointConfiguration.getSubscriptionExpirationTimeMillis()); - } - - /** - * Tests {@link PasspointConfiguration#getUniqueId()} method. - *

    - * Test unique identifier is not null - */ - public void testGetUniqueId() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // Create a configuration and make sure the unique ID is not null - PasspointConfiguration passpointConfiguration1 = createConfig(SIM_CREDENTIAL, "123456*", - 18 /* EAP_SIM */); - String uniqueId1 = passpointConfiguration1.getUniqueId(); - assertNotNull(uniqueId1); - - // Create another configuration and make sure the unique ID is not null - PasspointConfiguration passpointConfiguration2 = createConfig(SIM_CREDENTIAL, "567890*", - 23 /* EAP_AKA */); - String uniqueId2 = passpointConfiguration2.getUniqueId(); - assertNotNull(uniqueId2); - - // Make sure the IDs are not equal - assertFalse(uniqueId1.equals(uniqueId2)); - - passpointConfiguration2 = createConfig(USER_CREDENTIAL); - assertFalse(uniqueId1.equals(passpointConfiguration2.getUniqueId())); - - passpointConfiguration2 = createConfig(CERT_CREDENTIAL); - assertFalse(uniqueId1.equals(passpointConfiguration2.getUniqueId())); - } - - /** - * Tests {@link PasspointConfiguration#isAutojoinEnabled()} method. - *

    - * Test default value - */ - public void testIsAutojoinEnabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); - assertTrue(passpointConfiguration.isAutojoinEnabled()); - } - - /** - * Tests {@link PasspointConfiguration#isMacRandomizationEnabled()} method. - *

    - * Test default value - */ - public void testIsMacRandomizationEnabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); - assertTrue(passpointConfiguration.isMacRandomizationEnabled()); - } - - /** - * Tests {@link PasspointConfiguration#isOsuProvisioned()} method. - *

    - * Test default value - */ - public void testIsOsuProvisioned() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - PasspointConfiguration passpointConfiguration = createConfig(USER_CREDENTIAL); - assertFalse(passpointConfiguration.isOsuProvisioned()); - } - - /** - * Tests {@link PasspointConfiguration#PasspointConfiguration(PasspointConfiguration)} method. - *

    - * Test the PasspointConfiguration copy constructor - */ - public void testPasspointConfigurationCopyConstructor() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - PasspointConfiguration passpointConfiguration = createConfig(USER_CREDENTIAL); - PasspointConfiguration copyOfPasspointConfiguration = - new PasspointConfiguration(passpointConfiguration); - assertEquals(passpointConfiguration, copyOfPasspointConfiguration); - } - - /** - * Tests {@link HomeSp#HomeSp(HomeSp)} method. - *

    - * Test the HomeSp copy constructor - */ - public void testHomeSpCopyConstructor() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - HomeSp homeSp = createHomeSp(); - HomeSp copyOfHomeSp = new HomeSp(homeSp); - assertEquals(copyOfHomeSp, homeSp); - } - - /** - * Tests {@link Credential#Credential(Credential)} method. - *

    - * Test the Credential copy constructor - */ - public void testCredentialCopyConstructor() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - Credential credential = createCredentialWithSimCredential("123456*", 18 /* EAP_SIM */); - Credential copyOfCredential = new Credential(credential); - assertEquals(copyOfCredential, credential); - } - - /** - * Tests {@link Credential.UserCredential#UserCredential(Credential.UserCredential)} method. - *

    - * Test the Credential.UserCredential copy constructor - */ - public void testUserCredentialCopyConstructor() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - Credential.UserCredential userCredential = new Credential.UserCredential(); - userCredential.setUsername("username"); - userCredential.setPassword("password"); - userCredential.setEapType(21 /* EAP_TTLS */); - userCredential.setNonEapInnerMethod("MS-CHAP"); - - Credential.UserCredential copyOfUserCredential = - new Credential.UserCredential(userCredential); - assertEquals(copyOfUserCredential, userCredential); - } - - /** - * Tests - * {@link Credential.CertificateCredential#CertificateCredential(Credential.CertificateCredential)} - * method. - *

    - * Test the Credential.CertificateCredential copy constructor - */ - public void testCertCredentialCopyConstructor() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); - certCredential.setCertType("x509v3"); - - Credential.CertificateCredential copyOfCertificateCredential = - new Credential.CertificateCredential(certCredential); - assertEquals(copyOfCertificateCredential, certCredential); - } - - /** - * Tests {@link Credential.SimCredential#SimCredential(Credential.SimCredential)} method. - *

    - * Test the Credential.SimCredential copy constructor - */ - public void testSimCredentialCopyConstructor() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - Credential.SimCredential simCredential = new Credential.SimCredential(); - simCredential.setImsi("1234*"); - simCredential.setEapType(18/* EAP_SIM */); - - Credential.SimCredential copyOfSimCredential = new Credential.SimCredential(simCredential); - assertEquals(copyOfSimCredential, simCredential); - } - - /** - * Tests {@link Credential#getCaCertificate()} method. - *

    - * Test that getting a set certificate produces the same value - */ - public void testCredentialGetCertificate() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - Credential credential = new Credential(); - credential.setCaCertificate(FakeKeys.CA_CERT0); - - assertEquals(FakeKeys.CA_CERT0, credential.getCaCertificate()); - } - - /** - * Tests {@link Credential#getClientCertificateChain()} and {@link - * Credential#setCaCertificates(X509Certificate[])} methods. - *

    - * Test that getting a set client certificate chain produces the same value - */ - public void testCredentialClientCertificateChain() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - Credential credential = new Credential(); - X509Certificate[] certificates = new X509Certificate[]{FakeKeys.CLIENT_CERT}; - credential.setClientCertificateChain(certificates); - - assertTrue(Arrays.equals(certificates, credential.getClientCertificateChain())); - } - - /** - * Tests {@link Credential#getClientPrivateKey()} and - * {@link Credential#setClientPrivateKey(PrivateKey)} - * methods. - *

    - * Test that getting a set client private key produces the same value - */ - public void testCredentialSetGetClientPrivateKey() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - Credential credential = new Credential(); - credential.setClientPrivateKey(FakeKeys.RSA_KEY1); - - assertEquals(FakeKeys.RSA_KEY1, credential.getClientPrivateKey()); - } - - /** - * Tests {@link Credential#getClientPrivateKey()} and - * {@link Credential#setClientPrivateKey(PrivateKey)} - * methods. - *

    - * Test that getting a set client private key produces the same value - */ - public void testCredentialGetClientPrivateKey() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - Credential credential = new Credential(); - credential.setClientPrivateKey(FakeKeys.RSA_KEY1); - - assertEquals(FakeKeys.RSA_KEY1, credential.getClientPrivateKey()); - } - - private static PasspointConfiguration createConfig(int type) throws Exception { - return createConfig(type, "123456*", 18 /* EAP_SIM */); - } - - private static PasspointConfiguration createConfig(int type, String imsi, int eapType) - throws Exception { - PasspointConfiguration config = new PasspointConfiguration(); - config.setHomeSp(createHomeSp()); - switch (type) { - default: - case SIM_CREDENTIAL: - config.setCredential( - createCredentialWithSimCredential(imsi, eapType)); - break; - case USER_CREDENTIAL: - config.setCredential(createCredentialWithUserCredential()); - break; - case CERT_CREDENTIAL: - config.setCredential(createCredentialWithCertificateCredential()); - break; - } - - return config; - } - - /** - * Helper function for generating HomeSp for testing. - * - * @return {@link HomeSp} - */ - private static HomeSp createHomeSp() { - HomeSp homeSp = new HomeSp(); - homeSp.setFqdn("test.com"); - homeSp.setFriendlyName("friendly name"); - homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66}); - return homeSp; - } - - /** - * Helper function for generating Credential for testing. - * - * @param userCred Instance of UserCredential - * @param certCred Instance of CertificateCredential - * @param simCred Instance of SimCredential - * @param clientCertificateChain Chain of client certificates - * @param clientPrivateKey Client private key - * @param caCerts CA certificates - * @return {@link Credential} - */ - private static Credential createCredential(Credential.UserCredential userCred, - Credential.CertificateCredential certCred, - Credential.SimCredential simCred, - X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey, - X509Certificate... caCerts) { - Credential cred = new Credential(); - cred.setRealm("realm"); - cred.setUserCredential(userCred); - cred.setCertCredential(certCred); - cred.setSimCredential(simCred); - return cred; - } - - /** - * Helper function for generating certificate credential for testing. - * - * @return {@link Credential} - */ - private static Credential createCredentialWithCertificateCredential() - throws NoSuchAlgorithmException, CertificateEncodingException { - Credential.CertificateCredential certCred = new Credential.CertificateCredential(); - certCred.setCertType("x509v3"); - certCred.setCertSha256Fingerprint( - MessageDigest.getInstance("SHA-256").digest( - FakeKeys.CLIENT_CERT.getEncoded())); - return createCredential(null, certCred, null, new X509Certificate[]{ - FakeKeys.CLIENT_CERT}, - FakeKeys.RSA_KEY1, FakeKeys.CA_CERT0, - FakeKeys.CA_CERT1); - } - - /** - * Helper function for generating SIM credential for testing. - * - * @return {@link Credential} - */ - private static Credential createCredentialWithSimCredential(String imsi, int eapType) { - Credential.SimCredential simCred = new Credential.SimCredential(); - simCred.setImsi(imsi); - simCred.setEapType(eapType); - return createCredential(null, null, simCred, null, null, (X509Certificate[]) null); - } - - /** - * Helper function for generating user credential for testing. - * - * @return {@link Credential} - */ - private static Credential createCredentialWithUserCredential() { - Credential.UserCredential userCred = new Credential.UserCredential(); - userCred.setUsername("username"); - userCred.setPassword("password"); - userCred.setEapType(21 /* EAP_TTLS */); - userCred.setNonEapInnerMethod("MS-CHAP"); - return createCredential(userCred, null, null, null, null, - FakeKeys.CA_CERT0); - } - - /** - * Tests {@link OsuProvider#getFriendlyName()} and {@link OsuProvider#getServerUri()} methods. - *

    - * Test that getting a set friendly name and server URI produces the same value - */ - public void testOsuProviderGetters() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // Using Java reflection to construct an OsuProvider instance because its constructor is - // hidden and not available to apps. - Class osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider"); - Constructor osuProviderClassConstructor = osuProviderClass.getConstructor(String.class, - Map.class, String.class, Uri.class, String.class, List.class); - - OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID, - TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, - TEST_METHOD_LIST); - String lang = Locale.getDefault().getLanguage(); - String friendlyName = TEST_FRIENDLY_NAMES.get(lang); - if (TextUtils.isEmpty(friendlyName)) { - friendlyName = TEST_FRIENDLY_NAMES.get("en"); - } - assertEquals(friendlyName, osuProvider.getFriendlyName()); - assertEquals(TEST_SERVER_URI, osuProvider.getServerUri()); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java deleted file mode 100644 index 557710dcba..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.wifi.ScanResult; -import android.net.wifi.SupplicantState; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.WifiLock; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -import com.android.compatibility.common.util.PollingCheck; -import com.android.compatibility.common.util.SystemUtil; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.Callable; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiInfoTest extends AndroidTestCase { - private static class MySync { - int expectedState = STATE_NULL; - } - - private WifiManager mWifiManager; - private WifiLock mWifiLock; - private static MySync mMySync; - - private static final int STATE_NULL = 0; - private static final int STATE_WIFI_CHANGING = 1; - private static final int STATE_WIFI_CHANGED = 2; - - private static final String TEST_SSID = "Test123"; - private static final String TEST_BSSID = "12:12:12:12:12:12"; - private static final int TEST_RSSI = -60; - private static final int TEST_NETWORK_ID = 5; - private static final int TEST_NETWORK_ID2 = 6; - - private static final String TAG = "WifiInfoTest"; - private static final int TIMEOUT_MSEC = 6000; - private static final int WAIT_MSEC = 60; - private static final int DURATION = 10000; - private IntentFilter mIntentFilter; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGED; - mMySync.notify(); - } - } - } - }; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mMySync = new MySync(); - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - - mContext.registerReceiver(mReceiver, mIntentFilter); - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertThat(mWifiManager).isNotNull(); - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - Thread.sleep(DURATION); - assertThat(mWifiManager.isWifiEnabled()).isTrue(); - mMySync.expectedState = STATE_NULL; - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - mWifiLock.release(); - mContext.unregisterReceiver(mReceiver); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - Thread.sleep(DURATION); - super.tearDown(); - } - - private void setWifiEnabled(boolean enable) throws Exception { - synchronized (mMySync) { - mMySync.expectedState = STATE_WIFI_CHANGING; - if (enable) { - SystemUtil.runShellCommand("svc wifi enable"); - } else { - SystemUtil.runShellCommand("svc wifi disable"); - } - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && mMySync.expectedState == STATE_WIFI_CHANGING) - mMySync.wait(WAIT_MSEC); - } - } - - public void testWifiInfoProperties() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // wait for Wifi to be connected - PollingCheck.check( - "Wifi not connected - Please ensure there is a saved network in range of this " - + "device", - 20000, - () -> mWifiManager.getConnectionInfo().getNetworkId() != -1); - - // this test case should in Wifi environment - WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - - testWifiInfoPropertiesWhileConnected(wifiInfo); - - setWifiEnabled(false); - - PollingCheck.check("getNetworkId not -1", 20000, new Callable() { - @Override - public Boolean call() throws Exception { - WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - return wifiInfo.getNetworkId() == -1; - } - }); - - PollingCheck.check("getWifiState not disabled", 20000, new Callable() { - @Override - public Boolean call() throws Exception { - return mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED; - } - }); - } - - private void testWifiInfoPropertiesWhileConnected(WifiInfo wifiInfo) { - assertThat(wifiInfo).isNotNull(); - assertThat(wifiInfo.toString()).isNotNull(); - SupplicantState.isValidState(wifiInfo.getSupplicantState()); - WifiInfo.getDetailedStateOf(SupplicantState.DISCONNECTED); - String ssid = wifiInfo.getSSID(); - if (!ssid.startsWith("0x") && !ssid.equals(WifiManager.UNKNOWN_SSID)) { - // Non-hex string should be quoted - assertThat(ssid).startsWith("\""); - assertThat(ssid).endsWith("\""); - } - - assertThat(wifiInfo.getBSSID()).isNotNull(); - assertThat(wifiInfo.getFrequency()).isGreaterThan(0); - assertThat(wifiInfo.getMacAddress()).isNotNull(); - - wifiInfo.getRssi(); - wifiInfo.getIpAddress(); - wifiInfo.getHiddenSSID(); - wifiInfo.getScore(); - - // null for saved networks - assertThat(wifiInfo.getRequestingPackageName()).isNull(); - assertThat(wifiInfo.getPasspointFqdn()).isNull(); - assertThat(wifiInfo.getPasspointProviderFriendlyName()).isNull(); - - // false for saved networks - assertThat(wifiInfo.isEphemeral()).isFalse(); - assertThat(wifiInfo.isOsuAp()).isFalse(); - assertThat(wifiInfo.isPasspointAp()).isFalse(); - - assertThat(wifiInfo.getWifiStandard()).isAnyOf( - ScanResult.WIFI_STANDARD_UNKNOWN, - ScanResult.WIFI_STANDARD_LEGACY, - ScanResult.WIFI_STANDARD_11N, - ScanResult.WIFI_STANDARD_11AC, - ScanResult.WIFI_STANDARD_11AX - ); - - assertThat(wifiInfo.getLostTxPacketsPerSecond()).isAtLeast(0.0); - assertThat(wifiInfo.getRetriedTxPacketsPerSecond()).isAtLeast(0.0); - assertThat(wifiInfo.getSuccessfulRxPacketsPerSecond()).isAtLeast(0.0); - assertThat(wifiInfo.getSuccessfulTxPacketsPerSecond()).isAtLeast(0.0); - - // Can be -1 if link speed is unknown - assertThat(wifiInfo.getLinkSpeed()).isAtLeast(-1); - assertThat(wifiInfo.getTxLinkSpeedMbps()).isAtLeast(-1); - assertThat(wifiInfo.getRxLinkSpeedMbps()).isAtLeast(-1); - assertThat(wifiInfo.getMaxSupportedTxLinkSpeedMbps()).isAtLeast(-1); - assertThat(wifiInfo.getMaxSupportedRxLinkSpeedMbps()).isAtLeast(-1); - } - - /** - * Test that the WifiInfo Builder returns the same values that was set, and that - * calling build multiple times returns different instances. - */ - public void testWifiInfoBuilder() throws Exception { - WifiInfo.Builder builder = new WifiInfo.Builder() - .setSsid(TEST_SSID.getBytes(StandardCharsets.UTF_8)) - .setBssid(TEST_BSSID) - .setRssi(TEST_RSSI) - .setNetworkId(TEST_NETWORK_ID); - - WifiInfo info1 = builder.build(); - - assertThat(info1.getSSID()).isEqualTo("\"" + TEST_SSID + "\""); - assertThat(info1.getBSSID()).isEqualTo(TEST_BSSID); - assertThat(info1.getRssi()).isEqualTo(TEST_RSSI); - assertThat(info1.getNetworkId()).isEqualTo(TEST_NETWORK_ID); - - WifiInfo info2 = builder - .setNetworkId(TEST_NETWORK_ID2) - .build(); - - // different instances - assertThat(info1).isNotSameAs(info2); - - // assert that info1 didn't change - assertThat(info1.getSSID()).isEqualTo("\"" + TEST_SSID + "\""); - assertThat(info1.getBSSID()).isEqualTo(TEST_BSSID); - assertThat(info1.getRssi()).isEqualTo(TEST_RSSI); - assertThat(info1.getNetworkId()).isEqualTo(TEST_NETWORK_ID); - - // assert that info2 changed - assertThat(info2.getSSID()).isEqualTo("\"" + TEST_SSID + "\""); - assertThat(info2.getBSSID()).isEqualTo(TEST_BSSID); - assertThat(info2.getRssi()).isEqualTo(TEST_RSSI); - assertThat(info2.getNetworkId()).isEqualTo(TEST_NETWORK_ID2); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java deleted file mode 100644 index fee9ef026a..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2008 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.wifi.cts; - -import android.content.Context; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.WifiLock; -import android.os.WorkSource; -import android.platform.test.annotations.AppModeFull; -import android.test.AndroidTestCase; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiLockTest extends AndroidTestCase { - - private static final String WIFI_TAG = "WifiLockTest"; - - /** - * Verify acquire and release of High Performance wifi locks - */ - public void testHiPerfWifiLock() { - testWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF); - } - - /** - * Verify acquire and release of Low latency wifi locks - */ - public void testLowLatencyWifiLock() { - testWifiLock(WifiManager.WIFI_MODE_FULL_LOW_LATENCY); - } - - private void testWifiLock(int lockType) { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - WifiLock wl = wm.createWifiLock(lockType, WIFI_TAG); - - wl.setReferenceCounted(true); - wl.setWorkSource(new WorkSource()); - assertFalse(wl.isHeld()); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - wl.acquire(); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - assertNotNull(wl.toString()); - try { - wl.release(); - fail("should throw out exception because release is called" - +" a greater number of times than acquire"); - } catch (RuntimeException e) { - // expected - } - - wl = wm.createWifiLock(lockType, WIFI_TAG); - wl.setReferenceCounted(false); - assertFalse(wl.isHeld()); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - wl.acquire(); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - assertNotNull(wl.toString()); - // releasing again after release: but ignored for non-referenced locks - wl.release(); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java deleted file mode 100644 index 0cf984c08f..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ /dev/null @@ -1,2532 +0,0 @@ -/* - * Copyright (C) 2009 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.wifi.cts; - -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; -import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT; - -import static com.google.common.truth.Truth.assertWithMessage; - -import static org.junit.Assert.assertNotEquals; - -import android.app.UiAutomation; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.MacAddress; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkRequest; -import android.net.TetheringManager; -import android.net.Uri; -import android.net.util.MacAddressUtils; -import android.net.wifi.ScanResult; -import android.net.wifi.SoftApCapability; -import android.net.wifi.SoftApConfiguration; -import android.net.wifi.SoftApInfo; -import android.net.wifi.WifiClient; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.WifiLock; -import android.net.wifi.WifiNetworkConnectionStatistics; -import android.net.wifi.hotspot2.ConfigParser; -import android.net.wifi.hotspot2.OsuProvider; -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.ProvisioningCallback; -import android.net.wifi.hotspot2.pps.Credential; -import android.net.wifi.hotspot2.pps.HomeSp; -import android.os.Handler; -import android.os.HandlerExecutor; -import android.os.HandlerThread; -import android.os.Process; -import android.os.SystemClock; -import android.os.UserHandle; -import android.platform.test.annotations.AppModeFull; -import android.provider.Settings; -import android.support.test.uiautomator.UiDevice; -import android.telephony.TelephonyManager; -import android.test.AndroidTestCase; -import android.text.TextUtils; -import android.util.ArraySet; -import android.util.Log; - -import androidx.test.platform.app.InstrumentationRegistry; - -import com.android.compatibility.common.util.PollingCheck; -import com.android.compatibility.common.util.ShellIdentityUtils; -import com.android.compatibility.common.util.SystemUtil; -import com.android.compatibility.common.util.ThrowingRunnable; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Constructor; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiManagerTest extends AndroidTestCase { - private static class MySync { - int expectedState = STATE_NULL; - } - - private WifiManager mWifiManager; - private ConnectivityManager mConnectivityManager; - private TetheringManager mTetheringManager; - private WifiLock mWifiLock; - private static MySync mMySync; - private List mScanResults = null; - private NetworkInfo mNetworkInfo; - private final Object mLock = new Object(); - private UiDevice mUiDevice; - private boolean mWasVerboseLoggingEnabled; - private boolean mWasScanThrottleEnabled; - private SoftApConfiguration mOriginalSoftApConfig = null; - - // Please refer to WifiManager - private static final int MIN_RSSI = -100; - private static final int MAX_RSSI = -55; - - private static final int STATE_NULL = 0; - private static final int STATE_WIFI_CHANGING = 1; - private static final int STATE_WIFI_ENABLED = 2; - private static final int STATE_WIFI_DISABLED = 3; - private static final int STATE_SCANNING = 4; - private static final int STATE_SCAN_DONE = 5; - - private static final String TAG = "WifiManagerTest"; - private static final String SSID1 = "\"WifiManagerTest\""; - // A full single scan duration is about 6-7 seconds if country code is set - // to US. If country code is set to world mode (00), we would expect a scan - // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here. - private static final int SCAN_TIMEOUT_MSEC = 9000; - private static final int TIMEOUT_MSEC = 6000; - private static final int WAIT_MSEC = 60; - private static final int TEST_WAIT_DURATION_MS = 10_000; - private static final int DURATION_SCREEN_TOGGLE = 2000; - private static final int DURATION_SETTINGS_TOGGLE = 1_000; - private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000; - private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; - private static final int WIFI_SCAN_TEST_ITERATIONS = 5; - - private static final int ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP = 50; - - private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; - private static final String MANAGED_PROVISIONING_PACKAGE_NAME - = "com.android.managedprovisioning"; - - private static final String TEST_SSID_UNQUOTED = "testSsid1"; - private static final MacAddress TEST_MAC = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); - private static final String TEST_PASSPHRASE = "passphrase"; - private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT = - "assets/ValidPasspointProfile.base64"; - private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config"; - - private IntentFilter mIntentFilter; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - - synchronized (mMySync) { - if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) { - mScanResults = mWifiManager.getScanResults(); - } else { - mScanResults = null; - } - mMySync.expectedState = STATE_SCAN_DONE; - mMySync.notifyAll(); - } - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN); - synchronized (mMySync) { - if (newState == WifiManager.WIFI_STATE_ENABLED) { - Log.d(TAG, "*** New WiFi state is ENABLED ***"); - mMySync.expectedState = STATE_WIFI_ENABLED; - mMySync.notifyAll(); - } else if (newState == WifiManager.WIFI_STATE_DISABLED) { - Log.d(TAG, "*** New WiFi state is DISABLED ***"); - mMySync.expectedState = STATE_WIFI_DISABLED; - mMySync.notifyAll(); - } - } - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - synchronized (mMySync) { - mNetworkInfo = - (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) - mMySync.notifyAll(); - } - } - } - }; - // Initialize with an invalid status value (0) - private int mProvisioningStatus = 0; - // Initialize with an invalid status value (0) - private int mProvisioningFailureStatus = 0; - private boolean mProvisioningComplete = false; - private ProvisioningCallback mProvisioningCallback = new ProvisioningCallback() { - @Override - public void onProvisioningFailure(int status) { - synchronized (mLock) { - mProvisioningFailureStatus = status; - mLock.notify(); - } - } - - @Override - public void onProvisioningStatus(int status) { - synchronized (mLock) { - mProvisioningStatus = status; - mLock.notify(); - } - } - - @Override - public void onProvisioningComplete() { - mProvisioningComplete = true; - } - }; - private static final String TEST_SSID = "TEST SSID"; - private static final String TEST_FRIENDLY_NAME = "Friendly Name"; - private static final Map TEST_FRIENDLY_NAMES = - new HashMap() { - { - put("en", TEST_FRIENDLY_NAME); - put("kr", TEST_FRIENDLY_NAME + 2); - put("jp", TEST_FRIENDLY_NAME + 3); - } - }; - private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service"; - private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com"); - private static final String TEST_NAI = "test.access.com"; - private static final List TEST_METHOD_LIST = - Arrays.asList(1 /* METHOD_SOAP_XML_SPP */); - private final HandlerThread mHandlerThread = new HandlerThread("WifiManagerTest"); - protected final Executor mExecutor; - { - mHandlerThread.start(); - mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper())); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mMySync = new MySync(); - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); - - mContext.registerReceiver(mReceiver, mIntentFilter); - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - mConnectivityManager = getContext().getSystemService(ConnectivityManager.class); - mTetheringManager = getContext().getSystemService(TetheringManager.class); - assertNotNull(mWifiManager); - assertNotNull(mTetheringManager); - - // turn on verbose logging for tests - mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.isVerboseLoggingEnabled()); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(true)); - // Disable scan throttling for tests. - mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.isScanThrottleEnabled()); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setScanThrottleEnabled(false)); - - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - turnScreenOnNoDelay(); - Thread.sleep(TEST_WAIT_DURATION_MS); - assertTrue(mWifiManager.isWifiEnabled()); - synchronized (mMySync) { - mMySync.expectedState = STATE_NULL; - } - - List savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( - mWifiManager::getConfiguredNetworks); - assertFalse("Need at least one saved network", savedNetworks.isEmpty()); - - // Get original config for restore - mOriginalSoftApConfig = ShellIdentityUtils.invokeWithShellPermissions( - mWifiManager::getSoftApConfiguration); - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - if (!mWifiManager.isWifiEnabled()) - setWifiEnabled(true); - mWifiLock.release(); - mContext.unregisterReceiver(mReceiver); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled)); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); - // restore original softap config - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setSoftApConfiguration(mOriginalSoftApConfig)); - Thread.sleep(TEST_WAIT_DURATION_MS); - super.tearDown(); - } - - private void setWifiEnabled(boolean enable) throws Exception { - synchronized (mMySync) { - if (mWifiManager.isWifiEnabled() != enable) { - // the new state is different, we expect it to change - mMySync.expectedState = STATE_WIFI_CHANGING; - } else { - mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); - } - // now trigger the change using shell commands. - SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable")); - waitForExpectedWifiState(enable); - } - } - - private void waitForExpectedWifiState(boolean enabled) throws InterruptedException { - synchronized (mMySync) { - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); - while (System.currentTimeMillis() < timeout - && mMySync.expectedState != expected) { - mMySync.wait(WAIT_MSEC); - } - } - } - - // Get the current scan status from sticky broadcast. - private boolean isScanCurrentlyAvailable() { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED); - Intent intent = mContext.registerReceiver(null, intentFilter); - assertNotNull(intent); - if (intent.getAction().equals(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED)) { - return intent.getBooleanExtra(WifiManager.EXTRA_SCAN_AVAILABLE, false); - } - return false; - } - - private void startScan() throws Exception { - synchronized (mMySync) { - mMySync.expectedState = STATE_SCANNING; - mScanResults = null; - assertTrue(mWifiManager.startScan()); - long timeout = System.currentTimeMillis() + SCAN_TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANNING) - mMySync.wait(WAIT_MSEC); - } - } - - private void waitForNetworkInfoState(NetworkInfo.State state) throws Exception { - synchronized (mMySync) { - if (mNetworkInfo.getState() == state) return; - long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && mNetworkInfo.getState() != state) - mMySync.wait(WAIT_MSEC); - assertTrue(mNetworkInfo.getState() == state); - } - - } - - private void waitForConnection() throws Exception { - waitForNetworkInfoState(NetworkInfo.State.CONNECTED); - } - - private void waitForDisconnection() throws Exception { - waitForNetworkInfoState(NetworkInfo.State.DISCONNECTED); - } - - private boolean existSSID(String ssid) { - for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { - if (w.SSID.equals(ssid)) - return true; - } - return false; - } - - private int findConfiguredNetworks(String SSID, List networks) { - for (final WifiConfiguration w : networks) { - if (w.SSID.equals(SSID)) - return networks.indexOf(w); - } - return -1; - } - - /** - * Test creation of WifiManager Lock. - */ - public void testWifiManagerLock() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - final String TAG = "Test"; - assertNotNull(mWifiManager.createWifiLock(TAG)); - assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); - } - - /** - * Test wifi scanning when location scan is turned off. - */ - public void testWifiManagerScanWhenWifiOffLocationTurnedOn() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - if (!hasLocationFeature()) { - Log.d(TAG, "Skipping test as location is not supported"); - return; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since Marshmallow WiFi scan results are" - + " empty when location is disabled!"); - } - setWifiEnabled(false); - Thread.sleep(TEST_WAIT_DURATION_MS); - startScan(); - if (mWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) { - // Make sure at least one AP is found. - assertNotNull("mScanResult should not be null!", mScanResults); - assertFalse("empty scan results!", mScanResults.isEmpty()); - } else { - // Make sure no scan results are available. - assertNull("mScanResult should be null!", mScanResults); - } - final String TAG = "Test"; - assertNotNull(mWifiManager.createWifiLock(TAG)); - assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); - } - - /** - * test point of wifiManager properties: - * 1.enable properties - * 2.DhcpInfo properties - * 3.wifi state - * 4.ConnectionInfo - */ - public void testWifiManagerProperties() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - setWifiEnabled(true); - assertTrue(mWifiManager.isWifiEnabled()); - assertNotNull(mWifiManager.getDhcpInfo()); - assertEquals(WifiManager.WIFI_STATE_ENABLED, mWifiManager.getWifiState()); - mWifiManager.getConnectionInfo(); - setWifiEnabled(false); - assertFalse(mWifiManager.isWifiEnabled()); - } - - /** - * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with - * {@link SystemClock#elapsedRealtime()} on device.

    - * To run this test in cts-tradefed: - * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp - */ - public void testWifiScanTimestamp() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - Log.d(TAG, "Skipping test as WiFi is not supported"); - return; - } - if (!hasLocationFeature()) { - Log.d(TAG, "Skipping test as location is not supported"); - return; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since Marshmallow WiFi scan results are" - + " empty when location is disabled!"); - } - if (!mWifiManager.isWifiEnabled()) { - setWifiEnabled(true); - } - // Scan multiple times to make sure scan timestamps increase with device timestamp. - for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) { - startScan(); - // Make sure at least one AP is found. - assertTrue("mScanResult should not be null. This may be due to a scan timeout", - mScanResults != null); - assertFalse("empty scan results!", mScanResults.isEmpty()); - long nowMillis = SystemClock.elapsedRealtime(); - // Keep track of how many APs are fresh in one scan. - int numFreshAps = 0; - for (ScanResult result : mScanResults) { - long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp); - if (Math.abs(nowMillis - scanTimeMillis) < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) { - numFreshAps++; - } - } - // At least half of the APs in the scan should be fresh. - int numTotalAps = mScanResults.size(); - String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: " - + numFreshAps; - assertTrue(msg, numFreshAps * 2 >= mScanResults.size()); - if (i < WIFI_SCAN_TEST_ITERATIONS - 1) { - // Wait before running next iteration. - Thread.sleep(WIFI_SCAN_TEST_INTERVAL_MILLIS); - } - } - } - - // Return true if location is enabled. - private boolean isLocationEnabled() { - return Settings.Secure.getInt(getContext().getContentResolver(), - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) != - Settings.Secure.LOCATION_MODE_OFF; - } - - // Returns true if the device has location feature. - private boolean hasLocationFeature() { - return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); - } - - private boolean hasAutomotiveFeature() { - return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); - } - - public void testSignal() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - final int numLevels = 9; - int expectLevel = 0; - assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels)); - assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels)); - expectLevel = 4; - assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2, - numLevels)); - int rssiA = 4; - int rssiB = 5; - assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0); - rssiB = 4; - assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0); - rssiA = 5; - rssiB = 4; - assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0); - } - - /** - * Test that {@link WifiManager#calculateSignalLevel(int)} returns a value in the range - * [0, {@link WifiManager#getMaxSignalLevel()}], and its value is monotonically increasing as - * the RSSI increases. - */ - public void testCalculateSignalLevel() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - int maxSignalLevel = mWifiManager.getMaxSignalLevel(); - - int prevSignalLevel = 0; - for (int rssi = -150; rssi <= 50; rssi++) { - int signalLevel = mWifiManager.calculateSignalLevel(rssi); - - // between [0, maxSignalLevel] - assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(0); - assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtMost(maxSignalLevel); - - // calculateSignalLevel(rssi) <= calculateSignalLevel(rssi + 1) - assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(prevSignalLevel); - prevSignalLevel = signalLevel; - } - } - - public class TestSoftApCallback implements WifiManager.SoftApCallback { - Object softApLock; - int currentState; - int currentFailureReason; - List currentClientList; - SoftApInfo currentSoftApInfo; - SoftApCapability currentSoftApCapability; - MacAddress lastBlockedClientMacAddress; - int lastBlockedClientReason; - boolean onStateChangedCalled = false; - boolean onSoftapInfoChangedCalled = false; - boolean onSoftApCapabilityChangedCalled = false; - boolean onConnectedClientCalled = false; - boolean onBlockedClientConnectingCalled = false; - - TestSoftApCallback(Object lock) { - softApLock = lock; - } - - public boolean getOnStateChangedCalled() { - synchronized(softApLock) { - return onStateChangedCalled; - } - } - - public boolean getOnSoftapInfoChangedCalled() { - synchronized(softApLock) { - return onSoftapInfoChangedCalled; - } - } - - public boolean getOnSoftApCapabilityChangedCalled() { - synchronized(softApLock) { - return onSoftApCapabilityChangedCalled; - } - } - - public boolean getOnConnectedClientCalled() { - synchronized(softApLock) { - return onConnectedClientCalled; - } - } - - public boolean getOnBlockedClientConnectingCalled() { - synchronized(softApLock) { - return onBlockedClientConnectingCalled; - } - } - - public int getCurrentState() { - synchronized(softApLock) { - return currentState; - } - } - - public int getCurrentStateFailureReason() { - synchronized(softApLock) { - return currentFailureReason; - } - } - - public List getCurrentClientList() { - synchronized(softApLock) { - return currentClientList; - } - } - - public SoftApInfo getCurrentSoftApInfo() { - synchronized(softApLock) { - return currentSoftApInfo; - } - } - - public SoftApCapability getCurrentSoftApCapability() { - synchronized(softApLock) { - return currentSoftApCapability; - } - } - - public MacAddress getLastBlockedClientMacAddress() { - synchronized(softApLock) { - return lastBlockedClientMacAddress; - } - } - - public int getLastBlockedClientReason() { - synchronized(softApLock) { - return lastBlockedClientReason; - } - } - - @Override - public void onStateChanged(int state, int failureReason) { - synchronized(softApLock) { - currentState = state; - currentFailureReason = failureReason; - onStateChangedCalled = true; - } - } - - @Override - public void onConnectedClientsChanged(List clients) { - synchronized(softApLock) { - currentClientList = new ArrayList<>(clients); - onConnectedClientCalled = true; - } - } - - @Override - public void onInfoChanged(SoftApInfo softApInfo) { - synchronized(softApLock) { - currentSoftApInfo = softApInfo; - onSoftapInfoChangedCalled = true; - } - } - - @Override - public void onCapabilityChanged(SoftApCapability softApCapability) { - synchronized(softApLock) { - currentSoftApCapability = softApCapability; - onSoftApCapabilityChangedCalled = true; - } - } - - @Override - public void onBlockedClientConnecting(WifiClient client, int blockedReason) { - synchronized(softApLock) { - lastBlockedClientMacAddress = client.getMacAddress(); - lastBlockedClientReason = blockedReason; - onBlockedClientConnectingCalled = true; - } - } - } - - private static class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback { - Object hotspotLock; - WifiManager.LocalOnlyHotspotReservation reservation = null; - boolean onStartedCalled = false; - boolean onStoppedCalled = false; - boolean onFailedCalled = false; - int failureReason = -1; - - TestLocalOnlyHotspotCallback(Object lock) { - hotspotLock = lock; - } - - @Override - public void onStarted(WifiManager.LocalOnlyHotspotReservation r) { - synchronized (hotspotLock) { - reservation = r; - onStartedCalled = true; - hotspotLock.notify(); - } - } - - @Override - public void onStopped() { - synchronized (hotspotLock) { - onStoppedCalled = true; - hotspotLock.notify(); - } - } - - @Override - public void onFailed(int reason) { - synchronized (hotspotLock) { - onFailedCalled = true; - failureReason = reason; - hotspotLock.notify(); - } - } - } - - private TestLocalOnlyHotspotCallback startLocalOnlyHotspot() { - // Location mode must be enabled for this test - if (!isLocationEnabled()) { - fail("Please enable location for this test"); - } - - TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); - synchronized (mLock) { - try { - mWifiManager.startLocalOnlyHotspot(callback, null); - // now wait for callback - mLock.wait(TEST_WAIT_DURATION_MS); - } catch (InterruptedException e) { - } - // check if we got the callback - assertTrue(callback.onStartedCalled); - - SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); - assertNotNull(softApConfig); - assertNotNull(softApConfig.toWifiConfiguration()); - if (!hasAutomotiveFeature()) { - assertEquals( - SoftApConfiguration.BAND_2GHZ, - callback.reservation.getSoftApConfiguration().getBand()); - } - assertFalse(callback.onFailedCalled); - assertFalse(callback.onStoppedCalled); - } - return callback; - } - - private void stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled) { - synchronized (mMySync) { - // we are expecting a new state - mMySync.expectedState = STATE_WIFI_CHANGING; - - // now shut down LocalOnlyHotspot - callback.reservation.close(); - - try { - waitForExpectedWifiState(wifiEnabled); - } catch (InterruptedException e) {} - } - } - - /** - * Verify that calls to startLocalOnlyHotspot succeed with proper permissions. - * - * Note: Location mode must be enabled for this test. - */ - public void testStartLocalOnlyHotspotSuccess() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // check that softap mode is supported by the device - if (!mWifiManager.isPortableHotspotSupported()) { - return; - } - - boolean wifiEnabled = mWifiManager.isWifiEnabled(); - - TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - - // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. - // TODO: remove this sleep as soon as b/124330089 is fixed. - Log.d(TAG, "Sleeping for 2 seconds"); - Thread.sleep(2000); - - stopLocalOnlyHotspot(callback, wifiEnabled); - - // wifi should either stay on, or come back on - assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); - } - - /** - * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK. - */ - public void testDeprecatedApis() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - setWifiEnabled(true); - waitForConnection(); // ensures that there is at-least 1 saved network on the device. - - WifiConfiguration wifiConfiguration = new WifiConfiguration(); - wifiConfiguration.SSID = SSID1; - wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - - assertEquals(INVALID_NETWORK_ID, - mWifiManager.addNetwork(wifiConfiguration)); - assertEquals(INVALID_NETWORK_ID, - mWifiManager.updateNetwork(wifiConfiguration)); - assertFalse(mWifiManager.enableNetwork(0, true)); - assertFalse(mWifiManager.disableNetwork(0)); - assertFalse(mWifiManager.removeNetwork(0)); - assertFalse(mWifiManager.disconnect()); - assertFalse(mWifiManager.reconnect()); - assertFalse(mWifiManager.reassociate()); - assertTrue(mWifiManager.getConfiguredNetworks().isEmpty()); - - boolean wifiEnabled = mWifiManager.isWifiEnabled(); - // now we should fail to toggle wifi state. - assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled)); - Thread.sleep(TEST_WAIT_DURATION_MS); - assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); - } - - /** - * Verify that applications can only have one registered LocalOnlyHotspot request at a time. - * - * Note: Location mode must be enabled for this test. - */ - public void testStartLocalOnlyHotspotSingleRequestByApps() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // check that softap mode is supported by the device - if (!mWifiManager.isPortableHotspotSupported()) { - return; - } - - boolean caughtException = false; - - boolean wifiEnabled = mWifiManager.isWifiEnabled(); - - TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - - // now make a second request - this should fail. - TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLock); - try { - mWifiManager.startLocalOnlyHotspot(callback2, null); - } catch (IllegalStateException e) { - Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice"); - caughtException = true; - } - if (!caughtException) { - // second start did not fail, should clean up the hotspot. - - // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. - // TODO: remove this sleep as soon as b/124330089 is fixed. - Log.d(TAG, "Sleeping for 2 seconds"); - Thread.sleep(2000); - - stopLocalOnlyHotspot(callback2, wifiEnabled); - } - assertTrue(caughtException); - - // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. - // TODO: remove this sleep as soon as b/124330089 is fixed. - Log.d(TAG, "Sleeping for 2 seconds"); - Thread.sleep(2000); - - stopLocalOnlyHotspot(callback, wifiEnabled); - } - - private static class TestExecutor implements Executor { - private ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue<>(); - - @Override - public void execute(Runnable task) { - tasks.add(task); - } - - private void runAll() { - Runnable task = tasks.poll(); - while (task != null) { - task.run(); - task = tasks.poll(); - } - } - } - - public void testStartLocalOnlyHotspotWithConfig() throws Exception { - SoftApConfiguration customConfig = new SoftApConfiguration.Builder() - .setBssid(TEST_MAC) - .setSsid(TEST_SSID_UNQUOTED) - .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) - .build(); - TestExecutor executor = new TestExecutor(); - TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - try { - uiAutomation.adoptShellPermissionIdentity(); - - boolean wifiEnabled = mWifiManager.isWifiEnabled(); - mWifiManager.startLocalOnlyHotspot(customConfig, executor, callback); - Log.d(TAG, "Sleeping for 2 seconds"); - Thread.sleep(2000); - - // Verify callback is run on the supplied executor - assertFalse(callback.onStartedCalled); - executor.runAll(); - assertTrue(callback.onStartedCalled); - - assertNotNull(callback.reservation); - SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); - assertNotNull(softApConfig); - assertEquals(TEST_MAC, softApConfig.getBssid()); - assertEquals(TEST_SSID_UNQUOTED, softApConfig.getSsid()); - assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase()); - - // clean up - stopLocalOnlyHotspot(callback, wifiEnabled); - } finally { - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Read the content of the given resource file into a String. - * - * @param filename String name of the file - * @return String - * @throws IOException - */ - private String loadResourceFile(String filename) throws IOException { - InputStream in = getClass().getClassLoader().getResourceAsStream(filename); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - StringBuilder builder = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - builder.append(line).append("\n"); - } - return builder.toString(); - } - - /** - * Verify that changing the mac randomization setting of a Passpoint configuration. - */ - public void testMacRandomizationSettingPasspoint() throws Exception { - String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT); - PasspointConfiguration config = - ConfigParser.parsePasspointConfig(TYPE_WIFI_CONFIG, configStr.getBytes()); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - try { - uiAutomation.adoptShellPermissionIdentity(); - - mWifiManager.addOrUpdatePasspointConfiguration(config); - List passpointConfigs = - mWifiManager.getPasspointConfigurations(); - PasspointConfiguration passpointConfig = passpointConfigs.get(0); - assertEquals(1, passpointConfigs.size()); - assertTrue("Mac randomization should be enabled for passpoint networks by default.", - passpointConfig.isMacRandomizationEnabled()); - - String fqdn = passpointConfig.getHomeSp().getFqdn(); - mWifiManager.setMacRandomizationSettingPasspointEnabled(fqdn, false); - assertFalse("Mac randomization should be disabled by the API call.", - mWifiManager.getPasspointConfigurations().get(0).isMacRandomizationEnabled()); - } finally { - uiAutomation.dropShellPermissionIdentity(); - } - } - /** - * Verify that the {@link android.Manifest.permission#NETWORK_STACK} permission is never held by - * any package. - *

    - * No apps should ever attempt to acquire this permission, since it would give those - * apps extremely broad access to connectivity functionality. - */ - public void testNetworkStackPermission() { - final PackageManager pm = getContext().getPackageManager(); - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.NETWORK_STACK - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - for (PackageInfo pi : holding) { - fail("The NETWORK_STACK permission must not be held by " + pi.packageName - + " and must be revoked for security reasons"); - } - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_SETTINGS} permission is - * never held by any package. - *

    - * Only Settings, SysUi, NetworkStack and shell apps should ever attempt to acquire - * this permission, since it would give those apps extremely broad access to connectivity - * functionality. The permission is intended to be granted to only those apps with direct user - * access and no others. - */ - public void testNetworkSettingsPermission() { - final PackageManager pm = getContext().getPackageManager(); - - final ArraySet allowedPackages = new ArraySet(); - final ArraySet allowedUIDs = new ArraySet(); - // explicitly add allowed UIDs - allowedUIDs.add(Process.SYSTEM_UID); - allowedUIDs.add(Process.SHELL_UID); - allowedUIDs.add(Process.PHONE_UID); - allowedUIDs.add(Process.NETWORK_STACK_UID); - allowedUIDs.add(Process.NFC_UID); - - // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using - // this fact to determined allowed package name for sysui. This is a signature permission, - // so allow any package with this permission. - final List sysuiPackages = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.BIND_QUICK_SETTINGS_TILE - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - for (PackageInfo info : sysuiPackages) { - allowedPackages.add(info.packageName); - } - - // the captive portal flow also currently holds the NETWORK_SETTINGS permission - final Intent intent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); - final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); - if (ri != null) { - allowedPackages.add(ri.activityInfo.packageName); - } - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.NETWORK_SETTINGS - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - StringBuilder stringBuilder = new StringBuilder(); - for (PackageInfo pi : holding) { - String packageName = pi.packageName; - - // this is an explicitly allowed package - if (allowedPackages.contains(packageName)) continue; - - // now check if the packages are from allowed UIDs - int uid = -1; - try { - uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM); - } catch (PackageManager.NameNotFoundException e) { - continue; - } - if (!allowedUIDs.contains(uid)) { - stringBuilder.append("The NETWORK_SETTINGS permission must not be held by " - + packageName + ":" + uid + " and must be revoked for security reasons\n"); - } - } - if (stringBuilder.length() > 0) { - fail(stringBuilder.toString()); - } - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} permission is - * only held by the device setup wizard application. - *

    - * Only the SetupWizard app should ever attempt to acquire this - * permission, since it would give those apps extremely broad access to connectivity - * functionality. The permission is intended to be granted to only the device setup wizard. - */ - public void testNetworkSetupWizardPermission() { - final ArraySet allowedPackages = new ArraySet(); - - final PackageManager pm = getContext().getPackageManager(); - - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_SETUP_WIZARD); - final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); - String validPkg = ""; - if (ri != null) { - allowedPackages.add(ri.activityInfo.packageName); - validPkg = ri.activityInfo.packageName; - } - - final Intent preIntent = new Intent("com.android.setupwizard.OEM_PRE_SETUP"); - preIntent.addCategory(Intent.CATEGORY_DEFAULT); - final ResolveInfo preRi = pm - .resolveActivity(preIntent, PackageManager.MATCH_DISABLED_COMPONENTS); - String prePackageName = ""; - if (null != preRi) { - prePackageName = preRi.activityInfo.packageName; - } - - final Intent postIntent = new Intent("com.android.setupwizard.OEM_POST_SETUP"); - postIntent.addCategory(Intent.CATEGORY_DEFAULT); - final ResolveInfo postRi = pm - .resolveActivity(postIntent, PackageManager.MATCH_DISABLED_COMPONENTS); - String postPackageName = ""; - if (null != postRi) { - postPackageName = postRi.activityInfo.packageName; - } - if (!TextUtils.isEmpty(prePackageName) && !TextUtils.isEmpty(postPackageName) - && prePackageName.equals(postPackageName)) { - allowedPackages.add(prePackageName); - } - - final List holding = pm.getPackagesHoldingPermissions(new String[]{ - android.Manifest.permission.NETWORK_SETUP_WIZARD - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - for (PackageInfo pi : holding) { - if (!allowedPackages.contains(pi.packageName)) { - fail("The NETWORK_SETUP_WIZARD permission must not be held by " + pi.packageName - + " and must be revoked for security reasons [" + validPkg + "]"); - } - } - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_MANAGED_PROVISIONING} permission - * is only held by the device managed provisioning application. - *

    - * Only the ManagedProvisioning app should ever attempt to acquire this - * permission, since it would give those apps extremely broad access to connectivity - * functionality. The permission is intended to be granted to only the device managed - * provisioning. - */ - public void testNetworkManagedProvisioningPermission() { - final PackageManager pm = getContext().getPackageManager(); - - // TODO(b/115980767): Using hardcoded package name. Need a better mechanism to find the - // managed provisioning app. - // Ensure that the package exists. - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setPackage(MANAGED_PROVISIONING_PACKAGE_NAME); - final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); - String validPkg = ""; - if (ri != null) { - validPkg = ri.activityInfo.packageName; - } - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.NETWORK_MANAGED_PROVISIONING - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - for (PackageInfo pi : holding) { - if (!Objects.equals(pi.packageName, validPkg)) { - fail("The NETWORK_MANAGED_PROVISIONING permission must not be held by " - + pi.packageName + " and must be revoked for security reasons [" - + validPkg +"]"); - } - } - } - - /** - * Verify that the {@link android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE} permission - * is held by at most one application. - */ - public void testWifiSetDeviceMobilityStatePermission() { - final PackageManager pm = getContext().getPackageManager(); - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - - List uniquePackageNames = holding - .stream() - .map(pi -> pi.packageName) - .distinct() - .collect(Collectors.toList()); - - if (uniquePackageNames.size() > 1) { - fail("The WIFI_SET_DEVICE_MOBILITY_STATE permission must not be held by more than one " - + "application, but is held by " + uniquePackageNames.size() + " applications: " - + String.join(", ", uniquePackageNames)); - } - } - - /** - * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission - * is held by at most one application. - */ - public void testNetworkCarrierProvisioningPermission() { - final PackageManager pm = getContext().getPackageManager(); - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.NETWORK_CARRIER_PROVISIONING - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - - List uniquePackageNames = holding - .stream() - .map(pi -> pi.packageName) - .distinct() - .collect(Collectors.toList()); - - if (uniquePackageNames.size() > 2) { - fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than two " - + "applications, but is held by " + uniquePackageNames.size() + " applications: " - + String.join(", ", uniquePackageNames)); - } - } - - /** - * Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE} - * permission is held by at most one application. - */ - public void testUpdateWifiUsabilityStatsScorePermission() { - final PackageManager pm = getContext().getPackageManager(); - - final List holding = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE - }, PackageManager.MATCH_UNINSTALLED_PACKAGES); - - List uniquePackageNames = holding - .stream() - .map(pi -> pi.packageName) - .distinct() - .collect(Collectors.toList()); - - if (uniquePackageNames.size() > 1) { - fail("The WIFI_UPDATE_USABILITY_STATS_SCORE permission must not be held by more than " - + "one application, but is held by " + uniquePackageNames.size() + " applications: " - + String.join(", ", uniquePackageNames)); - } - } - - private void turnScreenOnNoDelay() throws Exception { - mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); - mUiDevice.executeShellCommand("wm dismiss-keyguard"); - } - - private void turnScreenOn() throws Exception { - turnScreenOnNoDelay(); - // Since the screen on/off intent is ordered, they will not be sent right now. - Thread.sleep(DURATION_SCREEN_TOGGLE); - } - - private void turnScreenOffNoDelay() throws Exception { - mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); - } - - private void turnScreenOff() throws Exception { - turnScreenOffNoDelay(); - // Since the screen on/off intent is ordered, they will not be sent right now. - Thread.sleep(DURATION_SCREEN_TOGGLE); - } - - private void assertWifiScanningIsOn() { - if (!mWifiManager.isScanAlwaysAvailable()) { - fail("Wi-Fi scanning should be on."); - } - } - - private void runWithScanningEnabled(ThrowingRunnable r) throws Exception { - boolean wasScanEnabledForTest = false; - if (!mWifiManager.isScanAlwaysAvailable()) { - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setScanAlwaysAvailable(true)); - wasScanEnabledForTest = true; - } - try { - r.run(); - } finally { - if (wasScanEnabledForTest) { - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setScanAlwaysAvailable(false)); - } - } - } - - /** - * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled - * but location is on. - * @throws Exception - */ - public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - if (!hasLocationFeature()) { - // skip the test if location is not supported - return; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since Marshmallow WiFi scan results are" - + " empty when location is disabled!"); - } - runWithScanningEnabled(() -> { - setWifiEnabled(false); - turnScreenOn(); - assertWifiScanningIsOn(); - // Toggle screen and verify Wi-Fi scanning is still on. - turnScreenOff(); - assertWifiScanningIsOn(); - turnScreenOn(); - assertWifiScanningIsOn(); - }); - } - - /** - * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is enabled. - * @throws Exception - */ - public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - if (!hasLocationFeature()) { - // skip the test if location is not supported - return; - } - if (!isLocationEnabled()) { - fail("Please enable location for this test - since Marshmallow WiFi scan results are" - + " empty when location is disabled!"); - } - runWithScanningEnabled(() -> { - setWifiEnabled(true); - turnScreenOn(); - assertWifiScanningIsOn(); - // Toggle screen and verify Wi-Fi scanning is still on. - turnScreenOff(); - assertWifiScanningIsOn(); - turnScreenOn(); - assertWifiScanningIsOn(); - }); - } - - /** - * Verify that the platform supports a reasonable number of suggestions per app. - * @throws Exception - */ - public void testMaxNumberOfNetworkSuggestionsPerApp() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - assertTrue(mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp() - > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP); - } - - private void verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback) - throws Exception{ - // Register callback to get SoftApCapability - mWifiManager.registerSoftApCallback(executor, callback); - PollingCheck.check( - "SoftAp register failed!", 1_000, - () -> { executor.runAll(); - // Verify callback is run on the supplied executor and called - return callback.getOnStateChangedCalled() && - callback.getOnSoftapInfoChangedCalled() && - callback.getOnSoftApCapabilityChangedCalled() && - callback.getOnConnectedClientCalled(); - }); - } - - private void verifySetGetSoftApConfig(SoftApConfiguration targetConfig) { - mWifiManager.setSoftApConfiguration(targetConfig); - // Bssid set dodesn't support for tethered hotspot - SoftApConfiguration currentConfig = mWifiManager.getSoftApConfiguration(); - compareSoftApConfiguration(targetConfig, currentConfig); - } - - private void compareSoftApConfiguration(SoftApConfiguration currentConfig, - SoftApConfiguration testSoftApConfig) { - assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid()); - assertEquals(currentConfig.getBssid(), testSoftApConfig.getBssid()); - assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType()); - assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase()); - assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid()); - assertEquals(currentConfig.getBand(), testSoftApConfig.getBand()); - assertEquals(currentConfig.getChannel(), testSoftApConfig.getChannel()); - assertEquals(currentConfig.getMaxNumberOfClients(), - testSoftApConfig.getMaxNumberOfClients()); - assertEquals(currentConfig.isAutoShutdownEnabled(), - testSoftApConfig.isAutoShutdownEnabled()); - assertEquals(currentConfig.getShutdownTimeoutMillis(), - testSoftApConfig.getShutdownTimeoutMillis()); - assertEquals(currentConfig.isClientControlByUserEnabled(), - testSoftApConfig.isClientControlByUserEnabled()); - assertEquals(currentConfig.getAllowedClientList(), - testSoftApConfig.getAllowedClientList()); - assertEquals(currentConfig.getBlockedClientList(), - testSoftApConfig.getBlockedClientList()); - } - - private void turnOffWifiAndTetheredHotspotIfEnabled() throws Exception { - if (mWifiManager.isWifiEnabled()) { - Log.d(TAG, "Turn off WiFi"); - mWifiManager.setWifiEnabled(false); - PollingCheck.check( - "Wifi turn off failed!", 2_000, - () -> mWifiManager.isWifiEnabled() == false); - } - if (mWifiManager.isWifiApEnabled()) { - mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); - Log.d(TAG, "Turn off tethered Hotspot"); - PollingCheck.check( - "SoftAp turn off failed!", 2_000, - () -> mWifiManager.isWifiApEnabled() == false); - mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); - } - } - - /** - * Verify that the configuration from getSoftApConfiguration is same as the configuration which - * set by setSoftApConfiguration. And depends softap capability callback to test different - * configuration. - * @throws Exception - */ - public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception { - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - TestExecutor executor = new TestExecutor(); - TestSoftApCallback callback = new TestSoftApCallback(mLock); - try { - uiAutomation.adoptShellPermissionIdentity(); - turnOffWifiAndTetheredHotspotIfEnabled(); - verifyRegisterSoftApCallback(executor, callback); - - SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder() - .setSsid(TEST_SSID_UNQUOTED) - .setBssid(TEST_MAC) - .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) - .setAutoShutdownEnabled(true) - .setShutdownTimeoutMillis(100000) - .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ) - .setHiddenSsid(false); - - // Test SoftApConfiguration set and get - verifySetGetSoftApConfig(softApConfigBuilder.build()); - - // Test CLIENT_FORCE_DISCONNECT supported config. - if (callback.getCurrentSoftApCapability() - .areFeaturesSupported( - SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { - softApConfigBuilder.setMaxNumberOfClients(10); - softApConfigBuilder.setClientControlByUserEnabled(true); - softApConfigBuilder.setBlockedClientList(new ArrayList<>()); - softApConfigBuilder.setAllowedClientList(new ArrayList<>()); - verifySetGetSoftApConfig(softApConfigBuilder.build()); - } - - // Test SAE config - if (callback.getCurrentSoftApCapability() - .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) { - softApConfigBuilder - .setPassphrase(TEST_PASSPHRASE, - SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION); - verifySetGetSoftApConfig(softApConfigBuilder.build()); - softApConfigBuilder - .setPassphrase(TEST_PASSPHRASE, - SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); - verifySetGetSoftApConfig(softApConfigBuilder.build()); - } - } finally { - mWifiManager.unregisterSoftApCallback(callback); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Verify that startTetheredHotspot with specific channel config. - * @throws Exception - */ - public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback() - throws Exception { - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - TestExecutor executor = new TestExecutor(); - TestSoftApCallback callback = new TestSoftApCallback(mLock); - try { - uiAutomation.adoptShellPermissionIdentity(); - turnOffWifiAndTetheredHotspotIfEnabled(); - verifyRegisterSoftApCallback(executor, callback); - - SoftApConfiguration testSoftApConfig = new SoftApConfiguration.Builder() - .setSsid(TEST_SSID_UNQUOTED) - .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) - .setChannel(11, SoftApConfiguration.BAND_2GHZ) // Channel 11 = Freq 2462 - .build(); - - mWifiManager.setSoftApConfiguration(testSoftApConfig); - - // start tethering which used to verify startTetheredHotspot - mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor, - new TetheringManager.StartTetheringCallback() { - @Override - public void onTetheringFailed(final int result) { - } - }); - - // Verify state and info callback value as expected - PollingCheck.check( - "SoftAp channel and state mismatch!!!", 5_000, - () -> { executor.runAll(); - return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState() && - 2462 == callback.getCurrentSoftApInfo().getFrequency(); - }); - - // stop tethering which used to verify stopSoftAp - mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); - - // Verify clean up - PollingCheck.check( - "Stop Softap failed", 2_000, - () -> { executor.runAll(); - return WifiManager.WIFI_AP_STATE_DISABLED == callback.getCurrentState() && - 0 == callback.getCurrentSoftApInfo().getBandwidth() && - 0 == callback.getCurrentSoftApInfo().getFrequency(); - }); - } finally { - mWifiManager.unregisterSoftApCallback(callback); - uiAutomation.dropShellPermissionIdentity(); - } - } - - private static class TestActionListener implements WifiManager.ActionListener { - private final Object mLock; - public boolean onSuccessCalled = false; - public boolean onFailedCalled = false; - public int failureReason = -1; - - TestActionListener(Object lock) { - mLock = lock; - } - - @Override - public void onSuccess() { - synchronized (mLock) { - onSuccessCalled = true; - mLock.notify(); - } - } - - @Override - public void onFailure(int reason) { - synchronized (mLock) { - onFailedCalled = true; - failureReason = reason; - mLock.notify(); - } - } - } - - /** - * Triggers connection to one of the saved networks using {@link WifiManager#connect( - * int, WifiManager.ActionListener)} or {@link WifiManager#connect(WifiConfiguration, - * WifiManager.ActionListener)} - * - * @param withNetworkId Use networkId for triggering connection, false for using - * WifiConfiguration. - * @throws Exception - */ - private void testConnect(boolean withNetworkId) throws Exception { - TestActionListener actionListener = new TestActionListener(mLock); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - List savedNetworks = null; - try { - uiAutomation.adoptShellPermissionIdentity(); - // These below API's only work with privileged permissions (obtained via shell identity - // for test) - savedNetworks = mWifiManager.getConfiguredNetworks(); - - // Disable all the saved networks to trigger disconnect & disable autojoin. - for (WifiConfiguration network : savedNetworks) { - assertTrue(mWifiManager.disableNetwork(network.networkId)); - } - waitForDisconnection(); - - // Now trigger connection to the first saved network. - synchronized (mLock) { - try { - if (withNetworkId) { - mWifiManager.connect(savedNetworks.get(0).networkId, actionListener); - } else { - mWifiManager.connect(savedNetworks.get(0), actionListener); - } - // now wait for callback - mLock.wait(TEST_WAIT_DURATION_MS); - } catch (InterruptedException e) { - } - } - // check if we got the success callback - assertTrue(actionListener.onSuccessCalled); - // Wait for connection to complete & ensure we are connected to the saved network. - waitForConnection(); - assertEquals(savedNetworks.get(0).networkId, - mWifiManager.getConnectionInfo().getNetworkId()); - } finally { - // Re-enable all saved networks before exiting. - if (savedNetworks != null) { - for (WifiConfiguration network : savedNetworks) { - mWifiManager.enableNetwork(network.networkId, false); - } - } - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#connect(int, WifiManager.ActionListener)} to an existing saved - * network. - */ - public void testConnectWithNetworkId() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - testConnect(true); - } - - /** - * Tests {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)} to an - * existing saved network. - */ - public void testConnectWithWifiConfiguration() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - testConnect(false); - - } - - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final Object mLock; - public boolean onAvailableCalled = false; - public Network network; - public NetworkCapabilities networkCapabilities; - - TestNetworkCallback(Object lock) { - mLock = lock; - } - - @Override - public void onAvailable(Network network, NetworkCapabilities networkCapabilities, - LinkProperties linkProperties, boolean blocked) { - synchronized (mLock) { - onAvailableCalled = true; - this.network = network; - this.networkCapabilities = networkCapabilities; - mLock.notify(); - } - } - } - - private void waitForNetworkCallbackAndCheckForMeteredness(boolean expectMetered) { - TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock); - synchronized (mLock) { - try { - // File a request for wifi network. - mConnectivityManager.registerNetworkCallback( - new NetworkRequest.Builder() - .addTransportType(TRANSPORT_WIFI) - .build(), - networkCallbackListener); - // now wait for callback - mLock.wait(TEST_WAIT_DURATION_MS); - } catch (InterruptedException e) { - } - } - assertTrue(networkCallbackListener.onAvailableCalled); - assertNotEquals(expectMetered, networkCallbackListener.networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED)); - } - - /** - * Tests {@link WifiManager#save(WifiConfiguration, WifiManager.ActionListener)} by marking - * an existing saved network metered. - */ - public void testSave() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - TestActionListener actionListener = new TestActionListener(mLock); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - List savedNetworks = null; - WifiConfiguration savedNetwork = null; - try { - uiAutomation.adoptShellPermissionIdentity(); - // These below API's only work with privileged permissions (obtained via shell identity - // for test) - savedNetworks = mWifiManager.getConfiguredNetworks(); - - // Ensure that the saved network is not metered. - savedNetwork = savedNetworks.get(0); - assertNotEquals("Ensure that the saved network is configured as unmetered", - savedNetwork.meteredOverride, - WifiConfiguration.METERED_OVERRIDE_METERED); - - // Trigger a scan & wait for connection to one of the saved networks. - mWifiManager.startScan(); - waitForConnection(); - - // Check the network capabilities to ensure that the network is marked not metered. - waitForNetworkCallbackAndCheckForMeteredness(false); - - // Now mark the network metered and save. - synchronized (mLock) { - try { - WifiConfiguration modSavedNetwork = new WifiConfiguration(savedNetwork); - modSavedNetwork.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED; - mWifiManager.save(modSavedNetwork, actionListener); - // now wait for callback - mLock.wait(TEST_WAIT_DURATION_MS); - } catch (InterruptedException e) { - } - } - // check if we got the success callback - assertTrue(actionListener.onSuccessCalled); - // Check the network capabilities to ensure that the network is marked metered now. - waitForNetworkCallbackAndCheckForMeteredness(true); - - } finally { - // Restore original network config (restore the meteredness back); - if (savedNetwork != null) { - mWifiManager.updateNetwork(savedNetwork); - } - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#forget(int, WifiManager.ActionListener)} by adding/removing a new - * network. - */ - public void testForget() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - TestActionListener actionListener = new TestActionListener(mLock); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - int newNetworkId = INVALID_NETWORK_ID; - try { - uiAutomation.adoptShellPermissionIdentity(); - // These below API's only work with privileged permissions (obtained via shell identity - // for test) - List savedNetworks = mWifiManager.getConfiguredNetworks(); - - WifiConfiguration newOpenNetwork = new WifiConfiguration(); - newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\""; - newNetworkId = mWifiManager.addNetwork(newOpenNetwork); - assertNotEquals(INVALID_NETWORK_ID, newNetworkId); - - assertEquals(savedNetworks.size() + 1, mWifiManager.getConfiguredNetworks().size()); - - // Now remove the network - synchronized (mLock) { - try { - mWifiManager.forget(newNetworkId, actionListener); - // now wait for callback - mLock.wait(TEST_WAIT_DURATION_MS); - } catch (InterruptedException e) { - } - } - // check if we got the success callback - assertTrue(actionListener.onSuccessCalled); - - // Ensure that the new network has been successfully removed. - assertEquals(savedNetworks.size(), mWifiManager.getConfiguredNetworks().size()); - } finally { - // For whatever reason, if the forget fails, try removing using the public remove API. - if (newNetworkId != INVALID_NETWORK_ID) mWifiManager.removeNetwork(newNetworkId); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#getFactoryMacAddresses()} returns at least one valid MAC address. - */ - public void testGetFactoryMacAddresses() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - TestActionListener actionListener = new TestActionListener(mLock); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - int newNetworkId = INVALID_NETWORK_ID; - try { - uiAutomation.adoptShellPermissionIdentity(); - // Obtain the factory MAC address - String[] macAddresses = mWifiManager.getFactoryMacAddresses(); - assertTrue("At list one MAC address should be returned.", macAddresses.length > 0); - try { - MacAddress mac = MacAddress.fromString(macAddresses[0]); - assertNotEquals(WifiInfo.DEFAULT_MAC_ADDRESS, mac); - assertFalse(MacAddressUtils.isMulticastAddress(mac)); - } catch (IllegalArgumentException e) { - fail("Factory MAC address is invalid"); - } - } finally { - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#isApMacRandomizationSupported()} does not crash. - */ - public void testIsApMacRandomizationSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager.isApMacRandomizationSupported(); - } - - /** - * Tests {@link WifiManager#isConnectedMacRandomizationSupported()} does not crash. - */ - public void testIsConnectedMacRandomizationSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager.isConnectedMacRandomizationSupported(); - } - - /** - * Tests {@link WifiManager#isPreferredNetworkOffloadSupported()} does not crash. - */ - public void testIsPreferredNetworkOffloadSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager.isPreferredNetworkOffloadSupported(); - } - - /** Test that PNO scans reconnects us when the device is disconnected and the screen is off. */ - public void testPnoScan() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - if (!mWifiManager.isPreferredNetworkOffloadSupported()) { - // skip the test if PNO scanning is not supported - return; - } - - // make sure we're connected - waitForConnection(); - - WifiInfo currentNetwork = ShellIdentityUtils.invokeWithShellPermissions( - mWifiManager::getConnectionInfo); - - // disable all networks that aren't already disabled - List savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( - mWifiManager::getConfiguredNetworks); - Set disabledNetworkIds = new HashSet<>(); - for (WifiConfiguration config : savedNetworks) { - if (config.getNetworkSelectionStatus().getNetworkSelectionDisableReason() - == WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE) { - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.disableNetwork(config.networkId)); - disabledNetworkIds.add(config.networkId); - } - } - - try { - // wait for disconnection from current network - waitForDisconnection(); - - // turn screen off - turnScreenOffNoDelay(); - - // re-enable the current network - this will trigger PNO - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.enableNetwork(currentNetwork.getNetworkId(), false)); - disabledNetworkIds.remove(currentNetwork.getNetworkId()); - - // PNO should reconnect us back to the network we disconnected from - waitForConnection(); - } finally { - // re-enable disabled networks - for (int disabledNetworkId : disabledNetworkIds) { - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.enableNetwork(disabledNetworkId, false)); - } - } - } - - /** - * Tests {@link WifiManager#isTdlsSupported()} does not crash. - */ - public void testIsTdlsSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager.isTdlsSupported(); - } - - /** - * Tests {@link WifiManager#isStaApConcurrencySupported(). - */ - public void testIsStaApConcurrencySupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // check that softap mode is supported by the device - if (!mWifiManager.isPortableHotspotSupported()) { - return; - } - assertTrue(mWifiManager.isWifiEnabled()); - - boolean isStaApConcurrencySupported = mWifiManager.isStaApConcurrencySupported(); - // start local only hotspot. - TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - if (isStaApConcurrencySupported) { - assertTrue(mWifiManager.isWifiEnabled()); - } else { - // no concurrency, wifi should be disabled. - assertFalse(mWifiManager.isWifiEnabled()); - } - stopLocalOnlyHotspot(callback, true); - - assertTrue(mWifiManager.isWifiEnabled()); - } - - private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback { - private final Object mLock; - private final int mWaitForState; - public boolean onStateChangedCalled = false; - public int state = -1; - - TestTrafficStateCallback(Object lock, int waitForState) { - mLock = lock; - mWaitForState = waitForState; - } - - @Override - public void onStateChanged(int state) { - synchronized (mLock) { - onStateChangedCalled = true; - this.state = state; - if (mWaitForState == state) { // only notify if we got the expected state. - mLock.notify(); - } - } - } - } - - private void sendTraffic() { - for (int i = 0; i < 10; i ++) { - // Do some network operations - HttpURLConnection connection = null; - try { - URL url = new URL("http://www.google.com/"); - connection = (HttpURLConnection) url.openConnection(); - connection.setInstanceFollowRedirects(false); - connection.setConnectTimeout(TIMEOUT_MSEC); - connection.setReadTimeout(TIMEOUT_MSEC); - connection.setUseCaches(false); - connection.getInputStream(); - } catch (Exception e) { - // ignore - } finally { - if (connection != null) connection.disconnect(); - } - } - } - - /** - * Tests {@link WifiManager#registerTrafficStateCallback(Executor, - * WifiManager.TrafficStateCallback)} by sending some traffic. - */ - public void testTrafficStateCallback() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - TestTrafficStateCallback trafficStateCallback = - new TestTrafficStateCallback(mLock, DATA_ACTIVITY_INOUT); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - try { - uiAutomation.adoptShellPermissionIdentity(); - // Trigger a scan & wait for connection to one of the saved networks. - mWifiManager.startScan(); - waitForConnection(); - - // Turn screen on for wifi traffic polling. - turnScreenOn(); - synchronized (mLock) { - try { - mWifiManager.registerTrafficStateCallback( - Executors.newSingleThreadExecutor(), trafficStateCallback); - // Send some traffic to trigger the traffic state change callbacks. - sendTraffic(); - // now wait for callback - mLock.wait(TEST_WAIT_DURATION_MS); - } catch (InterruptedException e) { - } - } - // check if we got the state changed callback - assertTrue(trafficStateCallback.onStateChangedCalled); - assertEquals(DATA_ACTIVITY_INOUT, trafficStateCallback.state); - } finally { - turnScreenOff(); - mWifiManager.unregisterTrafficStateCallback(trafficStateCallback); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#setScanAlwaysAvailable(boolean)} & - * {@link WifiManager#isScanAlwaysAvailable()}. - */ - public void testScanAlwaysAvailable() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - Boolean currState = null; - try { - uiAutomation.adoptShellPermissionIdentity(); - currState = mWifiManager.isScanAlwaysAvailable(); - boolean newState = !currState; - mWifiManager.setScanAlwaysAvailable(newState); - PollingCheck.check( - "Wifi settings toggle failed!", - DURATION_SETTINGS_TOGGLE, - () -> mWifiManager.isScanAlwaysAvailable() == newState); - assertEquals(newState, mWifiManager.isScanAlwaysAvailable()); - } finally { - if (currState != null) mWifiManager.setScanAlwaysAvailable(currState); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#setScanThrottleEnabled(boolean)} & - * {@link WifiManager#isScanThrottleEnabled()}. - */ - public void testScanThrottleEnabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - Boolean currState = null; - try { - uiAutomation.adoptShellPermissionIdentity(); - currState = mWifiManager.isScanThrottleEnabled(); - boolean newState = !currState; - mWifiManager.setScanThrottleEnabled(newState); - PollingCheck.check( - "Wifi settings toggle failed!", - DURATION_SETTINGS_TOGGLE, - () -> mWifiManager.isScanThrottleEnabled() == newState); - assertEquals(newState, mWifiManager.isScanThrottleEnabled()); - } finally { - if (currState != null) mWifiManager.setScanThrottleEnabled(currState); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#setAutoWakeupEnabled(boolean)} & - * {@link WifiManager#isAutoWakeupEnabled()}. - */ - public void testAutoWakeUpEnabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - Boolean currState = null; - try { - uiAutomation.adoptShellPermissionIdentity(); - currState = mWifiManager.isAutoWakeupEnabled(); - boolean newState = !currState; - mWifiManager.setAutoWakeupEnabled(newState); - PollingCheck.check( - "Wifi settings toggle failed!", - DURATION_SETTINGS_TOGGLE, - () -> mWifiManager.isAutoWakeupEnabled() == newState); - assertEquals(newState, mWifiManager.isAutoWakeupEnabled()); - } finally { - if (currState != null) mWifiManager.setAutoWakeupEnabled(currState); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#setVerboseLoggingEnabled(boolean)} & - * {@link WifiManager#isVerboseLoggingEnabled()}. - */ - public void testVerboseLoggingEnabled() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - Boolean currState = null; - try { - uiAutomation.adoptShellPermissionIdentity(); - currState = mWifiManager.isVerboseLoggingEnabled(); - boolean newState = !currState; - mWifiManager.setVerboseLoggingEnabled(newState); - PollingCheck.check( - "Wifi settings toggle failed!", - DURATION_SETTINGS_TOGGLE, - () -> mWifiManager.isVerboseLoggingEnabled() == newState); - assertEquals(newState, mWifiManager.isVerboseLoggingEnabled()); - } finally { - if (currState != null) mWifiManager.setVerboseLoggingEnabled(currState); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests {@link WifiManager#factoryReset()}. - * - * Note: This test assumes that the device only has 1 or more saved networks before the test. - * The test will restore those when the test exits. But, it does not restore the softap - * configuration, suggestions, etc which will also have been lost on factory reset. - */ - public void testFactoryReset() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - List savedNetworks = null; - try { - uiAutomation.adoptShellPermissionIdentity(); - // These below API's only work with privileged permissions (obtained via shell identity - // for test) - savedNetworks = mWifiManager.getPrivilegedConfiguredNetworks(); - - mWifiManager.factoryReset(); - // Ensure all the saved networks are removed. - assertEquals(0, mWifiManager.getConfiguredNetworks().size()); - } finally { - // Restore the original saved networks. - if (savedNetworks != null) { - for (WifiConfiguration network : savedNetworks) { - network.networkId = WifiConfiguration.INVALID_NETWORK_ID; - int networkId = mWifiManager.addNetwork(network); - mWifiManager.enableNetwork(networkId, false); - } - } - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Test {@link WifiNetworkConnectionStatistics} does not crash. - * TODO(b/150891569): deprecate it in Android S, this API is not used anywhere. - */ - public void testWifiNetworkConnectionStatistics() { - new WifiNetworkConnectionStatistics(); - WifiNetworkConnectionStatistics stats = new WifiNetworkConnectionStatistics(0, 0); - new WifiNetworkConnectionStatistics(stats); - } - - /** - * Test that the wifi country code is either null, or a length-2 string. - */ - public void testGetCountryCode() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - String wifiCountryCode = ShellIdentityUtils.invokeWithShellPermissions( - mWifiManager::getCountryCode); - - if (wifiCountryCode == null) { - return; - } - assertEquals(2, wifiCountryCode.length()); - - // assert that the country code is all uppercase - assertEquals(wifiCountryCode.toUpperCase(Locale.US), wifiCountryCode); - - String telephonyCountryCode = getContext().getSystemService(TelephonyManager.class) - .getNetworkCountryIso(); - assertEquals(telephonyCountryCode, wifiCountryCode.toLowerCase(Locale.US)); - } - - /** - * Test that {@link WifiManager#getCurrentNetwork()} returns a Network obeject consistent - * with {@link ConnectivityManager#registerNetworkCallback} when connected to a Wifi network, - * and returns null when not connected. - */ - public void testGetCurrentNetwork() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // wait for Wifi to be connected - PollingCheck.check( - "Wifi not connected - Please ensure there is a saved network in range of this " - + "device", - 20000, - () -> mWifiManager.getConnectionInfo().getNetworkId() != -1); - - Network wifiCurrentNetwork = ShellIdentityUtils.invokeWithShellPermissions( - mWifiManager::getCurrentNetwork); - assertNotNull(wifiCurrentNetwork); - - TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock); - synchronized (mLock) { - try { - // File a request for wifi network. - mConnectivityManager.registerNetworkCallback( - new NetworkRequest.Builder() - .addTransportType(TRANSPORT_WIFI) - .build(), - networkCallbackListener); - // now wait for callback - mLock.wait(TEST_WAIT_DURATION_MS); - } catch (InterruptedException e) { - } - } - assertTrue(networkCallbackListener.onAvailableCalled); - Network connectivityCurrentNetwork = networkCallbackListener.network; - assertEquals(connectivityCurrentNetwork, wifiCurrentNetwork); - - setWifiEnabled(false); - PollingCheck.check( - "Wifi not disconnected!", - 20000, - () -> mWifiManager.getConnectionInfo().getNetworkId() == -1); - - assertNull(ShellIdentityUtils.invokeWithShellPermissions(mWifiManager::getCurrentNetwork)); - } - - /** - * Tests {@link WifiManager#isWpa3SaeSupported()} does not crash. - */ - public void testIsWpa3SaeSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager.isWpa3SaeSupported(); - } - - /** - * Tests {@link WifiManager#isWpa3SuiteBSupported()} does not crash. - */ - public void testIsWpa3SuiteBSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager.isWpa3SuiteBSupported(); - } - - /** - * Tests {@link WifiManager#isEnhancedOpenSupported()} does not crash. - */ - public void testIsEnhancedOpenSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager.isEnhancedOpenSupported(); - } - - /** - * Test that {@link WifiManager#is5GHzBandSupported()} returns successfully in - * both WiFi enabled/disabled states. - * Note that the response depends on device support and hence both true/false - * are valid responses. - */ - public void testIs5GhzBandSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // Check for 5GHz support with wifi enabled - setWifiEnabled(true); - PollingCheck.check( - "Wifi not enabled!", - 20000, - () -> mWifiManager.isWifiEnabled()); - boolean isSupportedEnabled = mWifiManager.is5GHzBandSupported(); - - // Check for 5GHz support with wifi disabled - setWifiEnabled(false); - PollingCheck.check( - "Wifi not disabled!", - 20000, - () -> !mWifiManager.isWifiEnabled()); - boolean isSupportedDisabled = mWifiManager.is5GHzBandSupported(); - - // If Support is true when WiFi is disable, then it has to be true when it is enabled. - // Note, the reverse is a valid case. - if (isSupportedDisabled) { - assertTrue(isSupportedEnabled); - } - } - - /** - * Test that {@link WifiManager#is6GHzBandSupported()} returns successfully in - * both Wifi enabled/disabled states. - * Note that the response depends on device support and hence both true/false - * are valid responses. - */ - public void testIs6GhzBandSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // Check for 6GHz support with wifi enabled - setWifiEnabled(true); - PollingCheck.check( - "Wifi not enabled!", - 20000, - () -> mWifiManager.isWifiEnabled()); - boolean isSupportedEnabled = mWifiManager.is6GHzBandSupported(); - - // Check for 6GHz support with wifi disabled - setWifiEnabled(false); - PollingCheck.check( - "Wifi not disabled!", - 20000, - () -> !mWifiManager.isWifiEnabled()); - boolean isSupportedDisabled = mWifiManager.is6GHzBandSupported(); - - // If Support is true when WiFi is disable, then it has to be true when it is enabled. - // Note, the reverse is a valid case. - if (isSupportedDisabled) { - assertTrue(isSupportedEnabled); - } - } - - /** - * Test that {@link WifiManager#isWifiStandardSupported()} returns successfully in - * both Wifi enabled/disabled states. The test is to be performed on - * {@link WifiAnnotations}'s {@code WIFI_STANDARD_} - * Note that the response depends on device support and hence both true/false - * are valid responses. - */ - public void testIsWifiStandardsSupported() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // Check for WiFi standards support with wifi enabled - setWifiEnabled(true); - PollingCheck.check( - "Wifi not enabled!", - 20000, - () -> mWifiManager.isWifiEnabled()); - boolean isLegacySupportedEnabled = - mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY); - boolean is11nSupporedEnabled = - mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N); - boolean is11acSupportedEnabled = - mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC); - boolean is11axSupportedEnabled = - mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX); - - // Check for WiFi standards support with wifi disabled - setWifiEnabled(false); - PollingCheck.check( - "Wifi not disabled!", - 20000, - () -> !mWifiManager.isWifiEnabled()); - - boolean isLegacySupportedDisabled = - mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY); - boolean is11nSupportedDisabled = - mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N); - boolean is11acSupportedDisabled = - mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC); - boolean is11axSupportedDisabled = - mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX); - - if (isLegacySupportedDisabled) { - assertTrue(isLegacySupportedEnabled); - } - - if (is11nSupportedDisabled) { - assertTrue(is11nSupporedEnabled); - } - - if (is11acSupportedDisabled) { - assertTrue(is11acSupportedEnabled); - } - - if (is11axSupportedDisabled) { - assertTrue(is11axSupportedEnabled); - } - } - - private static PasspointConfiguration createPasspointConfiguration() { - PasspointConfiguration config = new PasspointConfiguration(); - HomeSp homeSp = new HomeSp(); - homeSp.setFqdn("test.com"); - homeSp.setFriendlyName("friendly name"); - homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66}); - config.setHomeSp(homeSp); - Credential.SimCredential simCred = new Credential.SimCredential(); - simCred.setImsi("123456*"); - simCred.setEapType(23 /* EAP_AKA */); - Credential cred = new Credential(); - cred.setRealm("realm"); - cred.setSimCredential(simCred); - config.setCredential(cred); - - return config; - } - - /** - * Tests {@link WifiManager#addOrUpdatePasspointConfiguration(PasspointConfiguration)} - * adds a Passpoint configuration correctly by getting it once it is added, and comparing it - * to the local copy of the configuration. - */ - public void testAddOrUpdatePasspointConfiguration() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // Create and install a Passpoint configuration - PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - try { - uiAutomation.adoptShellPermissionIdentity(); - mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); - - // Compare configurations - List configurations = mWifiManager.getPasspointConfigurations(); - assertNotNull(configurations); - assertEquals(passpointConfiguration, configurations.get(0)); - - // Clean up - mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); - } finally { - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests that - * {@link WifiManager#startSubscriptionProvisioning(OsuProvider, Executor, ProvisioningCallback)} - * starts a subscription provisioning, and confirm a status callback invoked once. - */ - public void testStartSubscriptionProvisioning() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // Using Java reflection to construct an OsuProvider instance because its constructor is - // hidden and not available to apps. - Class osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider"); - Constructor osuProviderClassConstructor = osuProviderClass.getConstructor(String.class, - Map.class, String.class, Uri.class, String.class, List.class); - - OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID, - TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, - TEST_METHOD_LIST); - - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - try { - uiAutomation.adoptShellPermissionIdentity(); - synchronized (mLock) { - // Start a subscription provisioning for a non-existent Passpoint R2 AP - mWifiManager.startSubscriptionProvisioning(osuProvider, mExecutor, - mProvisioningCallback); - mLock.wait(TEST_WAIT_DURATION_MS); - } - } finally { - uiAutomation.dropShellPermissionIdentity(); - } - - // Expect only a single callback event, connecting. Since AP doesn't exist, it ends here - assertEquals(ProvisioningCallback.OSU_STATUS_AP_CONNECTING, mProvisioningStatus); - // No failure callbacks expected - assertEquals(0, mProvisioningFailureStatus); - // No completion callback expected - assertFalse(mProvisioningComplete); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java deleted file mode 100644 index c74c177039..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiMigrationTest.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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.wifi.cts; - -import android.app.ActivityManager; -import android.net.wifi.WifiMigration; -import android.os.UserHandle; -import android.os.UserManager; -import android.test.AndroidTestCase; - -public class WifiMigrationTest extends AndroidTestCase { - private static final String TEST_SSID_UNQUOTED = "testSsid1"; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - super.tearDown(); - } - - /** - * Tests {@link android.net.wifi.WifiMigration.SettingsMigrationData.Builder} class. - */ - public void testWifiMigrationSettingsDataBuilder() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiMigration.SettingsMigrationData migrationData = - new WifiMigration.SettingsMigrationData.Builder() - .setScanAlwaysAvailable(true) - .setP2pFactoryResetPending(true) - .setScanThrottleEnabled(true) - .setSoftApTimeoutEnabled(true) - .setWakeUpEnabled(true) - .setVerboseLoggingEnabled(true) - .setP2pDeviceName(TEST_SSID_UNQUOTED) - .build(); - - assertNotNull(migrationData); - assertTrue(migrationData.isScanAlwaysAvailable()); - assertTrue(migrationData.isP2pFactoryResetPending()); - assertTrue(migrationData.isScanThrottleEnabled()); - assertTrue(migrationData.isSoftApTimeoutEnabled()); - assertTrue(migrationData.isWakeUpEnabled()); - assertTrue(migrationData.isVerboseLoggingEnabled()); - assertEquals(TEST_SSID_UNQUOTED, migrationData.getP2pDeviceName()); - } - - /** - * Tests {@link android.net.wifi.WifiMigration.SettingsMigrationData} class. - */ - public void testWifiMigrationSettings() throws Exception { - try { - WifiMigration.loadFromSettings(getContext()); - } catch (Exception ignore) { - } - } - - /** - * Tests {@link WifiMigration#convertAndRetrieveSharedConfigStoreFile(int)}, - * {@link WifiMigration#convertAndRetrieveUserConfigStoreFile(int, UserHandle)}, - * {@link WifiMigration#removeSharedConfigStoreFile(int)} and - * {@link WifiMigration#removeUserConfigStoreFile(int, UserHandle)}. - */ - public void testWifiMigrationConfigStore() throws Exception { - try { - WifiMigration.convertAndRetrieveSharedConfigStoreFile( - WifiMigration.STORE_FILE_SHARED_GENERAL); - } catch (Exception ignore) { - } - try { - WifiMigration.convertAndRetrieveSharedConfigStoreFile( - WifiMigration.STORE_FILE_SHARED_SOFTAP); - } catch (Exception ignore) { - } - try { - WifiMigration.convertAndRetrieveUserConfigStoreFile( - WifiMigration.STORE_FILE_USER_GENERAL, - UserHandle.of(ActivityManager.getCurrentUser())); - } catch (Exception ignore) { - } - try { - WifiMigration.convertAndRetrieveUserConfigStoreFile( - WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS, - UserHandle.of(ActivityManager.getCurrentUser())); - } catch (Exception ignore) { - } - try { - WifiMigration.removeSharedConfigStoreFile( - WifiMigration.STORE_FILE_SHARED_GENERAL); - } catch (Exception ignore) { - } - try { - WifiMigration.removeSharedConfigStoreFile( - WifiMigration.STORE_FILE_SHARED_SOFTAP); - } catch (Exception ignore) { - } - try { - WifiMigration.removeUserConfigStoreFile( - WifiMigration.STORE_FILE_USER_GENERAL, - UserHandle.of(ActivityManager.getCurrentUser())); - } catch (Exception ignore) { - } - try { - WifiMigration.removeUserConfigStoreFile( - WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS, - UserHandle.of(ActivityManager.getCurrentUser())); - } catch (Exception ignore) { - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java deleted file mode 100644 index eb6d6843eb..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java +++ /dev/null @@ -1,562 +0,0 @@ -/* - * 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.wifi.cts; - -import static android.net.NetworkCapabilitiesProto.TRANSPORT_WIFI; -import static android.os.Process.myUid; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.UiAutomation; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.MacAddress; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiEnterpriseConfig; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.NetworkRequestMatchCallback; -import android.net.wifi.WifiNetworkSpecifier; -import android.os.PatternMatcher; -import android.os.WorkSource; -import android.platform.test.annotations.AppModeFull; -import android.support.test.uiautomator.UiDevice; -import android.test.AndroidTestCase; -import android.text.TextUtils; - -import androidx.test.platform.app.InstrumentationRegistry; - -import com.android.compatibility.common.util.PollingCheck; -import com.android.compatibility.common.util.ShellIdentityUtils; -import com.android.compatibility.common.util.SystemUtil; - -import java.util.List; -import java.util.concurrent.Executors; - -/** - * Tests the entire connection flow using {@link WifiNetworkSpecifier} embedded in a - * {@link NetworkRequest} & passed into {@link ConnectivityManager#requestNetwork(NetworkRequest, - * ConnectivityManager.NetworkCallback)}. - * - * Assumes that all the saved networks is either open/WPA1/WPA2/WPA3 authenticated network. - * TODO(b/150716005): Use assumeTrue for wifi support check. - */ -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiNetworkSpecifierTest extends AndroidTestCase { - private static final String TAG = "WifiNetworkSpecifierTest"; - - private WifiManager mWifiManager; - private ConnectivityManager mConnectivityManager; - private UiDevice mUiDevice; - private final Object mLock = new Object(); - private final Object mUiLock = new Object(); - private WifiConfiguration mTestNetwork; - private boolean mWasVerboseLoggingEnabled; - private boolean mWasScanThrottleEnabled; - - private static final int DURATION = 10_000; - private static final int DURATION_UI_INTERACTION = 15_000; - private static final int DURATION_NETWORK_CONNECTION = 30_000; - private static final int DURATION_SCREEN_TOGGLE = 2000; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - mConnectivityManager = getContext().getSystemService(ConnectivityManager.class); - assertNotNull(mWifiManager); - - // turn on verbose logging for tests - mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.isVerboseLoggingEnabled()); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(true)); - // Disable scan throttling for tests. - mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.isScanThrottleEnabled()); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setScanThrottleEnabled(false)); - - if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - turnScreenOn(); - PollingCheck.check("Wifi not enabled", DURATION, () -> mWifiManager.isWifiEnabled()); - - List savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.getPrivilegedConfiguredNetworks()); - assertFalse("Need at least one saved network", savedNetworks.isEmpty()); - // Pick any one of the saved networks on the device (assumes that it is in range) - mTestNetwork = savedNetworks.get(0); - // Disconnect & disable auto-join on the saved network to prevent auto-connect from - // interfering with the test. - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.disableNetwork(mTestNetwork.networkId)); - // wait for Wifi to be disconnected - PollingCheck.check( - "Wifi not disconnected", - 20000, - () -> mWifiManager.getConnectionInfo().getNetworkId() == -1); - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); - turnScreenOff(); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.enableNetwork(mTestNetwork.networkId, false)); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled)); - ShellIdentityUtils.invokeWithShellPermissions( - () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); - super.tearDown(); - } - - private void setWifiEnabled(boolean enable) throws Exception { - // now trigger the change using shell commands. - SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable")); - } - - private void turnScreenOn() throws Exception { - mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); - mUiDevice.executeShellCommand("wm dismiss-keyguard"); - // Since the screen on/off intent is ordered, they will not be sent right now. - Thread.sleep(DURATION_SCREEN_TOGGLE); - } - - private void turnScreenOff() throws Exception { - mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); - // Since the screen on/off intent is ordered, they will not be sent right now. - Thread.sleep(DURATION_SCREEN_TOGGLE); - } - - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final Object mLock; - public boolean onAvailableCalled = false; - public boolean onUnavailableCalled = false; - public NetworkCapabilities networkCapabilities; - - TestNetworkCallback(Object lock) { - mLock = lock; - } - - @Override - public void onAvailable(Network network, NetworkCapabilities networkCapabilities, - LinkProperties linkProperties, boolean blocked) { - synchronized (mLock) { - onAvailableCalled = true; - this.networkCapabilities = networkCapabilities; - mLock.notify(); - } - } - - @Override - public void onUnavailable() { - synchronized (mLock) { - onUnavailableCalled = true; - mLock.notify(); - } - } - } - - private static class TestNetworkRequestMatchCallback implements NetworkRequestMatchCallback { - private final Object mLock; - - public boolean onRegistrationCalled = false; - public boolean onAbortCalled = false; - public boolean onMatchCalled = false; - public boolean onConnectSuccessCalled = false; - public boolean onConnectFailureCalled = false; - public WifiManager.NetworkRequestUserSelectionCallback userSelectionCallback = null; - public List matchedScanResults = null; - - TestNetworkRequestMatchCallback(Object lock) { - mLock = lock; - } - - @Override - public void onUserSelectionCallbackRegistration( - WifiManager.NetworkRequestUserSelectionCallback userSelectionCallback) { - synchronized (mLock) { - onRegistrationCalled = true; - this.userSelectionCallback = userSelectionCallback; - mLock.notify(); - } - } - - @Override - public void onAbort() { - synchronized (mLock) { - onAbortCalled = true; - mLock.notify(); - } - } - - @Override - public void onMatch(List scanResults) { - synchronized (mLock) { - // This can be invoked multiple times. So, ignore after the first one to avoid - // disturbing the rest of the test sequence. - if (onMatchCalled) return; - onMatchCalled = true; - matchedScanResults = scanResults; - mLock.notify(); - } - } - - @Override - public void onUserSelectionConnectSuccess(WifiConfiguration config) { - synchronized (mLock) { - onConnectSuccessCalled = true; - mLock.notify(); - } - } - - @Override - public void onUserSelectionConnectFailure(WifiConfiguration config) { - synchronized (mLock) { - onConnectFailureCalled = true; - mLock.notify(); - } - } - } - - private void handleUiInteractions(boolean shouldUserReject) { - UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - TestNetworkRequestMatchCallback networkRequestMatchCallback = - new TestNetworkRequestMatchCallback(mUiLock); - try { - uiAutomation.adoptShellPermissionIdentity(); - - // 1. Wait for registration callback. - synchronized (mUiLock) { - try { - mWifiManager.registerNetworkRequestMatchCallback( - Executors.newSingleThreadExecutor(), networkRequestMatchCallback); - // now wait for the registration callback first. - mUiLock.wait(DURATION_UI_INTERACTION); - } catch (InterruptedException e) { - } - } - assertTrue(networkRequestMatchCallback.onRegistrationCalled); - assertNotNull(networkRequestMatchCallback.userSelectionCallback); - - // 2. Wait for matching scan results - synchronized (mUiLock) { - try { - // now wait for the registration callback first. - mUiLock.wait(DURATION_UI_INTERACTION); - } catch (InterruptedException e) { - } - } - assertTrue(networkRequestMatchCallback.onMatchCalled); - assertNotNull(networkRequestMatchCallback.matchedScanResults); - assertThat(networkRequestMatchCallback.matchedScanResults.size()).isAtLeast(1); - - // 3. Trigger connection to one of the matched networks or reject the request. - if (shouldUserReject) { - networkRequestMatchCallback.userSelectionCallback.reject(); - } else { - networkRequestMatchCallback.userSelectionCallback.select(mTestNetwork); - } - - // 4. Wait for connection success or abort. - synchronized (mUiLock) { - try { - // now wait for the registration callback first. - mUiLock.wait(DURATION_UI_INTERACTION); - } catch (InterruptedException e) { - } - } - if (shouldUserReject) { - assertTrue(networkRequestMatchCallback.onAbortCalled); - } else { - assertTrue(networkRequestMatchCallback.onConnectSuccessCalled); - } - } finally { - mWifiManager.unregisterNetworkRequestMatchCallback(networkRequestMatchCallback); - uiAutomation.dropShellPermissionIdentity(); - } - } - - /** - * Tests the entire connection flow using the provided specifier. - * - * @param specifier Specifier to use for network request. - * @param shouldUserReject Whether to simulate user rejection or not. - */ - private void testConnectionFlowWithSpecifier( - WifiNetworkSpecifier specifier, boolean shouldUserReject) { - // Fork a thread to handle the UI interactions. - Thread uiThread = new Thread(() -> handleUiInteractions(shouldUserReject)); - - // File the network request & wait for the callback. - TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock); - synchronized (mLock) { - try { - // File a request for wifi network. - mConnectivityManager.requestNetwork( - new NetworkRequest.Builder() - .addTransportType(TRANSPORT_WIFI) - .setNetworkSpecifier(specifier) - .build(), - networkCallbackListener); - // Wait for the request to reach the wifi stack before kick-starting the UI - // interactions. - Thread.sleep(100); - // Start the UI interactions. - uiThread.run(); - // now wait for callback - mLock.wait(DURATION_NETWORK_CONNECTION); - } catch (InterruptedException e) { - } - } - if (shouldUserReject) { - assertTrue(networkCallbackListener.onUnavailableCalled); - } else { - assertTrue(networkCallbackListener.onAvailableCalled); - } - - try { - // Ensure that the UI interaction thread has completed. - uiThread.join(DURATION_UI_INTERACTION); - } catch (InterruptedException e) { - fail("UI interaction interrupted"); - } - - // Release the request after the test. - mConnectivityManager.unregisterNetworkCallback(networkCallbackListener); - } - - private void testSuccessfulConnectionWithSpecifier(WifiNetworkSpecifier specifier) { - testConnectionFlowWithSpecifier(specifier, false); - } - - private void testUserRejectionWithSpecifier(WifiNetworkSpecifier specifier) { - testConnectionFlowWithSpecifier(specifier, true); - } - - private static String removeDoubleQuotes(String string) { - return WifiInfo.sanitizeSsid(string); - } - - private WifiNetworkSpecifier.Builder createSpecifierBuilderWithCredentialFromSavedNetwork() { - WifiNetworkSpecifier.Builder specifierBuilder = new WifiNetworkSpecifier.Builder(); - if (mTestNetwork.preSharedKey != null) { - if (mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { - specifierBuilder.setWpa2Passphrase(removeDoubleQuotes(mTestNetwork.preSharedKey)); - } else if (mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE)) { - specifierBuilder.setWpa3Passphrase(removeDoubleQuotes(mTestNetwork.preSharedKey)); - } else { - fail("Unsupported security type found in saved networks"); - } - } else if (!mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE)) { - specifierBuilder.setIsEnhancedOpen(false); - } else if (!mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) { - fail("Unsupported security type found in saved networks"); - } - specifierBuilder.setIsHiddenSsid(mTestNetwork.hiddenSSID); - return specifierBuilder; - } - - /** - * Tests the entire connection flow using a specific SSID in the specifier. - */ - public void testConnectionWithSpecificSsid() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiNetworkSpecifier specifier = createSpecifierBuilderWithCredentialFromSavedNetwork() - .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) - .build(); - testSuccessfulConnectionWithSpecifier(specifier); - } - - /** - * Tests the entire connection flow using a SSID pattern in the specifier. - */ - public void testConnectionWithSsidPattern() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - // Creates a ssid pattern by dropping the last char in the saved network & pass that - // as a prefix match pattern in the request. - String ssidUnquoted = removeDoubleQuotes(mTestNetwork.SSID); - assertThat(ssidUnquoted.length()).isAtLeast(2); - String ssidPrefix = ssidUnquoted.substring(0, ssidUnquoted.length() - 1); - // Note: The match may return more than 1 network in this case since we use a prefix match, - // But, we will still ensure that the UI interactions in the test still selects the - // saved network for connection. - WifiNetworkSpecifier specifier = createSpecifierBuilderWithCredentialFromSavedNetwork() - .setSsidPattern(new PatternMatcher(ssidPrefix, PatternMatcher.PATTERN_PREFIX)) - .build(); - testSuccessfulConnectionWithSpecifier(specifier); - } - - private static class TestScanResultsCallback extends WifiManager.ScanResultsCallback { - private final Object mLock; - public boolean onAvailableCalled = false; - - TestScanResultsCallback(Object lock) { - mLock = lock; - } - - @Override - public void onScanResultsAvailable() { - synchronized (mLock) { - onAvailableCalled = true; - mLock.notify(); - } - } - } - - /** - * Loops through all available scan results and finds the first match for the saved network. - * - * Note: - * a) If there are more than 2 networks with the same SSID, but different credential type, then - * this matching may pick the wrong one. - */ - private ScanResult findScanResultMatchingSavedNetwork() { - // Trigger a scan to get fresh scan results. - TestScanResultsCallback scanResultsCallback = new TestScanResultsCallback(mLock); - synchronized (mLock) { - try { - mWifiManager.registerScanResultsCallback( - Executors.newSingleThreadExecutor(), scanResultsCallback); - mWifiManager.startScan(new WorkSource(myUid())); - // now wait for callback - mLock.wait(DURATION_NETWORK_CONNECTION); - } catch (InterruptedException e) { - } finally { - mWifiManager.unregisterScanResultsCallback(scanResultsCallback); - } - } - List scanResults = mWifiManager.getScanResults(); - if (scanResults == null || scanResults.isEmpty()) fail("No scan results available"); - for (ScanResult scanResult : scanResults) { - if (TextUtils.equals(scanResult.SSID, removeDoubleQuotes(mTestNetwork.SSID))) { - return scanResult; - } - } - fail("No matching scan results found"); - return null; - } - - /** - * Tests the entire connection flow using a specific BSSID in the specifier. - */ - public void testConnectionWithSpecificBssid() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - ScanResult scanResult = findScanResultMatchingSavedNetwork(); - WifiNetworkSpecifier specifier = createSpecifierBuilderWithCredentialFromSavedNetwork() - .setBssid(MacAddress.fromString(scanResult.BSSID)) - .build(); - testSuccessfulConnectionWithSpecifier(specifier); - } - - /** - * Tests the entire connection flow using a BSSID pattern in the specifier. - */ - public void testConnectionWithBssidPattern() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - ScanResult scanResult = findScanResultMatchingSavedNetwork(); - // Note: The match may return more than 1 network in this case since we use a prefix match, - // But, we will still ensure that the UI interactions in the test still selects the - // saved network for connection. - WifiNetworkSpecifier specifier = createSpecifierBuilderWithCredentialFromSavedNetwork() - .setBssidPattern(MacAddress.fromString(scanResult.BSSID), - MacAddress.fromString("ff:ff:ff:00:00:00")) - .build(); - testSuccessfulConnectionWithSpecifier(specifier); - } - - /** - * Tests the entire connection flow using a BSSID pattern in the specifier. - */ - public void testUserRejectionWithSpecificSsid() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiNetworkSpecifier specifier = createSpecifierBuilderWithCredentialFromSavedNetwork() - .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) - .build(); - testUserRejectionWithSpecifier(specifier); - } - - /** - * Tests the builder for WPA2 enterprise networks. - * Note: Can't do end to end tests for such networks in CTS environment. - */ - public void testBuilderForWpa2Enterprise() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() - .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) - .setWpa2EnterpriseConfig(new WifiEnterpriseConfig()) - .build(); - WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() - .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) - .setWpa2EnterpriseConfig(new WifiEnterpriseConfig()) - .build(); - assertThat(specifier1.satisfiedBy(specifier2)).isTrue(); - } - - /** - * Tests the builder for WPA3 enterprise networks. - * Note: Can't do end to end tests for such networks in CTS environment. - */ - public void testBuilderForWpa3Enterprise() { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() - .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) - .setWpa3EnterpriseConfig(new WifiEnterpriseConfig()) - .build(); - WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() - .setSsid(removeDoubleQuotes(mTestNetwork.SSID)) - .setWpa3EnterpriseConfig(new WifiEnterpriseConfig()) - .build(); - assertThat(specifier1.satisfiedBy(specifier2)).isTrue(); - } -} diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java deleted file mode 100644 index e73abb8b54..0000000000 --- a/tests/cts/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * 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.wifi.cts; - -import static android.net.wifi.WifiEnterpriseConfig.Eap.AKA; -import static android.net.wifi.WifiEnterpriseConfig.Eap.WAPI_CERT; - -import android.net.MacAddress; -import android.net.wifi.WifiEnterpriseConfig; -import android.net.wifi.WifiNetworkSuggestion; -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.pps.Credential; -import android.net.wifi.hotspot2.pps.HomeSp; -import android.telephony.TelephonyManager; -import android.test.AndroidTestCase; - -public class WifiNetworkSuggestionTest extends AndroidTestCase { - private static final String TEST_SSID = "testSsid"; - private static final String TEST_BSSID = "00:df:aa:bc:12:23"; - private static final String TEST_PASSPHRASE = "testPassword"; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - } - - @Override - protected void tearDown() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - super.tearDown(); - return; - } - super.tearDown(); - } - - private WifiNetworkSuggestion.Builder createBuilderWithCommonParams() { - return createBuilderWithCommonParams(false); - } - - private WifiNetworkSuggestion.Builder createBuilderWithCommonParams(boolean isPasspoint) { - WifiNetworkSuggestion.Builder builder = new WifiNetworkSuggestion.Builder(); - if (!isPasspoint) { - builder.setSsid(TEST_SSID); - builder.setBssid(MacAddress.fromString(TEST_BSSID)); - builder.setIsEnhancedOpen(false); - builder.setIsHiddenSsid(true); - } - builder.setPriority(0); - builder.setIsAppInteractionRequired(true); - builder.setIsUserInteractionRequired(true); - builder.setIsMetered(true); - builder.setCarrierId(TelephonyManager.UNKNOWN_CARRIER_ID); - builder.setCredentialSharedWithUser(true); - builder.setIsInitialAutojoinEnabled(true); - builder.setUntrusted(false); - return builder; - } - - private void validateCommonParams(WifiNetworkSuggestion suggestion) { - validateCommonParams(suggestion, false); - } - - private void validateCommonParams(WifiNetworkSuggestion suggestion, boolean isPasspoint) { - assertNotNull(suggestion); - assertNotNull(suggestion.getWifiConfiguration()); - if (!isPasspoint) { - assertEquals(TEST_SSID, suggestion.getSsid()); - assertEquals(TEST_BSSID, suggestion.getBssid().toString()); - assertFalse(suggestion.isEnhancedOpen()); - assertTrue(suggestion.isHiddenSsid()); - } - assertEquals(0, suggestion.getPriority()); - assertTrue(suggestion.isAppInteractionRequired()); - assertTrue(suggestion.isUserInteractionRequired()); - assertTrue(suggestion.isMetered()); - assertTrue(suggestion.isCredentialSharedWithUser()); - assertTrue(suggestion.isInitialAutojoinEnabled()); - assertFalse(suggestion.isUntrusted()); - } - - /** - * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class. - */ - public void testBuilderWithWpa2Passphrase() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiNetworkSuggestion suggestion = - createBuilderWithCommonParams() - .setWpa2Passphrase(TEST_PASSPHRASE) - .build(); - validateCommonParams(suggestion); - assertEquals(TEST_PASSPHRASE, suggestion.getPassphrase()); - assertNotNull(suggestion.getEnterpriseConfig()); - assertNull(suggestion.getPasspointConfig()); - } - - /** - * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class. - */ - public void testBuilderWithWpa3Passphrase() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiNetworkSuggestion suggestion = - createBuilderWithCommonParams() - .setWpa3Passphrase(TEST_PASSPHRASE) - .build(); - validateCommonParams(suggestion); - assertEquals(TEST_PASSPHRASE, suggestion.getPassphrase()); - assertNotNull(suggestion.getEnterpriseConfig()); - assertNull(suggestion.getPasspointConfig()); - } - - /** - * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class. - */ - public void testBuilderWithWapiPassphrase() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiNetworkSuggestion suggestion = - createBuilderWithCommonParams() - .setWapiPassphrase(TEST_PASSPHRASE) - .build(); - validateCommonParams(suggestion); - assertEquals(TEST_PASSPHRASE, suggestion.getPassphrase()); - assertNotNull(suggestion.getEnterpriseConfig()); - assertNull(suggestion.getPasspointConfig()); - } - - private static WifiEnterpriseConfig createEnterpriseConfig() { - WifiEnterpriseConfig config = new WifiEnterpriseConfig(); - config.setEapMethod(AKA); - return config; - } - - /** - * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class. - */ - public void testBuilderWithWpa2Enterprise() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiEnterpriseConfig enterpriseConfig = createEnterpriseConfig(); - WifiNetworkSuggestion suggestion = - createBuilderWithCommonParams() - .setWpa2EnterpriseConfig(enterpriseConfig) - .build(); - validateCommonParams(suggestion); - assertNull(suggestion.getPassphrase()); - assertNotNull(suggestion.getEnterpriseConfig()); - assertEquals(enterpriseConfig.getEapMethod(), - suggestion.getEnterpriseConfig().getEapMethod()); - assertNull(suggestion.getPasspointConfig()); - } - - /** - * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class. - */ - public void testBuilderWithWpa3Enterprise() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiEnterpriseConfig enterpriseConfig = createEnterpriseConfig(); - WifiNetworkSuggestion suggestion = - createBuilderWithCommonParams() - .setWpa3EnterpriseConfig(enterpriseConfig) - .build(); - validateCommonParams(suggestion); - assertNull(suggestion.getPassphrase()); - assertNotNull(suggestion.getEnterpriseConfig()); - assertEquals(enterpriseConfig.getEapMethod(), - suggestion.getEnterpriseConfig().getEapMethod()); - assertNull(suggestion.getPasspointConfig()); - } - - /** - * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class. - */ - public void testBuilderWithWapiEnterprise() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); - enterpriseConfig.setEapMethod(WAPI_CERT); - WifiNetworkSuggestion suggestion = - createBuilderWithCommonParams() - .setWapiEnterpriseConfig(enterpriseConfig) - .build(); - validateCommonParams(suggestion); - assertNull(suggestion.getPassphrase()); - assertNotNull(suggestion.getEnterpriseConfig()); - assertEquals(enterpriseConfig.getEapMethod(), - suggestion.getEnterpriseConfig().getEapMethod()); - assertNull(suggestion.getPasspointConfig()); - } - - /** - * Helper function for creating a {@link PasspointConfiguration} for testing. - * - * @return {@link PasspointConfiguration} - */ - private static PasspointConfiguration createPasspointConfig() { - HomeSp homeSp = new HomeSp(); - homeSp.setFqdn("fqdn"); - homeSp.setFriendlyName("friendly name"); - homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66}); - Credential cred = new Credential(); - cred.setRealm("realm"); - cred.setUserCredential(null); - cred.setCertCredential(null); - cred.setSimCredential(new Credential.SimCredential()); - cred.getSimCredential().setImsi("1234*"); - cred.getSimCredential().setEapType(23); // EAP-AKA - cred.setCaCertificate(null); - cred.setClientCertificateChain(null); - cred.setClientPrivateKey(null); - PasspointConfiguration config = new PasspointConfiguration(); - config.setHomeSp(homeSp); - config.setCredential(cred); - return config; - } - - /** - * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class. - */ - public void testBuilderWithPasspointConfig() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - PasspointConfiguration passpointConfig = createPasspointConfig(); - WifiNetworkSuggestion suggestion = - createBuilderWithCommonParams(true) - .setPasspointConfig(passpointConfig) - .build(); - validateCommonParams(suggestion, true); - assertNull(suggestion.getPassphrase()); - assertNotNull(suggestion.getEnterpriseConfig()); - assertEquals(passpointConfig, suggestion.getPasspointConfig()); - } -} diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java deleted file mode 100644 index d8f5e579da..0000000000 --- a/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.wifi.nl80211.cts; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assume.assumeTrue; - -import android.content.Context; -import android.net.wifi.ScanResult; -import android.net.wifi.cts.WifiFeature; -import android.net.wifi.nl80211.DeviceWiphyCapabilities; -import android.os.Parcel; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** CTS tests for {@link DeviceWiphyCapabilities}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class DeviceWiphyCapabilitiesTest { - - @Before - public void setUp() { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - // skip tests if Wifi is not supported - assumeTrue(WifiFeature.isWifiSupported(context)); - } - - /** - * Test that a {@link DeviceWiphyCapabilities} object can be serialized and deserialized, - * while keeping its values unchanged. - */ - @Test - public void canSerializeAndDeserialize() { - DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities(); - - capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true); - capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true); - capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false); - - Parcel parcel = Parcel.obtain(); - capa.writeToParcel(parcel, 0); - // Rewind the pointer to the head of the parcel. - parcel.setDataPosition(0); - DeviceWiphyCapabilities capaDeserialized = - DeviceWiphyCapabilities.CREATOR.createFromParcel(parcel); - - assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N)).isTrue(); - assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC)) - .isTrue(); - assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX)) - .isFalse(); - assertThat(capaDeserialized).isEqualTo(capa); - assertThat(capaDeserialized.hashCode()).isEqualTo(capa.hashCode()); - } - - /** Test mapping wifi standard support into channel width support */ - @Test - public void testMappingWifiStandardIntoChannelWidthSupport() { - DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities(); - - capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, false); - capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, false); - capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue(); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isFalse(); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isFalse(); - - capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue(); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isTrue(); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isFalse(); - - capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue(); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isTrue(); - assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isTrue(); - } -} diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java deleted file mode 100644 index 3149b54abd..0000000000 --- a/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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.wifi.nl80211.cts; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assume.assumeTrue; - -import android.content.Context; -import android.net.MacAddress; -import android.net.wifi.cts.WifiFeature; -import android.net.wifi.nl80211.NativeWifiClient; -import android.os.Parcel; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** CTS tests for {@link NativeWifiClient}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class NativeWifiClientTest { - - private static final byte[] TEST_MAC = { 1, 2, 3, 4, 5, 6 }; - - @Before - public void setUp() { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - // skip tests if Wifi is not supported - assumeTrue(WifiFeature.isWifiSupported(context)); - } - - @Test - public void testGetters() { - NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC)); - - assertThat(client.getMacAddress().toByteArray()).isEqualTo(TEST_MAC); - } - - @Test - public void canSerializeAndDeserialize() { - NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC)); - - Parcel parcel = Parcel.obtain(); - client.writeToParcel(parcel, 0); - // Rewind the pointer to the head of the parcel. - parcel.setDataPosition(0); - NativeWifiClient clientDeserialized = NativeWifiClient.CREATOR.createFromParcel(parcel); - - assertThat(clientDeserialized.getMacAddress().toByteArray()).isEqualTo(TEST_MAC); - assertThat(clientDeserialized).isEqualTo(client); - assertThat(clientDeserialized.hashCode()).isEqualTo(client.hashCode()); - } - - @Test - public void testEquals() { - NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC)); - NativeWifiClient client2 = - new NativeWifiClient(MacAddress.fromBytes(new byte[] { 7, 8, 9, 10, 11, 12 })); - - assertThat(client2).isNotEqualTo(client); - } -} diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java deleted file mode 100644 index f3a8f05927..0000000000 --- a/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.wifi.nl80211.cts; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assume.assumeTrue; - -import android.content.Context; -import android.net.wifi.cts.WifiFeature; -import android.net.wifi.nl80211.PnoNetwork; -import android.os.Parcel; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** CTS tests for {@link PnoNetwork}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class PnoNetworkTest { - - private static final byte[] TEST_SSID = { 's', 's', 'i', 'd' }; - private static final int[] TEST_FREQUENCIES = { 2412, 2417, 5035 }; - - @Before - public void setUp() { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - // skip tests if Wifi is not supported - assumeTrue(WifiFeature.isWifiSupported(context)); - } - - @Test - public void testGetters() { - PnoNetwork network = new PnoNetwork(); - network.setSsid(TEST_SSID); - network.setFrequenciesMhz(TEST_FREQUENCIES); - network.setHidden(true); - - assertThat(network.getSsid()).isEqualTo(TEST_SSID); - assertThat(network.getFrequenciesMhz()).isEqualTo(TEST_FREQUENCIES); - assertThat(network.isHidden()).isTrue(); - } - - @Test - public void canSerializeAndDeserialize() { - PnoNetwork network = new PnoNetwork(); - network.setSsid(TEST_SSID); - network.setFrequenciesMhz(TEST_FREQUENCIES); - network.setHidden(true); - - Parcel parcel = Parcel.obtain(); - network.writeToParcel(parcel, 0); - // Rewind the pointer to the head of the parcel. - parcel.setDataPosition(0); - PnoNetwork networkDeserialized = PnoNetwork.CREATOR.createFromParcel(parcel); - - assertThat(networkDeserialized.getSsid()).isEqualTo(TEST_SSID); - assertThat(networkDeserialized.getFrequenciesMhz()).isEqualTo(TEST_FREQUENCIES); - assertThat(networkDeserialized.isHidden()).isTrue(); - assertThat(networkDeserialized).isEqualTo(network); - assertThat(networkDeserialized.hashCode()).isEqualTo(network.hashCode()); - } - - @Test - public void testEquals() { - PnoNetwork network = new PnoNetwork(); - network.setSsid(TEST_SSID); - network.setFrequenciesMhz(TEST_FREQUENCIES); - network.setHidden(true); - - PnoNetwork network2 = new PnoNetwork(); - network.setSsid(new byte[] { 'a', 's', 'd', 'f'}); - network.setFrequenciesMhz(new int[] { 1, 2, 3 }); - network.setHidden(false); - - assertThat(network2).isNotEqualTo(network); - } -} diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java deleted file mode 100644 index 59f5d993a3..0000000000 --- a/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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.wifi.nl80211.cts; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assume.assumeTrue; - -import android.content.Context; -import android.net.wifi.cts.WifiFeature; -import android.net.wifi.nl80211.PnoNetwork; -import android.net.wifi.nl80211.PnoSettings; -import android.os.Parcel; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.Arrays; -import java.util.List; - -/** CTS tests for {@link PnoSettings}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class PnoSettingsTest { - - private static List createTestNetworks() { - PnoNetwork network1 = new PnoNetwork(); - network1.setSsid(new byte[] { 's', 's', 'i', 'd' }); - network1.setFrequenciesMhz(new int[] { 2412, 2417, 5035 }); - network1.setHidden(true); - - PnoNetwork network2 = new PnoNetwork(); - network2.setSsid(new byte[] { 'a', 's', 'd', 'f' }); - network2.setFrequenciesMhz(new int[] { 2422, 2427, 5040 }); - network2.setHidden(false); - - return Arrays.asList(network1, network2); - } - - @Before - public void setUp() { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - // skip tests if Wifi is not supported - assumeTrue(WifiFeature.isWifiSupported(context)); - } - - @Test - public void testGetters() { - PnoSettings settings = new PnoSettings(); - settings.setIntervalMillis(1000); - settings.setMin2gRssiDbm(-70); - settings.setMin5gRssiDbm(-60); - settings.setMin6gRssiDbm(-50); - settings.setPnoNetworks(createTestNetworks()); - - assertThat(settings.getIntervalMillis()).isEqualTo(1000); - assertThat(settings.getMin2gRssiDbm()).isEqualTo(-70); - assertThat(settings.getMin5gRssiDbm()).isEqualTo(-60); - assertThat(settings.getMin6gRssiDbm()).isEqualTo(-50); - assertThat(settings.getPnoNetworks()).isEqualTo(createTestNetworks()); - } - - @Test - public void canSerializeAndDeserialize() { - PnoSettings settings = new PnoSettings(); - settings.setIntervalMillis(1000); - settings.setMin2gRssiDbm(-70); - settings.setMin5gRssiDbm(-60); - settings.setMin6gRssiDbm(-50); - settings.setPnoNetworks(createTestNetworks()); - - Parcel parcel = Parcel.obtain(); - settings.writeToParcel(parcel, 0); - // Rewind the pointer to the head of the parcel. - parcel.setDataPosition(0); - PnoSettings settingsDeserialized = PnoSettings.CREATOR.createFromParcel(parcel); - - assertThat(settingsDeserialized.getIntervalMillis()).isEqualTo(1000); - assertThat(settingsDeserialized.getMin2gRssiDbm()).isEqualTo(-70); - assertThat(settingsDeserialized.getMin5gRssiDbm()).isEqualTo(-60); - assertThat(settingsDeserialized.getMin6gRssiDbm()).isEqualTo(-50); - assertThat(settingsDeserialized.getPnoNetworks()).isEqualTo(createTestNetworks()); - assertThat(settingsDeserialized).isEqualTo(settings); - assertThat(settingsDeserialized.hashCode()).isEqualTo(settings.hashCode()); - } - - @Test - public void testEquals() { - PnoSettings settings = new PnoSettings(); - settings.setIntervalMillis(1000); - settings.setMin2gRssiDbm(-70); - settings.setMin5gRssiDbm(-60); - settings.setMin6gRssiDbm(-50); - settings.setPnoNetworks(createTestNetworks()); - - PnoSettings settings2 = new PnoSettings(); - settings.setIntervalMillis(2000); - settings.setMin2gRssiDbm(-70); - settings.setMin5gRssiDbm(-60); - settings.setMin6gRssiDbm(-50); - settings.setPnoNetworks(createTestNetworks()); - - assertThat(settings2).isNotEqualTo(settings); - } -} diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java deleted file mode 100644 index 0a76bdbe32..0000000000 --- a/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.wifi.nl80211.cts; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assume.assumeTrue; - -import android.content.Context; -import android.net.wifi.cts.WifiFeature; -import android.net.wifi.nl80211.RadioChainInfo; -import android.os.Parcel; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** CTS tests for {@link RadioChainInfo}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class RadioChainInfoTest { - - private static final int TEST_CHAIN_ID = 1; - private static final int TEST_CHAIN_ID2 = 2; - private static final int TEST_LEVEL_DBM = -50; - private static final int TEST_LEVEL_DBM2 = -80; - - @Before - public void setUp() { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - // skip tests if Wifi is not supported - assumeTrue(WifiFeature.isWifiSupported(context)); - } - - @Test - public void testGetters() { - RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM); - assertThat(info.getChainId()).isEqualTo(TEST_CHAIN_ID); - assertThat(info.getLevelDbm()).isEqualTo(TEST_LEVEL_DBM); - } - - @Test - public void canSerializeAndDeserialize() { - RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM); - - Parcel parcel = Parcel.obtain(); - info.writeToParcel(parcel, 0); - // Rewind the pointer to the head of the parcel. - parcel.setDataPosition(0); - RadioChainInfo infoDeserialized = RadioChainInfo.CREATOR.createFromParcel(parcel); - - assertThat(infoDeserialized.getChainId()).isEqualTo(TEST_CHAIN_ID); - assertThat(infoDeserialized.getLevelDbm()).isEqualTo(TEST_LEVEL_DBM); - assertThat(infoDeserialized).isEqualTo(info); - assertThat(infoDeserialized.hashCode()).isEqualTo(info.hashCode()); - } - - @Test - public void testEquals() { - RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM); - RadioChainInfo info2 = new RadioChainInfo(TEST_CHAIN_ID2, TEST_LEVEL_DBM2); - - assertThat(info2).isNotEqualTo(info); - } -} diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java deleted file mode 100644 index f1f3010ddf..0000000000 --- a/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.wifi.nl80211.cts; - -import static android.net.wifi.nl80211.WifiNl80211Manager.OemSecurityType; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assume.assumeTrue; - -import android.content.Context; -import android.net.wifi.ScanResult; -import android.net.wifi.cts.WifiFeature; -import android.net.wifi.nl80211.WifiNl80211Manager; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.Arrays; - -/** CTS tests for {@link WifiNl80211Manager}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class WifiNl80211ManagerTest { - - private Context mContext; - - @Before - public void setUp() { - mContext = InstrumentationRegistry.getInstrumentation().getContext(); - // skip tests if Wifi is not supported - assumeTrue(WifiFeature.isWifiSupported(mContext)); - } - - @Test - public void testOemSecurityTypeConstructor() { - OemSecurityType securityType = new OemSecurityType( - ScanResult.PROTOCOL_WPA, - Arrays.asList(ScanResult.KEY_MGMT_PSK, ScanResult.KEY_MGMT_SAE), - Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP), - ScanResult.CIPHER_CCMP); - - assertThat(securityType.protocol).isEqualTo(ScanResult.PROTOCOL_WPA); - assertThat(securityType.keyManagement) - .isEqualTo(Arrays.asList(ScanResult.KEY_MGMT_PSK, ScanResult.KEY_MGMT_SAE)); - assertThat(securityType.pairwiseCipher) - .isEqualTo(Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP)); - assertThat(securityType.groupCipher).isEqualTo(ScanResult.CIPHER_CCMP); - } - - @Test - public void testSendMgmtFrame() { - try { - WifiNl80211Manager manager = mContext.getSystemService(WifiNl80211Manager.class); - manager.sendMgmtFrame("wlan0", new byte[]{}, -1, Runnable::run, - new WifiNl80211Manager.SendMgmtFrameCallback() { - @Override - public void onAck(int elapsedTimeMs) {} - - @Override - public void onFailure(int reason) {} - }); - } catch (Exception ignore) {} - } -} diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java deleted file mode 100644 index 0a2a2e6779..0000000000 --- a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2019 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.wifi.p2p.cts; - -import android.net.MacAddress; -import android.net.wifi.p2p.WifiP2pConfig; -import android.net.wifi.p2p.WifiP2pGroup; -import android.test.AndroidTestCase; - -public class WifiP2pConfigTest extends AndroidTestCase { - private static final String TEST_NETWORK_NAME = "DIRECT-xy-Hello"; - private static final String TEST_PASSPHRASE = "8etterW0r1d"; - private static final int TEST_OWNER_BAND = WifiP2pConfig.GROUP_OWNER_BAND_5GHZ; - private static final int TEST_OWNER_FREQ = 2447; - private static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff"; - - public void testWifiP2pConfigCopyConstructor() { - WifiP2pConfig config = new WifiP2pConfig.Builder() - .setNetworkName(TEST_NETWORK_NAME) - .setPassphrase(TEST_PASSPHRASE) - .setGroupOperatingBand(TEST_OWNER_BAND) - .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) - .enablePersistentMode(true) - .build(); - - WifiP2pConfig copiedConfig = new WifiP2pConfig(config); - - assertEquals(copiedConfig.deviceAddress, TEST_DEVICE_ADDRESS); - assertEquals(copiedConfig.getNetworkName(), TEST_NETWORK_NAME); - assertEquals(copiedConfig.getPassphrase(), TEST_PASSPHRASE); - assertEquals(copiedConfig.getGroupOwnerBand(), TEST_OWNER_BAND); - assertEquals(copiedConfig.getNetworkId(), WifiP2pGroup.NETWORK_ID_PERSISTENT); - } - - public void testWifiP2pConfigBuilderForPersist() { - WifiP2pConfig config = new WifiP2pConfig.Builder() - .setNetworkName(TEST_NETWORK_NAME) - .setPassphrase(TEST_PASSPHRASE) - .setGroupOperatingBand(TEST_OWNER_BAND) - .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) - .enablePersistentMode(true) - .build(); - - assertEquals(config.deviceAddress, TEST_DEVICE_ADDRESS); - assertEquals(config.getNetworkName(), TEST_NETWORK_NAME); - assertEquals(config.getPassphrase(), TEST_PASSPHRASE); - assertEquals(config.getGroupOwnerBand(), TEST_OWNER_BAND); - assertEquals(config.getNetworkId(), WifiP2pGroup.NETWORK_ID_PERSISTENT); - } - - public void testWifiP2pConfigBuilderForNonPersist() { - WifiP2pConfig config = new WifiP2pConfig.Builder() - .setNetworkName(TEST_NETWORK_NAME) - .setPassphrase(TEST_PASSPHRASE) - .setGroupOperatingFrequency(TEST_OWNER_FREQ) - .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) - .enablePersistentMode(false) - .build(); - - assertEquals(config.deviceAddress, TEST_DEVICE_ADDRESS); - assertEquals(config.getNetworkName(), TEST_NETWORK_NAME); - assertEquals(config.getPassphrase(), TEST_PASSPHRASE); - assertEquals(config.getGroupOwnerBand(), TEST_OWNER_FREQ); - assertEquals(config.getNetworkId(), WifiP2pGroup.NETWORK_ID_TEMPORARY); - } -} diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java deleted file mode 100644 index 1510d7cc1c..0000000000 --- a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.wifi.p2p.cts; - -import android.net.InetAddresses; -import android.net.wifi.p2p.WifiP2pDevice; -import android.test.AndroidTestCase; - -public class WifiP2pDeviceTest extends AndroidTestCase { - - public void testDefaultWpsMethodSupportCheck() { - WifiP2pDevice dev = new WifiP2pDevice(); - - assertFalse(dev.wpsPbcSupported()); - assertFalse(dev.wpsDisplaySupported()); - assertFalse(dev.wpsKeypadSupported()); - } - - public void testDefaultDeviceCapabilityCheck() { - WifiP2pDevice dev = new WifiP2pDevice(); - - assertFalse(dev.isServiceDiscoveryCapable()); - } -} diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pInfoTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pInfoTest.java deleted file mode 100644 index 8504f15e43..0000000000 --- a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pInfoTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.wifi.p2p.cts; - -import android.net.InetAddresses; -import android.net.wifi.p2p.WifiP2pInfo; -import android.test.AndroidTestCase; - -public class WifiP2pInfoTest extends AndroidTestCase { - - public String TEST_GROUP_OWNER_ADDRESS = "192.168.43.1"; - - public void testWifiP2pInfoNoGroup() { - WifiP2pInfo info = new WifiP2pInfo(); - info.groupFormed = false; - - WifiP2pInfo copiedInfo = new WifiP2pInfo(info); - assertEquals(info.groupFormed, copiedInfo.groupFormed); - assertEquals(info.isGroupOwner, copiedInfo.isGroupOwner); - assertEquals(info.groupOwnerAddress, copiedInfo.groupOwnerAddress); - } - - public void testWifiP2pInfoGroupOwner() { - WifiP2pInfo info = new WifiP2pInfo(); - info.groupFormed = true; - info.isGroupOwner = true; - info.groupOwnerAddress = InetAddresses.parseNumericAddress(TEST_GROUP_OWNER_ADDRESS); - - WifiP2pInfo copiedInfo = new WifiP2pInfo(info); - assertEquals(info.groupFormed, copiedInfo.groupFormed); - assertEquals(info.isGroupOwner, copiedInfo.isGroupOwner); - assertEquals(info.groupOwnerAddress, copiedInfo.groupOwnerAddress); - } - - public void testWifiP2pInfoGroupClient() { - WifiP2pInfo info = new WifiP2pInfo(); - info.groupFormed = true; - info.isGroupOwner = false; - info.groupOwnerAddress = InetAddresses.parseNumericAddress(TEST_GROUP_OWNER_ADDRESS); - - WifiP2pInfo copiedInfo = new WifiP2pInfo(info); - assertEquals(info.groupFormed, copiedInfo.groupFormed); - assertEquals(info.isGroupOwner, copiedInfo.isGroupOwner); - assertEquals(info.groupOwnerAddress, copiedInfo.groupOwnerAddress); - } -} diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java deleted file mode 100644 index b363b1ed19..0000000000 --- a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.wifi.p2p.cts; - -import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; -import android.net.wifi.p2p.nsd.WifiP2pServiceRequest; -import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest; -import android.test.AndroidTestCase; -import android.util.Log; - -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.stream.Collectors; - -public class WifiP2pServiceRequestTest extends AndroidTestCase { - - private final int TEST_UPNP_VERSION = 0x10; - private final String TEST_UPNP_QUERY = "ssdp:all"; - - private String bin2HexStr(byte[] data) { - StringBuffer sb = new StringBuffer(); - for (byte b: data) { - sb.append(String.format(Locale.US, "%02x", b & 0xff)); - } - return sb.toString(); - } - - public void testValidRawRequest() throws IllegalArgumentException { - StringBuffer sb = new StringBuffer(); - sb.append(String.format(Locale.US, "%02x", TEST_UPNP_VERSION)); - sb.append(bin2HexStr(TEST_UPNP_QUERY.getBytes())); - - WifiP2pServiceRequest rawRequest = - WifiP2pServiceRequest.newInstance( - WifiP2pServiceInfo.SERVICE_TYPE_UPNP, - sb.toString()); - - WifiP2pUpnpServiceRequest upnpRequest = - WifiP2pUpnpServiceRequest.newInstance( - TEST_UPNP_QUERY); - - assertEquals(rawRequest, upnpRequest); - } - - public void testInvalidRawRequest() { - StringBuffer sb = new StringBuffer(); - sb.append(String.format(Locale.US, "%02x", TEST_UPNP_VERSION)); - sb.append(bin2HexStr(TEST_UPNP_QUERY.getBytes())); - sb.append("x"); - - try { - WifiP2pServiceRequest request = - WifiP2pServiceRequest.newInstance( - WifiP2pServiceInfo.SERVICE_TYPE_UPNP, sb.toString()); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException ex) { - return; - } - } -} diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pWfdInfoTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pWfdInfoTest.java deleted file mode 100644 index 75df5bf928..0000000000 --- a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pWfdInfoTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.wifi.p2p.cts; - -import android.net.wifi.p2p.WifiP2pWfdInfo; -import android.test.AndroidTestCase; - -public class WifiP2pWfdInfoTest extends AndroidTestCase { - - private final int TEST_DEVICE_TYPE = WifiP2pWfdInfo.DEVICE_TYPE_WFD_SOURCE; - private final boolean TEST_DEVICE_ENABLE_STATUS = true; - private final boolean TEST_SESSION_STATUS = true; - private final int TEST_CONTROL_PORT = 9999; - private final int TEST_MAX_THROUGHPUT = 1024; - private final boolean TEST_CONTENT_PROTECTION_SUPPORTED_STATUS = true; - - public void testWifiP2pWfdInfo() { - WifiP2pWfdInfo info = new WifiP2pWfdInfo(); - - info.setDeviceType(TEST_DEVICE_TYPE); - info.setEnabled(TEST_DEVICE_ENABLE_STATUS); - info.setSessionAvailable(true); - info.setControlPort(TEST_CONTROL_PORT); - info.setMaxThroughput(TEST_MAX_THROUGHPUT); - info.setContentProtectionSupported(true); - - WifiP2pWfdInfo copiedInfo = new WifiP2pWfdInfo(info); - assertEquals(TEST_DEVICE_TYPE, copiedInfo.getDeviceType()); - assertEquals(TEST_DEVICE_ENABLE_STATUS, copiedInfo.isEnabled()); - assertEquals(TEST_SESSION_STATUS, copiedInfo.isSessionAvailable()); - assertEquals(TEST_CONTROL_PORT, copiedInfo.getControlPort()); - assertEquals(TEST_MAX_THROUGHPUT, copiedInfo.getMaxThroughput()); - assertEquals(TEST_CONTENT_PROTECTION_SUPPORTED_STATUS, - copiedInfo.isContentProtectionSupported()); - } -} diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/TestBase.java b/tests/cts/net/src/android/net/wifi/rtt/cts/TestBase.java deleted file mode 100644 index 07d5718044..0000000000 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/TestBase.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2018 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.wifi.rtt.cts; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.location.LocationManager; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiManager; -import android.net.wifi.rtt.RangingResult; -import android.net.wifi.rtt.RangingResultCallback; -import android.net.wifi.rtt.WifiRttManager; -import android.os.Handler; -import android.os.HandlerExecutor; -import android.os.HandlerThread; -import android.test.AndroidTestCase; - -import com.android.compatibility.common.util.SystemUtil; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; - -/** - * Base class for Wi-Fi RTT CTS test cases. Provides a uniform configuration and event management - * facility. - */ -public class TestBase extends AndroidTestCase { - protected static final String TAG = "WifiRttCtsTests"; - - // wait for Wi-Fi RTT to become available - private static final int WAIT_FOR_RTT_CHANGE_SECS = 10; - - // wait for Wi-Fi scan results to become available - private static final int WAIT_FOR_SCAN_RESULTS_SECS = 20; - - protected WifiRttManager mWifiRttManager; - protected WifiManager mWifiManager; - private LocationManager mLocationManager; - private WifiManager.WifiLock mWifiLock; - - private final HandlerThread mHandlerThread = new HandlerThread("SingleDeviceTest"); - protected final Executor mExecutor; - { - mHandlerThread.start(); - mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper())); - } - - /** - * Returns a flag indicating whether or not Wi-Fi RTT should be tested. Wi-Fi RTT - * should be tested if the feature is supported on the current device. - */ - static boolean shouldTestWifiRtt(Context context) { - final PackageManager pm = context.getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - if (!shouldTestWifiRtt(getContext())) { - return; - } - - mLocationManager = (LocationManager) getContext().getSystemService( - Context.LOCATION_SERVICE); - assertTrue("RTT testing requires Location to be enabled", - mLocationManager.isLocationEnabled()); - - mWifiRttManager = (WifiRttManager) getContext().getSystemService( - Context.WIFI_RTT_RANGING_SERVICE); - assertNotNull("Wi-Fi RTT Manager", mWifiRttManager); - - mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - assertNotNull("Wi-Fi Manager", mWifiManager); - mWifiLock = mWifiManager.createWifiLock(TAG); - mWifiLock.acquire(); - if (!mWifiManager.isWifiEnabled()) { - SystemUtil.runShellCommand("svc wifi enable"); - } - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED); - WifiRttBroadcastReceiver receiver = new WifiRttBroadcastReceiver(); - mContext.registerReceiver(receiver, intentFilter); - if (!mWifiRttManager.isAvailable()) { - assertTrue("Timeout waiting for Wi-Fi RTT to change status", - receiver.waitForStateChange()); - assertTrue("Wi-Fi RTT is not available (should be)", mWifiRttManager.isAvailable()); - } - } - - @Override - protected void tearDown() throws Exception { - if (!shouldTestWifiRtt(getContext())) { - super.tearDown(); - return; - } - - super.tearDown(); - } - - class WifiRttBroadcastReceiver extends BroadcastReceiver { - private CountDownLatch mBlocker = new CountDownLatch(1); - - @Override - public void onReceive(Context context, Intent intent) { - if (WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED.equals(intent.getAction())) { - mBlocker.countDown(); - } - } - - boolean waitForStateChange() throws InterruptedException { - return mBlocker.await(WAIT_FOR_RTT_CHANGE_SECS, TimeUnit.SECONDS); - } - } - - class WifiScansBroadcastReceiver extends BroadcastReceiver { - private CountDownLatch mBlocker = new CountDownLatch(1); - - @Override - public void onReceive(Context context, Intent intent) { - if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) { - mBlocker.countDown(); - } - } - - boolean waitForStateChange() throws InterruptedException { - return mBlocker.await(WAIT_FOR_SCAN_RESULTS_SECS, TimeUnit.SECONDS); - } - } - - class ResultCallback extends RangingResultCallback { - private CountDownLatch mBlocker = new CountDownLatch(1); - private int mCode; // 0: success, otherwise RangingResultCallback STATUS_CODE_*. - private List mResults; - - @Override - public void onRangingFailure(int code) { - mCode = code; - mResults = null; // not necessary since intialized to null - but for completeness - mBlocker.countDown(); - } - - @Override - public void onRangingResults(List results) { - mCode = 0; // not necessary since initialized to 0 - but for completeness - mResults = results; - mBlocker.countDown(); - } - - /** - * Waits for the listener callback to be called - or an error (timeout, interruption). - * Returns true on callback called, false on error (timeout, interruption). - */ - boolean waitForCallback() throws InterruptedException { - return mBlocker.await(WAIT_FOR_RTT_CHANGE_SECS, TimeUnit.SECONDS); - } - - /** - * Returns the code of the callback operation. Will be 0 for success (onRangingResults - * called), else (if onRangingFailure called) will be one of the STATUS_CODE_* values. - */ - int getCode() { - return mCode; - } - - /** - * Returns the list of ranging results. In cases of error (getCode() != 0) will return null. - */ - List getResults() { - return mResults; - } - } - - /** - * Start a scan and return a list of observed ScanResults (APs). - */ - protected List scanAps() throws InterruptedException { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - WifiScansBroadcastReceiver receiver = new WifiScansBroadcastReceiver(); - mContext.registerReceiver(receiver, intentFilter); - - mWifiManager.startScan(); - receiver.waitForStateChange(); - mContext.unregisterReceiver(receiver); - return mWifiManager.getScanResults(); - } - - /** - * Start a scan and return a test AP which supports IEEE 802.11mc and which has the highest - * RSSI. Will perform N (parameterized) scans and get the best AP across both scans. - * - * Returns null if test AP is not found in the specified number of scans. - * - * @param numScanRetries Maximum number of scans retries (in addition to first scan). - */ - protected ScanResult scanForTestAp(int numScanRetries) - throws InterruptedException { - int scanCount = 0; - ScanResult bestTestAp = null; - while (scanCount <= numScanRetries) { - for (ScanResult scanResult : scanAps()) { - if (!scanResult.is80211mcResponder()) { - continue; - } - if (bestTestAp == null || scanResult.level > bestTestAp.level) { - bestTestAp = scanResult; - } - } - - scanCount++; - } - - return bestTestAp; - } -} diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java deleted file mode 100644 index 9cbaf3953e..0000000000 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (C) 2018 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.wifi.rtt.cts; - -import static org.mockito.Mockito.mock; - -import android.net.MacAddress; -import android.net.wifi.ScanResult; -import android.net.wifi.aware.PeerHandle; -import android.net.wifi.rtt.RangingRequest; -import android.net.wifi.rtt.RangingResult; -import android.net.wifi.rtt.ResponderLocation; -import android.platform.test.annotations.AppModeFull; - -import com.android.compatibility.common.util.DeviceReportLog; -import com.android.compatibility.common.util.ResultType; -import com.android.compatibility.common.util.ResultUnit; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Wi-Fi RTT CTS test: range to all available Access Points which support IEEE 802.11mc. - */ -@AppModeFull(reason = "Cannot get WifiManager in instant app mode") -public class WifiRttTest extends TestBase { - // Number of scans to do while searching for APs supporting IEEE 802.11mc - private static final int NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP = 2; - - // Number of RTT measurements per AP - private static final int NUM_OF_RTT_ITERATIONS = 10; - - // Maximum failure rate of RTT measurements (percentage) - private static final int MAX_FAILURE_RATE_PERCENT = 10; - - // Maximum variation from the average measurement (measures consistency) - private static final int MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM = 1000; - - // Minimum valid RSSI value - private static final int MIN_VALID_RSSI = -100; - - // Valid Mac Address - private static final MacAddress MAC = MacAddress.fromString("00:01:02:03:04:05"); - - /** - * Test Wi-Fi RTT ranging operation: - * - Scan for visible APs for the test AP (which is validated to support IEEE 802.11mc) - * - Perform N (constant) RTT operations - * - Validate: - * - Failure ratio < threshold (constant) - * - Result margin < threshold (constant) - */ - public void testRangingToTestAp() throws InterruptedException { - if (!shouldTestWifiRtt(getContext())) { - return; - } - - // Scan for IEEE 802.11mc supporting APs - ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); - assertNotNull( - "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " - + "your test setup includes them!", testAp); - - // Perform RTT operations - RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build(); - List allResults = new ArrayList<>(); - int numFailures = 0; - int distanceSum = 0; - int distanceMin = 0; - int distanceMax = 0; - int[] statuses = new int[NUM_OF_RTT_ITERATIONS]; - int[] distanceMms = new int[NUM_OF_RTT_ITERATIONS]; - int[] distanceStdDevMms = new int[NUM_OF_RTT_ITERATIONS]; - int[] rssis = new int[NUM_OF_RTT_ITERATIONS]; - int[] numAttempted = new int[NUM_OF_RTT_ITERATIONS]; - int[] numSuccessful = new int[NUM_OF_RTT_ITERATIONS]; - long[] timestampsMs = new long[NUM_OF_RTT_ITERATIONS]; - byte[] lastLci = null; - byte[] lastLcr = null; - for (int i = 0; i < NUM_OF_RTT_ITERATIONS; ++i) { - ResultCallback callback = new ResultCallback(); - mWifiRttManager.startRanging(request, mExecutor, callback); - assertTrue("Wi-Fi RTT results: no callback on iteration " + i, - callback.waitForCallback()); - - List currentResults = callback.getResults(); - assertNotNull("Wi-Fi RTT results: null results (onRangingFailure) on iteration " + i, - currentResults); - assertEquals("Wi-Fi RTT results: unexpected # of results (expect 1) on iteration " + i, - 1, currentResults.size()); - RangingResult result = currentResults.get(0); - assertEquals("Wi-Fi RTT results: invalid result (wrong BSSID) entry on iteration " + i, - result.getMacAddress().toString(), testAp.BSSID); - assertNull("Wi-Fi RTT results: invalid result (non-null PeerHandle) entry on iteration " - + i, result.getPeerHandle()); - - allResults.add(result); - int status = result.getStatus(); - statuses[i] = status; - if (status == RangingResult.STATUS_SUCCESS) { - distanceSum += result.getDistanceMm(); - if (i == 0) { - distanceMin = result.getDistanceMm(); - distanceMax = result.getDistanceMm(); - } else { - distanceMin = Math.min(distanceMin, result.getDistanceMm()); - distanceMax = Math.max(distanceMax, result.getDistanceMm()); - } - - assertTrue("Wi-Fi RTT results: invalid RSSI on iteration " + i, - result.getRssi() >= MIN_VALID_RSSI); - - distanceMms[i - numFailures] = result.getDistanceMm(); - distanceStdDevMms[i - numFailures] = result.getDistanceStdDevMm(); - rssis[i - numFailures] = result.getRssi(); - numAttempted[i - numFailures] = result.getNumAttemptedMeasurements(); - numSuccessful[i - numFailures] = result.getNumSuccessfulMeasurements(); - timestampsMs[i - numFailures] = result.getRangingTimestampMillis(); - - byte[] currentLci = result.getLci(); - byte[] currentLcr = result.getLcr(); - if (i - numFailures > 0) { - assertTrue("Wi-Fi RTT results: invalid result (LCI mismatch) on iteration " + i, - Arrays.equals(currentLci, lastLci)); - assertTrue("Wi-Fi RTT results: invalid result (LCR mismatch) on iteration " + i, - Arrays.equals(currentLcr, lastLcr)); - } - lastLci = currentLci; - lastLcr = currentLcr; - } else { - numFailures++; - } - } - - // Save results to log - int numGoodResults = NUM_OF_RTT_ITERATIONS - numFailures; - DeviceReportLog reportLog = new DeviceReportLog(TAG, "testRangingToTestAp"); - reportLog.addValues("status_codes", statuses, ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("distance_mm", Arrays.copyOf(distanceMms, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("distance_stddev_mm", Arrays.copyOf(distanceStdDevMms, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("rssi_dbm", Arrays.copyOf(rssis, numGoodResults), ResultType.NEUTRAL, - ResultUnit.NONE); - reportLog.addValues("num_attempted", Arrays.copyOf(numAttempted, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("num_successful", Arrays.copyOf(numSuccessful, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.addValues("timestamps", Arrays.copyOf(timestampsMs, numGoodResults), - ResultType.NEUTRAL, ResultUnit.NONE); - reportLog.submit(); - - // Analyze results - assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures + ", ITERATIONS=" - + NUM_OF_RTT_ITERATIONS + ", AP RSSI=" + testAp.level - + ", AP SSID=" + testAp.SSID, - numFailures <= NUM_OF_RTT_ITERATIONS * MAX_FAILURE_RATE_PERCENT / 100); - if (numFailures != NUM_OF_RTT_ITERATIONS) { - double distanceAvg = distanceSum / (NUM_OF_RTT_ITERATIONS - numFailures); - assertTrue("Wi-Fi RTT: Variation (max direction) exceeds threshold", - (distanceMax - distanceAvg) <= MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM); - assertTrue("Wi-Fi RTT: Variation (min direction) exceeds threshold", - (distanceAvg - distanceMin) <= MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM); - for (int i = 0; i < numGoodResults; ++i) { - assertNotSame("Number of attempted measurements is 0", 0, numAttempted[i]); - assertNotSame("Number of successful measurements is 0", 0, numSuccessful[i]); - } - } - } - - /** - * Validate that when a request contains more range operations than allowed (by API) that we - * get an exception. - */ - public void testRequestTooLarge() throws InterruptedException { - if (!shouldTestWifiRtt(getContext())) { - return; - } - ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); - assertNotNull( - "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " - + "your test setup includes them!", testAp); - - RangingRequest.Builder builder = new RangingRequest.Builder(); - for (int i = 0; i < RangingRequest.getMaxPeers() - 2; ++i) { - builder.addAccessPoint(testAp); - } - - List scanResults = new ArrayList<>(); - scanResults.add(testAp); - scanResults.add(testAp); - scanResults.add(testAp); - - builder.addAccessPoints(scanResults); - - try { - mWifiRttManager.startRanging(builder.build(), mExecutor, new ResultCallback()); - } catch (IllegalArgumentException e) { - return; - } - - fail("Did not receive expected IllegalArgumentException when tried to range to too " - + "many peers"); - } - - /** - * Verify ResponderLocation API - */ - public void testRangingToTestApWithResponderLocation() throws InterruptedException { - if (!shouldTestWifiRtt(getContext())) { - return; - } - // Scan for IEEE 802.11mc supporting APs - ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); - assertNotNull( - "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " - + "your test setup includes them!", testAp); - - // Perform RTT operations - RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build(); - ResultCallback callback = new ResultCallback(); - mWifiRttManager.startRanging(request, mExecutor, callback); - assertTrue("Wi-Fi RTT results: no callback! ", - callback.waitForCallback()); - - RangingResult result = callback.getResults().get(0); - assertEquals("Ranging request not success", - result.getStatus(), RangingResult.STATUS_SUCCESS); - ResponderLocation responderLocation = result.getUnverifiedResponderLocation(); - assertNotNull("ResponderLocation should not be null", responderLocation); - assertTrue("ResponderLocation is not valid", responderLocation.isLciSubelementValid()); - - // Check LCI related APIs - int exceptionCount = 0; - int apiCount = 0; - try { - apiCount++; - responderLocation.getLatitudeUncertainty(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getLatitude(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getLongitudeUncertainty(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getLongitude(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getAltitudeType(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getAltitudeUncertainty(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getAltitude(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getDatum(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getRegisteredLocationAgreementIndication(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - responderLocation.getLciVersion(); - } catch (IllegalStateException e) { - exceptionCount++; - } - try { - apiCount++; - assertNotNull(responderLocation.toLocation()); - } catch (IllegalStateException e) { - exceptionCount++; - } - // If LCI is not valid, all APIs should throw exception, otherwise no exception. - assertEquals("Exception number should equal to API number", - responderLocation.isLciSubelementValid()? 0 : apiCount, exceptionCount); - - // Verify ZaxisSubelement APIs - apiCount = 0; - exceptionCount = 0; - - try { - apiCount++; - responderLocation.getExpectedToMove(); - } catch (IllegalStateException e) { - exceptionCount++; - } - - try { - apiCount++; - responderLocation.getFloorNumber(); - } catch (IllegalStateException e) { - exceptionCount++; - } - - try { - apiCount++; - responderLocation.getHeightAboveFloorMeters(); - } catch (IllegalStateException e) { - exceptionCount++; - } - - try { - apiCount++; - responderLocation.getHeightAboveFloorUncertaintyMeters(); - } catch (IllegalStateException e) { - exceptionCount++; - } - // If Zaxis is not valid, all APIs should throw exception, otherwise no exception. - assertEquals("Exception number should equal to API number", - responderLocation.isZaxisSubelementValid() ? 0 : apiCount, exceptionCount); - // Verify civic location - if (responderLocation.toCivicLocationAddress() == null) { - assertNull(responderLocation.toCivicLocationSparseArray()); - } else { - assertNotNull(responderLocation.toCivicLocationSparseArray()); - } - // Verify map image - if (responderLocation.getMapImageUri() == null) { - assertNull(responderLocation.getMapImageMimeType()); - } else { - assertNotNull(responderLocation.getMapImageMimeType()); - } - boolean extraInfoOnAssociationIndication = - responderLocation.getExtraInfoOnAssociationIndication(); - assertNotNull("ColocatedBSSID list should be nonNull", - responderLocation.getColocatedBssids()); - } - - /** - * Verify ranging request with aware peer Mac address and peer handle. - */ - public void testAwareRttWithMacAddress() throws InterruptedException { - RangingRequest request = new RangingRequest.Builder() - .addWifiAwarePeer(MAC).build(); - ResultCallback callback = new ResultCallback(); - mWifiRttManager.startRanging(request, mExecutor, callback); - assertTrue("Wi-Fi RTT results: no callback", - callback.waitForCallback()); - List rangingResults = callback.getResults(); - assertNotNull("Wi-Fi RTT results: null results", rangingResults); - assertEquals(1, rangingResults.size()); - assertEquals(RangingResult.STATUS_FAIL, rangingResults.get(0).getStatus()); - } - - /** - * Verify ranging request with aware peer handle. - */ - public void testAwareRttWithPeerHandle() throws InterruptedException { - PeerHandle peerHandle = mock(PeerHandle.class); - RangingRequest request = new RangingRequest.Builder() - .addWifiAwarePeer(peerHandle).build(); - ResultCallback callback = new ResultCallback(); - mWifiRttManager.startRanging(request, mExecutor, callback); - assertTrue("Wi-Fi RTT results: no callback", - callback.waitForCallback()); - List rangingResults = callback.getResults(); - assertNotNull("Wi-Fi RTT results: null results", rangingResults); - assertEquals("Invalid peerHandle should return 0 result", 0, rangingResults.size()); - } -} From e31fb9d7bdf631a0306d5303123044e47989ba26 Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 21 Feb 2020 14:28:03 +0800 Subject: [PATCH 0875/1415] Register callback and receiver after tethering is created Tethering service is created after boot complete which means most of the services are ready before tethering. Once tethering register the callback, callback event may come-in immediately. Make sure all of tethering related object is created, then register the callback, receiver, or listener. Bug: 149965121 Test: atest TetheringTests manual on/off tethering Change-Id: I3941a186770679e7b476073d774e2310e25e44c6 --- .../connectivity/tethering/Tethering.java | 31 ++++++++++--------- .../tethering/TetheringService.java | 1 + .../connectivity/tethering/TetheringTest.java | 1 + 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 3dcc15f92c..78131ab7c6 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -306,28 +306,22 @@ public class Tethering { mTetheringRestriction = new UserRestrictionActionListener(userManager, this); mExecutor = new TetheringThreadExecutor(mHandler); mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor); + mNetdCallback = new NetdCallback(); // Load tethering configuration. updateConfiguration(); - // NetdCallback should be registered after updateConfiguration() to ensure - // TetheringConfiguration is created. - mNetdCallback = new NetdCallback(); + } + + /** + * Start to register callbacks. + * Call this function when tethering is ready to handle callback events. + */ + public void startStateMachineUpdaters() { try { mNetd.registerUnsolicitedEventListener(mNetdCallback); } catch (RemoteException e) { mLog.e("Unable to register netd UnsolicitedEventListener"); } - - startStateMachineUpdaters(mHandler); - startTrackDefaultNetwork(); - - final WifiManager wifiManager = getWifiManager(); - if (wifiManager != null) { - wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback()); - } - } - - private void startStateMachineUpdaters(Handler handler) { mCarrierConfigChange.startListening(); mContext.getSystemService(TelephonyManager.class).listen(mActiveDataSubIdListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); @@ -340,7 +334,14 @@ public class Tethering { filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED); filter.addAction(ACTION_RESTRICT_BACKGROUND_CHANGED); - mContext.registerReceiver(mStateReceiver, filter, null, handler); + mContext.registerReceiver(mStateReceiver, filter, null, mHandler); + + final WifiManager wifiManager = getWifiManager(); + if (wifiManager != null) { + wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback()); + } + + startTrackDefaultNetwork(); } private class TetheringThreadExecutor implements Executor { diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java index c5329d8d33..c30be25dbd 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -80,6 +80,7 @@ public class TetheringService extends Service { mContext = mDeps.getContext(); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mTethering = makeTethering(mDeps); + mTethering.startStateMachineUpdaters(); } /** diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index d983fae09b..a99ca8da33 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -485,6 +485,7 @@ public class TetheringTest { mServiceContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_TETHER_STATE_CHANGED)); mTethering = makeTethering(); + mTethering.startStateMachineUpdaters(); verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any()); verify(mNetd).registerUnsolicitedEventListener(any()); final ArgumentCaptor phoneListenerCaptor = From 4896e3200fddcaaea06ba157b486a9af59f38c41 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 17 Mar 2020 01:07:47 +0900 Subject: [PATCH 0876/1415] Add an Ethernet tethering test. This test uses EthernetManager's ability to use test network interfaces to test tethering. This provides a fairly realistic integration test for Tethering and its callbacks, IpServer and DhcpServer, and so on. It is in a new integration/ directory under Tethering because I didn't really know where to put it. It's fast enough to run in presubmit, but it didn't seem to be appropriate to call it a unit test, and in the future we could also use this test to do some limited testing of real Ethernet tethering as well. Bug: 150644681 Test: atest TetheringIntegrationTests:EthernetTetheringTest --rerun-until-failure 100 Change-Id: Ifcda70b73848b1fd4c26b031e53f0a6500cc93d4 --- Tethering/tests/integration/Android.bp | 42 ++ .../tests/integration/AndroidManifest.xml | 29 ++ .../android/net/EthernetTetheringTest.java | 460 ++++++++++++++++++ 3 files changed, 531 insertions(+) create mode 100644 Tethering/tests/integration/Android.bp create mode 100644 Tethering/tests/integration/AndroidManifest.xml create mode 100644 Tethering/tests/integration/src/android/net/EthernetTetheringTest.java diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp new file mode 100644 index 0000000000..1a1c30d1d5 --- /dev/null +++ b/Tethering/tests/integration/Android.bp @@ -0,0 +1,42 @@ +// +// 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. +// + +android_test { + name: "TetheringIntegrationTests", + certificate: "platform", + platform_apis: true, + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + test_suites: [ + "device-tests", + "mts", + ], + static_libs: [ + "NetworkStackApiStableLib", + "androidx.test.rules", + "frameworks-base-testutils", + "mockito-target-extended-minus-junit4", + "net-tests-utils", + "testables", + ], + libs: [ + "android.test.runner", + "android.test.base", + "android.test.mock", + ], +} diff --git a/Tethering/tests/integration/AndroidManifest.xml b/Tethering/tests/integration/AndroidManifest.xml new file mode 100644 index 0000000000..233ba40b5d --- /dev/null +++ b/Tethering/tests/integration/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java new file mode 100644 index 0000000000..843a4f19c3 --- /dev/null +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -0,0 +1,460 @@ +/* + * 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; + +import static android.Manifest.permission.MANAGE_TEST_NETWORKS; +import static android.Manifest.permission.NETWORK_SETTINGS; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + +import android.app.UiAutomation; +import android.content.Context; +import android.net.EthernetManager.TetheredInterfaceCallback; +import android.net.EthernetManager.TetheredInterfaceRequest; +import android.net.TetheringManager.StartTetheringCallback; +import android.net.TetheringManager.TetheringEventCallback; +import android.net.TetheringManager.TetheringRequest; +import android.net.dhcp.DhcpAckPacket; +import android.net.dhcp.DhcpOfferPacket; +import android.net.dhcp.DhcpPacket; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.SystemClock; +import android.system.Os; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.TapPacketReader; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.FileDescriptor; +import java.net.Inet4Address; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@MediumTest +public class EthernetTetheringTest { + + private static final String TAG = EthernetTetheringTest.class.getSimpleName(); + private static final int TIMEOUT_MS = 1000; + private static final int PACKET_READ_TIMEOUT_MS = 100; + private static final int DHCP_DISCOVER_ATTEMPTS = 10; + private static final byte[] DHCP_REQUESTED_PARAMS = new byte[] { + DhcpPacket.DHCP_SUBNET_MASK, + DhcpPacket.DHCP_ROUTER, + DhcpPacket.DHCP_DNS_SERVER, + DhcpPacket.DHCP_LEASE_TIME, + }; + private static final String DHCP_HOSTNAME = "testhostname"; + + private final Context mContext = InstrumentationRegistry.getContext(); + private final EthernetManager mEm = mContext.getSystemService(EthernetManager.class); + private final TetheringManager mTm = mContext.getSystemService(TetheringManager.class); + + private TestNetworkInterface mTestIface; + private HandlerThread mHandlerThread; + private Handler mHandler; + private TapPacketReader mTapPacketReader; + + private TetheredInterfaceRequester mTetheredInterfaceRequester; + private MyTetheringEventCallback mTetheringEventCallback; + + private UiAutomation mUiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + + @Before + public void setUp() throws Exception { + mHandlerThread = new HandlerThread(getClass().getSimpleName()); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm); + // Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive + // tethered client callbacks. + mUiAutomation.adoptShellPermissionIdentity(MANAGE_TEST_NETWORKS, NETWORK_SETTINGS); + } + + private void cleanUp() throws Exception { + mTm.stopTethering(TetheringManager.TETHERING_ETHERNET); + if (mTetheringEventCallback != null) { + mTetheringEventCallback.awaitInterfaceUntethered(); + mTetheringEventCallback.unregister(); + mTetheringEventCallback = null; + } + if (mTapPacketReader != null) { + TapPacketReader reader = mTapPacketReader; + mHandler.post(() -> reader.stop()); + mTapPacketReader = null; + } + mHandlerThread.quitSafely(); + mTetheredInterfaceRequester.release(); + mEm.setIncludeTestInterfaces(false); + maybeDeleteTestInterface(); + } + + @After + public void tearDown() throws Exception { + try { + cleanUp(); + } finally { + mUiAutomation.dropShellPermissionIdentity(); + } + } + + @Test + public void testVirtualEthernetAlreadyExists() throws Exception { + // This test requires manipulating packets. Skip if there is a physical Ethernet connected. + assumeFalse(mEm.isAvailable()); + + mTestIface = createTestInterface(); + // This must be done now because as soon as setIncludeTestInterfaces(true) is called, the + // interface will be placed in client mode, which will delete the link-local address. + // At that point NetworkInterface.getByName() will cease to work on the interface, because + // starting in R NetworkInterface can no longer see interfaces without IP addresses. + int mtu = getMTU(mTestIface); + + Log.d(TAG, "Including test interfaces"); + mEm.setIncludeTestInterfaces(true); + + Log.d(TAG, "Requesting tethered interface"); + mTetheredInterfaceRequester.requestInterface(); + + final String iface = mTetheredInterfaceRequester.awaitRequestedInterface(); + assertEquals("TetheredInterfaceCallback for unexpected interface", + mTestIface.getInterfaceName(), iface); + + checkVirtualEthernet(mTestIface, mtu); + } + + @Test + public void testVirtualEthernet() throws Exception { + // This test requires manipulating packets. Skip if there is a physical Ethernet connected. + assumeFalse(mEm.isAvailable()); + + Log.d(TAG, "Requesting tethered interface"); + mTetheredInterfaceRequester.requestInterface(); + + mEm.setIncludeTestInterfaces(true); + + mTestIface = createTestInterface(); + + final String iface = mTetheredInterfaceRequester.awaitRequestedInterface(); + assertEquals("TetheredInterfaceCallback for unexpected interface", + mTestIface.getInterfaceName(), iface); + + checkVirtualEthernet(mTestIface, getMTU(mTestIface)); + } + + @Test + public void testPhysicalEthernet() throws Exception { + assumeTrue(mEm.isAvailable()); + + // Get an interface to use. + mTetheredInterfaceRequester.requestInterface(); + String iface = mTetheredInterfaceRequester.awaitRequestedInterface(); + + // Enable Ethernet tethering and check that it starts. + mTetheringEventCallback = enableEthernetTethering(iface); + + // There is nothing more we can do on a physical interface without connecting an actual + // client, which is not possible in this test. + } + + private static final class MyTetheringEventCallback implements TetheringEventCallback { + private final TetheringManager mTm; + private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1); + private final CountDownLatch mTetheringStoppedLatch = new CountDownLatch(1); + private final CountDownLatch mClientConnectedLatch = new CountDownLatch(1); + private final String mIface; + + private volatile boolean mInterfaceWasTethered = false; + private volatile boolean mUnregistered = false; + private volatile Collection mClients = null; + + MyTetheringEventCallback(TetheringManager tm, String iface) { + mTm = tm; + mIface = iface; + } + + public void unregister() { + mTm.unregisterTetheringEventCallback(this); + mUnregistered = true; + } + + @Override + public void onTetheredInterfacesChanged(List interfaces) { + // Ignore stale callbacks registered by previous test cases. + if (mUnregistered) return; + + final boolean wasTethered = mTetheringStartedLatch.getCount() == 0; + if (!mInterfaceWasTethered && (mIface == null || interfaces.contains(mIface))) { + // This interface is being tethered for the first time. + Log.d(TAG, "Tethering started: " + interfaces); + mInterfaceWasTethered = true; + mTetheringStartedLatch.countDown(); + } else if (mInterfaceWasTethered && !interfaces.contains(mIface)) { + Log.d(TAG, "Tethering stopped: " + interfaces); + mTetheringStoppedLatch.countDown(); + } + } + + public void awaitInterfaceTethered() throws Exception { + assertTrue("Ethernet not tethered after " + TIMEOUT_MS + "ms", + mTetheringStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + + public void awaitInterfaceUntethered() throws Exception { + // Don't block teardown if the interface was never tethered. + // This is racy because the interface might become tethered right after this check, but + // that can only happen in tearDown if startTethering timed out, which likely means + // the test has already failed. + if (!mInterfaceWasTethered) return; + + assertTrue(mIface + " not untethered after " + TIMEOUT_MS + "ms", + mTetheringStoppedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + + @Override + public void onError(String ifName, int error) { + // Ignore stale callbacks registered by previous test cases. + if (mUnregistered) return; + + fail("TetheringEventCallback got error:" + error + " on iface " + ifName); + } + + @Override + public void onClientsChanged(Collection clients) { + // Ignore stale callbacks registered by previous test cases. + if (mUnregistered) return; + + Log.d(TAG, "Got clients changed: " + clients); + mClients = clients; + if (clients.size() > 0) { + mClientConnectedLatch.countDown(); + } + } + + public Collection awaitClientConnected() throws Exception { + assertTrue("Did not receive client connected callback after " + TIMEOUT_MS + "ms", + mClientConnectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + return mClients; + } + } + + private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception { + MyTetheringEventCallback callback = new MyTetheringEventCallback(mTm, iface); + mTm.registerTetheringEventCallback(mHandler::post, callback); + + StartTetheringCallback startTetheringCallback = new StartTetheringCallback() { + @Override + public void onTetheringFailed(int resultCode) { + fail("Unexpectedly got onTetheringFailed"); + } + }; + Log.d(TAG, "Starting Ethernet tethering"); + mTm.startTethering( + new TetheringRequest.Builder(TetheringManager.TETHERING_ETHERNET).build(), + mHandler::post /* executor */, startTetheringCallback); + callback.awaitInterfaceTethered(); + return callback; + } + + private int getMTU(TestNetworkInterface iface) throws SocketException { + NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName()); + assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif); + return nif.getMTU(); + } + + private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception { + FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor(); + mTapPacketReader = new TapPacketReader(mHandler, fd, mtu); + mHandler.post(() -> mTapPacketReader.start()); + HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS); + + mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName()); + checkTetheredClientCallbacks(fd); + } + + private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception { + // Create a fake client. + byte[] clientMacAddr = new byte[6]; + new Random().nextBytes(clientMacAddr); + + // We have to retransmit DHCP requests because IpServer declares itself to be ready before + // its DhcpServer is actually started. TODO: fix this race and remove this loop. + DhcpPacket offerPacket = null; + for (int i = 0; i < DHCP_DISCOVER_ATTEMPTS; i++) { + Log.d(TAG, "Sending DHCP discover"); + sendDhcpDiscover(fd, clientMacAddr); + offerPacket = getNextDhcpPacket(); + if (offerPacket instanceof DhcpOfferPacket) break; + } + assertTrue("No DHCPOFFER received on interface within timeout", + offerPacket instanceof DhcpOfferPacket); + + sendDhcpRequest(fd, offerPacket, clientMacAddr); + DhcpPacket ackPacket = getNextDhcpPacket(); + assertTrue("No DHCPACK received on interface within timeout", + ackPacket instanceof DhcpAckPacket); + + final Collection clients = mTetheringEventCallback.awaitClientConnected(); + assertEquals(1, clients.size()); + final TetheredClient client = clients.iterator().next(); + + // Check the MAC address. + assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress()); + assertEquals(TetheringManager.TETHERING_ETHERNET, client.getTetheringType()); + + // Check the hostname. + assertEquals(1, client.getAddresses().size()); + TetheredClient.AddressInfo info = client.getAddresses().get(0); + assertEquals(DHCP_HOSTNAME, info.getHostname()); + + // Check the address is the one that was handed out in the DHCP ACK. + DhcpResults dhcpResults = offerPacket.toDhcpResults(); + assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress()); + + // Check that the lifetime is correct +/- 10s. + final long now = SystemClock.elapsedRealtime(); + final long actualLeaseDuration = (info.getAddress().getExpirationTime() - now) / 1000; + final String msg = String.format("IP address should have lifetime of %d, got %d", + dhcpResults.leaseDuration, actualLeaseDuration); + assertTrue(msg, Math.abs(dhcpResults.leaseDuration - actualLeaseDuration) < 10); + } + + private DhcpPacket getNextDhcpPacket() throws ParseException { + byte[] packet; + while ((packet = mTapPacketReader.popPacket(PACKET_READ_TIMEOUT_MS)) != null) { + try { + return DhcpPacket.decodeFullPacket(packet, packet.length, DhcpPacket.ENCAP_L2); + } catch (DhcpPacket.ParseException e) { + // Not a DHCP packet. Continue. + } + } + return null; + } + + private static final class TetheredInterfaceRequester implements TetheredInterfaceCallback { + private final CountDownLatch mInterfaceAvailableLatch = new CountDownLatch(1); + private final Handler mHandler; + private final EthernetManager mEm; + + private volatile TetheredInterfaceRequest mRequest; + private volatile String mIface; + + TetheredInterfaceRequester(Handler handler, EthernetManager em) { + mHandler = handler; + mEm = em; + } + + @Override + public void onAvailable(String iface) { + Log.d(TAG, "Ethernet interface available: " + iface); + mIface = iface; + mInterfaceAvailableLatch.countDown(); + } + @Override + public void onUnavailable() {} + + public void requestInterface() { + assertNull("BUG: more than one tethered interface request", mRequest); + mRequest = mEm.requestTetheredInterface(mHandler::post, this); + } + + public String awaitRequestedInterface() throws InterruptedException { + assertTrue("No tethered interface available after " + TIMEOUT_MS + "ms", + mInterfaceAvailableLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + return mIface; + } + + public void release() { + if (mRequest != null) { + mRequest.release(); + mRequest = null; + } + } + } + + private void sendDhcpDiscover(FileDescriptor fd, byte[] macAddress) throws Exception { + ByteBuffer packet = DhcpPacket.buildDiscoverPacket(DhcpPacket.ENCAP_L2, + new Random().nextInt() /* transactionId */, (short) 0 /* secs */, + macAddress, false /* unicast */, DHCP_REQUESTED_PARAMS, + false /* rapid commit */, DHCP_HOSTNAME); + sendPacket(fd, packet); + } + + private void sendDhcpRequest(FileDescriptor fd, DhcpPacket offerPacket, byte[] macAddress) + throws Exception { + DhcpResults results = offerPacket.toDhcpResults(); + Inet4Address clientIp = (Inet4Address) results.ipAddress.getAddress(); + Inet4Address serverIdentifier = results.serverAddress; + ByteBuffer packet = DhcpPacket.buildRequestPacket(DhcpPacket.ENCAP_L2, + 0 /* transactionId */, (short) 0 /* secs */, DhcpPacket.INADDR_ANY /* clientIp */, + false /* broadcast */, macAddress, clientIp /* requestedIpAddress */, + serverIdentifier, DHCP_REQUESTED_PARAMS, DHCP_HOSTNAME); + sendPacket(fd, packet); + } + + private void sendPacket(FileDescriptor fd, ByteBuffer packet) throws Exception { + assertNotNull("Only tests on virtual interfaces can send packets", fd); + Os.write(fd, packet); + } + + public void assertLinkAddressMatches(LinkAddress l1, LinkAddress l2) { + // Check all fields except the deprecation and expiry times. + String msg = String.format("LinkAddresses do not match. expected: %s actual: %s", l1, l2); + assertTrue(msg, l1.isSameAddressAs(l2)); + assertEquals("LinkAddress flags do not match", l1.getFlags(), l2.getFlags()); + assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope()); + } + + private TestNetworkInterface createTestInterface() throws Exception { + TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); + TestNetworkInterface iface = tnm.createTapInterface(); + Log.d(TAG, "Created test interface " + iface.getInterfaceName()); + assertNotNull(NetworkInterface.getByName(iface.getInterfaceName())); + return iface; + } + + private void maybeDeleteTestInterface() throws Exception { + if (mTestIface != null) { + mTestIface.getFileDescriptor().close(); + Log.d(TAG, "Deleted test interface " + mTestIface.getInterfaceName()); + mTestIface = null; + } + } +} From 0a61e95319a250842a669794a5076e4ed89d2622 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 27 Mar 2020 23:42:58 +0900 Subject: [PATCH 0877/1415] Use CompletableFuture instead of a latch. Addresses review comments on aosp/1260100. Bug: 150644681 Test: test-only change Change-Id: Ia73ba8a121a3744a5e36795d2d2bff2f099c1394 --- .../android/net/EthernetTetheringTest.java | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index 843a4f19c3..492ce3db34 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -63,6 +63,7 @@ import java.nio.ByteBuffer; import java.util.Collection; import java.util.List; import java.util.Random; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -150,10 +151,7 @@ public class EthernetTetheringTest { Log.d(TAG, "Including test interfaces"); mEm.setIncludeTestInterfaces(true); - Log.d(TAG, "Requesting tethered interface"); - mTetheredInterfaceRequester.requestInterface(); - - final String iface = mTetheredInterfaceRequester.awaitRequestedInterface(); + final String iface = mTetheredInterfaceRequester.getInterface(); assertEquals("TetheredInterfaceCallback for unexpected interface", mTestIface.getInterfaceName(), iface); @@ -165,14 +163,13 @@ public class EthernetTetheringTest { // This test requires manipulating packets. Skip if there is a physical Ethernet connected. assumeFalse(mEm.isAvailable()); - Log.d(TAG, "Requesting tethered interface"); - mTetheredInterfaceRequester.requestInterface(); + CompletableFuture futureIface = mTetheredInterfaceRequester.requestInterface(); mEm.setIncludeTestInterfaces(true); mTestIface = createTestInterface(); - final String iface = mTetheredInterfaceRequester.awaitRequestedInterface(); + final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); assertEquals("TetheredInterfaceCallback for unexpected interface", mTestIface.getInterfaceName(), iface); @@ -184,8 +181,7 @@ public class EthernetTetheringTest { assumeTrue(mEm.isAvailable()); // Get an interface to use. - mTetheredInterfaceRequester.requestInterface(); - String iface = mTetheredInterfaceRequester.awaitRequestedInterface(); + final String iface = mTetheredInterfaceRequester.getInterface(); // Enable Ethernet tethering and check that it starts. mTetheringEventCallback = enableEthernetTethering(iface); @@ -373,8 +369,8 @@ public class EthernetTetheringTest { private final Handler mHandler; private final EthernetManager mEm; - private volatile TetheredInterfaceRequest mRequest; - private volatile String mIface; + private TetheredInterfaceRequest mRequest; + private final CompletableFuture mFuture = new CompletableFuture<>(); TetheredInterfaceRequester(Handler handler, EthernetManager em) { mHandler = handler; @@ -384,25 +380,28 @@ public class EthernetTetheringTest { @Override public void onAvailable(String iface) { Log.d(TAG, "Ethernet interface available: " + iface); - mIface = iface; - mInterfaceAvailableLatch.countDown(); + mFuture.complete(iface); } + @Override - public void onUnavailable() {} - - public void requestInterface() { - assertNull("BUG: more than one tethered interface request", mRequest); - mRequest = mEm.requestTetheredInterface(mHandler::post, this); + public void onUnavailable() { + mFuture.completeExceptionally(new IllegalStateException("onUnavailable received")); } - public String awaitRequestedInterface() throws InterruptedException { - assertTrue("No tethered interface available after " + TIMEOUT_MS + "ms", - mInterfaceAvailableLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - return mIface; + public CompletableFuture requestInterface() { + assertNull("BUG: more than one tethered interface request", mRequest); + Log.d(TAG, "Requesting tethered interface"); + mRequest = mEm.requestTetheredInterface(mHandler::post, this); + return mFuture; + } + + public String getInterface() throws Exception { + return requestInterface().get(TIMEOUT_MS, TimeUnit.MILLISECONDS); } public void release() { if (mRequest != null) { + mFuture.obtrudeException(new IllegalStateException("Request already released")); mRequest.release(); mRequest = null; } From f0d478295ce0ecb54edbbc77ababb3bf0be30d86 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 28 Mar 2020 03:25:23 -0700 Subject: [PATCH 0878/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: Ie2f4603cc037a2f1ddfebf51d7639aa4e9d122f5 --- Tethering/res/values-af/strings.xml | 7 +++++ Tethering/res/values-am/strings.xml | 7 +++++ Tethering/res/values-ar/strings.xml | 7 +++++ Tethering/res/values-as/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-az/strings.xml | 7 +++++ Tethering/res/values-b+sr+Latn/strings.xml | 7 +++++ Tethering/res/values-be/strings.xml | 7 +++++ Tethering/res/values-bg/strings.xml | 7 +++++ Tethering/res/values-bn/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-bs/strings.xml | 7 +++++ Tethering/res/values-ca/strings.xml | 9 +++++- Tethering/res/values-cs/strings.xml | 7 +++++ Tethering/res/values-da/strings.xml | 7 +++++ Tethering/res/values-de/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-el/strings.xml | 7 +++++ Tethering/res/values-en-rAU/strings.xml | 7 +++++ Tethering/res/values-en-rCA/strings.xml | 7 +++++ Tethering/res/values-en-rGB/strings.xml | 7 +++++ Tethering/res/values-en-rIN/strings.xml | 7 +++++ Tethering/res/values-en-rXC/strings.xml | 7 +++++ Tethering/res/values-es-rUS/strings.xml | 9 +++++- Tethering/res/values-es/strings.xml | 7 +++++ Tethering/res/values-et/strings.xml | 7 +++++ Tethering/res/values-eu/strings.xml | 7 +++++ Tethering/res/values-fa/strings.xml | 7 +++++ Tethering/res/values-fi/strings.xml | 7 +++++ Tethering/res/values-fr-rCA/strings.xml | 7 +++++ Tethering/res/values-fr/strings.xml | 7 +++++ Tethering/res/values-gl/strings.xml | 7 +++++ Tethering/res/values-gu/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-hi/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-hr/strings.xml | 7 +++++ Tethering/res/values-hu/strings.xml | 7 +++++ Tethering/res/values-hy/strings.xml | 7 +++++ Tethering/res/values-in/strings.xml | 7 +++++ Tethering/res/values-is/strings.xml | 7 +++++ Tethering/res/values-it/strings.xml | 7 +++++ Tethering/res/values-iw/strings.xml | 7 +++++ Tethering/res/values-ja/strings.xml | 7 +++++ Tethering/res/values-ka/strings.xml | 7 +++++ Tethering/res/values-kk/strings.xml | 7 +++++ Tethering/res/values-km/strings.xml | 9 +++++- Tethering/res/values-kn/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-ko/strings.xml | 7 +++++ Tethering/res/values-ky/strings.xml | 7 +++++ Tethering/res/values-lo/strings.xml | 7 +++++ Tethering/res/values-lt/strings.xml | 7 +++++ Tethering/res/values-lv/strings.xml | 7 +++++ .../res/values-mcc204-mnc04-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-az/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-b+sr+Latn/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-el/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fi/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-pl/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-vi/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-zu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-az/strings.xml | 25 +++++++++++++++ .../strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-el/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fi/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-pl/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-vi/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-zu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-az/strings.xml | 25 +++++++++++++++ .../strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-el/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fi/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-pl/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-vi/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-zu/strings.xml | 25 +++++++++++++++ Tethering/res/values-mk/strings.xml | 7 +++++ Tethering/res/values-ml/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-mn/strings.xml | 7 +++++ Tethering/res/values-mr/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-ms/strings.xml | 7 +++++ Tethering/res/values-my/strings.xml | 7 +++++ Tethering/res/values-nb/strings.xml | 7 +++++ Tethering/res/values-ne/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-nl/strings.xml | 7 +++++ Tethering/res/values-or/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-pa/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-pl/strings.xml | 7 +++++ Tethering/res/values-pt-rBR/strings.xml | 7 +++++ Tethering/res/values-pt-rPT/strings.xml | 9 +++++- Tethering/res/values-pt/strings.xml | 7 +++++ Tethering/res/values-ro/strings.xml | 7 +++++ Tethering/res/values-ru/strings.xml | 9 +++++- Tethering/res/values-si/strings.xml | 7 +++++ Tethering/res/values-sk/strings.xml | 7 +++++ Tethering/res/values-sl/strings.xml | 7 +++++ Tethering/res/values-sq/strings.xml | 7 +++++ Tethering/res/values-sr/strings.xml | 7 +++++ Tethering/res/values-sv/strings.xml | 7 +++++ Tethering/res/values-sw/strings.xml | 7 +++++ Tethering/res/values-ta/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-te/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-th/strings.xml | 7 +++++ Tethering/res/values-tl/strings.xml | 7 +++++ Tethering/res/values-tr/strings.xml | 7 +++++ Tethering/res/values-uk/strings.xml | 7 +++++ Tethering/res/values-ur/strings.xml | 31 +++++++++++++++++++ Tethering/res/values-uz/strings.xml | 7 +++++ Tethering/res/values-vi/strings.xml | 7 +++++ Tethering/res/values-zh-rCN/strings.xml | 7 +++++ Tethering/res/values-zh-rHK/strings.xml | 7 +++++ Tethering/res/values-zh-rTW/strings.xml | 7 +++++ Tethering/res/values-zu/strings.xml | 7 +++++ 340 files changed, 7491 insertions(+), 5 deletions(-) create mode 100644 Tethering/res/values-as/strings.xml create mode 100644 Tethering/res/values-bn/strings.xml create mode 100644 Tethering/res/values-de/strings.xml create mode 100644 Tethering/res/values-gu/strings.xml create mode 100644 Tethering/res/values-hi/strings.xml create mode 100644 Tethering/res/values-kn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-af/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-am/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ar/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-as/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-az/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-be/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bg/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bs/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ca/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-cs/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-da/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-de/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-el/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-es/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-et/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-eu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fa/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-gl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-gu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hy/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-in/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-is/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-it/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-iw/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ja/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ka/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-kk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-km/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-kn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ko/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ky/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lo/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lt/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lv/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ml/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ms/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-my/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-nb/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ne/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-nl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-or/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pa/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ro/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ru/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-si/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sq/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sv/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sw/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ta/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-te/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-th/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-tl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-tr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-uk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ur/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-uz/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-vi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-af/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-am/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ar/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-as/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-az/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-be/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bg/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ca/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-cs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-da/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-de/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-el/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-et/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-eu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hy/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-in/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-is/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-it/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-iw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ja/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ka/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-km/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ko/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ky/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lo/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ml/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ms/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-my/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nb/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ne/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-or/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ro/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ru/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-si/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sq/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ta/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-te/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-th/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ur/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uz/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-vi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-af/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-am/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ar/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-as/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-az/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-be/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bg/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ca/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-cs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-da/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-de/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-el/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-et/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-eu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hy/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-in/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-is/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-it/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-iw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ja/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ka/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-km/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ko/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ky/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lo/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ml/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ms/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-my/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nb/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ne/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-or/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ro/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ru/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-si/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sq/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ta/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-te/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-th/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ur/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uz/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-vi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zu/strings.xml create mode 100644 Tethering/res/values-ml/strings.xml create mode 100644 Tethering/res/values-mr/strings.xml create mode 100644 Tethering/res/values-ne/strings.xml create mode 100644 Tethering/res/values-or/strings.xml create mode 100644 Tethering/res/values-pa/strings.xml create mode 100644 Tethering/res/values-ta/strings.xml create mode 100644 Tethering/res/values-te/strings.xml create mode 100644 Tethering/res/values-ur/strings.xml diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index f06d1a208f..f4c43b16a2 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Verbinding of warmkol is aktief" "Tik om op te stel." + "Verbinding is gedeaktiveer" "Kontak jou administrateur vir besonderhede" "Warmkol- en verbindingstatus" + + + + + + diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index aa0e693449..3a8de1200e 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" "ለማዋቀር መታ ያድርጉ።" + "እንደ ሞደም መሰካት ተሰናክሏል" "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" + + + + + + diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index ce7372085b..355f59f096 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "النطاق نشط أو نقطة الاتصال نشطة" "انقر للإعداد." + "التوصيل متوقف." "تواصَل مع المشرف للحصول على التفاصيل." "حالة نقطة الاتصال والتوصيل" + + + + + + diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml new file mode 100644 index 0000000000..f44cec0be8 --- /dev/null +++ b/Tethering/res/values-as/strings.xml @@ -0,0 +1,31 @@ + + + + + "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" + "ছেট আপ কৰিবলৈ টিপক।" + + "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" + "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" + + + + + + + diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index 82661f48e8..afd29dffbd 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Birləşmə və ya hotspot aktivdir" "Ayarlamaq üçün toxunun." + "Birləşmə deaktivdir" "Detallar üçün adminlə əlaqə saxlayın" "Hotspot & birləşmə statusu" + + + + + + diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 0f1fb9e159..3ec6b75b34 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Privezivanje ili hotspot je aktivan" "Dodirnite da biste podesili." + "Privezivanje je onemogućeno" "Potražite detalje od administratora" "Status hotspota i privezivanja" + + + + + + diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 31c6957a3c..577c1d7bdd 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Мадэм або хот-спот актыўныя" "Дакраніцеся, каб наладзіць." + "Рэжым мадэма выключаны" "Звярніцеся да адміністратара па падрабязную інфармацыю" "Стан \"Хот-спот і мадэм\"" + + + + + + diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index 22d03202f5..9956a6191b 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Има активна споделена връзка или точка за достъп" "Докоснете, за да настроите." + "Функцията за тетъринг е деактивирана" "Свържете се с администратора си за подробности" "Състояние на функцията за точка за достъп и тетъринг" + + + + + + diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml new file mode 100644 index 0000000000..44d8dc6191 --- /dev/null +++ b/Tethering/res/values-bn/strings.xml @@ -0,0 +1,31 @@ + + + + + "টিথারিং বা হটস্পট চালু আছে" + "সেট-আপ করতে ট্যাপ করুন।" + + "টিথারিং বন্ধ করা আছে" + "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" + "হটস্পট ও টিথারিং স্ট্যাটাস" + + + + + + + diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index f22180d4d7..bf0395b7ea 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktivno je povezivanje putem mobitela ili pristupna tačka" "Dodirnite da postavite." + "Povezivanje putem mobitela je onemogućeno" "Kontaktirajte svog administratora za detalje" "Status pristupne tačke i povezivanja putem mobitela" + + + + + + diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index a91a9b4fbc..cbc161a4e9 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -16,9 +16,16 @@ - "Compartició de xarxa o punt d\'accés Wi‑Fi activat" + "Compartició de xarxa o punt d\'accés Wi‑Fi actius" "Toca per configurar." + "La compartició de xarxa està desactivada" "Contacta amb el teu administrador per obtenir més informació" "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" + + + + + + diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 4a8ce53b4c..5c21603987 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering nebo hotspot je aktivní" "Klepnutím zahájíte nastavení." + "Tethering je zakázán" "O podrobnosti požádejte administrátora" "Stav hotspotu a tetheringu" + + + + + + diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 1fe048bf58..741c7e2d79 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Netdeling eller hotspot er aktivt" "Tryk for at konfigurere." + "Netdeling er deaktiveret" "Kontakt din administrator for at få oplysninger" "Status for hotspot og netdeling" + + + + + + diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml new file mode 100644 index 0000000000..980a062674 --- /dev/null +++ b/Tethering/res/values-de/strings.xml @@ -0,0 +1,31 @@ + + + + + "Tethering oder Hotspot aktiv" + "Zum Einrichten tippen." + + "Tethering ist deaktiviert" + "Bitte wende dich für weitere Informationen an den Administrator" + "Hotspot- und Tethering-Status" + + + + + + + diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 045d707e82..3d8ad1efef 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" "Πατήστε για ρύθμιση." + "Η σύνδεση είναι απενεργοποιημένη" "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" + + + + + + diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 14bf2aa88f..18db440b3e 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." + "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 14bf2aa88f..18db440b3e 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." + "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 14bf2aa88f..18db440b3e 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." + "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 14bf2aa88f..18db440b3e 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." + "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 43f504c244..23866e0db1 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" + + + + + + diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index 8706a93e67..0bf6c4ed09 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -16,9 +16,16 @@ - "Anclaje a red o zona activa conectados" + "Conexión a red o hotspot conectados" "Presiona para configurar esta opción." + "Se inhabilitó la conexión mediante dispositivo portátil" "Para obtener más información, comunícate con el administrador" "Estado del hotspot y la conexión mediante dispositivo portátil" + + + + + + diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 67f8f2eb3d..195868b5d0 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión compartida o punto de acceso activos" "Toca para configurar." + "La conexión compartida está inhabilitada" "Solicita más información a tu administrador" "Estado del punto de acceso y de la conexión compartida" + + + + + + diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index 1ebf7b124d..c4700a9638 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Jagamine või kuumkoht on aktiivne" "Puudutage seadistamiseks." + "Jagamine on keelatud" "Lisateabe saamiseks võtke ühendust oma administraatoriga" "Kuumkoha ja jagamise olek" + + + + + + diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index 8e39d4789e..bcb92d96be 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Konexioa partekatzea edo sare publikoa aktibo" "Sakatu konfiguratzeko." + "Desgaituta dago konexioa partekatzeko aukera" "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" "Sare publikoaren eta konexioa partekatzeko eginbidearen egoera" + + + + + + diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index ee722ffbe7..51c3d731c0 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" "برای راه‌اندازی ضربه بزنید." + "اشتراک‌گذاری اینترنت غیرفعال است" "برای جزئیات، با سرپرستتان تماس بگیرید" "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" + + + + + + diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index fae2e8e9a2..7a54e16157 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Yhteyden jakaminen tai hotspot käytössä" "Ota käyttöön napauttamalla." + "Yhteyden jakaminen on poistettu käytöstä" "Pyydä lisätietoja järjestelmänvalvojalta" "Hotspotin ja yhteyden jakamisen tila" + + + + + + diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index afe5df8c5b..556748f5f7 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Partage de connexion ou point d\'accès sans fil activé" "Touchez pour configurer." + "Le partage de connexion est désactivé" "Communiquez avec votre administrateur pour obtenir plus de détails" "Point d\'accès et partage de connexion" + + + + + + diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index 4d54be124b..9fe55a2394 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Partage de connexion ou point d\'accès activé" "Appuyez pour effectuer la configuration." + "Le partage de connexion est désactivé" "Pour en savoir plus, contactez votre administrateur" "État du point d\'accès et du partage de connexion" + + + + + + diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 8f803e9cda..474371a128 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión compartida ou zona wifi activada" "Toca para configurar." + "A conexión compartida está desactivada" "Contacta co administrador para obter información" "Estado da zona wifi e da conexión compartida" + + + + + + diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml new file mode 100644 index 0000000000..cdb830a79a --- /dev/null +++ b/Tethering/res/values-gu/strings.xml @@ -0,0 +1,31 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" + "સેટઅપ કરવા માટે ટૅપ કરો." + + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" + "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" + + + + + + + diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml new file mode 100644 index 0000000000..f9e157c9f5 --- /dev/null +++ b/Tethering/res/values-hi/strings.xml @@ -0,0 +1,31 @@ + + + + + "टेदरिंग या हॉटस्पॉट चालू है" + "सेट अप करने के लिए टैप करें." + + "टेदरिंग बंद है" + "जानकारी के लिए अपने एडमिन से संपर्क करें" + "हॉटस्पॉट और टेदरिंग की स्थिति" + + + + + + + diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index 9727bc9dc4..9a99c6457c 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Modemsko povezivanje ili žarišna točka aktivni" "Dodirnite da biste postavili." + "Modemsko je povezivanje onemogućeno" "Obratite se administratoru da biste saznali pojedinosti" "Status žarišne točke i modemskog povezivanja" + + + + + + diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index ce4ccbec6c..f27c1c3e63 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Megosztás vagy aktív hotspot" "Koppintson a beállításhoz." + "Az internetmegosztás le van tiltva" "A részletekért forduljon rendszergazdájához" "Hotspot és internetmegosztás állapota" + + + + + + diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index b4a68483af..b8b95ea5f9 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Մոդեմի ռեժիմը միացված է" "Հպեք՝ կարգավորելու համար։" + "Մոդեմի ռեժիմն անջատված է" "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" + + + + + + diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 6f33685eb9..24ead4eb3c 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering atau hotspot aktif" "Ketuk untuk menyiapkan." + "Tethering dinonaktifkan" "Hubungi admin untuk mengetahui detailnya" "Status hotspot & tethering" + + + + + + diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index c149818a56..839b0b96fc 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kveikt á tjóðrun eða aðgangsstað" "Ýttu til að setja upp." + "Slökkt er á tjóðrun" "Hafðu samband við kerfisstjórann til að fá upplýsingar" "Staða heits reits og tjóðrunar" + + + + + + diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index 09d0c92ce6..31e2b73cf6 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Hotspot o tethering attivo" "Tocca per impostare." + "Tethering disattivato" "Contatta il tuo amministratore per avere informazioni dettagliate" "Stato hotspot e tethering" + + + + + + diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index 101fb514b4..c97064b8d2 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" "יש להקיש כדי להגדיר." + "שיתוף האינטרנט בין מכשירים מושבת" "לפרטים, יש לפנות למנהל המערכת" "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" + + + + + + diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index 214780dfa4..c65f6e2f71 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "テザリングまたはアクセス ポイントが有効です" "タップしてセットアップします。" + "テザリングは無効に設定されています" "詳しくは、管理者にお問い合わせください" "アクセス ポイントとテザリングのステータス" + + + + + + diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 68dcecc174..0dca3763f6 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ტეტერინგი ან უსადენო ქსელი აქტიურია" "შეეხეთ დასაყენებლად." + "ტეტერინგი გათიშულია" "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" "უსადენო ქსელის და ტეტერინგის სტატუსი" + + + + + + diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 39de166545..9b4423536b 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Тетеринг немесе хотспот қосулы" "Реттеу үшін түртіңіз." + "Тетеринг өшірілді." "Мәліметтерді әкімшіден алыңыз." "Хотспот және тетеринг күйі" + + + + + + diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index be0f0aa69e..7a6ab98d88 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" "ចុច​ដើម្បី​រៀបចំ។" + "ការភ្ជាប់​ត្រូវបានបិទ" "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" - "ស្ថានភាពការភ្ជាប់ និងហតស្ប៉ត" + "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" + + + + + + diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml new file mode 100644 index 0000000000..7c744b83e4 --- /dev/null +++ b/Tethering/res/values-kn/strings.xml @@ -0,0 +1,31 @@ + + + + + "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" + "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." + + "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" + "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" + + + + + + + diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index 7ce45a24ef..ecbddf5fdc 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "테더링 또는 핫스팟 사용" "설정하려면 탭하세요." + "테더링이 사용 중지됨" "자세한 정보는 관리자에게 문의하세요." "핫스팟 및 테더링 상태" + + + + + + diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 9a5088e44e..f763bf3ff0 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Жалгаштыруу же хотспот жандырылган" "Жөндөө үчүн таптап коюңуз." + "Жалгаштыруу функциясы өчүрүлгөн" "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" "Хотспот жана байланыш түйүнүүн статусу" + + + + + + diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index 7384237356..d85b1bd096 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" "ແຕະເພື່ອຕັ້ງຄ່າ." + "ການປ່ອຍສັນຍານຖືກປິດໄວ້" "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" + + + + + + diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index dc4fdf592d..9a875932ff 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" "Palieskite, kad nustatytumėte." + "Įrenginio kaip modemo naudojimas išjungtas" "Jei reikia išsamios informacijos, susisiekite su administratoriumi" "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" + + + + + + diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index db0401aa42..bb32ab41b1 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Piesaiste vai tīklājs ir aktīvs." "Pieskarieties, lai to iestatītu." + "Piesaiste ir atspējota" "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." "Tīklāja un piesaistes statuss" + + + + + + diff --git a/Tethering/res/values-mcc204-mnc04-af/strings.xml b/Tethering/res/values-mcc204-mnc04-af/strings.xml new file mode 100644 index 0000000000..052ca091ac --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc204-mnc04-am/strings.xml b/Tethering/res/values-mcc204-mnc04-am/strings.xml new file mode 100644 index 0000000000..0518c5a14f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc204-mnc04-ar/strings.xml b/Tethering/res/values-mcc204-mnc04-ar/strings.xml new file mode 100644 index 0000000000..40eb9a741c --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc204-mnc04-as/strings.xml b/Tethering/res/values-mcc204-mnc04-as/strings.xml new file mode 100644 index 0000000000..4c57f21eae --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc204-mnc04-az/strings.xml b/Tethering/res/values-mcc204-mnc04-az/strings.xml new file mode 100644 index 0000000000..2610ab1bec --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml b/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..7b032badf0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-be/strings.xml b/Tethering/res/values-mcc204-mnc04-be/strings.xml new file mode 100644 index 0000000000..2362a1e6a5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc204-mnc04-bg/strings.xml b/Tethering/res/values-mcc204-mnc04-bg/strings.xml new file mode 100644 index 0000000000..6ef1b0bbaf --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc204-mnc04-bn/strings.xml b/Tethering/res/values-mcc204-mnc04-bn/strings.xml new file mode 100644 index 0000000000..7f9efba7f0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc204-mnc04-bs/strings.xml b/Tethering/res/values-mcc204-mnc04-bs/strings.xml new file mode 100644 index 0000000000..7539736415 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-ca/strings.xml b/Tethering/res/values-mcc204-mnc04-ca/strings.xml new file mode 100644 index 0000000000..e3ad666c0b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc204-mnc04-cs/strings.xml b/Tethering/res/values-mcc204-mnc04-cs/strings.xml new file mode 100644 index 0000000000..f0992814c1 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc204-mnc04-da/strings.xml b/Tethering/res/values-mcc204-mnc04-da/strings.xml new file mode 100644 index 0000000000..1fb2374487 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc204-mnc04-de/strings.xml b/Tethering/res/values-mcc204-mnc04-de/strings.xml new file mode 100644 index 0000000000..56d1d1df58 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc204-mnc04-el/strings.xml b/Tethering/res/values-mcc204-mnc04-el/strings.xml new file mode 100644 index 0000000000..674f1f6798 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml new file mode 100644 index 0000000000..20c9b94cd5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml new file mode 100644 index 0000000000..196303fa83 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-es/strings.xml b/Tethering/res/values-mcc204-mnc04-es/strings.xml new file mode 100644 index 0000000000..cac5b23bd9 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-et/strings.xml b/Tethering/res/values-mcc204-mnc04-et/strings.xml new file mode 100644 index 0000000000..ff8dde5422 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc204-mnc04-eu/strings.xml b/Tethering/res/values-mcc204-mnc04-eu/strings.xml new file mode 100644 index 0000000000..1758a4fada --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc204-mnc04-fa/strings.xml b/Tethering/res/values-mcc204-mnc04-fa/strings.xml new file mode 100644 index 0000000000..79e3ef11d6 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc204-mnc04-fi/strings.xml b/Tethering/res/values-mcc204-mnc04-fi/strings.xml new file mode 100644 index 0000000000..64921bca9f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml b/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml new file mode 100644 index 0000000000..eda7b59761 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc204-mnc04-fr/strings.xml b/Tethering/res/values-mcc204-mnc04-fr/strings.xml new file mode 100644 index 0000000000..eda7b59761 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc204-mnc04-gl/strings.xml b/Tethering/res/values-mcc204-mnc04-gl/strings.xml new file mode 100644 index 0000000000..c163c61fbd --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-gu/strings.xml b/Tethering/res/values-mcc204-mnc04-gu/strings.xml new file mode 100644 index 0000000000..0f4d26afdd --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc204-mnc04-hi/strings.xml b/Tethering/res/values-mcc204-mnc04-hi/strings.xml new file mode 100644 index 0000000000..a2442009b5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc204-mnc04-hr/strings.xml b/Tethering/res/values-mcc204-mnc04-hr/strings.xml new file mode 100644 index 0000000000..41618afb2e --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-hu/strings.xml b/Tethering/res/values-mcc204-mnc04-hu/strings.xml new file mode 100644 index 0000000000..39b7a6975b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc204-mnc04-hy/strings.xml b/Tethering/res/values-mcc204-mnc04-hy/strings.xml new file mode 100644 index 0000000000..c14ae10ad1 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc204-mnc04-in/strings.xml b/Tethering/res/values-mcc204-mnc04-in/strings.xml new file mode 100644 index 0000000000..4998474a36 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc204-mnc04-is/strings.xml b/Tethering/res/values-mcc204-mnc04-is/strings.xml new file mode 100644 index 0000000000..82a7d01234 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc204-mnc04-it/strings.xml b/Tethering/res/values-mcc204-mnc04-it/strings.xml new file mode 100644 index 0000000000..a10d511c17 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc204-mnc04-iw/strings.xml b/Tethering/res/values-mcc204-mnc04-iw/strings.xml new file mode 100644 index 0000000000..80807bc232 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc204-mnc04-ja/strings.xml b/Tethering/res/values-mcc204-mnc04-ja/strings.xml new file mode 100644 index 0000000000..0e21a7f322 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc204-mnc04-ka/strings.xml b/Tethering/res/values-mcc204-mnc04-ka/strings.xml new file mode 100644 index 0000000000..6d3b548744 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc204-mnc04-kk/strings.xml b/Tethering/res/values-mcc204-mnc04-kk/strings.xml new file mode 100644 index 0000000000..985fc3ff99 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc204-mnc04-km/strings.xml b/Tethering/res/values-mcc204-mnc04-km/strings.xml new file mode 100644 index 0000000000..03b5cb6e4b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc204-mnc04-kn/strings.xml b/Tethering/res/values-mcc204-mnc04-kn/strings.xml new file mode 100644 index 0000000000..0427a77659 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc204-mnc04-ko/strings.xml b/Tethering/res/values-mcc204-mnc04-ko/strings.xml new file mode 100644 index 0000000000..9218e9a09b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc204-mnc04-ky/strings.xml b/Tethering/res/values-mcc204-mnc04-ky/strings.xml new file mode 100644 index 0000000000..bc3d555597 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc204-mnc04-lo/strings.xml b/Tethering/res/values-mcc204-mnc04-lo/strings.xml new file mode 100644 index 0000000000..06dcbcbccc --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc204-mnc04-lt/strings.xml b/Tethering/res/values-mcc204-mnc04-lt/strings.xml new file mode 100644 index 0000000000..db5178bf2d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc204-mnc04-lv/strings.xml b/Tethering/res/values-mcc204-mnc04-lv/strings.xml new file mode 100644 index 0000000000..c712173ca2 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc204-mnc04-mk/strings.xml b/Tethering/res/values-mcc204-mnc04-mk/strings.xml new file mode 100644 index 0000000000..aa4490912b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc204-mnc04-ml/strings.xml b/Tethering/res/values-mcc204-mnc04-ml/strings.xml new file mode 100644 index 0000000000..0ef956a5a4 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc204-mnc04-mn/strings.xml b/Tethering/res/values-mcc204-mnc04-mn/strings.xml new file mode 100644 index 0000000000..417213f543 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc204-mnc04-mr/strings.xml b/Tethering/res/values-mcc204-mnc04-mr/strings.xml new file mode 100644 index 0000000000..2ed153fb17 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc204-mnc04-ms/strings.xml b/Tethering/res/values-mcc204-mnc04-ms/strings.xml new file mode 100644 index 0000000000..50817fd4a2 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc204-mnc04-my/strings.xml b/Tethering/res/values-mcc204-mnc04-my/strings.xml new file mode 100644 index 0000000000..c0d70e3d5f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc204-mnc04-nb/strings.xml b/Tethering/res/values-mcc204-mnc04-nb/strings.xml new file mode 100644 index 0000000000..1e7f1c6d0a --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc204-mnc04-ne/strings.xml b/Tethering/res/values-mcc204-mnc04-ne/strings.xml new file mode 100644 index 0000000000..fadd357ebf --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc204-mnc04-nl/strings.xml b/Tethering/res/values-mcc204-mnc04-nl/strings.xml new file mode 100644 index 0000000000..bf14a0fced --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc204-mnc04-or/strings.xml b/Tethering/res/values-mcc204-mnc04-or/strings.xml new file mode 100644 index 0000000000..1cdfce04d8 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc204-mnc04-pa/strings.xml b/Tethering/res/values-mcc204-mnc04-pa/strings.xml new file mode 100644 index 0000000000..93402c35d0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc204-mnc04-pl/strings.xml b/Tethering/res/values-mcc204-mnc04-pl/strings.xml new file mode 100644 index 0000000000..8becd0715f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml b/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml new file mode 100644 index 0000000000..8e01736f64 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml b/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml new file mode 100644 index 0000000000..2356379e2f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-pt/strings.xml b/Tethering/res/values-mcc204-mnc04-pt/strings.xml new file mode 100644 index 0000000000..8e01736f64 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-ro/strings.xml b/Tethering/res/values-mcc204-mnc04-ro/strings.xml new file mode 100644 index 0000000000..2e62bd611c --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc204-mnc04-ru/strings.xml b/Tethering/res/values-mcc204-mnc04-ru/strings.xml new file mode 100644 index 0000000000..69f8c59613 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc204-mnc04-si/strings.xml b/Tethering/res/values-mcc204-mnc04-si/strings.xml new file mode 100644 index 0000000000..632748a3e8 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc204-mnc04-sk/strings.xml b/Tethering/res/values-mcc204-mnc04-sk/strings.xml new file mode 100644 index 0000000000..247fc1b0e7 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc204-mnc04-sl/strings.xml b/Tethering/res/values-mcc204-mnc04-sl/strings.xml new file mode 100644 index 0000000000..ed22372197 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc204-mnc04-sq/strings.xml b/Tethering/res/values-mcc204-mnc04-sq/strings.xml new file mode 100644 index 0000000000..4bfab6e474 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc204-mnc04-sr/strings.xml b/Tethering/res/values-mcc204-mnc04-sr/strings.xml new file mode 100644 index 0000000000..478d53a255 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc204-mnc04-sv/strings.xml b/Tethering/res/values-mcc204-mnc04-sv/strings.xml new file mode 100644 index 0000000000..a793ed6483 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc204-mnc04-sw/strings.xml b/Tethering/res/values-mcc204-mnc04-sw/strings.xml new file mode 100644 index 0000000000..3fe09fc22a --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc204-mnc04-ta/strings.xml b/Tethering/res/values-mcc204-mnc04-ta/strings.xml new file mode 100644 index 0000000000..63c28c6702 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc204-mnc04-te/strings.xml b/Tethering/res/values-mcc204-mnc04-te/strings.xml new file mode 100644 index 0000000000..2cf579ca0e --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc204-mnc04-th/strings.xml b/Tethering/res/values-mcc204-mnc04-th/strings.xml new file mode 100644 index 0000000000..3837002b29 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc204-mnc04-tl/strings.xml b/Tethering/res/values-mcc204-mnc04-tl/strings.xml new file mode 100644 index 0000000000..208f893447 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc204-mnc04-tr/strings.xml b/Tethering/res/values-mcc204-mnc04-tr/strings.xml new file mode 100644 index 0000000000..3482fafa2d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc204-mnc04-uk/strings.xml b/Tethering/res/values-mcc204-mnc04-uk/strings.xml new file mode 100644 index 0000000000..dea311443f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc204-mnc04-ur/strings.xml b/Tethering/res/values-mcc204-mnc04-ur/strings.xml new file mode 100644 index 0000000000..09bc0c9eab --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc204-mnc04-uz/strings.xml b/Tethering/res/values-mcc204-mnc04-uz/strings.xml new file mode 100644 index 0000000000..5231c5fff5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc204-mnc04-vi/strings.xml b/Tethering/res/values-mcc204-mnc04-vi/strings.xml new file mode 100644 index 0000000000..bf4ee1011b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml new file mode 100644 index 0000000000..38c2563638 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml new file mode 100644 index 0000000000..3bb52e491f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml new file mode 100644 index 0000000000..298c3eac70 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc204-mnc04-zu/strings.xml b/Tethering/res/values-mcc204-mnc04-zu/strings.xml new file mode 100644 index 0000000000..3dc0078834 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml new file mode 100644 index 0000000000..8f16cd19ac --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml new file mode 100644 index 0000000000..d064fd81d5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml new file mode 100644 index 0000000000..e5e7e5e03d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml new file mode 100644 index 0000000000..5bcadfd7fc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml new file mode 100644 index 0000000000..41c018eec1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..8acc587975 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml new file mode 100644 index 0000000000..b03379a899 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml new file mode 100644 index 0000000000..122bdb69c6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml new file mode 100644 index 0000000000..d5ee1a91ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml new file mode 100644 index 0000000000..ae86e0aa8e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml new file mode 100644 index 0000000000..9c46426601 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml new file mode 100644 index 0000000000..66e4dfb3da --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml new file mode 100644 index 0000000000..04a48a77c4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml new file mode 100644 index 0000000000..a9136784e9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml new file mode 100644 index 0000000000..19be3c7077 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml new file mode 100644 index 0000000000..6384e89ce0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml new file mode 100644 index 0000000000..d4b6937881 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml new file mode 100644 index 0000000000..158fd86296 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml new file mode 100644 index 0000000000..271f82ad6a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml new file mode 100644 index 0000000000..7a2b99e028 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml new file mode 100644 index 0000000000..b370e0fd81 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml new file mode 100644 index 0000000000..da86391ee9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml new file mode 100644 index 0000000000..6ffd8116e8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml new file mode 100644 index 0000000000..6ffd8116e8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml new file mode 100644 index 0000000000..9e7f00cbe0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml new file mode 100644 index 0000000000..e85c00c648 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml new file mode 100644 index 0000000000..b6faa3a0f7 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml new file mode 100644 index 0000000000..86b58ded22 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml new file mode 100644 index 0000000000..27ddabf29d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml new file mode 100644 index 0000000000..abdb207626 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml new file mode 100644 index 0000000000..513d2fb040 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml new file mode 100644 index 0000000000..f4e5dd4ad3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml new file mode 100644 index 0000000000..b82363270b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml new file mode 100644 index 0000000000..0922ee9e4d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml new file mode 100644 index 0000000000..63ddc476e6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml new file mode 100644 index 0000000000..4f20c76a12 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml new file mode 100644 index 0000000000..11e293416b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml new file mode 100644 index 0000000000..b8d94d40a3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml new file mode 100644 index 0000000000..3e8aaebbe9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml new file mode 100644 index 0000000000..59de04c55d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml new file mode 100644 index 0000000000..7ecb6970e7 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml new file mode 100644 index 0000000000..5d1766707c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml new file mode 100644 index 0000000000..aa15bfe1f5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml new file mode 100644 index 0000000000..1e0d2f1c6f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml new file mode 100644 index 0000000000..5fe2a49af6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml new file mode 100644 index 0000000000..930ffa184e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml new file mode 100644 index 0000000000..462e73f7a4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml new file mode 100644 index 0000000000..b1d9b8505b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml new file mode 100644 index 0000000000..936629ca14 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml new file mode 100644 index 0000000000..052df883eb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml new file mode 100644 index 0000000000..09012cbfec --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml new file mode 100644 index 0000000000..e1770b3f77 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml new file mode 100644 index 0000000000..912290cb67 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml new file mode 100644 index 0000000000..6a842428e0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml new file mode 100644 index 0000000000..bb1479d3fb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml new file mode 100644 index 0000000000..51d5c3fd7e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml new file mode 100644 index 0000000000..6e605797d0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml new file mode 100644 index 0000000000..79957977dc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml new file mode 100644 index 0000000000..6e605797d0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml new file mode 100644 index 0000000000..7be2f72195 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml new file mode 100644 index 0000000000..6ab396d50d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml new file mode 100644 index 0000000000..357dd904ac --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml new file mode 100644 index 0000000000..276e5797ee --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml new file mode 100644 index 0000000000..884bddd292 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml new file mode 100644 index 0000000000..a2caddf667 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml new file mode 100644 index 0000000000..7745923331 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml new file mode 100644 index 0000000000..906862aa17 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml new file mode 100644 index 0000000000..0eb922fff6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml new file mode 100644 index 0000000000..1d66c6d689 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml new file mode 100644 index 0000000000..2ee0fa8dda --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml new file mode 100644 index 0000000000..44114e5891 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml new file mode 100644 index 0000000000..440999014c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml new file mode 100644 index 0000000000..d21ad95181 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml new file mode 100644 index 0000000000..e7b8c68eb1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml new file mode 100644 index 0000000000..08edfcffeb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml new file mode 100644 index 0000000000..9def0a1b06 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml new file mode 100644 index 0000000000..e4f818bf42 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml new file mode 100644 index 0000000000..cee4682e7d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml new file mode 100644 index 0000000000..05321db9f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml new file mode 100644 index 0000000000..57b9e0de3b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml new file mode 100644 index 0000000000..7e899705af --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml new file mode 100644 index 0000000000..6fc432256a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml new file mode 100644 index 0000000000..749cb54022 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml new file mode 100644 index 0000000000..9460023663 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml new file mode 100644 index 0000000000..e18e4ec67d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml new file mode 100644 index 0000000000..77740cb6c6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..7170c06662 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml new file mode 100644 index 0000000000..7388d218fd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml new file mode 100644 index 0000000000..aa7a40bfa1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml new file mode 100644 index 0000000000..00bac782ed --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml new file mode 100644 index 0000000000..907821260b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml new file mode 100644 index 0000000000..43c9e137bb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml new file mode 100644 index 0000000000..c9210f7f40 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml new file mode 100644 index 0000000000..3615ff49ff --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml new file mode 100644 index 0000000000..ee8809d80b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml new file mode 100644 index 0000000000..3a79be8735 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml new file mode 100644 index 0000000000..2daad6ad1c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml new file mode 100644 index 0000000000..68d5fc26de --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml new file mode 100644 index 0000000000..930e088642 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml new file mode 100644 index 0000000000..e59e12e71d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml new file mode 100644 index 0000000000..4358266323 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml new file mode 100644 index 0000000000..a2324d84f0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml new file mode 100644 index 0000000000..ec6ac929fb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml new file mode 100644 index 0000000000..eeaf8f3ad4 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml new file mode 100644 index 0000000000..eeaf8f3ad4 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml new file mode 100644 index 0000000000..56b3a9b79d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml new file mode 100644 index 0000000000..c2af9a6688 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml new file mode 100644 index 0000000000..8bb5fb29ae --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml new file mode 100644 index 0000000000..551b1b36fe --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml new file mode 100644 index 0000000000..4113195c19 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml new file mode 100644 index 0000000000..393eac056c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml new file mode 100644 index 0000000000..e2538328cf --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml new file mode 100644 index 0000000000..d28383f51b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml new file mode 100644 index 0000000000..388aa7a2c5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml new file mode 100644 index 0000000000..bbc379501c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml new file mode 100644 index 0000000000..d7cb66b1dd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml new file mode 100644 index 0000000000..9651a563bd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml new file mode 100644 index 0000000000..f2db66b11e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml new file mode 100644 index 0000000000..16699c5a0a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml new file mode 100644 index 0000000000..3c75b1205b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml new file mode 100644 index 0000000000..3892bc36a9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml new file mode 100644 index 0000000000..85e92e0a3c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml new file mode 100644 index 0000000000..881e05c5e0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml new file mode 100644 index 0000000000..83aabd176f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml new file mode 100644 index 0000000000..83feb11f8a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml new file mode 100644 index 0000000000..040e2a5d8e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml new file mode 100644 index 0000000000..c9b12cd706 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml new file mode 100644 index 0000000000..e5a845051d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml new file mode 100644 index 0000000000..c7f1cc6c66 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml new file mode 100644 index 0000000000..35d36f69f1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml new file mode 100644 index 0000000000..bc374725ae --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml new file mode 100644 index 0000000000..413e165c0f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml new file mode 100644 index 0000000000..9b2256abfc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml new file mode 100644 index 0000000000..7f7f39187f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml new file mode 100644 index 0000000000..b478d1393b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml new file mode 100644 index 0000000000..e0940a518d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml new file mode 100644 index 0000000000..c578b278d9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml new file mode 100644 index 0000000000..502b5ddb7d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml new file mode 100644 index 0000000000..a477516145 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml new file mode 100644 index 0000000000..502b5ddb7d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml new file mode 100644 index 0000000000..d6808b04e6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml new file mode 100644 index 0000000000..22dcfcf42d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml new file mode 100644 index 0000000000..5008b7326c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml new file mode 100644 index 0000000000..010677d1d6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml new file mode 100644 index 0000000000..3662ca9e2a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml new file mode 100644 index 0000000000..5453d54fd9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml new file mode 100644 index 0000000000..f52cbf387e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml new file mode 100644 index 0000000000..8474342f26 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml new file mode 100644 index 0000000000..5a812e3f0c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml new file mode 100644 index 0000000000..315403135d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml new file mode 100644 index 0000000000..414def5963 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml new file mode 100644 index 0000000000..a26ac0403b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml new file mode 100644 index 0000000000..6e98146cd5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml new file mode 100644 index 0000000000..423bd76689 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml new file mode 100644 index 0000000000..193b3c348b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml new file mode 100644 index 0000000000..3564ead361 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml new file mode 100644 index 0000000000..769cc2c385 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml new file mode 100644 index 0000000000..998ebe4d7b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml new file mode 100644 index 0000000000..75786086b6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml new file mode 100644 index 0000000000..7f7453c306 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml new file mode 100644 index 0000000000..4b4afc017e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml new file mode 100644 index 0000000000..48ac295ebc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index ad255b6201..04f0fa8c71 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Активно е врзување или точка на пристап" "Допрете за поставување." + "Врзувањето е оневозможено" "Контактирајте со администраторот за детали" "Статус на точката на пристап и врзувањето" + + + + + + diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml new file mode 100644 index 0000000000..2d14f8e0f5 --- /dev/null +++ b/Tethering/res/values-ml/strings.xml @@ -0,0 +1,31 @@ + + + + + "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" + "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." + + "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" + "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" + + + + + + + diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index ed5b69bb2f..4f3334c8e3 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" "Тохируулахын тулд товшино уу." + "Модем болгохыг идэвхгүй болгосон" "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" "Сүлжээний цэг болон модем болгох төлөв" + + + + + + diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml new file mode 100644 index 0000000000..ba9f324982 --- /dev/null +++ b/Tethering/res/values-mr/strings.xml @@ -0,0 +1,31 @@ + + + + + "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" + "सेट करण्यासाठी टॅप करा." + + "टेदरिंग बंद केले आहे" + "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" + "हॉटस्पॉट आणि टेदरिंगची स्थिती" + + + + + + + diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index 09c5a0e059..c343e311f4 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Penambatan atau tempat liputan aktif" "Ketik untuk membuat persediaan." + "Penambatan dilumpuhkan" "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" "Status tempat liputan & penambatan" + + + + + + diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index ff96086600..84bcdb4c07 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" "စနစ်ထည့်သွင်းရန် တို့ပါ။" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" + + + + + + diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index d6e1fee103..877c128c2d 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Internettdeling eller Wi-Fi-sone er aktiv" "Trykk for å konfigurere." + "Internettdeling er slått av" "Ta kontakt med administratoren din for å få mer informasjon" "Status for Wi-Fi-sone og internettdeling" + + + + + + diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml new file mode 100644 index 0000000000..d50fe240c4 --- /dev/null +++ b/Tethering/res/values-ne/strings.xml @@ -0,0 +1,31 @@ + + + + + "टेदरिङ वा हटस्पट सक्रिय छ" + "सेटअप गर्न ट्याप गर्नुहोस्।" + + "टेदरिङ सुविधा असक्षम पारिएको छ" + "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "हटस्पट तथा टेदरिङको स्थिति" + + + + + + + diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 49f8fd6ee7..6950c239ab 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering of hotspot actief" "Tik om in te stellen." + "Tethering is uitgeschakeld" "Neem contact op met je beheerder voor meer informatie" "Status van hotspot en tethering" + + + + + + diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml new file mode 100644 index 0000000000..2500a6f66b --- /dev/null +++ b/Tethering/res/values-or/strings.xml @@ -0,0 +1,31 @@ + + + + + "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" + "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" + + "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" + "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" + + + + + + + diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml new file mode 100644 index 0000000000..1fd496f968 --- /dev/null +++ b/Tethering/res/values-pa/strings.xml @@ -0,0 +1,31 @@ + + + + + "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" + "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" + + "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" + "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" + + + + + + + diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index 98cfbbbddb..df1d5aeffa 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktywny tethering lub punkt dostępu" "Kliknij, by skonfigurować" + "Tethering został wyłączony" "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" "Hotspot i tethering – stan" + + + + + + diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 338f8fcc1b..2c3757d6de 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ponto de acesso ou tethering ativo" "Toque para configurar." + "Tethering desativado" "Fale com seu administrador para saber detalhes" "Status de ponto de acesso e tethering" + + + + + + diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index a06f033f5a..5af2d22a57 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -16,9 +16,16 @@ - "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativos" + "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" "Toque para configurar." + "A ligação (à Internet) via telemóvel está desativada." "Contacte o administrador para obter detalhes." "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" + + + + + + diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 338f8fcc1b..2c3757d6de 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ponto de acesso ou tethering ativo" "Toque para configurar." + "Tethering desativado" "Fale com seu administrador para saber detalhes" "Status de ponto de acesso e tethering" + + + + + + diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index 7480ec559e..1dad542d4f 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering sau hotspot activ" "Atingeți ca să configurați." + "Tetheringul este dezactivat" "Contactați administratorul pentru detalii" "Starea hotspotului și a tetheringului" + + + + + + diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 3153e0b9a0..4d31484229 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -16,9 +16,16 @@ - "Включен режим модема или хот-спот" + "Включен режим модема или точка доступа" "Нажмите, чтобы настроить." + "Использование телефона в качестве модема запрещено" "Чтобы узнать подробности, обратитесь к администратору." "Статус хот-спота и режима модема" + + + + + + diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index 2b117bc227..d21f2b5388 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" "පිහිටුවීමට තට්ටු කරන්න." + "ටෙදරින් අබල කර ඇත" "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" + + + + + + diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index e1db50a41b..f2242b93b3 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering alebo prístupový bod je aktívny" "Klepnutím prejdete na nastavenie." + "Tethering je deaktivovaný" "O podrobnosti požiadajte svojho správcu" "Stav hotspotu a tetheringu" + + + + + + diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index bcfe487050..c01cace360 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" "Dotaknite se, če želite nastaviti." + "Povezava z internetom prek mobilnega telefona je onemogočena" "Za podrobnosti se obrnite na skrbnika" "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" + + + + + + diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index 2e56020768..f7e2a7be74 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ndarja e internetit ose zona e qasjes së internetit është aktive" "Trokit për ta konfiguruar." + "Ndarja e internetit është çaktivizuar" "Kontakto me administratorin për detaje" "Statusi i zonës së qasjes dhe ndarjes së internetit" + + + + + + diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index 09c7c16739..c5f84eb45d 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Привезивање или хотспот је активан" "Додирните да бисте подесили." + "Привезивање је онемогућено" "Потражите детаље од администратора" "Статус хотспота и привезивања" + + + + + + diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index adb6b8184c..d745dad2ff 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Internetdelning eller surfzon har aktiverats" "Tryck om du vill konfigurera." + "Internetdelning har inaktiverats" "Kontakta administratören om du vill veta mer" "Trådlös surfzon och internetdelning har inaktiverats" + + + + + + diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index 3f10e47901..beaa306374 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kusambaza mtandao au mtandaopepe umewashwa" "Gusa ili uweke mipangilio." + "Umezima kipengele cha kusambaza mtandao" "Wasiliana na msimamizi wako ili upate maelezo zaidi" "Mtandaopepe na hali ya kusambaza mtandao" + + + + + + diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml new file mode 100644 index 0000000000..bc8957e096 --- /dev/null +++ b/Tethering/res/values-ta/strings.xml @@ -0,0 +1,31 @@ + + + + + "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" + "அமைக்க, தட்டவும்." + + "டெதெரிங் முடக்கப்பட்டுள்ளது" + "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" + + + + + + + diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml new file mode 100644 index 0000000000..b7afdb4cad --- /dev/null +++ b/Tethering/res/values-te/strings.xml @@ -0,0 +1,31 @@ + + + + + "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" + "సెటప్ చేయడానికి ట్యాప్ చేయండి." + + "టెథరింగ్ డిజేబుల్ చేయబడింది" + "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" + "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" + + + + + + + diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index 33a8b0c592..e60d43496e 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" "แตะเพื่อตั้งค่า" + "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + + + + + + diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 0f31daf53c..79523bb0f4 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktibo ang pag-tether o hotspot" "I-tap para i-set up." + "Naka-disable ang pag-tether" "Makipag-ugnayan sa iyong admin para sa mga detalye" "Status ng hotspot at pag-tether" + + + + + + diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index aaa264f04d..cf100a42e2 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering veya hotspot etkin" "Ayarlamak için dokunun." + "Tethering devre dışı bırakıldı" "Ayrıntılı bilgi için yöneticinize başvurun" "Hotspot ve tethering durumu" + + + + + + diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 875ba84b4e..0a8ceddad7 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем чи точка доступу активні" "Натисніть, щоб налаштувати." + "Використання телефона як модема вимкнено" "Щоб дізнатися більше, зв\'яжіться з адміністратором" "Статус точки доступу та модема" + + + + + + diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml new file mode 100644 index 0000000000..043dba3161 --- /dev/null +++ b/Tethering/res/values-ur/strings.xml @@ -0,0 +1,31 @@ + + + + + "ٹیدرنگ یا ہاٹ اسپاٹ فعال" + "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" + + "ٹیدرنگ غیر فعال ہے" + "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" + + + + + + + diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 50b3998339..5b9d62afd9 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Modem rejimi yoki hotspot yoniq" "Sozlash uchun bosing." + "Modem rejimi faolsizlantirildi" "Tafsilotlari uchun administratoringizga murojaat qiling" "Hotspot va modem rejimi holati" + + + + + + diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index b6e294221c..19240700ee 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tính năng chia sẻ kết nối hoặc điểm phát sóng đang hoạt động" "Hãy nhấn để thiết lập." + "Đã tắt tính năng chia sẻ kết nối" "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" "Trạng thái điểm phát sóng và trạng thái chia sẻ kết nối" + + + + + + diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index 55e2f1a76b..d137df5f33 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "网络共享或热点已启用" "点按即可设置。" + "网络共享已停用" "如需了解详情,请与您的管理员联系" "热点和网络共享状态" + + + + + + diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 5d4c4e86ff..12c071091b 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "網絡共享或熱點已啟用" "輕按即可設定。" + "網絡共享已停用" "請聯絡您的管理員以瞭解詳情" "熱點和網絡共享狀態" + + + + + + diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index a6561a2dfe..24fb76e824 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "數據連線或無線基地台已啟用" "輕觸即可進行設定。" + "數據連線已停用" "詳情請洽你的管理員" "無線基地台與數據連線狀態" + + + + + + diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index aa65c80df5..f4859aa195 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -18,7 +18,14 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" "Thepha ukuze usethe." + "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" "Xhumana nomphathi wakho ukuze uthole imininingwane" "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" + + + + + + From a81c274f041f9bfe1eb07c1b909dd350a451d3b1 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 28 Mar 2020 05:23:44 -0700 Subject: [PATCH 0879/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: Idaf80948b14cb5a1269f2aaaafec4aa1e500894b --- Tethering/res/values-af/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-am/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ar/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-as/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-az/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-b+sr+Latn/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-be/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-bg/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-bn/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-bs/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ca/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-cs/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-da/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-de/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-el/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rAU/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rCA/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rGB/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rIN/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rXC/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-es-rUS/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-es/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-et/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-eu/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-fa/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-fi/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-fr-rCA/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-fr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-gl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-gu/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-hi/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-hr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-hu/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-hy/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-in/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-is/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-it/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-iw/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ja/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ka/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-kk/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-km/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-kn/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ko/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ky/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-lo/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-lt/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-lv/strings.xml | 31 ++++++++++++++++--- .../res/values-mcc204-mnc04-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-az/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-b+sr+Latn/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-el/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fi/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-pl/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-vi/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-zu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-az/strings.xml | 25 +++++++++++++++ .../strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-el/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fi/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-pl/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-vi/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-zu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-az/strings.xml | 25 +++++++++++++++ .../strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-el/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fi/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-pl/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-vi/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-zu/strings.xml | 25 +++++++++++++++ Tethering/res/values-mk/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ml/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-mn/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-mr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ms/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-my/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-nb/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ne/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-nl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-or/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pa/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pt-rBR/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pt-rPT/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pt/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ro/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ru/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-si/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sk/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sq/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sv/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sw/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ta/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-te/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-th/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-tl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-tr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-uk/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ur/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-uz/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-vi/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-zh-rCN/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-zh-rHK/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-zh-rTW/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-zu/strings.xml | 31 ++++++++++++++++--- 340 files changed, 8850 insertions(+), 340 deletions(-) create mode 100644 Tethering/res/values-mcc204-mnc04-af/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-am/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ar/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-as/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-az/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-be/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bg/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bs/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ca/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-cs/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-da/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-de/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-el/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-es/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-et/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-eu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fa/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-gl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-gu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hy/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-in/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-is/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-it/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-iw/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ja/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ka/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-kk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-km/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-kn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ko/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ky/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lo/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lt/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lv/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ml/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ms/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-my/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-nb/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ne/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-nl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-or/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pa/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ro/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ru/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-si/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sq/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sv/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sw/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ta/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-te/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-th/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-tl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-tr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-uk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ur/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-uz/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-vi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-af/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-am/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ar/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-as/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-az/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-be/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bg/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ca/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-cs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-da/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-de/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-el/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-et/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-eu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hy/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-in/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-is/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-it/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-iw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ja/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ka/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-km/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ko/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ky/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lo/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ml/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ms/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-my/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nb/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ne/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-or/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ro/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ru/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-si/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sq/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ta/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-te/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-th/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ur/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uz/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-vi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-af/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-am/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ar/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-as/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-az/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-be/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bg/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ca/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-cs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-da/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-de/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-el/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-et/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-eu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hy/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-in/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-is/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-it/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-iw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ja/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ka/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-km/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ko/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ky/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lo/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ml/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ms/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-my/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nb/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ne/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-or/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ro/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ru/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-si/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sq/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ta/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-te/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-th/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ur/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uz/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-vi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zu/strings.xml diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index 1258805378..f4c43b16a2 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -1,8 +1,31 @@ + + - "Verbinding of Wi-Fi-warmkol aktief" - "Tik om op te stel." - "Verbinding is gedeaktiveer" - "Kontak jou administrateur vir besonderhede" + "Verbinding of warmkol is aktief" + "Tik om op te stel." + + "Verbinding is gedeaktiveer" + "Kontak jou administrateur vir besonderhede" + "Warmkol- en verbindingstatus" + + + + + + diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 9c36192257..3a8de1200e 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -1,8 +1,31 @@ + + - "መሰካት ወይም ገባሪ ድረስ ነጥብ" - "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" - "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" + "ለማዋቀር መታ ያድርጉ።" + + "እንደ ሞደም መሰካት ተሰናክሏል" + "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" + + + + + + diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 9f84ce4090..355f59f096 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -1,8 +1,31 @@ + + - "النطاق أو نقطة الاتصال نشطة" - "انقر للإعداد." - "تم إيقاف التوصيل" - "اتصل بالمشرف للحصول على التفاصيل" + "النطاق نشط أو نقطة الاتصال نشطة" + "انقر للإعداد." + + "التوصيل متوقف." + "تواصَل مع المشرف للحصول على التفاصيل." + "حالة نقطة الاتصال والتوصيل" + + + + + + diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index 8855822e7c..f44cec0be8 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -1,8 +1,31 @@ + + - "টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে" - "ছেট আপ কৰিবলৈ টিপক।" - "টেডাৰিং অক্ষম কৰি থোৱা হৈছে" - "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" + "ছেট আপ কৰিবলৈ টিপক।" + + "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" + "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" + + + + + + diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index eba50eb636..afd29dffbd 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -1,8 +1,31 @@ + + - "Tezerinq və ya hotspot aktivdir" - "Quraşdırmaq üçün tıklayın." - "Birləşmə deaktivdir" - "Məlumat üçün adminlə əlaqə saxlayın" + "Birləşmə və ya hotspot aktivdir" + "Ayarlamaq üçün toxunun." + + "Birləşmə deaktivdir" + "Detallar üçün adminlə əlaqə saxlayın" + "Hotspot & birləşmə statusu" + + + + + + diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 5b0e488ba5..3ec6b75b34 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -1,8 +1,31 @@ + + - "Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot" - "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" - "Potražite detalje od administratora" + "Privezivanje ili hotspot je aktivan" + "Dodirnite da biste podesili." + + "Privezivanje je onemogućeno" + "Potražite detalje od administratora" + "Status hotspota i privezivanja" + + + + + + diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 5966c7155e..577c1d7bdd 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -1,8 +1,31 @@ + + - "USB-мадэм або хот-спот Wi-Fi актыўныя" - "Дакраніцеся, каб наладзіць." - "Рэжым мадэма адключаны" - "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Мадэм або хот-спот актыўныя" + "Дакраніцеся, каб наладзіць." + + "Рэжым мадэма выключаны" + "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Стан \"Хот-спот і мадэм\"" + + + + + + diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index ed58d7311a..9956a6191b 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -1,8 +1,31 @@ + + - "Има активна споделена връзка или безжична точка за достъп" - "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" - "Свържете се с администратора си за подробности" + "Има активна споделена връзка или точка за достъп" + "Докоснете, за да настроите." + + "Функцията за тетъринг е деактивирана" + "Свържете се с администратора си за подробности" + "Състояние на функцията за точка за достъп и тетъринг" + + + + + + diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 8d9880aa9a..44d8dc6191 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -1,8 +1,31 @@ + + - "টিথারিং বা হটস্পট সক্রিয় আছে" - "সেট-আপ করার জন্য আলতো চাপুন৷" - "টিথারিং অক্ষম করা আছে" - "বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন" + "টিথারিং বা হটস্পট চালু আছে" + "সেট-আপ করতে ট্যাপ করুন।" + + "টিথারিং বন্ধ করা আছে" + "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" + "হটস্পট ও টিথারিং স্ট্যাটাস" + + + + + + diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index 2361b9dd38..bf0395b7ea 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -1,8 +1,31 @@ + + - "Uređaj dijeli vezu ili djeluje kao pristupna tačka" - "Dodirnite za postavke" - "Povezivanje putem mobitela je onemogućeno" - "Kontaktirajte svog administratora za dodatne detalje" + "Aktivno je povezivanje putem mobitela ili pristupna tačka" + "Dodirnite da postavite." + + "Povezivanje putem mobitela je onemogućeno" + "Kontaktirajte svog administratora za detalje" + "Status pristupne tačke i povezivanja putem mobitela" + + + + + + diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index 6752b519e2..cbc161a4e9 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -1,8 +1,31 @@ + + - "Compartició de xarxa o punt d\'accés Wi-Fi activat" - "Toca per configurar." - "La compartició de xarxa està desactivada" - "Contacta amb el teu administrador per obtenir més informació" + "Compartició de xarxa o punt d\'accés Wi‑Fi actius" + "Toca per configurar." + + "La compartició de xarxa està desactivada" + "Contacta amb el teu administrador per obtenir més informació" + "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" + + + + + + diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5fdd53adf1..5c21603987 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -1,8 +1,31 @@ + + - "Sdílené připojení nebo hotspot je aktivní." - "Klepnutím zahájíte nastavení." - "Tethering je zakázán" - "O podrobnosti požádejte administrátora" + "Tethering nebo hotspot je aktivní" + "Klepnutím zahájíte nastavení." + + "Tethering je zakázán" + "O podrobnosti požádejte administrátora" + "Stav hotspotu a tetheringu" + + + + + + diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 2775dfa551..741c7e2d79 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -1,8 +1,31 @@ + + - "Netdeling eller hotspot er aktivt" - "Tryk for at konfigurere" - "Netdeling er deaktiveret" - "Kontakt din administrator for at få oplysninger" + "Netdeling eller hotspot er aktivt" + "Tryk for at konfigurere." + + "Netdeling er deaktiveret" + "Kontakt din administrator for at få oplysninger" + "Status for hotspot og netdeling" + + + + + + diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 9046cd5e11..980a062674 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering oder Hotspot aktiv" - "Zum Einrichten tippen." - "Tethering ist deaktiviert" - "Bitte wende dich für weitere Informationen an den Administrator" + "Tethering oder Hotspot aktiv" + "Zum Einrichten tippen." + + "Tethering ist deaktiviert" + "Bitte wende dich für weitere Informationen an den Administrator" + "Hotspot- und Tethering-Status" + + + + + + diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3b9f53733b..3d8ad1efef 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -1,8 +1,31 @@ + + - "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" - "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" - "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" + "Πατήστε για ρύθμιση." + + "Η σύνδεση είναι απενεργοποιημένη" + "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" + + + + + + diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 56b88a5fb3..18db440b3e 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 56b88a5fb3..18db440b3e 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 56b88a5fb3..18db440b3e 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 56b88a5fb3..18db440b3e 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 7f47fc89d2..23866e0db1 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -1,8 +1,31 @@ + + - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎Tethering is disabled‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" + + + + + + diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index e4618b8cec..0bf6c4ed09 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -1,8 +1,31 @@ + + - "Anclaje a red o zona activa conectados" - "Presiona para configurar." - "Se inhabilitó la conexión mediante dispositivo portátil" - "Para obtener más información, comunícate con el administrador" + "Conexión a red o hotspot conectados" + "Presiona para configurar esta opción." + + "Se inhabilitó la conexión mediante dispositivo portátil" + "Para obtener más información, comunícate con el administrador" + "Estado del hotspot y la conexión mediante dispositivo portátil" + + + + + + diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 8dc1575ce8..195868b5d0 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -1,8 +1,31 @@ + + - "Compartir conexión/Zona Wi-Fi activada" - "Toca para configurar." - "La conexión compartida está inhabilitada" - "Ponte en contacto con el administrador para obtener más información" + "Conexión compartida o punto de acceso activos" + "Toca para configurar." + + "La conexión compartida está inhabilitada" + "Solicita más información a tu administrador" + "Estado del punto de acceso y de la conexión compartida" + + + + + + diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index 872c8a74cc..c4700a9638 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -1,8 +1,31 @@ + + - "Jagamine või kuumkoht on aktiivne" - "Puudutage seadistamiseks." - "Jagamine on keelatud" - "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Jagamine või kuumkoht on aktiivne" + "Puudutage seadistamiseks." + + "Jagamine on keelatud" + "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Kuumkoha ja jagamise olek" + + + + + + diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index 6c4605e616..bcb92d96be 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -1,8 +1,31 @@ + + - "Konexioa partekatzea edo sare publikoa aktibo" - "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" - "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Konexioa partekatzea edo sare publikoa aktibo" + "Sakatu konfiguratzeko." + + "Desgaituta dago konexioa partekatzeko aukera" + "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Sare publikoaren eta konexioa partekatzeko eginbidearen egoera" + + + + + + diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index bc2ee23609..51c3d731c0 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -1,8 +1,31 @@ + + - "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" - "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" - "برای جزئیات، با سرپرستتان تماس بگیرید" + "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" + "برای راه‌اندازی ضربه بزنید." + + "اشتراک‌گذاری اینترنت غیرفعال است" + "برای جزئیات، با سرپرستتان تماس بگیرید" + "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" + + + + + + diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index ff0fca6502..7a54e16157 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -1,8 +1,31 @@ + + - "Internetin jakaminen tai yhteyspiste käytössä" - "Määritä napauttamalla." - "Yhteyden jakaminen poistettu käytöstä" - "Kysy lisätietoja järjestelmänvalvojalta." + "Yhteyden jakaminen tai hotspot käytössä" + "Ota käyttöön napauttamalla." + + "Yhteyden jakaminen on poistettu käytöstä" + "Pyydä lisätietoja järjestelmänvalvojalta" + "Hotspotin ja yhteyden jakamisen tila" + + + + + + diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 1f5df0ee0c..556748f5f7 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -1,8 +1,31 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Touchez pour configurer." - "Le partage de connexion est désactivé" - "Communiquez avec votre administrateur pour obtenir plus de détails" + "Partage de connexion ou point d\'accès sans fil activé" + "Touchez pour configurer." + + "Le partage de connexion est désactivé" + "Communiquez avec votre administrateur pour obtenir plus de détails" + "Point d\'accès et partage de connexion" + + + + + + diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index daf7c9d830..9fe55a2394 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -1,8 +1,31 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Appuyez ici pour configurer." - "Le partage de connexion est désactivé" - "Pour en savoir plus, contactez votre administrateur" + "Partage de connexion ou point d\'accès activé" + "Appuyez pour effectuer la configuration." + + "Le partage de connexion est désactivé" + "Pour en savoir plus, contactez votre administrateur" + "État du point d\'accès et du partage de connexion" + + + + + + diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 0d16a1de09..474371a128 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -1,8 +1,31 @@ + + - "Conexión compartida ou zona wifi activada" - "Tocar para configurar." - "A conexión compartida está desactivada" - "Contacta co administrador para obter información" + "Conexión compartida ou zona wifi activada" + "Toca para configurar." + + "A conexión compartida está desactivada" + "Contacta co administrador para obter información" + "Estado da zona wifi e da conexión compartida" + + + + + + diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index 9d6b02f85f..cdb830a79a 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -1,8 +1,31 @@ + + - "ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય" - "સેટ કરવા માટે ટૅપ કરો." - "ટિથરિંગ અક્ષમ કરેલ છે" - "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" + "સેટઅપ કરવા માટે ટૅપ કરો." + + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" + "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" + + + + + + diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index 9c29d9a8f9..f9e157c9f5 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -1,8 +1,31 @@ + + - "टेदरिंग या हॉटस्‍पॉट सक्रिय" - "सेट करने के लिए टैप करें." - "टेदरिंग अक्षम है" - "जानकारी के लिए अपने एडमिन से संपर्क करें" + "टेदरिंग या हॉटस्पॉट चालू है" + "सेट अप करने के लिए टैप करें." + + "टेदरिंग बंद है" + "जानकारी के लिए अपने एडमिन से संपर्क करें" + "हॉटस्पॉट और टेदरिंग की स्थिति" + + + + + + diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index d0d25bb755..9a99c6457c 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -1,8 +1,31 @@ + + - "Ograničenje ili aktivan hotspot" - "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" - "Obratite se administratoru da biste saznali pojedinosti" + "Modemsko povezivanje ili žarišna točka aktivni" + "Dodirnite da biste postavili." + + "Modemsko je povezivanje onemogućeno" + "Obratite se administratoru da biste saznali pojedinosti" + "Status žarišne točke i modemskog povezivanja" + + + + + + diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index 3129659923..f27c1c3e63 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -1,8 +1,31 @@ + + - "Megosztás vagy aktív hotspot" - "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" - "A részletekért forduljon rendszergazdájához" + "Megosztás vagy aktív hotspot" + "Koppintson a beállításhoz." + + "Az internetmegosztás le van tiltva" + "A részletekért forduljon rendszergazdájához" + "Hotspot és internetmegosztás állapota" + + + + + + diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index 8ba6435fd5..b8b95ea5f9 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -1,8 +1,31 @@ + + - "Մոդեմի ռեժիմը միացված է" - "Հպեք՝ կարգավորելու համար:" - "Մոդեմի ռեժիմն անջատված է" - "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Մոդեմի ռեժիմը միացված է" + "Հպեք՝ կարգավորելու համար։" + + "Մոդեմի ռեժիմն անջատված է" + "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" + + + + + + diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 1e093ab237..24ead4eb3c 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering (Penambatan) atau hotspot aktif" - "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" - "Hubungi admin untuk mengetahui detailnya" + "Tethering atau hotspot aktif" + "Ketuk untuk menyiapkan." + + "Tethering dinonaktifkan" + "Hubungi admin untuk mengetahui detailnya" + "Status hotspot & tethering" + + + + + + diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index f5769d5344..839b0b96fc 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -1,8 +1,31 @@ + + - "Kveikt á tjóðrun eða aðgangsstað" - "Ýttu til að setja upp." - "Slökkt er á tjóðrun" - "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Kveikt á tjóðrun eða aðgangsstað" + "Ýttu til að setja upp." + + "Slökkt er á tjóðrun" + "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Staða heits reits og tjóðrunar" + + + + + + diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index e0b3724325..31e2b73cf6 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering oppure hotspot attivo" - "Tocca per impostare." - "Tethering disattivato" - "Contatta il tuo amministratore per avere informazioni dettagliate" + "Hotspot o tethering attivo" + "Tocca per impostare." + + "Tethering disattivato" + "Contatta il tuo amministratore per avere informazioni dettagliate" + "Stato hotspot e tethering" + + + + + + diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c002c44b23..c97064b8d2 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -1,8 +1,31 @@ + + - "שיתוף אינטרנט פעיל" - "הקש כדי להגדיר." - "שיתוף האינטרנט בין ניידים מושבת" - "לפרטים, יש לפנות למנהל המערכת" + "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" + "יש להקיש כדי להגדיר." + + "שיתוף האינטרנט בין מכשירים מושבת" + "לפרטים, יש לפנות למנהל המערכת" + "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" + + + + + + diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index 314bde00df..c65f6e2f71 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -1,8 +1,31 @@ + + - "テザリングまたはアクセスポイントが有効です" - "タップしてセットアップします。" - "テザリングは無効に設定されています" - "詳しくは、管理者にお問い合わせください" + "テザリングまたはアクセス ポイントが有効です" + "タップしてセットアップします。" + + "テザリングは無効に設定されています" + "詳しくは、管理者にお問い合わせください" + "アクセス ポイントとテザリングのステータス" + + + + + + diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 7bbd81d343..0dca3763f6 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -1,8 +1,31 @@ + + - "ტეტერინგი ან უსადენო ქსელი აქტიურია" - "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" - "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "ტეტერინგი ან უსადენო ქსელი აქტიურია" + "შეეხეთ დასაყენებლად." + + "ტეტერინგი გათიშულია" + "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "უსადენო ქსელის და ტეტერინგის სტატუსი" + + + + + + diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 7fd87a1596..9b4423536b 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -1,8 +1,31 @@ + + - "Тетеринг немесе хотспот қосулы" - "Реттеу үшін түртіңіз." - "Тетеринг өшірілді" - "Мәліметтерді әкімшіден алыңыз" + "Тетеринг немесе хотспот қосулы" + "Реттеу үшін түртіңіз." + + "Тетеринг өшірілді." + "Мәліметтерді әкімшіден алыңыз." + "Хотспот және тетеринг күйі" + + + + + + diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 2f85224679..7a6ab98d88 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -1,8 +1,31 @@ + + - "ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម" - "ប៉ះដើម្បីកំណត់" - "ការភ្ជាប់​ត្រូវបានបិទ" - "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត" + "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" + "ចុច​ដើម្បី​រៀបចំ។" + + "ការភ្ជាប់​ត្រូវបានបិទ" + "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" + "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" + + + + + + diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index f11a83ea40..7c744b83e4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -1,8 +1,31 @@ + + - "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" - "ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" - "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" + "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." + + "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" + "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" + + + + + + diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index 57f24f5b1a..ecbddf5fdc 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -1,8 +1,31 @@ + + - "테더링 또는 핫스팟 사용" - "설정하려면 탭하세요." - "테더링이 사용 중지됨" - "자세한 정보는 관리자에게 문의하세요." + "테더링 또는 핫스팟 사용" + "설정하려면 탭하세요." + + "테더링이 사용 중지됨" + "자세한 정보는 관리자에게 문의하세요." + "핫스팟 및 테더링 상태" + + + + + + diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 79854859d4..f763bf3ff0 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -1,8 +1,31 @@ + + - "Жалгаштыруу же хотспот жандырылган" - "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" - "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Жалгаштыруу же хотспот жандырылган" + "Жөндөө үчүн таптап коюңуз." + + "Жалгаштыруу функциясы өчүрүлгөн" + "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Хотспот жана байланыш түйүнүүн статусу" + + + + + + diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index 78f1585f60..d85b1bd096 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -1,8 +1,31 @@ + + - "ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ" - "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" - "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" + "ແຕະເພື່ອຕັ້ງຄ່າ." + + "ການປ່ອຍສັນຍານຖືກປິດໄວ້" + "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" + + + + + + diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index ebff8ac9d1..9a875932ff 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -1,8 +1,31 @@ + + - "Susietas ar aktyvus" - "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" - "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" + "Palieskite, kad nustatytumėte." + + "Įrenginio kaip modemo naudojimas išjungtas" + "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" + + + + + + diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index 54d0048b52..bb32ab41b1 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -1,8 +1,31 @@ + + - "Piesaiste vai tīklājs ir aktīvs." - "Pieskarieties, lai iestatītu." - "Piesaiste ir atspējota" - "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Piesaiste vai tīklājs ir aktīvs." + "Pieskarieties, lai to iestatītu." + + "Piesaiste ir atspējota" + "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Tīklāja un piesaistes statuss" + + + + + + diff --git a/Tethering/res/values-mcc204-mnc04-af/strings.xml b/Tethering/res/values-mcc204-mnc04-af/strings.xml new file mode 100644 index 0000000000..052ca091ac --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc204-mnc04-am/strings.xml b/Tethering/res/values-mcc204-mnc04-am/strings.xml new file mode 100644 index 0000000000..0518c5a14f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc204-mnc04-ar/strings.xml b/Tethering/res/values-mcc204-mnc04-ar/strings.xml new file mode 100644 index 0000000000..40eb9a741c --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc204-mnc04-as/strings.xml b/Tethering/res/values-mcc204-mnc04-as/strings.xml new file mode 100644 index 0000000000..4c57f21eae --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc204-mnc04-az/strings.xml b/Tethering/res/values-mcc204-mnc04-az/strings.xml new file mode 100644 index 0000000000..2610ab1bec --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml b/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..7b032badf0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-be/strings.xml b/Tethering/res/values-mcc204-mnc04-be/strings.xml new file mode 100644 index 0000000000..2362a1e6a5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc204-mnc04-bg/strings.xml b/Tethering/res/values-mcc204-mnc04-bg/strings.xml new file mode 100644 index 0000000000..6ef1b0bbaf --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc204-mnc04-bn/strings.xml b/Tethering/res/values-mcc204-mnc04-bn/strings.xml new file mode 100644 index 0000000000..7f9efba7f0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc204-mnc04-bs/strings.xml b/Tethering/res/values-mcc204-mnc04-bs/strings.xml new file mode 100644 index 0000000000..7539736415 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-ca/strings.xml b/Tethering/res/values-mcc204-mnc04-ca/strings.xml new file mode 100644 index 0000000000..e3ad666c0b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc204-mnc04-cs/strings.xml b/Tethering/res/values-mcc204-mnc04-cs/strings.xml new file mode 100644 index 0000000000..f0992814c1 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc204-mnc04-da/strings.xml b/Tethering/res/values-mcc204-mnc04-da/strings.xml new file mode 100644 index 0000000000..1fb2374487 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc204-mnc04-de/strings.xml b/Tethering/res/values-mcc204-mnc04-de/strings.xml new file mode 100644 index 0000000000..56d1d1df58 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc204-mnc04-el/strings.xml b/Tethering/res/values-mcc204-mnc04-el/strings.xml new file mode 100644 index 0000000000..674f1f6798 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml new file mode 100644 index 0000000000..20c9b94cd5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml new file mode 100644 index 0000000000..196303fa83 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-es/strings.xml b/Tethering/res/values-mcc204-mnc04-es/strings.xml new file mode 100644 index 0000000000..cac5b23bd9 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-et/strings.xml b/Tethering/res/values-mcc204-mnc04-et/strings.xml new file mode 100644 index 0000000000..ff8dde5422 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc204-mnc04-eu/strings.xml b/Tethering/res/values-mcc204-mnc04-eu/strings.xml new file mode 100644 index 0000000000..1758a4fada --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc204-mnc04-fa/strings.xml b/Tethering/res/values-mcc204-mnc04-fa/strings.xml new file mode 100644 index 0000000000..79e3ef11d6 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc204-mnc04-fi/strings.xml b/Tethering/res/values-mcc204-mnc04-fi/strings.xml new file mode 100644 index 0000000000..64921bca9f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml b/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml new file mode 100644 index 0000000000..eda7b59761 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc204-mnc04-fr/strings.xml b/Tethering/res/values-mcc204-mnc04-fr/strings.xml new file mode 100644 index 0000000000..eda7b59761 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc204-mnc04-gl/strings.xml b/Tethering/res/values-mcc204-mnc04-gl/strings.xml new file mode 100644 index 0000000000..c163c61fbd --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-gu/strings.xml b/Tethering/res/values-mcc204-mnc04-gu/strings.xml new file mode 100644 index 0000000000..0f4d26afdd --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc204-mnc04-hi/strings.xml b/Tethering/res/values-mcc204-mnc04-hi/strings.xml new file mode 100644 index 0000000000..a2442009b5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc204-mnc04-hr/strings.xml b/Tethering/res/values-mcc204-mnc04-hr/strings.xml new file mode 100644 index 0000000000..41618afb2e --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-hu/strings.xml b/Tethering/res/values-mcc204-mnc04-hu/strings.xml new file mode 100644 index 0000000000..39b7a6975b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc204-mnc04-hy/strings.xml b/Tethering/res/values-mcc204-mnc04-hy/strings.xml new file mode 100644 index 0000000000..c14ae10ad1 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc204-mnc04-in/strings.xml b/Tethering/res/values-mcc204-mnc04-in/strings.xml new file mode 100644 index 0000000000..4998474a36 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc204-mnc04-is/strings.xml b/Tethering/res/values-mcc204-mnc04-is/strings.xml new file mode 100644 index 0000000000..82a7d01234 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc204-mnc04-it/strings.xml b/Tethering/res/values-mcc204-mnc04-it/strings.xml new file mode 100644 index 0000000000..a10d511c17 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc204-mnc04-iw/strings.xml b/Tethering/res/values-mcc204-mnc04-iw/strings.xml new file mode 100644 index 0000000000..80807bc232 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc204-mnc04-ja/strings.xml b/Tethering/res/values-mcc204-mnc04-ja/strings.xml new file mode 100644 index 0000000000..0e21a7f322 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc204-mnc04-ka/strings.xml b/Tethering/res/values-mcc204-mnc04-ka/strings.xml new file mode 100644 index 0000000000..6d3b548744 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc204-mnc04-kk/strings.xml b/Tethering/res/values-mcc204-mnc04-kk/strings.xml new file mode 100644 index 0000000000..985fc3ff99 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc204-mnc04-km/strings.xml b/Tethering/res/values-mcc204-mnc04-km/strings.xml new file mode 100644 index 0000000000..03b5cb6e4b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc204-mnc04-kn/strings.xml b/Tethering/res/values-mcc204-mnc04-kn/strings.xml new file mode 100644 index 0000000000..0427a77659 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc204-mnc04-ko/strings.xml b/Tethering/res/values-mcc204-mnc04-ko/strings.xml new file mode 100644 index 0000000000..9218e9a09b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc204-mnc04-ky/strings.xml b/Tethering/res/values-mcc204-mnc04-ky/strings.xml new file mode 100644 index 0000000000..bc3d555597 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc204-mnc04-lo/strings.xml b/Tethering/res/values-mcc204-mnc04-lo/strings.xml new file mode 100644 index 0000000000..06dcbcbccc --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc204-mnc04-lt/strings.xml b/Tethering/res/values-mcc204-mnc04-lt/strings.xml new file mode 100644 index 0000000000..db5178bf2d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc204-mnc04-lv/strings.xml b/Tethering/res/values-mcc204-mnc04-lv/strings.xml new file mode 100644 index 0000000000..c712173ca2 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc204-mnc04-mk/strings.xml b/Tethering/res/values-mcc204-mnc04-mk/strings.xml new file mode 100644 index 0000000000..aa4490912b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc204-mnc04-ml/strings.xml b/Tethering/res/values-mcc204-mnc04-ml/strings.xml new file mode 100644 index 0000000000..0ef956a5a4 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc204-mnc04-mn/strings.xml b/Tethering/res/values-mcc204-mnc04-mn/strings.xml new file mode 100644 index 0000000000..417213f543 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc204-mnc04-mr/strings.xml b/Tethering/res/values-mcc204-mnc04-mr/strings.xml new file mode 100644 index 0000000000..2ed153fb17 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc204-mnc04-ms/strings.xml b/Tethering/res/values-mcc204-mnc04-ms/strings.xml new file mode 100644 index 0000000000..50817fd4a2 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc204-mnc04-my/strings.xml b/Tethering/res/values-mcc204-mnc04-my/strings.xml new file mode 100644 index 0000000000..c0d70e3d5f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc204-mnc04-nb/strings.xml b/Tethering/res/values-mcc204-mnc04-nb/strings.xml new file mode 100644 index 0000000000..1e7f1c6d0a --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc204-mnc04-ne/strings.xml b/Tethering/res/values-mcc204-mnc04-ne/strings.xml new file mode 100644 index 0000000000..fadd357ebf --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc204-mnc04-nl/strings.xml b/Tethering/res/values-mcc204-mnc04-nl/strings.xml new file mode 100644 index 0000000000..bf14a0fced --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc204-mnc04-or/strings.xml b/Tethering/res/values-mcc204-mnc04-or/strings.xml new file mode 100644 index 0000000000..1cdfce04d8 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc204-mnc04-pa/strings.xml b/Tethering/res/values-mcc204-mnc04-pa/strings.xml new file mode 100644 index 0000000000..93402c35d0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc204-mnc04-pl/strings.xml b/Tethering/res/values-mcc204-mnc04-pl/strings.xml new file mode 100644 index 0000000000..8becd0715f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml b/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml new file mode 100644 index 0000000000..8e01736f64 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml b/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml new file mode 100644 index 0000000000..2356379e2f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-pt/strings.xml b/Tethering/res/values-mcc204-mnc04-pt/strings.xml new file mode 100644 index 0000000000..8e01736f64 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-ro/strings.xml b/Tethering/res/values-mcc204-mnc04-ro/strings.xml new file mode 100644 index 0000000000..2e62bd611c --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc204-mnc04-ru/strings.xml b/Tethering/res/values-mcc204-mnc04-ru/strings.xml new file mode 100644 index 0000000000..69f8c59613 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc204-mnc04-si/strings.xml b/Tethering/res/values-mcc204-mnc04-si/strings.xml new file mode 100644 index 0000000000..632748a3e8 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc204-mnc04-sk/strings.xml b/Tethering/res/values-mcc204-mnc04-sk/strings.xml new file mode 100644 index 0000000000..247fc1b0e7 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc204-mnc04-sl/strings.xml b/Tethering/res/values-mcc204-mnc04-sl/strings.xml new file mode 100644 index 0000000000..ed22372197 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc204-mnc04-sq/strings.xml b/Tethering/res/values-mcc204-mnc04-sq/strings.xml new file mode 100644 index 0000000000..4bfab6e474 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc204-mnc04-sr/strings.xml b/Tethering/res/values-mcc204-mnc04-sr/strings.xml new file mode 100644 index 0000000000..478d53a255 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc204-mnc04-sv/strings.xml b/Tethering/res/values-mcc204-mnc04-sv/strings.xml new file mode 100644 index 0000000000..a793ed6483 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc204-mnc04-sw/strings.xml b/Tethering/res/values-mcc204-mnc04-sw/strings.xml new file mode 100644 index 0000000000..3fe09fc22a --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc204-mnc04-ta/strings.xml b/Tethering/res/values-mcc204-mnc04-ta/strings.xml new file mode 100644 index 0000000000..63c28c6702 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc204-mnc04-te/strings.xml b/Tethering/res/values-mcc204-mnc04-te/strings.xml new file mode 100644 index 0000000000..2cf579ca0e --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc204-mnc04-th/strings.xml b/Tethering/res/values-mcc204-mnc04-th/strings.xml new file mode 100644 index 0000000000..3837002b29 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc204-mnc04-tl/strings.xml b/Tethering/res/values-mcc204-mnc04-tl/strings.xml new file mode 100644 index 0000000000..208f893447 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc204-mnc04-tr/strings.xml b/Tethering/res/values-mcc204-mnc04-tr/strings.xml new file mode 100644 index 0000000000..3482fafa2d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc204-mnc04-uk/strings.xml b/Tethering/res/values-mcc204-mnc04-uk/strings.xml new file mode 100644 index 0000000000..dea311443f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc204-mnc04-ur/strings.xml b/Tethering/res/values-mcc204-mnc04-ur/strings.xml new file mode 100644 index 0000000000..09bc0c9eab --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc204-mnc04-uz/strings.xml b/Tethering/res/values-mcc204-mnc04-uz/strings.xml new file mode 100644 index 0000000000..5231c5fff5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc204-mnc04-vi/strings.xml b/Tethering/res/values-mcc204-mnc04-vi/strings.xml new file mode 100644 index 0000000000..bf4ee1011b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml new file mode 100644 index 0000000000..38c2563638 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml new file mode 100644 index 0000000000..3bb52e491f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml new file mode 100644 index 0000000000..298c3eac70 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc204-mnc04-zu/strings.xml b/Tethering/res/values-mcc204-mnc04-zu/strings.xml new file mode 100644 index 0000000000..3dc0078834 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml new file mode 100644 index 0000000000..8f16cd19ac --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml new file mode 100644 index 0000000000..d064fd81d5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml new file mode 100644 index 0000000000..e5e7e5e03d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml new file mode 100644 index 0000000000..5bcadfd7fc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml new file mode 100644 index 0000000000..41c018eec1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..8acc587975 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml new file mode 100644 index 0000000000..b03379a899 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml new file mode 100644 index 0000000000..122bdb69c6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml new file mode 100644 index 0000000000..d5ee1a91ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml new file mode 100644 index 0000000000..ae86e0aa8e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml new file mode 100644 index 0000000000..9c46426601 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml new file mode 100644 index 0000000000..66e4dfb3da --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml new file mode 100644 index 0000000000..04a48a77c4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml new file mode 100644 index 0000000000..a9136784e9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml new file mode 100644 index 0000000000..19be3c7077 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml new file mode 100644 index 0000000000..6384e89ce0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml new file mode 100644 index 0000000000..d4b6937881 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml new file mode 100644 index 0000000000..158fd86296 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml new file mode 100644 index 0000000000..271f82ad6a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml new file mode 100644 index 0000000000..7a2b99e028 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml new file mode 100644 index 0000000000..b370e0fd81 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml new file mode 100644 index 0000000000..da86391ee9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml new file mode 100644 index 0000000000..6ffd8116e8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml new file mode 100644 index 0000000000..6ffd8116e8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml new file mode 100644 index 0000000000..9e7f00cbe0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml new file mode 100644 index 0000000000..e85c00c648 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml new file mode 100644 index 0000000000..b6faa3a0f7 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml new file mode 100644 index 0000000000..86b58ded22 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml new file mode 100644 index 0000000000..27ddabf29d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml new file mode 100644 index 0000000000..abdb207626 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml new file mode 100644 index 0000000000..513d2fb040 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml new file mode 100644 index 0000000000..f4e5dd4ad3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml new file mode 100644 index 0000000000..b82363270b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml new file mode 100644 index 0000000000..0922ee9e4d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml new file mode 100644 index 0000000000..63ddc476e6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml new file mode 100644 index 0000000000..4f20c76a12 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml new file mode 100644 index 0000000000..11e293416b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml new file mode 100644 index 0000000000..b8d94d40a3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml new file mode 100644 index 0000000000..3e8aaebbe9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml new file mode 100644 index 0000000000..59de04c55d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml new file mode 100644 index 0000000000..7ecb6970e7 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml new file mode 100644 index 0000000000..5d1766707c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml new file mode 100644 index 0000000000..aa15bfe1f5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml new file mode 100644 index 0000000000..1e0d2f1c6f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml new file mode 100644 index 0000000000..5fe2a49af6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml new file mode 100644 index 0000000000..930ffa184e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml new file mode 100644 index 0000000000..462e73f7a4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml new file mode 100644 index 0000000000..b1d9b8505b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml new file mode 100644 index 0000000000..936629ca14 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml new file mode 100644 index 0000000000..052df883eb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml new file mode 100644 index 0000000000..09012cbfec --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml new file mode 100644 index 0000000000..e1770b3f77 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml new file mode 100644 index 0000000000..912290cb67 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml new file mode 100644 index 0000000000..6a842428e0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml new file mode 100644 index 0000000000..bb1479d3fb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml new file mode 100644 index 0000000000..51d5c3fd7e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml new file mode 100644 index 0000000000..6e605797d0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml new file mode 100644 index 0000000000..79957977dc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml new file mode 100644 index 0000000000..6e605797d0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml new file mode 100644 index 0000000000..7be2f72195 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml new file mode 100644 index 0000000000..6ab396d50d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml new file mode 100644 index 0000000000..357dd904ac --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml new file mode 100644 index 0000000000..276e5797ee --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml new file mode 100644 index 0000000000..884bddd292 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml new file mode 100644 index 0000000000..a2caddf667 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml new file mode 100644 index 0000000000..7745923331 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml new file mode 100644 index 0000000000..906862aa17 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml new file mode 100644 index 0000000000..0eb922fff6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml new file mode 100644 index 0000000000..1d66c6d689 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml new file mode 100644 index 0000000000..2ee0fa8dda --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml new file mode 100644 index 0000000000..44114e5891 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml new file mode 100644 index 0000000000..440999014c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml new file mode 100644 index 0000000000..d21ad95181 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml new file mode 100644 index 0000000000..e7b8c68eb1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml new file mode 100644 index 0000000000..08edfcffeb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml new file mode 100644 index 0000000000..9def0a1b06 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml new file mode 100644 index 0000000000..e4f818bf42 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml new file mode 100644 index 0000000000..cee4682e7d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml new file mode 100644 index 0000000000..05321db9f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml new file mode 100644 index 0000000000..57b9e0de3b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml new file mode 100644 index 0000000000..7e899705af --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml new file mode 100644 index 0000000000..6fc432256a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml new file mode 100644 index 0000000000..749cb54022 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml new file mode 100644 index 0000000000..9460023663 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml new file mode 100644 index 0000000000..e18e4ec67d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml new file mode 100644 index 0000000000..77740cb6c6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..7170c06662 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml new file mode 100644 index 0000000000..7388d218fd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml new file mode 100644 index 0000000000..aa7a40bfa1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml new file mode 100644 index 0000000000..00bac782ed --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml new file mode 100644 index 0000000000..907821260b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml new file mode 100644 index 0000000000..43c9e137bb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml new file mode 100644 index 0000000000..c9210f7f40 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml new file mode 100644 index 0000000000..3615ff49ff --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml new file mode 100644 index 0000000000..ee8809d80b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml new file mode 100644 index 0000000000..3a79be8735 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml new file mode 100644 index 0000000000..2daad6ad1c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml new file mode 100644 index 0000000000..68d5fc26de --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml new file mode 100644 index 0000000000..930e088642 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml new file mode 100644 index 0000000000..e59e12e71d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml new file mode 100644 index 0000000000..4358266323 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml new file mode 100644 index 0000000000..a2324d84f0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml new file mode 100644 index 0000000000..ec6ac929fb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml new file mode 100644 index 0000000000..eeaf8f3ad4 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml new file mode 100644 index 0000000000..eeaf8f3ad4 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml new file mode 100644 index 0000000000..56b3a9b79d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml new file mode 100644 index 0000000000..c2af9a6688 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml new file mode 100644 index 0000000000..8bb5fb29ae --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml new file mode 100644 index 0000000000..551b1b36fe --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml new file mode 100644 index 0000000000..4113195c19 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml new file mode 100644 index 0000000000..393eac056c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml new file mode 100644 index 0000000000..e2538328cf --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml new file mode 100644 index 0000000000..d28383f51b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml new file mode 100644 index 0000000000..388aa7a2c5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml new file mode 100644 index 0000000000..bbc379501c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml new file mode 100644 index 0000000000..d7cb66b1dd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml new file mode 100644 index 0000000000..9651a563bd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml new file mode 100644 index 0000000000..f2db66b11e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml new file mode 100644 index 0000000000..16699c5a0a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml new file mode 100644 index 0000000000..3c75b1205b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml new file mode 100644 index 0000000000..3892bc36a9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml new file mode 100644 index 0000000000..85e92e0a3c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml new file mode 100644 index 0000000000..881e05c5e0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml new file mode 100644 index 0000000000..83aabd176f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml new file mode 100644 index 0000000000..83feb11f8a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml new file mode 100644 index 0000000000..040e2a5d8e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml new file mode 100644 index 0000000000..c9b12cd706 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml new file mode 100644 index 0000000000..e5a845051d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml new file mode 100644 index 0000000000..c7f1cc6c66 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml new file mode 100644 index 0000000000..35d36f69f1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml new file mode 100644 index 0000000000..bc374725ae --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml new file mode 100644 index 0000000000..413e165c0f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml new file mode 100644 index 0000000000..9b2256abfc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml new file mode 100644 index 0000000000..7f7f39187f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml new file mode 100644 index 0000000000..b478d1393b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml new file mode 100644 index 0000000000..e0940a518d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml new file mode 100644 index 0000000000..c578b278d9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml new file mode 100644 index 0000000000..502b5ddb7d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml new file mode 100644 index 0000000000..a477516145 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml new file mode 100644 index 0000000000..502b5ddb7d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml new file mode 100644 index 0000000000..d6808b04e6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml new file mode 100644 index 0000000000..22dcfcf42d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml new file mode 100644 index 0000000000..5008b7326c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml new file mode 100644 index 0000000000..010677d1d6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml new file mode 100644 index 0000000000..3662ca9e2a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml new file mode 100644 index 0000000000..5453d54fd9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml new file mode 100644 index 0000000000..f52cbf387e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml new file mode 100644 index 0000000000..8474342f26 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml new file mode 100644 index 0000000000..5a812e3f0c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml new file mode 100644 index 0000000000..315403135d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml new file mode 100644 index 0000000000..414def5963 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml new file mode 100644 index 0000000000..a26ac0403b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml new file mode 100644 index 0000000000..6e98146cd5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml new file mode 100644 index 0000000000..423bd76689 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml new file mode 100644 index 0000000000..193b3c348b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml new file mode 100644 index 0000000000..3564ead361 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml new file mode 100644 index 0000000000..769cc2c385 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml new file mode 100644 index 0000000000..998ebe4d7b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml new file mode 100644 index 0000000000..75786086b6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml new file mode 100644 index 0000000000..7f7453c306 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml new file mode 100644 index 0000000000..4b4afc017e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml new file mode 100644 index 0000000000..48ac295ebc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 0fab8aa476..04f0fa8c71 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -1,8 +1,31 @@ + + - "Поврзувањето или точката на пристап се активни" - "Допрете за поставување." - "Врзувањето е оневозможено" - "Контактирајте со администраторот за детали" + "Активно е врзување или точка на пристап" + "Допрете за поставување." + + "Врзувањето е оневозможено" + "Контактирајте со администраторот за детали" + "Статус на точката на пристап и врзувањето" + + + + + + diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index fd7e556e38..2d14f8e0f5 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -1,8 +1,31 @@ + + - "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" - "സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" - "വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" + "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." + + "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" + "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" + + + + + + diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4596577c5d..4f3334c8e3 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -1,8 +1,31 @@ + + - "Модем болгох эсвэл идэвхтэй цэг болгох" - "Тохируулахын тулд товшино уу." - "Модем болгох боломжгүй байна" - "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" + "Тохируулахын тулд товшино уу." + + "Модем болгохыг идэвхгүй болгосон" + "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Сүлжээний цэг болон модем болгох төлөв" + + + + + + diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index 85c9ade4fe..ba9f324982 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -1,8 +1,31 @@ + + - "टेदरिंग किंवा हॉटस्पॉट सक्रिय" - "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद आहे" - "तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा" + "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" + "सेट करण्यासाठी टॅप करा." + + "टेदरिंग बंद केले आहे" + "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" + "हॉटस्पॉट आणि टेदरिंगची स्थिती" + + + + + + diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index ec6bdbda08..c343e311f4 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -1,8 +1,31 @@ + + - "Penambatan atau titik panas aktif" - "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" - "Hubungi pentadbir anda untuk maklumat lanjut" + "Penambatan atau tempat liputan aktif" + "Ketik untuk membuat persediaan." + + "Penambatan dilumpuhkan" + "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" + "Status tempat liputan & penambatan" + + + + + + diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 83978b67d4..84bcdb4c07 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -1,8 +1,31 @@ + + - "တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" - "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်" - "အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" + "စနစ်ထည့်သွင်းရန် တို့ပါ။" + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" + "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" + + + + + + diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 9abf32dd7b..877c128c2d 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -1,8 +1,31 @@ + + - "Internettdeling eller trådløs sone er aktiv" - "Trykk for å konfigurere." - "Internettdeling er slått av" - "Ta kontakt med administratoren din for å få mer informasjon" + "Internettdeling eller Wi-Fi-sone er aktiv" + "Trykk for å konfigurere." + + "Internettdeling er slått av" + "Ta kontakt med administratoren din for å få mer informasjon" + "Status for Wi-Fi-sone og internettdeling" + + + + + + diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index c8869298a5..d50fe240c4 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -1,8 +1,31 @@ + + - "टेथर गर्ने वा हटस्पट सक्रिय" - "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङलाई असक्षम पारिएको छ" - "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "टेदरिङ वा हटस्पट सक्रिय छ" + "सेटअप गर्न ट्याप गर्नुहोस्।" + + "टेदरिङ सुविधा असक्षम पारिएको छ" + "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "हटस्पट तथा टेदरिङको स्थिति" + + + + + + diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 0ec4bff621..6950c239ab 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering of hotspot actief" - "Tik om in te stellen." - "Tethering is uitgeschakeld" - "Neem contact op met je beheerder voor meer informatie" + "Tethering of hotspot actief" + "Tik om in te stellen." + + "Tethering is uitgeschakeld" + "Neem contact op met je beheerder voor meer informatie" + "Status van hotspot en tethering" + + + + + + diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 457685795a..2500a6f66b 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -1,8 +1,31 @@ + + - "ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି" - "ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।" - "ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି" - "ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" + "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" + + "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" + "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" + + + + + + diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index deddf2ea27..1fd496f968 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -1,8 +1,31 @@ + + - "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" - "ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ" - "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ" + "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" + "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" + + "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" + "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" + + + + + + diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index 48d8468935..df1d5aeffa 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -1,8 +1,31 @@ + + - "Aktywny tethering lub punkt dostępu" - "Kliknij, by skonfigurować." - "Tethering został wyłączony" - "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Aktywny tethering lub punkt dostępu" + "Kliknij, by skonfigurować" + + "Tethering został wyłączony" + "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Hotspot i tethering – stan" + + + + + + diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 32c22b8713..2c3757d6de 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -1,8 +1,31 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + + diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 641e22f44f..5af2d22a57 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -1,8 +1,31 @@ + + - "Ligação ponto a ponto ou hotspot activos" - "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." - "Contacte o gestor para obter detalhes." + "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" + "Toque para configurar." + + "A ligação (à Internet) via telemóvel está desativada." + "Contacte o administrador para obter detalhes." + "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" + + + + + + diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 32c22b8713..2c3757d6de 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -1,8 +1,31 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + + diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index f861f733b4..1dad542d4f 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering sau hotspot activ" - "Atingeți ca să configurați." - "Tetheringul este dezactivat" - "Contactați administratorul pentru detalii" + "Tethering sau hotspot activ" + "Atingeți ca să configurați." + + "Tetheringul este dezactivat" + "Contactați administratorul pentru detalii" + "Starea hotspotului și a tetheringului" + + + + + + diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 027cb410c5..4d31484229 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -1,8 +1,31 @@ + + - "Включен режим модема" - "Нажмите, чтобы настроить." - "Включить режим модема нельзя" - "Обратитесь к администратору, чтобы узнать подробности." + "Включен режим модема или точка доступа" + "Нажмите, чтобы настроить." + + "Использование телефона в качестве модема запрещено" + "Чтобы узнать подробности, обратитесь к администратору." + "Статус хот-спота и режима модема" + + + + + + diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index 7d8599f2c2..d21f2b5388 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -1,8 +1,31 @@ + + - "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" - "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" - "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" + "පිහිටුවීමට තට්ටු කරන්න." + + "ටෙදරින් අබල කර ඇත" + "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" + + + + + + diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index a8fe297c00..f2242b93b3 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering alebo prístupový bod je aktívny" - "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" - "O podrobnosti požiadajte svojho správcu" + "Tethering alebo prístupový bod je aktívny" + "Klepnutím prejdete na nastavenie." + + "Tethering je deaktivovaný" + "O podrobnosti požiadajte svojho správcu" + "Stav hotspotu a tetheringu" + + + + + + diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index b5e5e3856f..c01cace360 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -1,8 +1,31 @@ + + - "Aktivna povezava z internetom ali dostopna točka sta aktivni" - "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" - "Za podrobnosti se obrnite na skrbnika" + "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" + "Dotaknite se, če želite nastaviti." + + "Povezava z internetom prek mobilnega telefona je onemogočena" + "Za podrobnosti se obrnite na skrbnika" + "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" + + + + + + diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index fdd4906cc5..f7e2a7be74 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -1,8 +1,31 @@ + + - "Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive" - "Trokit për ta konfiguruar." - "Lidhja e çiftimit është çaktivizuar" - "Kontakto me administratorin për detaje" + "Ndarja e internetit ose zona e qasjes së internetit është aktive" + "Trokit për ta konfiguruar." + + "Ndarja e internetit është çaktivizuar" + "Kontakto me administratorin për detaje" + "Statusi i zonës së qasjes dhe ndarjes së internetit" + + + + + + diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index 9fab345897..c5f84eb45d 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -1,8 +1,31 @@ + + - "Активно повезивање са интернетом преко мобилног уређаја или хотспот" - "Додирните да бисте подесили." - "Привезивање је онемогућено" - "Потражите детаље од администратора" + "Привезивање или хотспот је активан" + "Додирните да бисте подесили." + + "Привезивање је онемогућено" + "Потражите детаље од администратора" + "Статус хотспота и привезивања" + + + + + + diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index 10eeb0fe12..d745dad2ff 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -1,8 +1,31 @@ + + - "Internetdelning eller surfzon aktiverad" - "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" - "Kontakta administratören om du vill veta mer" + "Internetdelning eller surfzon har aktiverats" + "Tryck om du vill konfigurera." + + "Internetdelning har inaktiverats" + "Kontakta administratören om du vill veta mer" + "Trådlös surfzon och internetdelning har inaktiverats" + + + + + + diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index 3353963077..beaa306374 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -1,8 +1,31 @@ + + - "Kushiriki au kusambaza intaneti kumewashwa" - "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" - "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Kusambaza mtandao au mtandaopepe umewashwa" + "Gusa ili uweke mipangilio." + + "Umezima kipengele cha kusambaza mtandao" + "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Mtandaopepe na hali ya kusambaza mtandao" + + + + + + diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index b1e5cc2413..bc8957e096 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -1,8 +1,31 @@ + + - "டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது" - "அமைக்க, தட்டவும்." - "இணைப்பு முறை முடக்கப்பட்டுள்ளது" - "விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" + "அமைக்க, தட்டவும்." + + "டெதெரிங் முடக்கப்பட்டுள்ளது" + "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" + + + + + + diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index aae40dee40..b7afdb4cad 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -1,8 +1,31 @@ + + - "టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది" - "సెటప్ చేయడానికి నొక్కండి." - "టెథెరింగ్ నిలిపివేయబడింది" - "వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి" + "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" + "సెటప్ చేయడానికి ట్యాప్ చేయండి." + + "టెథరింగ్ డిజేబుల్ చేయబడింది" + "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" + "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" + + + + + + diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index 1b800565ad..e60d43496e 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -1,8 +1,31 @@ + + - "การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่" - "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" - "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" + "แตะเพื่อตั้งค่า" + + "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" + "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + + + + + + diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 12863f90e1..79523bb0f4 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -1,8 +1,31 @@ + + - "Pagsasama o aktibong hotspot" - "I-tap upang i-set up." - "Naka-disable ang pag-tether" - "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Aktibo ang pag-tether o hotspot" + "I-tap para i-set up." + + "Naka-disable ang pag-tether" + "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Status ng hotspot at pag-tether" + + + + + + diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index bfcf1ace2c..cf100a42e2 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering veya hotspot etkin" - "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" - "Ayrıntılı bilgi için yöneticinize başvurun" + "Tethering veya hotspot etkin" + "Ayarlamak için dokunun." + + "Tethering devre dışı bırakıldı" + "Ayrıntılı bilgi için yöneticinize başvurun" + "Hotspot ve tethering durumu" + + + + + + diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 8e159c0723..0a8ceddad7 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -1,8 +1,31 @@ + + - "Прив\'язка чи точка дост. активна" - "Торкніться, щоб налаштувати." - "Використання телефона в режимі модема вимкнено" - "Щоб дізнатися більше, зв’яжіться з адміністратором" + "Модем чи точка доступу активні" + "Натисніть, щоб налаштувати." + + "Використання телефона як модема вимкнено" + "Щоб дізнатися більше, зв\'яжіться з адміністратором" + "Статус точки доступу та модема" + + + + + + diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 89195d4aae..043dba3161 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -1,8 +1,31 @@ + + - "ٹیدرنگ یا ہاٹ اسپاٹ فعال" - "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" - "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ٹیدرنگ یا ہاٹ اسپاٹ فعال" + "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" + + "ٹیدرنگ غیر فعال ہے" + "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" + + + + + + diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 0ac4d4a741..5b9d62afd9 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -1,8 +1,31 @@ + + - "Modem rejimi yoniq" - "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" - "Tafsilotlari uchun administratoringizga murojaat qiling" + "Modem rejimi yoki hotspot yoniq" + "Sozlash uchun bosing." + + "Modem rejimi faolsizlantirildi" + "Tafsilotlari uchun administratoringizga murojaat qiling" + "Hotspot va modem rejimi holati" + + + + + + diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 85a4db8aa5..19240700ee 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -1,8 +1,31 @@ + + - "Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động" - "Nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" - "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Tính năng chia sẻ kết nối hoặc điểm phát sóng đang hoạt động" + "Hãy nhấn để thiết lập." + + "Đã tắt tính năng chia sẻ kết nối" + "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Trạng thái điểm phát sóng và trạng thái chia sẻ kết nối" + + + + + + diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index ff1fe03953..d137df5f33 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -1,8 +1,31 @@ + + - "网络共享或热点已启用" - "点按即可进行设置。" - "网络共享已停用" - "请与您的管理员联系以了解详情" + "网络共享或热点已启用" + "点按即可设置。" + + "网络共享已停用" + "如需了解详情,请与您的管理员联系" + "热点和网络共享状态" + + + + + + diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 0de39fac97..12c071091b 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -1,8 +1,31 @@ + + - "已啟用網絡共享或熱點" - "輕按即可設定。" - "網絡共享已停用" - "請聯絡您的管理員以瞭解詳情" + "網絡共享或熱點已啟用" + "輕按即可設定。" + + "網絡共享已停用" + "請聯絡您的管理員以瞭解詳情" + "熱點和網絡共享狀態" + + + + + + diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9a117bbca4..24fb76e824 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -1,8 +1,31 @@ + + - "網路共用或無線基地台已啟用" - "輕觸即可進行設定。" - "數據連線已停用" - "詳情請洽你的管理員" + "數據連線或無線基地台已啟用" + "輕觸即可進行設定。" + + "數據連線已停用" + "詳情請洽你的管理員" + "無線基地台與數據連線狀態" + + + + + + diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index 8fe10d86cb..f4859aa195 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -1,8 +1,31 @@ + + - "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" - "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" - "Xhumana nomphathi wakho ukuze uthole imininingwane" + "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" + "Thepha ukuze usethe." + + "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" + "Xhumana nomphathi wakho ukuze uthole imininingwane" + "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" + + + + + + From 49ea07f087dea73d78cc8de2462ac5cfe6d89116 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 28 Mar 2020 07:21:37 -0700 Subject: [PATCH 0880/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I4bedd02ee1c673d604782844f69ee2803f61729c --- Tethering/res/values-af/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-am/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ar/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-as/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-az/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-b+sr+Latn/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-be/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-bg/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-bn/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-bs/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ca/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-cs/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-da/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-de/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-el/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rAU/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rCA/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rGB/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rIN/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-en-rXC/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-es-rUS/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-es/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-et/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-eu/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-fa/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-fi/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-fr-rCA/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-fr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-gl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-gu/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-hi/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-hr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-hu/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-hy/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-in/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-is/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-it/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-iw/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ja/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ka/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-kk/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-km/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-kn/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ko/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ky/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-lo/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-lt/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-lv/strings.xml | 31 ++++++++++++++++--- .../res/values-mcc204-mnc04-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-az/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-b+sr+Latn/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-el/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fi/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-pl/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc204-mnc04-vi/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc204-mnc04-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc204-mnc04-zu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-az/strings.xml | 25 +++++++++++++++ .../strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-el/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fi/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-pl/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc310-mnc004-vi/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc310-mnc004-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc310-mnc004-zu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-af/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-am/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ar/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-as/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-az/strings.xml | 25 +++++++++++++++ .../strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-be/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-bg/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-bn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-bs/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ca/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-cs/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-da/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-de/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-el/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rAU/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rCA/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rGB/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rIN/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-en-rXC/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-es-rUS/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-es/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-et/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-eu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fa/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fi/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-fr-rCA/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-fr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-gl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-gu/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-hi/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hu/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-hy/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-in/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-is/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-it/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-iw/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ja/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ka/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-kk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-km/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-kn/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-ko/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ky/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-lo/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-lt/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-lv/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-mk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ml/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-mn/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-mr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ms/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-my/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-nb/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ne/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-nl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-or/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-pa/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-pl/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-pt-rBR/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-pt-rPT/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-pt/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ro/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ru/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-si/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sq/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sv/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-sw/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ta/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-te/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-th/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-tl/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-tr/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-uk/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-ur/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-uz/strings.xml | 30 ++++++++++++++++++ .../res/values-mcc311-mnc480-vi/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rCN/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rHK/strings.xml | 25 +++++++++++++++ .../values-mcc311-mnc480-zh-rTW/strings.xml | 25 +++++++++++++++ .../res/values-mcc311-mnc480-zu/strings.xml | 25 +++++++++++++++ Tethering/res/values-mk/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ml/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-mn/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-mr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ms/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-my/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-nb/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ne/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-nl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-or/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pa/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pt-rBR/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pt-rPT/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-pt/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ro/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ru/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-si/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sk/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sq/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sv/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-sw/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ta/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-te/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-th/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-tl/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-tr/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-uk/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-ur/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-uz/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-vi/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-zh-rCN/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-zh-rHK/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-zh-rTW/strings.xml | 31 ++++++++++++++++--- Tethering/res/values-zu/strings.xml | 31 ++++++++++++++++--- 340 files changed, 8850 insertions(+), 340 deletions(-) create mode 100644 Tethering/res/values-mcc204-mnc04-af/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-am/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ar/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-as/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-az/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-be/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bg/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-bs/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ca/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-cs/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-da/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-de/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-el/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-es/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-et/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-eu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fa/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-fr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-gl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-gu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hu/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-hy/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-in/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-is/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-it/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-iw/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ja/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ka/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-kk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-km/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-kn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ko/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ky/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lo/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lt/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-lv/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ml/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mn/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-mr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ms/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-my/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-nb/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ne/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-nl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-or/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pa/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-pt/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ro/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ru/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-si/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sq/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sv/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-sw/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ta/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-te/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-th/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-tl/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-tr/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-uk/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-ur/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-uz/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-vi/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc204-mnc04-zu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-af/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-am/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ar/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-as/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-az/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-be/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bg/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ca/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-cs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-da/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-de/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-el/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-et/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-eu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hy/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-in/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-is/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-it/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-iw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ja/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ka/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-km/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ko/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ky/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lo/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ml/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ms/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-my/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nb/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ne/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-or/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ro/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ru/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-si/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sq/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ta/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-te/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-th/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ur/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uz/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-vi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-af/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-am/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ar/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-as/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-az/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-be/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bg/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ca/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-cs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-da/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-de/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-el/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-et/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-eu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hy/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-in/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-is/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-it/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-iw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ja/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ka/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-km/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ko/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ky/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lo/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ml/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ms/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-my/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nb/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ne/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-or/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ro/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ru/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-si/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sq/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ta/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-te/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-th/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ur/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uz/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-vi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zu/strings.xml diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index 1258805378..f4c43b16a2 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -1,8 +1,31 @@ + + - "Verbinding of Wi-Fi-warmkol aktief" - "Tik om op te stel." - "Verbinding is gedeaktiveer" - "Kontak jou administrateur vir besonderhede" + "Verbinding of warmkol is aktief" + "Tik om op te stel." + + "Verbinding is gedeaktiveer" + "Kontak jou administrateur vir besonderhede" + "Warmkol- en verbindingstatus" + + + + + + diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 9c36192257..3a8de1200e 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -1,8 +1,31 @@ + + - "መሰካት ወይም ገባሪ ድረስ ነጥብ" - "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" - "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" + "ለማዋቀር መታ ያድርጉ።" + + "እንደ ሞደም መሰካት ተሰናክሏል" + "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" + + + + + + diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 9f84ce4090..355f59f096 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -1,8 +1,31 @@ + + - "النطاق أو نقطة الاتصال نشطة" - "انقر للإعداد." - "تم إيقاف التوصيل" - "اتصل بالمشرف للحصول على التفاصيل" + "النطاق نشط أو نقطة الاتصال نشطة" + "انقر للإعداد." + + "التوصيل متوقف." + "تواصَل مع المشرف للحصول على التفاصيل." + "حالة نقطة الاتصال والتوصيل" + + + + + + diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index 8855822e7c..f44cec0be8 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -1,8 +1,31 @@ + + - "টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে" - "ছেট আপ কৰিবলৈ টিপক।" - "টেডাৰিং অক্ষম কৰি থোৱা হৈছে" - "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" + "ছেট আপ কৰিবলৈ টিপক।" + + "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" + "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" + + + + + + diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index eba50eb636..afd29dffbd 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -1,8 +1,31 @@ + + - "Tezerinq və ya hotspot aktivdir" - "Quraşdırmaq üçün tıklayın." - "Birləşmə deaktivdir" - "Məlumat üçün adminlə əlaqə saxlayın" + "Birləşmə və ya hotspot aktivdir" + "Ayarlamaq üçün toxunun." + + "Birləşmə deaktivdir" + "Detallar üçün adminlə əlaqə saxlayın" + "Hotspot & birləşmə statusu" + + + + + + diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 5b0e488ba5..3ec6b75b34 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -1,8 +1,31 @@ + + - "Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot" - "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" - "Potražite detalje od administratora" + "Privezivanje ili hotspot je aktivan" + "Dodirnite da biste podesili." + + "Privezivanje je onemogućeno" + "Potražite detalje od administratora" + "Status hotspota i privezivanja" + + + + + + diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 5966c7155e..577c1d7bdd 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -1,8 +1,31 @@ + + - "USB-мадэм або хот-спот Wi-Fi актыўныя" - "Дакраніцеся, каб наладзіць." - "Рэжым мадэма адключаны" - "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Мадэм або хот-спот актыўныя" + "Дакраніцеся, каб наладзіць." + + "Рэжым мадэма выключаны" + "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Стан \"Хот-спот і мадэм\"" + + + + + + diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index ed58d7311a..9956a6191b 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -1,8 +1,31 @@ + + - "Има активна споделена връзка или безжична точка за достъп" - "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" - "Свържете се с администратора си за подробности" + "Има активна споделена връзка или точка за достъп" + "Докоснете, за да настроите." + + "Функцията за тетъринг е деактивирана" + "Свържете се с администратора си за подробности" + "Състояние на функцията за точка за достъп и тетъринг" + + + + + + diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 8d9880aa9a..44d8dc6191 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -1,8 +1,31 @@ + + - "টিথারিং বা হটস্পট সক্রিয় আছে" - "সেট-আপ করার জন্য আলতো চাপুন৷" - "টিথারিং অক্ষম করা আছে" - "বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন" + "টিথারিং বা হটস্পট চালু আছে" + "সেট-আপ করতে ট্যাপ করুন।" + + "টিথারিং বন্ধ করা আছে" + "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" + "হটস্পট ও টিথারিং স্ট্যাটাস" + + + + + + diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index 2361b9dd38..bf0395b7ea 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -1,8 +1,31 @@ + + - "Uređaj dijeli vezu ili djeluje kao pristupna tačka" - "Dodirnite za postavke" - "Povezivanje putem mobitela je onemogućeno" - "Kontaktirajte svog administratora za dodatne detalje" + "Aktivno je povezivanje putem mobitela ili pristupna tačka" + "Dodirnite da postavite." + + "Povezivanje putem mobitela je onemogućeno" + "Kontaktirajte svog administratora za detalje" + "Status pristupne tačke i povezivanja putem mobitela" + + + + + + diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index 6752b519e2..cbc161a4e9 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -1,8 +1,31 @@ + + - "Compartició de xarxa o punt d\'accés Wi-Fi activat" - "Toca per configurar." - "La compartició de xarxa està desactivada" - "Contacta amb el teu administrador per obtenir més informació" + "Compartició de xarxa o punt d\'accés Wi‑Fi actius" + "Toca per configurar." + + "La compartició de xarxa està desactivada" + "Contacta amb el teu administrador per obtenir més informació" + "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" + + + + + + diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5fdd53adf1..5c21603987 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -1,8 +1,31 @@ + + - "Sdílené připojení nebo hotspot je aktivní." - "Klepnutím zahájíte nastavení." - "Tethering je zakázán" - "O podrobnosti požádejte administrátora" + "Tethering nebo hotspot je aktivní" + "Klepnutím zahájíte nastavení." + + "Tethering je zakázán" + "O podrobnosti požádejte administrátora" + "Stav hotspotu a tetheringu" + + + + + + diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 2775dfa551..741c7e2d79 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -1,8 +1,31 @@ + + - "Netdeling eller hotspot er aktivt" - "Tryk for at konfigurere" - "Netdeling er deaktiveret" - "Kontakt din administrator for at få oplysninger" + "Netdeling eller hotspot er aktivt" + "Tryk for at konfigurere." + + "Netdeling er deaktiveret" + "Kontakt din administrator for at få oplysninger" + "Status for hotspot og netdeling" + + + + + + diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 9046cd5e11..980a062674 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering oder Hotspot aktiv" - "Zum Einrichten tippen." - "Tethering ist deaktiviert" - "Bitte wende dich für weitere Informationen an den Administrator" + "Tethering oder Hotspot aktiv" + "Zum Einrichten tippen." + + "Tethering ist deaktiviert" + "Bitte wende dich für weitere Informationen an den Administrator" + "Hotspot- und Tethering-Status" + + + + + + diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3b9f53733b..3d8ad1efef 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -1,8 +1,31 @@ + + - "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" - "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" - "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" + "Πατήστε για ρύθμιση." + + "Η σύνδεση είναι απενεργοποιημένη" + "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" + + + + + + diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 56b88a5fb3..18db440b3e 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 56b88a5fb3..18db440b3e 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 56b88a5fb3..18db440b3e 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 56b88a5fb3..18db440b3e 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + + diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 7f47fc89d2..23866e0db1 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -1,8 +1,31 @@ + + - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎Tethering is disabled‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" + + + + + + diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index e4618b8cec..0bf6c4ed09 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -1,8 +1,31 @@ + + - "Anclaje a red o zona activa conectados" - "Presiona para configurar." - "Se inhabilitó la conexión mediante dispositivo portátil" - "Para obtener más información, comunícate con el administrador" + "Conexión a red o hotspot conectados" + "Presiona para configurar esta opción." + + "Se inhabilitó la conexión mediante dispositivo portátil" + "Para obtener más información, comunícate con el administrador" + "Estado del hotspot y la conexión mediante dispositivo portátil" + + + + + + diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 8dc1575ce8..195868b5d0 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -1,8 +1,31 @@ + + - "Compartir conexión/Zona Wi-Fi activada" - "Toca para configurar." - "La conexión compartida está inhabilitada" - "Ponte en contacto con el administrador para obtener más información" + "Conexión compartida o punto de acceso activos" + "Toca para configurar." + + "La conexión compartida está inhabilitada" + "Solicita más información a tu administrador" + "Estado del punto de acceso y de la conexión compartida" + + + + + + diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index 872c8a74cc..c4700a9638 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -1,8 +1,31 @@ + + - "Jagamine või kuumkoht on aktiivne" - "Puudutage seadistamiseks." - "Jagamine on keelatud" - "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Jagamine või kuumkoht on aktiivne" + "Puudutage seadistamiseks." + + "Jagamine on keelatud" + "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Kuumkoha ja jagamise olek" + + + + + + diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index 6c4605e616..bcb92d96be 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -1,8 +1,31 @@ + + - "Konexioa partekatzea edo sare publikoa aktibo" - "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" - "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Konexioa partekatzea edo sare publikoa aktibo" + "Sakatu konfiguratzeko." + + "Desgaituta dago konexioa partekatzeko aukera" + "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Sare publikoaren eta konexioa partekatzeko eginbidearen egoera" + + + + + + diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index bc2ee23609..51c3d731c0 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -1,8 +1,31 @@ + + - "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" - "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" - "برای جزئیات، با سرپرستتان تماس بگیرید" + "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" + "برای راه‌اندازی ضربه بزنید." + + "اشتراک‌گذاری اینترنت غیرفعال است" + "برای جزئیات، با سرپرستتان تماس بگیرید" + "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" + + + + + + diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index ff0fca6502..7a54e16157 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -1,8 +1,31 @@ + + - "Internetin jakaminen tai yhteyspiste käytössä" - "Määritä napauttamalla." - "Yhteyden jakaminen poistettu käytöstä" - "Kysy lisätietoja järjestelmänvalvojalta." + "Yhteyden jakaminen tai hotspot käytössä" + "Ota käyttöön napauttamalla." + + "Yhteyden jakaminen on poistettu käytöstä" + "Pyydä lisätietoja järjestelmänvalvojalta" + "Hotspotin ja yhteyden jakamisen tila" + + + + + + diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 1f5df0ee0c..556748f5f7 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -1,8 +1,31 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Touchez pour configurer." - "Le partage de connexion est désactivé" - "Communiquez avec votre administrateur pour obtenir plus de détails" + "Partage de connexion ou point d\'accès sans fil activé" + "Touchez pour configurer." + + "Le partage de connexion est désactivé" + "Communiquez avec votre administrateur pour obtenir plus de détails" + "Point d\'accès et partage de connexion" + + + + + + diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index daf7c9d830..9fe55a2394 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -1,8 +1,31 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Appuyez ici pour configurer." - "Le partage de connexion est désactivé" - "Pour en savoir plus, contactez votre administrateur" + "Partage de connexion ou point d\'accès activé" + "Appuyez pour effectuer la configuration." + + "Le partage de connexion est désactivé" + "Pour en savoir plus, contactez votre administrateur" + "État du point d\'accès et du partage de connexion" + + + + + + diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 0d16a1de09..474371a128 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -1,8 +1,31 @@ + + - "Conexión compartida ou zona wifi activada" - "Tocar para configurar." - "A conexión compartida está desactivada" - "Contacta co administrador para obter información" + "Conexión compartida ou zona wifi activada" + "Toca para configurar." + + "A conexión compartida está desactivada" + "Contacta co administrador para obter información" + "Estado da zona wifi e da conexión compartida" + + + + + + diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index 9d6b02f85f..cdb830a79a 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -1,8 +1,31 @@ + + - "ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય" - "સેટ કરવા માટે ટૅપ કરો." - "ટિથરિંગ અક્ષમ કરેલ છે" - "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" + "સેટઅપ કરવા માટે ટૅપ કરો." + + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" + "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" + + + + + + diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index 9c29d9a8f9..f9e157c9f5 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -1,8 +1,31 @@ + + - "टेदरिंग या हॉटस्‍पॉट सक्रिय" - "सेट करने के लिए टैप करें." - "टेदरिंग अक्षम है" - "जानकारी के लिए अपने एडमिन से संपर्क करें" + "टेदरिंग या हॉटस्पॉट चालू है" + "सेट अप करने के लिए टैप करें." + + "टेदरिंग बंद है" + "जानकारी के लिए अपने एडमिन से संपर्क करें" + "हॉटस्पॉट और टेदरिंग की स्थिति" + + + + + + diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index d0d25bb755..9a99c6457c 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -1,8 +1,31 @@ + + - "Ograničenje ili aktivan hotspot" - "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" - "Obratite se administratoru da biste saznali pojedinosti" + "Modemsko povezivanje ili žarišna točka aktivni" + "Dodirnite da biste postavili." + + "Modemsko je povezivanje onemogućeno" + "Obratite se administratoru da biste saznali pojedinosti" + "Status žarišne točke i modemskog povezivanja" + + + + + + diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index 3129659923..f27c1c3e63 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -1,8 +1,31 @@ + + - "Megosztás vagy aktív hotspot" - "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" - "A részletekért forduljon rendszergazdájához" + "Megosztás vagy aktív hotspot" + "Koppintson a beállításhoz." + + "Az internetmegosztás le van tiltva" + "A részletekért forduljon rendszergazdájához" + "Hotspot és internetmegosztás állapota" + + + + + + diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index 8ba6435fd5..b8b95ea5f9 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -1,8 +1,31 @@ + + - "Մոդեմի ռեժիմը միացված է" - "Հպեք՝ կարգավորելու համար:" - "Մոդեմի ռեժիմն անջատված է" - "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Մոդեմի ռեժիմը միացված է" + "Հպեք՝ կարգավորելու համար։" + + "Մոդեմի ռեժիմն անջատված է" + "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" + + + + + + diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 1e093ab237..24ead4eb3c 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering (Penambatan) atau hotspot aktif" - "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" - "Hubungi admin untuk mengetahui detailnya" + "Tethering atau hotspot aktif" + "Ketuk untuk menyiapkan." + + "Tethering dinonaktifkan" + "Hubungi admin untuk mengetahui detailnya" + "Status hotspot & tethering" + + + + + + diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index f5769d5344..839b0b96fc 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -1,8 +1,31 @@ + + - "Kveikt á tjóðrun eða aðgangsstað" - "Ýttu til að setja upp." - "Slökkt er á tjóðrun" - "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Kveikt á tjóðrun eða aðgangsstað" + "Ýttu til að setja upp." + + "Slökkt er á tjóðrun" + "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Staða heits reits og tjóðrunar" + + + + + + diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index e0b3724325..31e2b73cf6 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering oppure hotspot attivo" - "Tocca per impostare." - "Tethering disattivato" - "Contatta il tuo amministratore per avere informazioni dettagliate" + "Hotspot o tethering attivo" + "Tocca per impostare." + + "Tethering disattivato" + "Contatta il tuo amministratore per avere informazioni dettagliate" + "Stato hotspot e tethering" + + + + + + diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c002c44b23..c97064b8d2 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -1,8 +1,31 @@ + + - "שיתוף אינטרנט פעיל" - "הקש כדי להגדיר." - "שיתוף האינטרנט בין ניידים מושבת" - "לפרטים, יש לפנות למנהל המערכת" + "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" + "יש להקיש כדי להגדיר." + + "שיתוף האינטרנט בין מכשירים מושבת" + "לפרטים, יש לפנות למנהל המערכת" + "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" + + + + + + diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index 314bde00df..c65f6e2f71 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -1,8 +1,31 @@ + + - "テザリングまたはアクセスポイントが有効です" - "タップしてセットアップします。" - "テザリングは無効に設定されています" - "詳しくは、管理者にお問い合わせください" + "テザリングまたはアクセス ポイントが有効です" + "タップしてセットアップします。" + + "テザリングは無効に設定されています" + "詳しくは、管理者にお問い合わせください" + "アクセス ポイントとテザリングのステータス" + + + + + + diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 7bbd81d343..0dca3763f6 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -1,8 +1,31 @@ + + - "ტეტერინგი ან უსადენო ქსელი აქტიურია" - "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" - "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "ტეტერინგი ან უსადენო ქსელი აქტიურია" + "შეეხეთ დასაყენებლად." + + "ტეტერინგი გათიშულია" + "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "უსადენო ქსელის და ტეტერინგის სტატუსი" + + + + + + diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 7fd87a1596..9b4423536b 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -1,8 +1,31 @@ + + - "Тетеринг немесе хотспот қосулы" - "Реттеу үшін түртіңіз." - "Тетеринг өшірілді" - "Мәліметтерді әкімшіден алыңыз" + "Тетеринг немесе хотспот қосулы" + "Реттеу үшін түртіңіз." + + "Тетеринг өшірілді." + "Мәліметтерді әкімшіден алыңыз." + "Хотспот және тетеринг күйі" + + + + + + diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 2f85224679..7a6ab98d88 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -1,8 +1,31 @@ + + - "ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម" - "ប៉ះដើម្បីកំណត់" - "ការភ្ជាប់​ត្រូវបានបិទ" - "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត" + "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" + "ចុច​ដើម្បី​រៀបចំ។" + + "ការភ្ជាប់​ត្រូវបានបិទ" + "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" + "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" + + + + + + diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index f11a83ea40..7c744b83e4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -1,8 +1,31 @@ + + - "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" - "ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" - "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" + "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." + + "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" + "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" + + + + + + diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index 57f24f5b1a..ecbddf5fdc 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -1,8 +1,31 @@ + + - "테더링 또는 핫스팟 사용" - "설정하려면 탭하세요." - "테더링이 사용 중지됨" - "자세한 정보는 관리자에게 문의하세요." + "테더링 또는 핫스팟 사용" + "설정하려면 탭하세요." + + "테더링이 사용 중지됨" + "자세한 정보는 관리자에게 문의하세요." + "핫스팟 및 테더링 상태" + + + + + + diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 79854859d4..f763bf3ff0 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -1,8 +1,31 @@ + + - "Жалгаштыруу же хотспот жандырылган" - "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" - "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Жалгаштыруу же хотспот жандырылган" + "Жөндөө үчүн таптап коюңуз." + + "Жалгаштыруу функциясы өчүрүлгөн" + "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Хотспот жана байланыш түйүнүүн статусу" + + + + + + diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index 78f1585f60..d85b1bd096 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -1,8 +1,31 @@ + + - "ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ" - "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" - "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" + "ແຕະເພື່ອຕັ້ງຄ່າ." + + "ການປ່ອຍສັນຍານຖືກປິດໄວ້" + "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" + + + + + + diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index ebff8ac9d1..9a875932ff 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -1,8 +1,31 @@ + + - "Susietas ar aktyvus" - "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" - "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" + "Palieskite, kad nustatytumėte." + + "Įrenginio kaip modemo naudojimas išjungtas" + "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" + + + + + + diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index 54d0048b52..bb32ab41b1 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -1,8 +1,31 @@ + + - "Piesaiste vai tīklājs ir aktīvs." - "Pieskarieties, lai iestatītu." - "Piesaiste ir atspējota" - "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Piesaiste vai tīklājs ir aktīvs." + "Pieskarieties, lai to iestatītu." + + "Piesaiste ir atspējota" + "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Tīklāja un piesaistes statuss" + + + + + + diff --git a/Tethering/res/values-mcc204-mnc04-af/strings.xml b/Tethering/res/values-mcc204-mnc04-af/strings.xml new file mode 100644 index 0000000000..052ca091ac --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc204-mnc04-am/strings.xml b/Tethering/res/values-mcc204-mnc04-am/strings.xml new file mode 100644 index 0000000000..0518c5a14f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc204-mnc04-ar/strings.xml b/Tethering/res/values-mcc204-mnc04-ar/strings.xml new file mode 100644 index 0000000000..40eb9a741c --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc204-mnc04-as/strings.xml b/Tethering/res/values-mcc204-mnc04-as/strings.xml new file mode 100644 index 0000000000..4c57f21eae --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc204-mnc04-az/strings.xml b/Tethering/res/values-mcc204-mnc04-az/strings.xml new file mode 100644 index 0000000000..2610ab1bec --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml b/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..7b032badf0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-be/strings.xml b/Tethering/res/values-mcc204-mnc04-be/strings.xml new file mode 100644 index 0000000000..2362a1e6a5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc204-mnc04-bg/strings.xml b/Tethering/res/values-mcc204-mnc04-bg/strings.xml new file mode 100644 index 0000000000..6ef1b0bbaf --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc204-mnc04-bn/strings.xml b/Tethering/res/values-mcc204-mnc04-bn/strings.xml new file mode 100644 index 0000000000..7f9efba7f0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc204-mnc04-bs/strings.xml b/Tethering/res/values-mcc204-mnc04-bs/strings.xml new file mode 100644 index 0000000000..7539736415 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-ca/strings.xml b/Tethering/res/values-mcc204-mnc04-ca/strings.xml new file mode 100644 index 0000000000..e3ad666c0b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc204-mnc04-cs/strings.xml b/Tethering/res/values-mcc204-mnc04-cs/strings.xml new file mode 100644 index 0000000000..f0992814c1 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc204-mnc04-da/strings.xml b/Tethering/res/values-mcc204-mnc04-da/strings.xml new file mode 100644 index 0000000000..1fb2374487 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc204-mnc04-de/strings.xml b/Tethering/res/values-mcc204-mnc04-de/strings.xml new file mode 100644 index 0000000000..56d1d1df58 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc204-mnc04-el/strings.xml b/Tethering/res/values-mcc204-mnc04-el/strings.xml new file mode 100644 index 0000000000..674f1f6798 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml new file mode 100644 index 0000000000..3046a3725d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml b/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml new file mode 100644 index 0000000000..20c9b94cd5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml new file mode 100644 index 0000000000..196303fa83 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-es/strings.xml b/Tethering/res/values-mcc204-mnc04-es/strings.xml new file mode 100644 index 0000000000..cac5b23bd9 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-et/strings.xml b/Tethering/res/values-mcc204-mnc04-et/strings.xml new file mode 100644 index 0000000000..ff8dde5422 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc204-mnc04-eu/strings.xml b/Tethering/res/values-mcc204-mnc04-eu/strings.xml new file mode 100644 index 0000000000..1758a4fada --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc204-mnc04-fa/strings.xml b/Tethering/res/values-mcc204-mnc04-fa/strings.xml new file mode 100644 index 0000000000..79e3ef11d6 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc204-mnc04-fi/strings.xml b/Tethering/res/values-mcc204-mnc04-fi/strings.xml new file mode 100644 index 0000000000..64921bca9f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml b/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml new file mode 100644 index 0000000000..eda7b59761 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc204-mnc04-fr/strings.xml b/Tethering/res/values-mcc204-mnc04-fr/strings.xml new file mode 100644 index 0000000000..eda7b59761 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc204-mnc04-gl/strings.xml b/Tethering/res/values-mcc204-mnc04-gl/strings.xml new file mode 100644 index 0000000000..c163c61fbd --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-gu/strings.xml b/Tethering/res/values-mcc204-mnc04-gu/strings.xml new file mode 100644 index 0000000000..0f4d26afdd --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc204-mnc04-hi/strings.xml b/Tethering/res/values-mcc204-mnc04-hi/strings.xml new file mode 100644 index 0000000000..a2442009b5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc204-mnc04-hr/strings.xml b/Tethering/res/values-mcc204-mnc04-hr/strings.xml new file mode 100644 index 0000000000..41618afb2e --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc204-mnc04-hu/strings.xml b/Tethering/res/values-mcc204-mnc04-hu/strings.xml new file mode 100644 index 0000000000..39b7a6975b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc204-mnc04-hy/strings.xml b/Tethering/res/values-mcc204-mnc04-hy/strings.xml new file mode 100644 index 0000000000..c14ae10ad1 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc204-mnc04-in/strings.xml b/Tethering/res/values-mcc204-mnc04-in/strings.xml new file mode 100644 index 0000000000..4998474a36 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc204-mnc04-is/strings.xml b/Tethering/res/values-mcc204-mnc04-is/strings.xml new file mode 100644 index 0000000000..82a7d01234 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc204-mnc04-it/strings.xml b/Tethering/res/values-mcc204-mnc04-it/strings.xml new file mode 100644 index 0000000000..a10d511c17 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc204-mnc04-iw/strings.xml b/Tethering/res/values-mcc204-mnc04-iw/strings.xml new file mode 100644 index 0000000000..80807bc232 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc204-mnc04-ja/strings.xml b/Tethering/res/values-mcc204-mnc04-ja/strings.xml new file mode 100644 index 0000000000..0e21a7f322 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc204-mnc04-ka/strings.xml b/Tethering/res/values-mcc204-mnc04-ka/strings.xml new file mode 100644 index 0000000000..6d3b548744 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc204-mnc04-kk/strings.xml b/Tethering/res/values-mcc204-mnc04-kk/strings.xml new file mode 100644 index 0000000000..985fc3ff99 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc204-mnc04-km/strings.xml b/Tethering/res/values-mcc204-mnc04-km/strings.xml new file mode 100644 index 0000000000..03b5cb6e4b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc204-mnc04-kn/strings.xml b/Tethering/res/values-mcc204-mnc04-kn/strings.xml new file mode 100644 index 0000000000..0427a77659 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc204-mnc04-ko/strings.xml b/Tethering/res/values-mcc204-mnc04-ko/strings.xml new file mode 100644 index 0000000000..9218e9a09b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc204-mnc04-ky/strings.xml b/Tethering/res/values-mcc204-mnc04-ky/strings.xml new file mode 100644 index 0000000000..bc3d555597 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc204-mnc04-lo/strings.xml b/Tethering/res/values-mcc204-mnc04-lo/strings.xml new file mode 100644 index 0000000000..06dcbcbccc --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc204-mnc04-lt/strings.xml b/Tethering/res/values-mcc204-mnc04-lt/strings.xml new file mode 100644 index 0000000000..db5178bf2d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc204-mnc04-lv/strings.xml b/Tethering/res/values-mcc204-mnc04-lv/strings.xml new file mode 100644 index 0000000000..c712173ca2 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc204-mnc04-mk/strings.xml b/Tethering/res/values-mcc204-mnc04-mk/strings.xml new file mode 100644 index 0000000000..aa4490912b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc204-mnc04-ml/strings.xml b/Tethering/res/values-mcc204-mnc04-ml/strings.xml new file mode 100644 index 0000000000..0ef956a5a4 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc204-mnc04-mn/strings.xml b/Tethering/res/values-mcc204-mnc04-mn/strings.xml new file mode 100644 index 0000000000..417213f543 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc204-mnc04-mr/strings.xml b/Tethering/res/values-mcc204-mnc04-mr/strings.xml new file mode 100644 index 0000000000..2ed153fb17 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc204-mnc04-ms/strings.xml b/Tethering/res/values-mcc204-mnc04-ms/strings.xml new file mode 100644 index 0000000000..50817fd4a2 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc204-mnc04-my/strings.xml b/Tethering/res/values-mcc204-mnc04-my/strings.xml new file mode 100644 index 0000000000..c0d70e3d5f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc204-mnc04-nb/strings.xml b/Tethering/res/values-mcc204-mnc04-nb/strings.xml new file mode 100644 index 0000000000..1e7f1c6d0a --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc204-mnc04-ne/strings.xml b/Tethering/res/values-mcc204-mnc04-ne/strings.xml new file mode 100644 index 0000000000..fadd357ebf --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc204-mnc04-nl/strings.xml b/Tethering/res/values-mcc204-mnc04-nl/strings.xml new file mode 100644 index 0000000000..bf14a0fced --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc204-mnc04-or/strings.xml b/Tethering/res/values-mcc204-mnc04-or/strings.xml new file mode 100644 index 0000000000..1cdfce04d8 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc204-mnc04-pa/strings.xml b/Tethering/res/values-mcc204-mnc04-pa/strings.xml new file mode 100644 index 0000000000..93402c35d0 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc204-mnc04-pl/strings.xml b/Tethering/res/values-mcc204-mnc04-pl/strings.xml new file mode 100644 index 0000000000..8becd0715f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml b/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml new file mode 100644 index 0000000000..8e01736f64 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml b/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml new file mode 100644 index 0000000000..2356379e2f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-pt/strings.xml b/Tethering/res/values-mcc204-mnc04-pt/strings.xml new file mode 100644 index 0000000000..8e01736f64 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc204-mnc04-ro/strings.xml b/Tethering/res/values-mcc204-mnc04-ro/strings.xml new file mode 100644 index 0000000000..2e62bd611c --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc204-mnc04-ru/strings.xml b/Tethering/res/values-mcc204-mnc04-ru/strings.xml new file mode 100644 index 0000000000..69f8c59613 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc204-mnc04-si/strings.xml b/Tethering/res/values-mcc204-mnc04-si/strings.xml new file mode 100644 index 0000000000..632748a3e8 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc204-mnc04-sk/strings.xml b/Tethering/res/values-mcc204-mnc04-sk/strings.xml new file mode 100644 index 0000000000..247fc1b0e7 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc204-mnc04-sl/strings.xml b/Tethering/res/values-mcc204-mnc04-sl/strings.xml new file mode 100644 index 0000000000..ed22372197 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc204-mnc04-sq/strings.xml b/Tethering/res/values-mcc204-mnc04-sq/strings.xml new file mode 100644 index 0000000000..4bfab6e474 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc204-mnc04-sr/strings.xml b/Tethering/res/values-mcc204-mnc04-sr/strings.xml new file mode 100644 index 0000000000..478d53a255 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc204-mnc04-sv/strings.xml b/Tethering/res/values-mcc204-mnc04-sv/strings.xml new file mode 100644 index 0000000000..a793ed6483 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc204-mnc04-sw/strings.xml b/Tethering/res/values-mcc204-mnc04-sw/strings.xml new file mode 100644 index 0000000000..3fe09fc22a --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc204-mnc04-ta/strings.xml b/Tethering/res/values-mcc204-mnc04-ta/strings.xml new file mode 100644 index 0000000000..63c28c6702 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc204-mnc04-te/strings.xml b/Tethering/res/values-mcc204-mnc04-te/strings.xml new file mode 100644 index 0000000000..2cf579ca0e --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc204-mnc04-th/strings.xml b/Tethering/res/values-mcc204-mnc04-th/strings.xml new file mode 100644 index 0000000000..3837002b29 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc204-mnc04-tl/strings.xml b/Tethering/res/values-mcc204-mnc04-tl/strings.xml new file mode 100644 index 0000000000..208f893447 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc204-mnc04-tr/strings.xml b/Tethering/res/values-mcc204-mnc04-tr/strings.xml new file mode 100644 index 0000000000..3482fafa2d --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc204-mnc04-uk/strings.xml b/Tethering/res/values-mcc204-mnc04-uk/strings.xml new file mode 100644 index 0000000000..dea311443f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc204-mnc04-ur/strings.xml b/Tethering/res/values-mcc204-mnc04-ur/strings.xml new file mode 100644 index 0000000000..09bc0c9eab --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc204-mnc04-uz/strings.xml b/Tethering/res/values-mcc204-mnc04-uz/strings.xml new file mode 100644 index 0000000000..5231c5fff5 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc204-mnc04-vi/strings.xml b/Tethering/res/values-mcc204-mnc04-vi/strings.xml new file mode 100644 index 0000000000..bf4ee1011b --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml new file mode 100644 index 0000000000..38c2563638 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml new file mode 100644 index 0000000000..3bb52e491f --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml new file mode 100644 index 0000000000..298c3eac70 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc204-mnc04-zu/strings.xml b/Tethering/res/values-mcc204-mnc04-zu/strings.xml new file mode 100644 index 0000000000..3dc0078834 --- /dev/null +++ b/Tethering/res/values-mcc204-mnc04-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml new file mode 100644 index 0000000000..8f16cd19ac --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml new file mode 100644 index 0000000000..d064fd81d5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml new file mode 100644 index 0000000000..e5e7e5e03d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml new file mode 100644 index 0000000000..5bcadfd7fc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml new file mode 100644 index 0000000000..41c018eec1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..8acc587975 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml new file mode 100644 index 0000000000..b03379a899 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml new file mode 100644 index 0000000000..122bdb69c6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml new file mode 100644 index 0000000000..d5ee1a91ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml new file mode 100644 index 0000000000..ae86e0aa8e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml new file mode 100644 index 0000000000..9c46426601 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml new file mode 100644 index 0000000000..66e4dfb3da --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml new file mode 100644 index 0000000000..04a48a77c4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml new file mode 100644 index 0000000000..a9136784e9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml new file mode 100644 index 0000000000..19be3c7077 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml new file mode 100644 index 0000000000..b844c09c62 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml new file mode 100644 index 0000000000..6384e89ce0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml new file mode 100644 index 0000000000..d4b6937881 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml new file mode 100644 index 0000000000..158fd86296 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml new file mode 100644 index 0000000000..271f82ad6a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml new file mode 100644 index 0000000000..7a2b99e028 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml new file mode 100644 index 0000000000..b370e0fd81 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml new file mode 100644 index 0000000000..da86391ee9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml new file mode 100644 index 0000000000..6ffd8116e8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml new file mode 100644 index 0000000000..6ffd8116e8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml new file mode 100644 index 0000000000..9e7f00cbe0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml new file mode 100644 index 0000000000..e85c00c648 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml new file mode 100644 index 0000000000..b6faa3a0f7 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml new file mode 100644 index 0000000000..86b58ded22 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml new file mode 100644 index 0000000000..27ddabf29d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml new file mode 100644 index 0000000000..abdb207626 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml new file mode 100644 index 0000000000..513d2fb040 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml new file mode 100644 index 0000000000..f4e5dd4ad3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml new file mode 100644 index 0000000000..b82363270b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml new file mode 100644 index 0000000000..0922ee9e4d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml new file mode 100644 index 0000000000..63ddc476e6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml new file mode 100644 index 0000000000..4f20c76a12 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml new file mode 100644 index 0000000000..11e293416b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml new file mode 100644 index 0000000000..b8d94d40a3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml new file mode 100644 index 0000000000..3e8aaebbe9 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml new file mode 100644 index 0000000000..59de04c55d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml new file mode 100644 index 0000000000..7ecb6970e7 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml new file mode 100644 index 0000000000..5d1766707c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml new file mode 100644 index 0000000000..aa15bfe1f5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml new file mode 100644 index 0000000000..1e0d2f1c6f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml new file mode 100644 index 0000000000..5fe2a49af6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml new file mode 100644 index 0000000000..930ffa184e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml new file mode 100644 index 0000000000..462e73f7a4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml new file mode 100644 index 0000000000..b1d9b8505b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml new file mode 100644 index 0000000000..936629ca14 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml new file mode 100644 index 0000000000..052df883eb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml new file mode 100644 index 0000000000..09012cbfec --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml new file mode 100644 index 0000000000..e1770b3f77 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml new file mode 100644 index 0000000000..912290cb67 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml new file mode 100644 index 0000000000..6a842428e0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml new file mode 100644 index 0000000000..bb1479d3fb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml new file mode 100644 index 0000000000..51d5c3fd7e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml new file mode 100644 index 0000000000..6e605797d0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml new file mode 100644 index 0000000000..79957977dc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml new file mode 100644 index 0000000000..6e605797d0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml new file mode 100644 index 0000000000..7be2f72195 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml new file mode 100644 index 0000000000..6ab396d50d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml new file mode 100644 index 0000000000..357dd904ac --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml new file mode 100644 index 0000000000..276e5797ee --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml new file mode 100644 index 0000000000..884bddd292 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml new file mode 100644 index 0000000000..a2caddf667 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml new file mode 100644 index 0000000000..7745923331 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml new file mode 100644 index 0000000000..906862aa17 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml new file mode 100644 index 0000000000..0eb922fff6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml new file mode 100644 index 0000000000..1d66c6d689 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml new file mode 100644 index 0000000000..2ee0fa8dda --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml new file mode 100644 index 0000000000..44114e5891 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml new file mode 100644 index 0000000000..440999014c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml new file mode 100644 index 0000000000..d21ad95181 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml new file mode 100644 index 0000000000..e7b8c68eb1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml new file mode 100644 index 0000000000..08edfcffeb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml new file mode 100644 index 0000000000..9def0a1b06 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml new file mode 100644 index 0000000000..e4f818bf42 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml new file mode 100644 index 0000000000..cee4682e7d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml new file mode 100644 index 0000000000..05321db9f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml new file mode 100644 index 0000000000..57b9e0de3b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml new file mode 100644 index 0000000000..7e899705af --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml new file mode 100644 index 0000000000..6fc432256a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -0,0 +1,25 @@ + + + + + "Warmkol het nie internet nie" + "Toestelle kan nie aan internet koppel nie" + "Skakel warmkol af" + "Warmkol is aan" + "Bykomende heffings kan geld terwyl jy swerf" + "Gaan voort" + diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml new file mode 100644 index 0000000000..749cb54022 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -0,0 +1,25 @@ + + + + + "መገናኛ ነጥቡ በይነመረብ የለውም" + "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" + "መገናኛ ነጥብ ያጥፉ" + "የመገናኛ ነጥብ በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + "ቀጥል" + diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml new file mode 100644 index 0000000000..9460023663 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "متابعة" + diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml new file mode 100644 index 0000000000..e18e4ec67d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -0,0 +1,25 @@ + + + + + "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" + "হটস্পট অফ কৰক" + "হটস্পট অন হৈ আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + "অব্যাহত ৰাখক" + diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml new file mode 100644 index 0000000000..77740cb6c6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotun internetə girişi yoxdur" + "Cihazlar internetə qoşula bilmir" + "Hotspot\'u deaktiv edin" + "Hotspot aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + "Davam edin" + diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..7170c06662 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nema pristup internetu" + "Uređaji ne mogu da se povežu na internet" + "Isključi hotspot" + "Hotspot je uključen" + "Možda važe dodatni troškovi u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml new file mode 100644 index 0000000000..7388d218fd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хот-спот не падключаны да інтэрнэту" + "Прылады не могуць падключацца да інтэрнэту" + "Выключыць хот-спот" + "Хот-спот уключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + "Працягнуць" + diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml new file mode 100644 index 0000000000..aa7a40bfa1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката за достъп няма връзка с интернет" + "Устройствата не могат да се свържат с интернет" + "Изключване на точката за достъп" + "Точката за достъп е включена" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + "Напред" + diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml new file mode 100644 index 0000000000..00bac782ed --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "চালিয়ে যান" + diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml new file mode 100644 index 0000000000..907821260b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Pristupna tačka nema internet" + "Uređaji se ne mogu povezati na internet" + "Isključi pristupnu tačku" + "Pristupna tačka je uključena" + "Primjenjuju se dodatne tarife u romingu" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml new file mode 100644 index 0000000000..43c9e137bb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punt d\'accés Wi‑Fi no té accés a Internet" + "Els dispositius no es poden connectar a Internet" + "Desactiva el punt d\'accés Wi‑Fi" + "El punt d\'accés Wi‑Fi està activat" + "És possible que s\'apliquin costos addicionals en itinerància" + "Continua" + diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml new file mode 100644 index 0000000000..c9210f7f40 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá připojení k internetu" + "Zařízení se nemohou připojit k internetu" + "Vypnout hotspot" + "Hotspot je aktivní" + "Při roamingu mohou být účtovány dodatečné poplatky" + "Pokračovat" + diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml new file mode 100644 index 0000000000..3615ff49ff --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspottet har intet internet" + "Enheder kan ikke oprette forbindelse til internettet" + "Deaktiver hotspot" + "Hotspottet er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + "Fortsæt" + diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml new file mode 100644 index 0000000000..ee8809d80b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot ist nicht mit dem Internet verbunden" + "Geräte können nicht mit dem Internet verbunden werden" + "Hotspot deaktivieren" + "Hotspot aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + "Weiter" + diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml new file mode 100644 index 0000000000..3a79be8735 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -0,0 +1,25 @@ + + + + + "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." + "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." + "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" + "Σημείο πρόσβασης Wi-Fi ενεργό" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + "Συνέχεια" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml new file mode 100644 index 0000000000..4c7de17998 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot has no Internet" + "Devices can’t connect to Internet" + "Turn off hotspot" + "Hotspot is on" + "Additional charges may apply while roaming" + "Continue" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml new file mode 100644 index 0000000000..2daad6ad1c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎Turn off hotspot‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml new file mode 100644 index 0000000000..68d5fc26de --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -0,0 +1,25 @@ + + + + + "El hotspot no tiene Internet" + "Los dispositivos no pueden conectarse a Internet" + "Desactiva el hotspot" + "El hotspot está activado" + "Es posible que apliquen cargos adicionales por roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml new file mode 100644 index 0000000000..930e088642 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -0,0 +1,25 @@ + + + + + "El punto de acceso no tiene conexión a Internet" + "Los dispositivos no se pueden conectar a Internet" + "Desactivar punto de acceso" + "Zona Wi-Fi activada" + "Puede que se apliquen cargos adicionales en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml new file mode 100644 index 0000000000..e59e12e71d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -0,0 +1,25 @@ + + + + + "Kuumkohal puudub Interneti-ühendus" + "Seadmed ei saa Internetiga ühendust luua" + "Lülita kuumkoht välja" + "Kuumkoht on sees" + "Rändluse kasutamisega võivad kaasneda lisatasud" + "Jätka" + diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml new file mode 100644 index 0000000000..4358266323 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -0,0 +1,25 @@ + + + + + "Sare publikoak ez du Interneteko konexiorik" + "Gailuak ezin dira konektatu Internetera" + "Desaktibatu sare publikoa" + "Sare publikoa aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Egin aurrera" + diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml new file mode 100644 index 0000000000..a2324d84f0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -0,0 +1,25 @@ + + + + + "نقطه اتصال به اینترنت دسترسی ندارد" + "دستگاه‌ها به اینترنت متصل نشدند" + "نقطه اتصال را خاموش کنید" + "نقطه اتصال روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + "ادامه" + diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml new file mode 100644 index 0000000000..ec6ac929fb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotilla ei ole internetyhteyttä" + "Laitteet eivät voi yhdistää internetiin" + "Laita hotspot pois päältä" + "Hotspot on päällä" + "Roaming voi aiheuttaa lisämaksuja" + "Jatka" + diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml new file mode 100644 index 0000000000..eeaf8f3ad4 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml new file mode 100644 index 0000000000..eeaf8f3ad4 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Le point d\'accès n\'est pas connecté à Internet" + "Appareils non connectés à Internet" + "Désactiver le point d\'accès" + "Le point d\'accès est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + "Continuer" + diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml new file mode 100644 index 0000000000..56b3a9b79d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona wifi non ten acceso a Internet" + "Os dispositivos non se poden conectar a Internet" + "Desactivar zona wifi" + "A zona wifi está activada" + "Pódense aplicar cargos adicionais en itinerancia" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml new file mode 100644 index 0000000000..c2af9a6688 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "આગળ વધો" + diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml new file mode 100644 index 0000000000..8bb5fb29ae --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉट से इंटरनेट नहीं चल रहा" + "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" + "हॉटस्पॉट बंद करें" + "हॉटस्पॉट चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + "जारी रखें" + diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml new file mode 100644 index 0000000000..551b1b36fe --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Žarišna točka nema pristup internetu" + "Uređaji se ne mogu povezati s internetom" + "Isključi žarišnu točku" + "Žarišna je točka uključena" + "U roamingu su mogući dodatni troškovi" + "Nastavi" + diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml new file mode 100644 index 0000000000..4113195c19 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -0,0 +1,25 @@ + + + + + "A hotspot nem csatlakozik az internethez" + "Az eszközök nem tudnak csatlakozni az internethez" + "Hotspot kikapcsolása" + "A hotspot be van kapcsolva" + "Roaming során további díjak léphetnek fel" + "Tovább" + diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml new file mode 100644 index 0000000000..393eac056c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -0,0 +1,25 @@ + + + + + "Թեժ կետը միացված չէ ինտերնետին" + "Սարքերը չեն կարողանում միանալ ինտերնետին" + "Անջատել թեժ կետը" + "Թեժ կետը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + "Շարունակել" + diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml new file mode 100644 index 0000000000..e2538328cf --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot tidak memiliki internet" + "Perangkat tidak dapat tersambung ke internet" + "Nonaktifkan hotspot" + "Hotspot aktif" + "Biaya tambahan mungkin berlaku saat roaming" + "Lanjutkan" + diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml new file mode 100644 index 0000000000..d28383f51b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -0,0 +1,25 @@ + + + + + "Heitur reitur er ekki nettengdur" + "Tæki geta ekki tengst við internetið" + "Slökkva á heitum reit" + "Kveikt er á heitum reit" + "Viðbótargjöld kunna að eiga við í reiki" + "Halda áfram" + diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml new file mode 100644 index 0000000000..388aa7a2c5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -0,0 +1,25 @@ + + + + + "L\'hotspot non ha accesso a Internet" + "I dispositivi non possono connettersi a Internet" + "Disattiva l\'hotspot" + "Hotspot attivo" + "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Continua" + diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml new file mode 100644 index 0000000000..bbc379501c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -0,0 +1,25 @@ + + + + + "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" + "המכשירים לא יכולים להתחבר לאינטרנט" + "כיבוי הנקודה לשיתוף אינטרנט" + "הנקודה לשיתוף אינטרנט פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + "המשך" + diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml new file mode 100644 index 0000000000..d7cb66b1dd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -0,0 +1,25 @@ + + + + + "アクセス ポイントがインターネットに接続されていません" + "デバイスをインターネットに接続できません" + "アクセス ポイントを OFF にする" + "アクセス ポイント: ON" + "ローミング時に追加料金が発生することがあります" + "続行" + diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml new file mode 100644 index 0000000000..9651a563bd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -0,0 +1,25 @@ + + + + + "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ უკავშირდება ინტერნეტს" + "გამორთეთ უსადენო ქსელი" + "უსადენო ქსელი ჩართულია" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + "გაგრძელება" + diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml new file mode 100644 index 0000000000..f2db66b11e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспотта интернет жоқ" + "Құрылғылар интернетке қосылмайды" + "Хотспотты өшіру" + "Хотспот қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + "Жалғастыру" + diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml new file mode 100644 index 0000000000..16699c5a0a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -0,0 +1,25 @@ + + + + + "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" + "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" + "បិទ​ហតស្ប៉ត" + "ហតស្ប៉ត​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + "បន្ត" + diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml new file mode 100644 index 0000000000..3c75b1205b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ಮುಂದುವರಿಸಿ" + diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml new file mode 100644 index 0000000000..3892bc36a9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -0,0 +1,25 @@ + + + + + "핫스팟이 인터넷에 연결되지 않음" + "기기를 인터넷에 연결할 수 없음" + "핫스팟 사용 중지" + "핫스팟 사용 중" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + "계속" + diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml new file mode 100644 index 0000000000..85e92e0a3c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспоттун Интернети жок" + "Түзмөктөр Интернетке туташпай жатат" + "Туташуу түйүнүн өчүрүү" + "Кошулуу түйүнү күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + "Улантуу" + diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml new file mode 100644 index 0000000000..881e05c5e0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ສືບຕໍ່" + diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml new file mode 100644 index 0000000000..83aabd176f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -0,0 +1,25 @@ + + + + + "Nėra viešosios interneto prieigos taško interneto ryšio" + "Įrenginiams nepavyksta prisijungti prie interneto" + "Išjungti viešosios interneto prieigos tašką" + "Viešosios interneto prieigos taškas įjungtas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + "Tęsti" + diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml new file mode 100644 index 0000000000..83feb11f8a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tīklājam nav interneta savienojuma" + "Ierīces nevar izveidot savienojumu ar internetu" + "Izslēgt tīklāju" + "Tīklājs ir ieslēgts" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + "Tālāk" + diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml new file mode 100644 index 0000000000..040e2a5d8e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точката на пристап нема интернет" + "Уредите не може да се поврзат на интернет" + "Исклучи ја точката на пристап" + "Точката на пристап е вклучена" + "При роаминг може да се наплатат дополнителни трошоци" + "Продолжи" + diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml new file mode 100644 index 0000000000..c9b12cd706 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "തുടരുക" + diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml new file mode 100644 index 0000000000..e5a845051d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -0,0 +1,25 @@ + + + + + "Сүлжээний цэг дээр интернэт алга байна" + "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" + "Сүлжээний цэгийг унтраах" + "Сүлжээний цэг асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + "Үргэлжлүүлэх" + diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml new file mode 100644 index 0000000000..c7f1cc6c66 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + "हॉटस्पॉटला इंटरनेट नाही" + "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" + "हॉटस्पॉट बंद करा" + "हॉटस्पॉट सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + "सुरू ठेवा" + diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml new file mode 100644 index 0000000000..35d36f69f1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -0,0 +1,25 @@ + + + + + "Tempat liputan tiada Internet" + "Peranti tidak dapat menyambung kepada Internet" + "Matikan tempat liputan" + "Tempat liputan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + "Teruskan" + diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml new file mode 100644 index 0000000000..bc374725ae --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -0,0 +1,25 @@ + + + + + "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" + "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" + "ဟော့စပေါ့ ပိတ်ရန်" + "ဟော့စပေါ့ ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + "ရှေ့ဆက်ရန်" + diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml new file mode 100644 index 0000000000..413e165c0f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -0,0 +1,25 @@ + + + + + "Wi-Fi-sonen har ikke internettilgang" + "Enheter kan ikke koble til internett" + "Slå av Wi-Fi-sonen" + "Wi-Fi-sonen er på" + "Ytterligere kostnader kan påløpe under roaming" + "Fortsett" + diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml new file mode 100644 index 0000000000..9b2256abfc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "जारी राख्नुहोस्" + diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml new file mode 100644 index 0000000000..7f7f39187f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot heeft geen internet" + "Apparaten kunnen geen verbinding maken met internet" + "Hotspot uitschakelen" + "Hotspot is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + "Doorgaan" + diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml new file mode 100644 index 0000000000..b478d1393b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ଜାରି ରଖନ୍ତୁ" + diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml new file mode 100644 index 0000000000..e0940a518d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "ਜਾਰੀ ਰੱਖੋ" + diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml new file mode 100644 index 0000000000..c578b278d9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nie ma internetu" + "Urządzenia nie mogą połączyć się z internetem" + "Wyłącz hotspot" + "Hotspot jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + "Dalej" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml new file mode 100644 index 0000000000..502b5ddb7d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml new file mode 100644 index 0000000000..a477516145 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -0,0 +1,25 @@ + + + + + "A zona Wi-Fi não tem Internet" + "Não é possível ligar os dispositivos à Internet" + "Desativar zona Wi-Fi" + "A zona Wi-Fi está ativada" + "Podem aplicar-se custos adicionais em roaming." + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml new file mode 100644 index 0000000000..502b5ddb7d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -0,0 +1,25 @@ + + + + + "O ponto de acesso não tem conexão com a Internet" + "Não foi possível conectar os dispositivos à Internet" + "Desativar ponto de acesso" + "O ponto de acesso está ativado" + "Pode haver cobranças extras durante o roaming" + "Continuar" + diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml new file mode 100644 index 0000000000..d6808b04e6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspotul nu are internet" + "Dispozitivele nu se pot conecta la internet" + "Dezactivați hotspotul" + "Hotspotul este activ" + "Se pot aplica taxe suplimentare pentru roaming" + "Continuați" + diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml new file mode 100644 index 0000000000..22dcfcf42d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступа не подключена к Интернету" + "Не удается подключить устройства к Интернету" + "Отключить точку доступа" + "Точка доступа включена" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + "Продолжить" + diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml new file mode 100644 index 0000000000..5008b7326c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -0,0 +1,25 @@ + + + + + "හොට්ස්පොට් හට අන්තර්ජාලය නැත" + "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" + "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + "ඉදිරියට යන්න" + diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml new file mode 100644 index 0000000000..010677d1d6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot nemá internetové pripojenie" + "Zariadenia sa nedajú pripojiť k internetu" + "Vypnúť hotspot" + "Hotspot je zapnutý" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + "Pokračovať" + diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml new file mode 100644 index 0000000000..3662ca9e2a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Dostopna točka nima internetne povezave" + "Naprave ne morejo vzpostaviti internetne povezave" + "Izklopi dostopno točko" + "Dostopna točka je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + "Naprej" + diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml new file mode 100644 index 0000000000..5453d54fd9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + "Zona e qasjes për internet nuk ka internet" + "Pajisjet nuk mund të lidhen me internetin" + "Çaktivizo zonën e qasjes për internet" + "Zona e qasjes për internet është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + "Vazhdo" + diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml new file mode 100644 index 0000000000..f52cbf387e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Хотспот нема приступ интернету" + "Уређаји не могу да се повежу на интернет" + "Искључи хотспот" + "Хотспот је укључен" + "Можда важе додатни трошкови у ромингу" + "Настави" + diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml new file mode 100644 index 0000000000..8474342f26 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -0,0 +1,25 @@ + + + + + "Surfzonen har ingen internetanslutning" + "Enheterna har ingen internetanslutning" + "Inaktivera surfzon" + "Surfzonen är aktiverad" + "Ytterligare avgifter kan tillkomma vid roaming" + "Fortsätt" + diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml new file mode 100644 index 0000000000..5a812e3f0c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -0,0 +1,25 @@ + + + + + "Mtandao pepe hauna intaneti" + "Vifaa vimeshindwa kuunganisha kwenye intaneti" + "Zima mtandao pepe" + "Mtandaopepe umewashwa" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + "Endelea" + diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml new file mode 100644 index 0000000000..315403135d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "தொடர்க" + diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml new file mode 100644 index 0000000000..414def5963 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "కొనసాగించు" + diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml new file mode 100644 index 0000000000..a26ac0403b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -0,0 +1,25 @@ + + + + + "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" + "ปิดฮอตสปอต" + "ฮอตสปอตเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + "ต่อไป" + diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml new file mode 100644 index 0000000000..6e98146cd5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -0,0 +1,25 @@ + + + + + "Walang internet ang hotspot" + "Hindi makakonekta sa internet ang mga device" + "I-off ang hotspot" + "Naka-on ang hotspot" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + "Ituloy" + diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml new file mode 100644 index 0000000000..423bd76689 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -0,0 +1,25 @@ + + + + + "Hotspot\'un internet bağlantısı yok" + "Cihazlar internete bağlanamıyor" + "Hotspot\'u kapat" + "Hotspot açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + "Devam" + diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml new file mode 100644 index 0000000000..193b3c348b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -0,0 +1,25 @@ + + + + + "Точка доступу не підключена до Інтернету" + "Не вдається підключити пристрої до Інтернету" + "Вимкнути точку доступу" + "Точку доступу ввімкнено" + "У роумінгу може стягуватися додаткова плата" + "Продовжити" + diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml new file mode 100644 index 0000000000..3564ead361 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" + "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" + "ہاٹ اسپاٹ آف کریں" + "ہاٹ اسپاٹ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + "جاری رکھیں" + diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml new file mode 100644 index 0000000000..769cc2c385 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + "Davom etish" + diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml new file mode 100644 index 0000000000..998ebe4d7b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -0,0 +1,25 @@ + + + + + "Điểm phát sóng không có kết nối Internet" + "Các thiết bị không thể kết nối Internet" + "Tắt điểm phát sóng" + "Điểm phát sóng đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + "Tiếp tục" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml new file mode 100644 index 0000000000..75786086b6 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -0,0 +1,25 @@ + + + + + "热点无法访问互联网" + "设备无法连接到互联网" + "关闭热点" + "热点已开启" + "漫游时可能会产生额外的费用" + "继续" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml new file mode 100644 index 0000000000..7f7453c306 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -0,0 +1,25 @@ + + + + + "熱點沒有互聯網連線" + "裝置無法連線至互聯網" + "關閉熱點" + "已開啟熱點" + "漫遊時可能需要支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml new file mode 100644 index 0000000000..4b4afc017e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -0,0 +1,25 @@ + + + + + "無線基地台沒有網際網路連線" + "裝置無法連上網際網路" + "關閉無線基地台" + "無線基地台已開啟" + "使用漫遊服務可能須支付額外費用" + "繼續" + diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml new file mode 100644 index 0000000000..48ac295ebc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -0,0 +1,25 @@ + + + + + "I-Hotspot ayina-inthanethi" + "Amadivayisi awakwazi ukuxhuma ku-inthanethi" + "Vala i-hotspot" + "I-Hotspot ivuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + "Qhubeka" + diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 0fab8aa476..04f0fa8c71 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -1,8 +1,31 @@ + + - "Поврзувањето или точката на пристап се активни" - "Допрете за поставување." - "Врзувањето е оневозможено" - "Контактирајте со администраторот за детали" + "Активно е врзување или точка на пристап" + "Допрете за поставување." + + "Врзувањето е оневозможено" + "Контактирајте со администраторот за детали" + "Статус на точката на пристап и врзувањето" + + + + + + diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index fd7e556e38..2d14f8e0f5 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -1,8 +1,31 @@ + + - "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" - "സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" - "വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" + "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." + + "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" + "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" + + + + + + diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4596577c5d..4f3334c8e3 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -1,8 +1,31 @@ + + - "Модем болгох эсвэл идэвхтэй цэг болгох" - "Тохируулахын тулд товшино уу." - "Модем болгох боломжгүй байна" - "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" + "Тохируулахын тулд товшино уу." + + "Модем болгохыг идэвхгүй болгосон" + "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Сүлжээний цэг болон модем болгох төлөв" + + + + + + diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index 85c9ade4fe..ba9f324982 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -1,8 +1,31 @@ + + - "टेदरिंग किंवा हॉटस्पॉट सक्रिय" - "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद आहे" - "तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा" + "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" + "सेट करण्यासाठी टॅप करा." + + "टेदरिंग बंद केले आहे" + "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" + "हॉटस्पॉट आणि टेदरिंगची स्थिती" + + + + + + diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index ec6bdbda08..c343e311f4 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -1,8 +1,31 @@ + + - "Penambatan atau titik panas aktif" - "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" - "Hubungi pentadbir anda untuk maklumat lanjut" + "Penambatan atau tempat liputan aktif" + "Ketik untuk membuat persediaan." + + "Penambatan dilumpuhkan" + "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" + "Status tempat liputan & penambatan" + + + + + + diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 83978b67d4..84bcdb4c07 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -1,8 +1,31 @@ + + - "တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" - "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်" - "အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" + "စနစ်ထည့်သွင်းရန် တို့ပါ။" + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" + "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" + + + + + + diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 9abf32dd7b..877c128c2d 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -1,8 +1,31 @@ + + - "Internettdeling eller trådløs sone er aktiv" - "Trykk for å konfigurere." - "Internettdeling er slått av" - "Ta kontakt med administratoren din for å få mer informasjon" + "Internettdeling eller Wi-Fi-sone er aktiv" + "Trykk for å konfigurere." + + "Internettdeling er slått av" + "Ta kontakt med administratoren din for å få mer informasjon" + "Status for Wi-Fi-sone og internettdeling" + + + + + + diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index c8869298a5..d50fe240c4 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -1,8 +1,31 @@ + + - "टेथर गर्ने वा हटस्पट सक्रिय" - "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङलाई असक्षम पारिएको छ" - "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "टेदरिङ वा हटस्पट सक्रिय छ" + "सेटअप गर्न ट्याप गर्नुहोस्।" + + "टेदरिङ सुविधा असक्षम पारिएको छ" + "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "हटस्पट तथा टेदरिङको स्थिति" + + + + + + diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 0ec4bff621..6950c239ab 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering of hotspot actief" - "Tik om in te stellen." - "Tethering is uitgeschakeld" - "Neem contact op met je beheerder voor meer informatie" + "Tethering of hotspot actief" + "Tik om in te stellen." + + "Tethering is uitgeschakeld" + "Neem contact op met je beheerder voor meer informatie" + "Status van hotspot en tethering" + + + + + + diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 457685795a..2500a6f66b 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -1,8 +1,31 @@ + + - "ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି" - "ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।" - "ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି" - "ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" + "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" + + "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" + "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" + + + + + + diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index deddf2ea27..1fd496f968 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -1,8 +1,31 @@ + + - "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" - "ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ" - "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ" + "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" + "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" + + "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" + "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" + + + + + + diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index 48d8468935..df1d5aeffa 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -1,8 +1,31 @@ + + - "Aktywny tethering lub punkt dostępu" - "Kliknij, by skonfigurować." - "Tethering został wyłączony" - "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Aktywny tethering lub punkt dostępu" + "Kliknij, by skonfigurować" + + "Tethering został wyłączony" + "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Hotspot i tethering – stan" + + + + + + diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 32c22b8713..2c3757d6de 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -1,8 +1,31 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + + diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 641e22f44f..5af2d22a57 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -1,8 +1,31 @@ + + - "Ligação ponto a ponto ou hotspot activos" - "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." - "Contacte o gestor para obter detalhes." + "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" + "Toque para configurar." + + "A ligação (à Internet) via telemóvel está desativada." + "Contacte o administrador para obter detalhes." + "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" + + + + + + diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 32c22b8713..2c3757d6de 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -1,8 +1,31 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + + diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index f861f733b4..1dad542d4f 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering sau hotspot activ" - "Atingeți ca să configurați." - "Tetheringul este dezactivat" - "Contactați administratorul pentru detalii" + "Tethering sau hotspot activ" + "Atingeți ca să configurați." + + "Tetheringul este dezactivat" + "Contactați administratorul pentru detalii" + "Starea hotspotului și a tetheringului" + + + + + + diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 027cb410c5..4d31484229 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -1,8 +1,31 @@ + + - "Включен режим модема" - "Нажмите, чтобы настроить." - "Включить режим модема нельзя" - "Обратитесь к администратору, чтобы узнать подробности." + "Включен режим модема или точка доступа" + "Нажмите, чтобы настроить." + + "Использование телефона в качестве модема запрещено" + "Чтобы узнать подробности, обратитесь к администратору." + "Статус хот-спота и режима модема" + + + + + + diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index 7d8599f2c2..d21f2b5388 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -1,8 +1,31 @@ + + - "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" - "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" - "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" + "පිහිටුවීමට තට්ටු කරන්න." + + "ටෙදරින් අබල කර ඇත" + "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" + + + + + + diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index a8fe297c00..f2242b93b3 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering alebo prístupový bod je aktívny" - "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" - "O podrobnosti požiadajte svojho správcu" + "Tethering alebo prístupový bod je aktívny" + "Klepnutím prejdete na nastavenie." + + "Tethering je deaktivovaný" + "O podrobnosti požiadajte svojho správcu" + "Stav hotspotu a tetheringu" + + + + + + diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index b5e5e3856f..c01cace360 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -1,8 +1,31 @@ + + - "Aktivna povezava z internetom ali dostopna točka sta aktivni" - "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" - "Za podrobnosti se obrnite na skrbnika" + "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" + "Dotaknite se, če želite nastaviti." + + "Povezava z internetom prek mobilnega telefona je onemogočena" + "Za podrobnosti se obrnite na skrbnika" + "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" + + + + + + diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index fdd4906cc5..f7e2a7be74 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -1,8 +1,31 @@ + + - "Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive" - "Trokit për ta konfiguruar." - "Lidhja e çiftimit është çaktivizuar" - "Kontakto me administratorin për detaje" + "Ndarja e internetit ose zona e qasjes së internetit është aktive" + "Trokit për ta konfiguruar." + + "Ndarja e internetit është çaktivizuar" + "Kontakto me administratorin për detaje" + "Statusi i zonës së qasjes dhe ndarjes së internetit" + + + + + + diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index 9fab345897..c5f84eb45d 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -1,8 +1,31 @@ + + - "Активно повезивање са интернетом преко мобилног уређаја или хотспот" - "Додирните да бисте подесили." - "Привезивање је онемогућено" - "Потражите детаље од администратора" + "Привезивање или хотспот је активан" + "Додирните да бисте подесили." + + "Привезивање је онемогућено" + "Потражите детаље од администратора" + "Статус хотспота и привезивања" + + + + + + diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index 10eeb0fe12..d745dad2ff 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -1,8 +1,31 @@ + + - "Internetdelning eller surfzon aktiverad" - "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" - "Kontakta administratören om du vill veta mer" + "Internetdelning eller surfzon har aktiverats" + "Tryck om du vill konfigurera." + + "Internetdelning har inaktiverats" + "Kontakta administratören om du vill veta mer" + "Trådlös surfzon och internetdelning har inaktiverats" + + + + + + diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index 3353963077..beaa306374 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -1,8 +1,31 @@ + + - "Kushiriki au kusambaza intaneti kumewashwa" - "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" - "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Kusambaza mtandao au mtandaopepe umewashwa" + "Gusa ili uweke mipangilio." + + "Umezima kipengele cha kusambaza mtandao" + "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Mtandaopepe na hali ya kusambaza mtandao" + + + + + + diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index b1e5cc2413..bc8957e096 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -1,8 +1,31 @@ + + - "டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது" - "அமைக்க, தட்டவும்." - "இணைப்பு முறை முடக்கப்பட்டுள்ளது" - "விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" + "அமைக்க, தட்டவும்." + + "டெதெரிங் முடக்கப்பட்டுள்ளது" + "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" + + + + + + diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index aae40dee40..b7afdb4cad 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -1,8 +1,31 @@ + + - "టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది" - "సెటప్ చేయడానికి నొక్కండి." - "టెథెరింగ్ నిలిపివేయబడింది" - "వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి" + "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" + "సెటప్ చేయడానికి ట్యాప్ చేయండి." + + "టెథరింగ్ డిజేబుల్ చేయబడింది" + "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" + "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" + + + + + + diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index 1b800565ad..e60d43496e 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -1,8 +1,31 @@ + + - "การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่" - "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" - "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" + "แตะเพื่อตั้งค่า" + + "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" + "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + + + + + + diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 12863f90e1..79523bb0f4 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -1,8 +1,31 @@ + + - "Pagsasama o aktibong hotspot" - "I-tap upang i-set up." - "Naka-disable ang pag-tether" - "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Aktibo ang pag-tether o hotspot" + "I-tap para i-set up." + + "Naka-disable ang pag-tether" + "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Status ng hotspot at pag-tether" + + + + + + diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index bfcf1ace2c..cf100a42e2 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -1,8 +1,31 @@ + + - "Tethering veya hotspot etkin" - "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" - "Ayrıntılı bilgi için yöneticinize başvurun" + "Tethering veya hotspot etkin" + "Ayarlamak için dokunun." + + "Tethering devre dışı bırakıldı" + "Ayrıntılı bilgi için yöneticinize başvurun" + "Hotspot ve tethering durumu" + + + + + + diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 8e159c0723..0a8ceddad7 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -1,8 +1,31 @@ + + - "Прив\'язка чи точка дост. активна" - "Торкніться, щоб налаштувати." - "Використання телефона в режимі модема вимкнено" - "Щоб дізнатися більше, зв’яжіться з адміністратором" + "Модем чи точка доступу активні" + "Натисніть, щоб налаштувати." + + "Використання телефона як модема вимкнено" + "Щоб дізнатися більше, зв\'яжіться з адміністратором" + "Статус точки доступу та модема" + + + + + + diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 89195d4aae..043dba3161 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -1,8 +1,31 @@ + + - "ٹیدرنگ یا ہاٹ اسپاٹ فعال" - "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" - "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ٹیدرنگ یا ہاٹ اسپاٹ فعال" + "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" + + "ٹیدرنگ غیر فعال ہے" + "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" + + + + + + diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 0ac4d4a741..5b9d62afd9 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -1,8 +1,31 @@ + + - "Modem rejimi yoniq" - "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" - "Tafsilotlari uchun administratoringizga murojaat qiling" + "Modem rejimi yoki hotspot yoniq" + "Sozlash uchun bosing." + + "Modem rejimi faolsizlantirildi" + "Tafsilotlari uchun administratoringizga murojaat qiling" + "Hotspot va modem rejimi holati" + + + + + + diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 85a4db8aa5..19240700ee 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -1,8 +1,31 @@ + + - "Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động" - "Nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" - "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Tính năng chia sẻ kết nối hoặc điểm phát sóng đang hoạt động" + "Hãy nhấn để thiết lập." + + "Đã tắt tính năng chia sẻ kết nối" + "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Trạng thái điểm phát sóng và trạng thái chia sẻ kết nối" + + + + + + diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index ff1fe03953..d137df5f33 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -1,8 +1,31 @@ + + - "网络共享或热点已启用" - "点按即可进行设置。" - "网络共享已停用" - "请与您的管理员联系以了解详情" + "网络共享或热点已启用" + "点按即可设置。" + + "网络共享已停用" + "如需了解详情,请与您的管理员联系" + "热点和网络共享状态" + + + + + + diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 0de39fac97..12c071091b 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -1,8 +1,31 @@ + + - "已啟用網絡共享或熱點" - "輕按即可設定。" - "網絡共享已停用" - "請聯絡您的管理員以瞭解詳情" + "網絡共享或熱點已啟用" + "輕按即可設定。" + + "網絡共享已停用" + "請聯絡您的管理員以瞭解詳情" + "熱點和網絡共享狀態" + + + + + + diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9a117bbca4..24fb76e824 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -1,8 +1,31 @@ + + - "網路共用或無線基地台已啟用" - "輕觸即可進行設定。" - "數據連線已停用" - "詳情請洽你的管理員" + "數據連線或無線基地台已啟用" + "輕觸即可進行設定。" + + "數據連線已停用" + "詳情請洽你的管理員" + "無線基地台與數據連線狀態" + + + + + + diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index 8fe10d86cb..f4859aa195 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -1,8 +1,31 @@ + + - "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" - "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" - "Xhumana nomphathi wakho ukuze uthole imininingwane" + "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" + "Thepha ukuze usethe." + + "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" + "Xhumana nomphathi wakho ukuze uthole imininingwane" + "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" + + + + + + From 146e767b32b4f73ac5af289d376ef438f655d282 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 30 Mar 2020 08:16:52 -0700 Subject: [PATCH 0881/1415] CtsWifiTests: Move wifi assets over to wifi test suite Bug: 152733292 Test: atest android.net.wifi.cts.ConfigParserTest Test: atest android.net.wifi.cts.PpsMoParserTest Test: atest android.net.wifi.cts.WifiManagerTest Change-Id: I47179210a4074bc9600ee07eaeb12c56f2f7bfc0 --- .../net/assets/HSR1ProfileWithCACert.base64 | 85 ------------------- tests/cts/net/assets/OWNERS | 4 - .../net/assets/PerProviderSubscription.xml | 80 ----------------- .../net/assets/ValidPasspointProfile.base64 | 1 - 4 files changed, 170 deletions(-) delete mode 100644 tests/cts/net/assets/HSR1ProfileWithCACert.base64 delete mode 100644 tests/cts/net/assets/OWNERS delete mode 100644 tests/cts/net/assets/PerProviderSubscription.xml delete mode 100644 tests/cts/net/assets/ValidPasspointProfile.base64 diff --git a/tests/cts/net/assets/HSR1ProfileWithCACert.base64 b/tests/cts/net/assets/HSR1ProfileWithCACert.base64 deleted file mode 100644 index 995963d2b4..0000000000 --- a/tests/cts/net/assets/HSR1ProfileWithCACert.base64 +++ /dev/null @@ -1,85 +0,0 @@ -Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu -dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh -cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6 -IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n -SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo -YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn -UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi -V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ -M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM -MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth -VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt -RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD -QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD -QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD -QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx -bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1 -MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv -Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2 -ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo -YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4 -VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo -YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi -RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj -bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i -MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM -MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy -UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX -eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD -QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD -OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3 -dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0 -S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV -K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G -dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur -TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn -SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2 -WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0 -VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM -MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ -Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi -V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ -a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX -eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD -QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q -VTJSbWx1WjJWeWNISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV -KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG -bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB -OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB -Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4 -VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs -UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn -SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2 -WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk -V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU -bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ -QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94 -LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD -UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR -VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U -bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU -azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V -VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw -TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY -TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T -dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV -RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo -U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK -ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz -M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh -CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX -TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH -U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF -YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk -MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV -akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ -MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD -amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY -ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew -OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX -MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF -MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw -aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG -S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS -a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts -RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo= diff --git a/tests/cts/net/assets/OWNERS b/tests/cts/net/assets/OWNERS deleted file mode 100644 index 14edd1d505..0000000000 --- a/tests/cts/net/assets/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -# Bug component: 31808 -etancohen@google.com -lorenzo@google.com -satk@google.com diff --git a/tests/cts/net/assets/PerProviderSubscription.xml b/tests/cts/net/assets/PerProviderSubscription.xml deleted file mode 100644 index de6c0c6dd2..0000000000 --- a/tests/cts/net/assets/PerProviderSubscription.xml +++ /dev/null @@ -1,80 +0,0 @@ - - 1.2 - - PerProviderSubscription - - - urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0 - - - - i001 - - HomeSP - - FriendlyName - Century House - - - FQDN - mi6.co.uk - - - RoamingConsortiumOI - 112233,445566 - - - - Credential - - Realm - shaken.stirred.com - - - UsernamePassword - - Username - james - - - Password - Ym9uZDAwNw== - - - EAPMethod - - EAPType - 21 - - - InnerMethod - MS-CHAP-V2 - - - - - DigitalCertificate - - CertificateType - x509v3 - - - CertSHA256Fingerprint - 1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f - - - - SIM - - IMSI - imsi - - - EAPType - 24 - - - - - - diff --git a/tests/cts/net/assets/ValidPasspointProfile.base64 b/tests/cts/net/assets/ValidPasspointProfile.base64 deleted file mode 100644 index 3f60eb85cc..0000000000 --- a/tests/cts/net/assets/ValidPasspointProfile.base64 +++ /dev/null @@ -1 +0,0 @@ -Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29nSUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRK0NpQWdQRTV2WkdVK0NpQWdJQ0E4VG05a1pVNWhiV1UrVUdWeVVISnZkbWxrWlhKVGRXSnpZM0pwY0hScGIyNDhMMDV2WkdWT1lXMWxQZ29nSUNBZ1BGSlVVSEp2Y0dWeWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldVK2RYSnVPbmRtWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZM0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZ0lDQWdJQ0E4TDFSNWNHVStDaUFnSUNBOEwxSlVVSEp2Y0dWeWRHbGxjejRLSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0E4VG05a1pVNWhiV1UrYVRBd01Ud3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SWIyMWxVMUE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVStRVlJVSUZCaGMzTndiMmx1ZER3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQa1pSUkU0OEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtRjBkSGRwWm1rdVkyOXRQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrTnlaV1JsYm5ScFlXdzhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEpsWVd4dFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNTNiR0Z1TG0xdVl6UXhNQzV0WTJNek1UQXVNMmR3Y0c1bGRIZHZjbXN1YjNKblBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrVTBsTlBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrU1UxVFNUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lXeDFaVDR6TVRBME1UQXFQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrVkJVRlI1Y0dVOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4V1lXeDFaVDR5TXp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUR3dlRtOWtaVDRLSUNBOEwwNXZaR1UrQ2p3dlRXZHRkRlJ5WldVKwotLXtib3VuZGFyeX0tLQo= From cdc8658403330a5a25cc29950ee54ff51f867619 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Fri, 27 Mar 2020 12:29:18 +0000 Subject: [PATCH 0882/1415] Feed framework-tethering-stubs the src filegroup This filegroups strips the "src" prefix away from the src path for the filter_packages check in droiddoc. Bug: 149293194 Test: m update-api (no change) Change-Id: I5b9ffa211be9c1a7dd8f63d5e7ba2a825d0d3190 Merged-In: I5b9ffa211be9c1a7dd8f63d5e7ba2a825d0d3190 --- Tethering/common/TetheringLib/Android.bp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 6af5fe54f2..31c40d2a33 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -65,12 +65,7 @@ java_library { stubs_defaults { name: "framework-tethering-stubs-defaults", - srcs: [ - "src/android/net/TetheredClient.java", - "src/android/net/TetheringManager.java", - "src/android/net/TetheringConstants.java", - ], - libs: ["tethering-aidl-interfaces-java"], + srcs: [":framework-tethering-srcs"], } filegroup { From 4175676eab8c4a327bfcf3df84a8a31808aada84 Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 31 Mar 2020 14:53:20 +0800 Subject: [PATCH 0883/1415] Fix EntitlementManager issues 1. Add TETHERING_ETHERNET to vaild downstream type. So starting ethernet tethering will do entitlement check as well. 2. Ignore request with invalid downstream type on handleRequestLatestTetheringEntitlementValue() Bug: 152828758 Bug: 152828142 Test: atests TetheringTests CtsTetheringTest Change-Id: Id0cb59cc4681f5ffbde7be54de05a05e46f0ffb8 --- .../tethering/EntitlementManager.java | 7 ++++ .../tethering/EntitlementManagerTest.java | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java index bd60594f27..639cf65d79 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java @@ -20,6 +20,7 @@ import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_INVALID; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; @@ -537,6 +538,7 @@ public class EntitlementManager { private static boolean isValidDownstreamType(int type) { switch (type) { case TETHERING_BLUETOOTH: + case TETHERING_ETHERNET: case TETHERING_USB: case TETHERING_WIFI: return true; @@ -650,6 +652,11 @@ public class EntitlementManager { private void handleRequestLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver, boolean showEntitlementUi) { + if (!isValidDownstreamType(downstream)) { + receiver.send(TETHER_ERROR_ENTITLEMENT_UNKNOWN, null); + return; + } + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); if (!isTetherProvisioningRequired(config)) { receiver.send(TETHER_ERROR_NO_ERROR, null); diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java index 0a7850b680..b3a30abca6 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -17,8 +17,10 @@ package com.android.server.connectivity.tethering; import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; @@ -353,6 +355,20 @@ public final class EntitlementManagerTest { callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); + // 8. Test get value for invalid downstream type. + mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; + receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode); + mCallbacklatch.countDown(); + } + }; + mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI_P2P, receiver, true); + mLooper.dispatchAll(); + callbackTimeoutHelper(mCallbacklatch); + assertEquals(0, mEnMgr.uiProvisionCount); + mEnMgr.reset(); } void callbackTimeoutHelper(final CountDownLatch latch) throws Exception { @@ -471,6 +487,22 @@ public final class EntitlementManagerTest { mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(3, mEnMgr.silentProvisionCount); + assertFalse(mEnMgr.isCellularUpstreamPermitted()); + mEnMgr.reset(); + // 7. start ui provisioning, upstream is mobile, downstream is ethernet + mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; + mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true); + mLooper.dispatchAll(); + assertEquals(1, mEnMgr.uiProvisionCount); + assertEquals(0, mEnMgr.silentProvisionCount); + assertTrue(mEnMgr.isCellularUpstreamPermitted()); + mEnMgr.reset(); + // 8. downstream is invalid + mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; + mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true); + mLooper.dispatchAll(); + assertEquals(0, mEnMgr.uiProvisionCount); + assertEquals(0, mEnMgr.silentProvisionCount); mEnMgr.reset(); } From ff1b6ec2dc8c2b8313f5f9a4e6fa8d5c5d20cec9 Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 3 Mar 2020 10:35:16 +0800 Subject: [PATCH 0884/1415] Add a cts test for PermissionMonitor security problem Add a cts test to check whether app can have netd sytem permission even the app didn't grant the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. Bug: 144679405 Test: atest android.net.cts.ConnectivityManagerTest Change-Id: I2c717a11bda43db166a55d343eb752ab45947fe8 Merged-In: I2c717a11bda43db166a55d343eb752ab45947fe8 (cherry picked from commit ag/10285567) --- tests/cts/net/AndroidManifest.xml | 1 + .../net/cts/ConnectivityManagerTest.java | 45 ++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index c2b3bf77ad..267b05f7af 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -26,6 +26,7 @@ + diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index fa7e1381b3..ae3def6633 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,13 +16,17 @@ package android.net.cts; +import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.content.pm.PackageManager.FEATURE_ETHERNET; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; -import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.content.pm.PackageManager.FEATURE_USB_HOST; +import static android.content.pm.PackageManager.FEATURE_WIFI; +import static android.content.pm.PackageManager.GET_PERMISSIONS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver; import static android.net.cts.util.CtsNetUtils.HTTP_PORT; @@ -45,6 +49,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.ConnectivityManager; @@ -59,10 +64,12 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; +import android.net.NetworkUtils; import android.net.SocketKeepalive; import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; +import android.os.Binder; import android.os.Build; import android.os.Looper; import android.os.MessageQueue; @@ -78,6 +85,8 @@ import android.util.Pair; import androidx.test.InstrumentationRegistry; +import com.android.internal.util.ArrayUtils; + import libcore.io.Streams; import java.io.FileDescriptor; @@ -1272,4 +1281,38 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue("" + greater + " expected to be greater than or equal to " + lesser, greater >= lesser); } + + /** + * Verifies that apps are not allowed to access restricted networks even if they declare the + * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests. + * See. b/144679405. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + public void testRestrictedNetworkPermission() throws Exception { + // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package. + final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(), + GET_PERMISSIONS); + final int index = ArrayUtils.indexOf( + app.requestedPermissions, CONNECTIVITY_USE_RESTRICTED_NETWORKS); + assertTrue(index >= 0); + assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED); + + // Ensure that NetworkUtils.queryUserAccess always returns false since this package should + // not have netd system permission to call this function. + final Network wifiNetwork = ensureWifiConnected(); + assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId)); + + // Ensure that this package cannot bind to any restricted network that's currently + // connected. + Network[] networks = mCm.getAllNetworks(); + for (Network network : networks) { + NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { + try { + network.bindSocket(new Socket()); + fail("Bind to restricted network " + network + " unexpectedly succeeded"); + } catch (IOException expected) {} + } + } + } } From ae7a0709b3370e6033c37a048752a854d40ebea0 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 26 Mar 2020 23:44:34 +0800 Subject: [PATCH 0885/1415] Add TetheringRequest CTS tests Test APIs below: TetheringRequest.getClientStaticIpv4Address() TetheringRequest.getLocalIpv4Address() TetheringRequest.getShouldShowEntitlementUi() TetheringRequest.getTetheringType() TetheringRequest.isExemptFromEntitlementCheck() TetheringRequest.Builder(int) TetheringRequest.Builder.build() TetheringRequest.Builder.setExemptFromEntitlementCheck(boolean) TetheringRequest.Builder.setShouldShowEntitlementUi(boolean) TetheringRequest.Builder.setStaticIpv4Addresses( \ android.net.LinkAddress, android.net.LinkAddress) Bug: 150632842 Test: atest CtsTetheringTest Change-Id: Ice5aefa1bacc1a635a7a79ce91d5d30ec5dcf335 --- .../tethering/cts/TetheringManagerTest.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 4d72eae3e4..86fe54ce54 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,17 +15,22 @@ */ package android.tethering.test; +import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.LinkAddress; import android.net.TetheringManager; import android.net.TetheringManager.TetheringRequest; -import android.os.ConditionVariable; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -37,8 +42,6 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; -import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -225,4 +228,27 @@ public class TetheringManagerTest { mTM.stopTethering(TETHERING_WIFI); mTetherChangeReceiver.expectNoActiveTethering(DEFAULT_TIMEOUT_MS); } + + @Test + public void testTetheringRequest() { + final TetheringRequest tr = new TetheringRequest.Builder(TETHERING_WIFI).build(); + assertEquals(TETHERING_WIFI, tr.getTetheringType()); + assertNull(tr.getLocalIpv4Address()); + assertNull(tr.getClientStaticIpv4Address()); + assertFalse(tr.isExemptFromEntitlementCheck()); + assertTrue(tr.getShouldShowEntitlementUi()); + + final LinkAddress localAddr = new LinkAddress("192.168.24.5/24"); + final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24"); + final TetheringRequest tr2 = new TetheringRequest.Builder(TETHERING_USB) + .setStaticIpv4Addresses(localAddr, clientAddr) + .setExemptFromEntitlementCheck(true) + .setShouldShowEntitlementUi(false).build(); + + assertEquals(localAddr, tr2.getLocalIpv4Address()); + assertEquals(clientAddr, tr2.getClientStaticIpv4Address()); + assertEquals(TETHERING_USB, tr2.getTetheringType()); + assertTrue(tr2.isExemptFromEntitlementCheck()); + assertFalse(tr2.getShouldShowEntitlementUi()); + } } From d4bff6cd28f96f5ab399643b52c45ebc7513dd54 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 31 Mar 2020 12:53:18 -0700 Subject: [PATCH 0886/1415] Remove tests from vts suite After vts-core is renamed to vts, the CTS tests won't be needed in vts suite. Bug: 151896491 Test: local build Exempt-From-Owner-Approval: This CL removes all CTS tests in vts suite, as vts is renamed to vts10. This CL won't change test logic or behavior. Change-Id: Idc9e9cc1d1080ff689823671a736bbb78bd7a740 --- tests/cts/hostside/Android.bp | 1 - tests/cts/hostside/app/Android.bp | 1 - tests/cts/hostside/app2/Android.bp | 1 - tests/cts/net/Android.bp | 1 - tests/cts/net/api23Test/Android.bp | 1 - tests/cts/net/appForApi23/Android.bp | 1 - tests/cts/net/native/qtaguid/Android.bp | 1 - 7 files changed, 7 deletions(-) diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp index a8cc95ba5f..741c961e5f 100644 --- a/tests/cts/hostside/Android.bp +++ b/tests/cts/hostside/Android.bp @@ -24,7 +24,6 @@ java_test_host { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index 8b6d38b821..7a1145609f 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp @@ -35,7 +35,6 @@ android_test_helper_app { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp index 0bb0d2f631..a6e9b118ff 100644 --- a/tests/cts/hostside/app2/Android.bp +++ b/tests/cts/hostside/app2/Android.bp @@ -23,7 +23,6 @@ android_test_helper_app { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index d77f416557..76bb27e448 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -64,7 +64,6 @@ android_test { defaults: ["CtsNetTestCasesDefaults"], test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index 614a5a2a76..ffeef48a88 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -45,7 +45,6 @@ android_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/net/appForApi23/Android.bp b/tests/cts/net/appForApi23/Android.bp index 17cfe3821b..399c199508 100644 --- a/tests/cts/net/appForApi23/Android.bp +++ b/tests/cts/net/appForApi23/Android.bp @@ -26,7 +26,6 @@ android_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/net/native/qtaguid/Android.bp b/tests/cts/net/native/qtaguid/Android.bp index 054937b4fa..23a0cf764d 100644 --- a/tests/cts/net/native/qtaguid/Android.bp +++ b/tests/cts/net/native/qtaguid/Android.bp @@ -42,7 +42,6 @@ cc_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", ], From 21793bad185f1d2054c0fee90a82d40b7287a11f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 9 Mar 2020 21:22:04 +0900 Subject: [PATCH 0887/1415] Add a first NetworkAgent CTS test This is a basic test that only tests register(), markConnected(), unregister and onNetworkUnwanted. It provides the backbone for the tests, a harness to test callbacks on NetworkAgent, and demonstrates how the instrumentation in ConnectivityService can be used to test this API. Test: this Bug: 139268426 Change-Id: I022c9e237fdaec27338047c171c04e5a96cf89e3 --- tests/cts/net/AndroidManifest.xml | 5 + .../net/cts/IpSecManagerTunnelTest.java | 3 +- .../src/android/net/cts/NetworkAgentTest.kt | 142 ++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/NetworkAgentTest.kt diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index c2b3bf77ad..baf914f1ac 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -35,6 +35,11 @@ + + diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 999d2f187b..1d83dda33c 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -192,9 +192,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Build a network request NetworkRequest nr = new NetworkRequest.Builder() + .clearCapabilities() .addTransportType(TRANSPORT_TEST) - .removeCapability(NET_CAPABILITY_TRUSTED) - .removeCapability(NET_CAPABILITY_NOT_VPN) .setNetworkSpecifier(ifname) .build(); diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt new file mode 100644 index 0000000000..85c94e7db2 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -0,0 +1,142 @@ +/* + * 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 android.app.Instrumentation +import android.content.Context +import android.net.ConnectivityManager +import android.net.LinkProperties +import android.net.NetworkAgent +import android.net.NetworkAgentConfig +import android.net.NetworkCapabilities +import android.net.NetworkProvider +import android.net.NetworkRequest +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted +import android.os.Build +import android.os.HandlerThread +import android.os.Looper +import androidx.test.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.ArrayTrackRecord +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.RecorderCallback.CallbackEntry.Lost +import com.android.testutils.TestableNetworkCallback +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +// This test doesn't really have a constraint on how fast the methods should return. If it's +// going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio +// without affecting the run time of successful runs. Thus, set a very high timeout. +private const val DEFAULT_TIMEOUT_MS = 5000L +// Any legal score (0~99) for the test network would do, as it is going to be kept up by the +// requests filed by the test and should never match normal internet requests. 70 is the default +// score of Ethernet networks, it's as good a value as any other. +private const val TEST_NETWORK_SCORE = 70 +private val instrumentation: Instrumentation + get() = InstrumentationRegistry.getInstrumentation() +private val context: Context + get() = InstrumentationRegistry.getContext() + +@RunWith(AndroidJUnit4::class) +class NetworkAgentTest { + @Rule @JvmField + val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) + + private val mCM = context.getSystemService(ConnectivityManager::class.java) + private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") + + private class Provider(context: Context, looper: Looper) : + NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") + + @Before + fun setUp() { + instrumentation.getUiAutomation().adoptShellPermissionIdentity() + mHandlerThread.start() + } + + @After + fun tearDown() { + mHandlerThread.quitSafely() + instrumentation.getUiAutomation().dropShellPermissionIdentity() + } + + internal class TestableNetworkAgent( + looper: Looper, + nc: NetworkCapabilities, + lp: LinkProperties, + conf: NetworkAgentConfig + ) : NetworkAgent(context, looper, TestableNetworkAgent::class.java.simpleName /* tag */, + nc, lp, TEST_NETWORK_SCORE, conf, Provider(context, looper)) { + private val history = ArrayTrackRecord().newReadHead() + + sealed class CallbackEntry { + object OnNetworkUnwanted : CallbackEntry() + } + + override fun onNetworkUnwanted() { + super.onNetworkUnwanted() + history.add(OnNetworkUnwanted) + } + + inline fun expectCallback() { + val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) + assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") + } + } + + private fun createNetworkAgent(): TestableNetworkAgent { + val nc = NetworkCapabilities().apply { + addTransportType(NetworkCapabilities.TRANSPORT_TEST) + removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + } + val lp = LinkProperties() + val config = NetworkAgentConfig.Builder().build() + return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config) + } + + private fun createConnectedNetworkAgent(): Pair { + val request: NetworkRequest = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) + mCM.requestNetwork(request, callback) + val agent = createNetworkAgent().also { it.register() } + agent.markConnected() + return agent to callback + } + + @Test + fun testConnectAndUnregister() { + val (agent, callback) = createConnectedNetworkAgent() + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.unregister() + callback.expectCallback(agent.network) + agent.expectCallback() + assertFailsWith("Must not be able to register an agent twice") { + agent.register() + } + } +} From cfd82d436184dd7454cabe8c6bf8f6e38a23ceca Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 28 Mar 2020 00:48:07 +0900 Subject: [PATCH 0888/1415] Add a test for static IPv4 address tethering configuration. Bug: 150644681 Test: test-only change Change-Id: I8f4a99da2351fdb5467f561a9732b14a8ebf674b --- .../android/net/EthernetTetheringTest.java | 129 +++++++++++++++--- 1 file changed, 109 insertions(+), 20 deletions(-) diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index 492ce3db34..dbd68ef77c 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -18,6 +18,7 @@ package android.net; import static android.Manifest.permission.MANAGE_TEST_NETWORKS; import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.net.TetheringManager.TETHERING_ETHERNET; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -57,6 +58,7 @@ import org.junit.runner.RunWith; import java.io.FileDescriptor; import java.net.Inet4Address; +import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.nio.ByteBuffer; @@ -66,6 +68,7 @@ import java.util.Random; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; @RunWith(AndroidJUnit4.class) @MediumTest @@ -110,7 +113,7 @@ public class EthernetTetheringTest { } private void cleanUp() throws Exception { - mTm.stopTethering(TetheringManager.TETHERING_ETHERNET); + mTm.stopTethering(TETHERING_ETHERNET); if (mTetheringEventCallback != null) { mTetheringEventCallback.awaitInterfaceUntethered(); mTetheringEventCallback.unregister(); @@ -176,6 +179,49 @@ public class EthernetTetheringTest { checkVirtualEthernet(mTestIface, getMTU(mTestIface)); } + @Test + public void testStaticIpv4() throws Exception { + assumeFalse(mEm.isAvailable()); + + mEm.setIncludeTestInterfaces(true); + + mTestIface = createTestInterface(); + + final String iface = mTetheredInterfaceRequester.getInterface(); + assertEquals("TetheredInterfaceCallback for unexpected interface", + mTestIface.getInterfaceName(), iface); + + assertInvalidStaticIpv4Request(iface, null, null); + assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64"); + assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28"); + assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28"); + assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null); + assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28"); + assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28"); + + final String localAddr = "192.0.2.3/28"; + final String clientAddr = "192.0.2.2/28"; + mTetheringEventCallback = enableEthernetTethering(iface, + requestWithStaticIpv4(localAddr, clientAddr)); + + mTetheringEventCallback.awaitInterfaceTethered(); + assertInterfaceHasIpAddress(iface, clientAddr); + + byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray(); + byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray(); + + FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor(); + mTapPacketReader = makePacketReader(fd, getMTU(mTestIface)); + DhcpResults dhcpResults = runDhcp(fd, client1); + assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress); + + try { + runDhcp(fd, client2); + fail("Only one client should get an IP address"); + } catch (TimeoutException expected) { } + + } + @Test public void testPhysicalEthernet() throws Exception { assumeTrue(mEm.isAvailable()); @@ -271,7 +317,8 @@ public class EthernetTetheringTest { } } - private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception { + private MyTetheringEventCallback enableEthernetTethering(String iface, + TetheringRequest request) throws Exception { MyTetheringEventCallback callback = new MyTetheringEventCallback(mTm, iface); mTm.registerTetheringEventCallback(mHandler::post, callback); @@ -282,34 +329,37 @@ public class EthernetTetheringTest { } }; Log.d(TAG, "Starting Ethernet tethering"); - mTm.startTethering( - new TetheringRequest.Builder(TetheringManager.TETHERING_ETHERNET).build(), - mHandler::post /* executor */, startTetheringCallback); + mTm.startTethering(request, mHandler::post /* executor */, startTetheringCallback); callback.awaitInterfaceTethered(); return callback; } + private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception { + return enableEthernetTethering(iface, + new TetheringRequest.Builder(TETHERING_ETHERNET).build()); + } + private int getMTU(TestNetworkInterface iface) throws SocketException { NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName()); assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif); return nif.getMTU(); } + private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) { + final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu); + mHandler.post(() -> reader.start()); + HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS); + return reader; + } + private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception { FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor(); - mTapPacketReader = new TapPacketReader(mHandler, fd, mtu); - mHandler.post(() -> mTapPacketReader.start()); - HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS); - + mTapPacketReader = makePacketReader(fd, mtu); mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName()); checkTetheredClientCallbacks(fd); } - private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception { - // Create a fake client. - byte[] clientMacAddr = new byte[6]; - new Random().nextBytes(clientMacAddr); - + private DhcpResults runDhcp(FileDescriptor fd, byte[] clientMacAddr) throws Exception { // We have to retransmit DHCP requests because IpServer declares itself to be ready before // its DhcpServer is actually started. TODO: fix this race and remove this loop. DhcpPacket offerPacket = null; @@ -319,13 +369,25 @@ public class EthernetTetheringTest { offerPacket = getNextDhcpPacket(); if (offerPacket instanceof DhcpOfferPacket) break; } - assertTrue("No DHCPOFFER received on interface within timeout", - offerPacket instanceof DhcpOfferPacket); + if (!(offerPacket instanceof DhcpOfferPacket)) { + throw new TimeoutException("No DHCPOFFER received on interface within timeout"); + } sendDhcpRequest(fd, offerPacket, clientMacAddr); DhcpPacket ackPacket = getNextDhcpPacket(); - assertTrue("No DHCPACK received on interface within timeout", - ackPacket instanceof DhcpAckPacket); + if (!(ackPacket instanceof DhcpAckPacket)) { + throw new TimeoutException("No DHCPACK received on interface within timeout"); + } + + return ackPacket.toDhcpResults(); + } + + private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception { + // Create a fake client. + byte[] clientMacAddr = new byte[6]; + new Random().nextBytes(clientMacAddr); + + DhcpResults dhcpResults = runDhcp(fd, clientMacAddr); final Collection clients = mTetheringEventCallback.awaitClientConnected(); assertEquals(1, clients.size()); @@ -333,7 +395,7 @@ public class EthernetTetheringTest { // Check the MAC address. assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress()); - assertEquals(TetheringManager.TETHERING_ETHERNET, client.getTetheringType()); + assertEquals(TETHERING_ETHERNET, client.getTetheringType()); // Check the hostname. assertEquals(1, client.getAddresses().size()); @@ -341,7 +403,6 @@ public class EthernetTetheringTest { assertEquals(DHCP_HOSTNAME, info.getHostname()); // Check the address is the one that was handed out in the DHCP ACK. - DhcpResults dhcpResults = offerPacket.toDhcpResults(); assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress()); // Check that the lifetime is correct +/- 10s. @@ -441,6 +502,34 @@ public class EthernetTetheringTest { assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope()); } + private TetheringRequest requestWithStaticIpv4(String local, String client) { + LinkAddress localAddr = local == null ? null : new LinkAddress(local); + LinkAddress clientAddr = client == null ? null : new LinkAddress(client); + return new TetheringRequest.Builder(TETHERING_ETHERNET) + .setStaticIpv4Addresses(localAddr, clientAddr).build(); + } + + private void assertInvalidStaticIpv4Request(String iface, String local, String client) + throws Exception { + try { + enableEthernetTethering(iface, requestWithStaticIpv4(local, client)); + fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client); + } catch (IllegalArgumentException | NullPointerException expected) { } + } + + private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception { + LinkAddress expectedAddr = new LinkAddress(expected); + NetworkInterface nif = NetworkInterface.getByName(iface); + for (InterfaceAddress ia : nif.getInterfaceAddresses()) { + final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength()); + if (expectedAddr.equals(addr)) { + return; + } + } + fail("Expected " + iface + " to have IP address " + expected + ", found " + + nif.getInterfaceAddresses()); + } + private TestNetworkInterface createTestInterface() throws Exception { TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); TestNetworkInterface iface = tnm.createTapInterface(); From a2686116292edaa8e25a0997251721778ad7d845 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Thu, 2 Apr 2020 19:14:44 +0000 Subject: [PATCH 0889/1415] Add TetheringRequest CTS tests Test APIs below: TetheringRequest.getClientStaticIpv4Address() TetheringRequest.getLocalIpv4Address() TetheringRequest.getShouldShowEntitlementUi() TetheringRequest.getTetheringType() TetheringRequest.isExemptFromEntitlementCheck() TetheringRequest.Builder(int) TetheringRequest.Builder.build() TetheringRequest.Builder.setExemptFromEntitlementCheck(boolean) TetheringRequest.Builder.setShouldShowEntitlementUi(boolean) TetheringRequest.Builder.setStaticIpv4Addresses( \ android.net.LinkAddress, android.net.LinkAddress) Bug: 150632842 Test: atest CtsTetheringTest Change-Id: Ice5aefa1bacc1a635a7a79ce91d5d30ec5dcf335 Merged-In: Ice5aefa1bacc1a635a7a79ce91d5d30ec5dcf335 (cherry picked from commit 3780b3720ca19063e0d4c0372422f3105dc5bb86) --- .../tethering/cts/TetheringManagerTest.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 4d72eae3e4..86fe54ce54 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,17 +15,22 @@ */ package android.tethering.test; +import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.LinkAddress; import android.net.TetheringManager; import android.net.TetheringManager.TetheringRequest; -import android.os.ConditionVariable; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -37,8 +42,6 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; -import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -225,4 +228,27 @@ public class TetheringManagerTest { mTM.stopTethering(TETHERING_WIFI); mTetherChangeReceiver.expectNoActiveTethering(DEFAULT_TIMEOUT_MS); } + + @Test + public void testTetheringRequest() { + final TetheringRequest tr = new TetheringRequest.Builder(TETHERING_WIFI).build(); + assertEquals(TETHERING_WIFI, tr.getTetheringType()); + assertNull(tr.getLocalIpv4Address()); + assertNull(tr.getClientStaticIpv4Address()); + assertFalse(tr.isExemptFromEntitlementCheck()); + assertTrue(tr.getShouldShowEntitlementUi()); + + final LinkAddress localAddr = new LinkAddress("192.168.24.5/24"); + final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24"); + final TetheringRequest tr2 = new TetheringRequest.Builder(TETHERING_USB) + .setStaticIpv4Addresses(localAddr, clientAddr) + .setExemptFromEntitlementCheck(true) + .setShouldShowEntitlementUi(false).build(); + + assertEquals(localAddr, tr2.getLocalIpv4Address()); + assertEquals(clientAddr, tr2.getClientStaticIpv4Address()); + assertEquals(TETHERING_USB, tr2.getTetheringType()); + assertTrue(tr2.isExemptFromEntitlementCheck()); + assertFalse(tr2.getShouldShowEntitlementUi()); + } } From 5c22928658f73e720dbebd31f9c8ad9d728bb12f Mon Sep 17 00:00:00 2001 From: evitayan Date: Sun, 8 Mar 2020 18:26:51 -0700 Subject: [PATCH 0890/1415] Create build files for CtsIkeTestCases Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I2f49fc12314ac648e8df816058d599033c822dca --- tests/cts/net/ipsec/Android.bp | 46 +++++++++++++++++++ tests/cts/net/ipsec/AndroidManifest.xml | 39 ++++++++++++++++ tests/cts/net/ipsec/AndroidTest.xml | 30 ++++++++++++ .../net/ipsec/ike/cts/SaProposalTest.java | 30 ++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 tests/cts/net/ipsec/Android.bp create mode 100644 tests/cts/net/ipsec/AndroidManifest.xml create mode 100644 tests/cts/net/ipsec/AndroidTest.xml create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp new file mode 100644 index 0000000000..86969c31ae --- /dev/null +++ b/tests/cts/net/ipsec/Android.bp @@ -0,0 +1,46 @@ +// 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. + +android_test { + name: "CtsIkeTestCases", + defaults: ["cts_defaults"], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", + + libs: [ + "android.net.ipsec.ike.stubs.system", + "android.test.base.stubs", + ], + + srcs: [ + "src/**/*.java", + ], + + static_libs: [ + "androidx.test.ext.junit", + "compatibility-device-util-axt", + "ctstestrunner-axt", + ], + + platform_apis: true, + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "mts", + "vts", + "general-tests", + ], +} diff --git a/tests/cts/net/ipsec/AndroidManifest.xml b/tests/cts/net/ipsec/AndroidManifest.xml new file mode 100644 index 0000000000..de7d23cbd5 --- /dev/null +++ b/tests/cts/net/ipsec/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cts/net/ipsec/AndroidTest.xml b/tests/cts/net/ipsec/AndroidTest.xml new file mode 100644 index 0000000000..09e5c93cf8 --- /dev/null +++ b/tests/cts/net/ipsec/AndroidTest.xml @@ -0,0 +1,30 @@ + + + diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java new file mode 100644 index 0000000000..47e8f0174d --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java @@ -0,0 +1,30 @@ +/* + * 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.ipsec.ike.cts; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SaProposalTest { + @Test + public void testBuildIkeSaProposal() { + // TODO(b/148689509): Add real tests here + } +} From 03dfb41f8cd8bd0a5bde2a884d355fdb82d0be9f Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 3 Apr 2020 23:08:47 +0000 Subject: [PATCH 0891/1415] Create build files for CtsIkeTestCases Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I2f49fc12314ac648e8df816058d599033c822dca Merged-In: I2f49fc12314ac648e8df816058d599033c822dca (cherry picked from commit aead83c98a09c70a20e034474c4b4a4995cc3bac) --- tests/cts/net/ipsec/Android.bp | 46 +++++++++++++++++++ tests/cts/net/ipsec/AndroidManifest.xml | 39 ++++++++++++++++ tests/cts/net/ipsec/AndroidTest.xml | 30 ++++++++++++ .../net/ipsec/ike/cts/SaProposalTest.java | 30 ++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 tests/cts/net/ipsec/Android.bp create mode 100644 tests/cts/net/ipsec/AndroidManifest.xml create mode 100644 tests/cts/net/ipsec/AndroidTest.xml create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp new file mode 100644 index 0000000000..86969c31ae --- /dev/null +++ b/tests/cts/net/ipsec/Android.bp @@ -0,0 +1,46 @@ +// 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. + +android_test { + name: "CtsIkeTestCases", + defaults: ["cts_defaults"], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", + + libs: [ + "android.net.ipsec.ike.stubs.system", + "android.test.base.stubs", + ], + + srcs: [ + "src/**/*.java", + ], + + static_libs: [ + "androidx.test.ext.junit", + "compatibility-device-util-axt", + "ctstestrunner-axt", + ], + + platform_apis: true, + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "mts", + "vts", + "general-tests", + ], +} diff --git a/tests/cts/net/ipsec/AndroidManifest.xml b/tests/cts/net/ipsec/AndroidManifest.xml new file mode 100644 index 0000000000..de7d23cbd5 --- /dev/null +++ b/tests/cts/net/ipsec/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cts/net/ipsec/AndroidTest.xml b/tests/cts/net/ipsec/AndroidTest.xml new file mode 100644 index 0000000000..09e5c93cf8 --- /dev/null +++ b/tests/cts/net/ipsec/AndroidTest.xml @@ -0,0 +1,30 @@ + + + diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java new file mode 100644 index 0000000000..47e8f0174d --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java @@ -0,0 +1,30 @@ +/* + * 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.ipsec.ike.cts; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SaProposalTest { + @Test + public void testBuildIkeSaProposal() { + // TODO(b/148689509): Add real tests here + } +} From beb28405b14ec4e20849741a190e75b9f28b584e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 3 Apr 2020 22:05:14 +0900 Subject: [PATCH 0892/1415] Migrate to TetherOffloadRuleParcel in IpServer The netd tethering offload IPCs are changing from taking a list of primitives to taking a TetherOffloadRuleParcel. Modify their only caller. Bug: 140541991 Test: atest IpServerTest Change-Id: I83718c80ef9d31199c87021b4dd5821717fd5ba5 --- Tethering/src/android/net/ip/IpServer.java | 20 +++- .../unit/src/android/net/ip/IpServerTest.java | 109 +++++++++++++----- 2 files changed, 95 insertions(+), 34 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 82b17acae5..69885d04bf 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -34,6 +34,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.RouteInfo; +import android.net.TetherOffloadRuleParcel; import android.net.TetheredClient; import android.net.TetheringManager; import android.net.TetheringRequestParcel; @@ -280,6 +281,19 @@ public class IpServer extends StateMachine { return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac, dstMac); } + + // Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream() + // would be error-prone due to generated stable AIDL classes not having a copy constructor. + public TetherOffloadRuleParcel toTetherOffloadRuleParcel() { + final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel(); + parcel.inputInterfaceIndex = upstreamIfindex; + parcel.outputInterfaceIndex = downstreamIfindex; + parcel.destination = address.getAddress(); + parcel.prefixLength = 128; + parcel.srcL2Address = srcMac.toByteArray(); + parcel.dstL2Address = dstMac.toByteArray(); + return parcel; + } } private final LinkedHashMap mIpv6ForwardingRules = new LinkedHashMap<>(); @@ -824,9 +838,7 @@ public class IpServer extends StateMachine { private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) { try { - mNetd.tetherRuleAddDownstreamIpv6(mInterfaceParams.index, rule.upstreamIfindex, - rule.address.getAddress(), mInterfaceParams.macAddr.toByteArray(), - rule.dstMac.toByteArray()); + mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel()); mIpv6ForwardingRules.put(rule.address, rule); } catch (RemoteException | ServiceSpecificException e) { mLog.e("Could not add IPv6 downstream rule: ", e); @@ -835,7 +847,7 @@ public class IpServer extends StateMachine { private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) { try { - mNetd.tetherRuleRemoveDownstreamIpv6(rule.upstreamIfindex, rule.address.getAddress()); + mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel()); if (removeFromMap) { mIpv6ForwardingRules.remove(rule.address); } diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 3106e0e5e1..fdfdae837d 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -43,7 +43,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; @@ -66,6 +65,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.RouteInfo; +import android.net.TetherOffloadRuleParcel; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpServer; import android.net.dhcp.IDhcpServerCallbacks; @@ -85,6 +85,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; import org.mockito.Captor; import org.mockito.InOrder; import org.mockito.Mock; @@ -92,6 +93,7 @@ import org.mockito.MockitoAnnotations; import java.net.Inet4Address; import java.net.InetAddress; +import java.util.Arrays; @RunWith(AndroidJUnit4.class) @SmallTest @@ -514,6 +516,65 @@ public class IpServerTest { mLooper.dispatchAll(); } + /** + * Custom ArgumentMatcher for TetherOffloadRuleParcel. This is needed because generated stable + * AIDL classes don't have equals(), so we cannot just use eq(). A custom assert, such as: + * + * private void checkFooCalled(StableParcelable p, ...) { + * ArgumentCaptor captor = ArgumentCaptor.forClass(FooParam.class); + * verify(mMock).foo(captor.capture()); + * Foo foo = captor.getValue(); + * assertFooMatchesExpectations(foo); + * } + * + * almost works, but not quite. This is because if the code under test calls foo() twice, the + * first call to checkFooCalled() matches both the calls, putting both calls into the captor, + * and then fails with TooManyActualInvocations. It also makes it harder to use other mockito + * features such as never(), inOrder(), etc. + * + * This approach isn't great because if the match fails, the error message is unhelpful + * (actual: "android.net.TetherOffloadRuleParcel@8c827b0" or some such), but at least it does + * work. + * + * See ConnectivityServiceTest#assertRoutesAdded for an alternative approach which solves the + * TooManyActualInvocations problem described above by forcing the caller of the custom assert + * method to specify all expected invocations in one call. This is useful when the stable + * parcelable class being asserted on has a corresponding Java object (eg., RouteInfo and + * RouteInfoParcelable), and the caller can just pass in a list of them. It not useful here + * because there is no such object. + */ + private static class TetherOffloadRuleParcelMatcher implements + ArgumentMatcher { + public final int upstreamIfindex; + public final InetAddress dst; + public final MacAddress dstMac; + + TetherOffloadRuleParcelMatcher(int upstreamIfindex, InetAddress dst, MacAddress dstMac) { + this.upstreamIfindex = upstreamIfindex; + this.dst = dst; + this.dstMac = dstMac; + } + + public boolean matches(TetherOffloadRuleParcel parcel) { + return upstreamIfindex == parcel.inputInterfaceIndex + && (TEST_IFACE_PARAMS.index == parcel.outputInterfaceIndex) + && Arrays.equals(dst.getAddress(), parcel.destination) + && (128 == parcel.prefixLength) + && Arrays.equals(TEST_IFACE_PARAMS.macAddr.toByteArray(), parcel.srcL2Address) + && Arrays.equals(dstMac.toByteArray(), parcel.dstL2Address); + } + + public String toString() { + return String.format("TetherOffloadRuleParcelMatcher(%d, %s, %s", + upstreamIfindex, dst.getHostAddress(), dstMac); + } + } + + private TetherOffloadRuleParcel matches( + int upstreamIfindex, InetAddress dst, MacAddress dstMac) { + return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac)); + } + @Test public void addRemoveipv6ForwardingRules() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */); @@ -537,13 +598,11 @@ public class IpServerTest { // Events on this interface are received and sent to netd. recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); - verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), - eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray())); + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); reset(mNetd); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); - verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), - eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); reset(mNetd); // Link-local and multicast neighbors are ignored. @@ -554,12 +613,12 @@ public class IpServerTest { // A neighbor that is no longer valid causes the rule to be removed. recvNewNeigh(myIfindex, neighA, NUD_FAILED, macA); - verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress())); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); reset(mNetd); // A neighbor that is deleted causes the rule to be removed. recvDelNeigh(myIfindex, neighB, NUD_STALE, macB); - verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); reset(mNetd); // Upstream changes result in deleting and re-adding the rules. @@ -571,22 +630,16 @@ public class IpServerTest { LinkProperties lp = new LinkProperties(); lp.setInterfaceName(UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp); - inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2), - eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray())); - inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), - eq(neighA.getAddress())); - inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2), - eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); - inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), - eq(neighB.getAddress())); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA)); + inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB)); + inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); reset(mNetd); // When the upstream is lost, rules are removed. dispatchTetherConnectionChanged(null, null); - verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2), - eq(neighA.getAddress())); - verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2), - eq(neighB.getAddress())); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA)); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB)); reset(mNetd); // If the upstream is IPv4-only, no rules are added. @@ -599,31 +652,27 @@ public class IpServerTest { lp.setInterfaceName(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); - verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), - eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); - verify(mNetd, never()).tetherRuleAddDownstreamIpv6(anyInt(), anyInt(), - eq(neighA.getAddress()), any(), any()); + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); + verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); // If upstream IPv6 connectivity is lost, rules are removed. reset(mNetd); dispatchTetherConnectionChanged(UPSTREAM_IFACE, null); - verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); // When the interface goes down, rules are removed. lp.setInterfaceName(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); - verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), - eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray())); - verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), - eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); reset(mNetd); mIpServer.stop(); mLooper.dispatchAll(); - verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress())); - verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); reset(mNetd); } From 1f4e465b5af26a105c59930af337b6a99d1a9e70 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Sun, 5 Apr 2020 01:51:10 -0700 Subject: [PATCH 0893/1415] Dump debug logs after a test failure before running tearDown()s. Bug: 145420790 Test: atest hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Change-Id: I19516046f05bd4564c57542ae82a82a1cc362f48 --- ...ractRestrictBackgroundNetworkTestCase.java | 8 +--- .../net/hostside/NetworkPolicyTestRunner.java | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 69dd2adb48..21212af824 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -62,13 +62,10 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - /** * Superclass for tests related to background network restrictions. */ -@RunWith(AndroidJUnit4.class) +@RunWith(NetworkPolicyTestRunner.class) public abstract class AbstractRestrictBackgroundNetworkTestCase { public static final String TAG = "RestrictBackgroundNetworkTests"; @@ -137,8 +134,7 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { private boolean mIsLocationOn; @Rule - public final RuleChain mRuleChain = RuleChain.outerRule(new DumpOnFailureRule()) - .around(new RequiredPropertiesRule()) + public final RuleChain mRuleChain = RuleChain.outerRule(new RequiredPropertiesRule()) .around(new MeterednessConfigurationRule()); protected void setUp() throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java new file mode 100644 index 0000000000..f340907ae5 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java @@ -0,0 +1,44 @@ +/* + * 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 com.android.cts.net.hostside; + +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner; + +import org.junit.rules.RunRules; +import org.junit.rules.TestRule; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; + +import java.util.List; + +/** + * Custom runner to allow dumping logs after a test failure before the @After methods get to run. + */ +public class NetworkPolicyTestRunner extends AndroidJUnit4ClassRunner { + private TestRule mDumpOnFailureRule = new DumpOnFailureRule(); + + public NetworkPolicyTestRunner(Class klass) throws InitializationError { + super(klass); + } + + @Override + public Statement methodInvoker(FrameworkMethod method, Object test) { + return new RunRules(super.methodInvoker(method, test), List.of(mDumpOnFailureRule), + describeChild(method)); + } +} From e96f42d27b9a84457fef41bbdf0696eb8b2f444c Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 31 Mar 2020 00:30:12 +0800 Subject: [PATCH 0894/1415] Add TetheringServiceTest unitest Bug: 145490751 Test: atest TetheringTests Change-Id: I68cd403302848c041444e6d47652435d67f59273 --- Tethering/tests/unit/AndroidManifest.xml | 9 + .../tethering/MockTetheringService.java | 56 +++++ .../tethering/TetheringServiceTest.java | 194 ++++++++++++++++++ .../connectivity/tethering/TetheringTest.java | 14 ++ 4 files changed, 273 insertions(+) create mode 100644 Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java create mode 100644 Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java diff --git a/Tethering/tests/unit/AndroidManifest.xml b/Tethering/tests/unit/AndroidManifest.xml index 530bc0788a..4ff1d3777f 100644 --- a/Tethering/tests/unit/AndroidManifest.xml +++ b/Tethering/tests/unit/AndroidManifest.xml @@ -20,7 +20,16 @@ + + + + + + diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java new file mode 100644 index 0000000000..355ece9a44 --- /dev/null +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java @@ -0,0 +1,56 @@ +/* + * 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 com.android.server.connectivity.tethering; + +import static org.mockito.Mockito.mock; + +import android.content.Intent; +import android.net.ITetheringConnector; +import android.os.Binder; +import android.os.IBinder; + +public class MockTetheringService extends TetheringService { + private final Tethering mTethering = mock(Tethering.class); + + @Override + public IBinder onBind(Intent intent) { + return new MockTetheringConnector(super.onBind(intent)); + } + + @Override + public Tethering makeTethering(TetheringDependencies deps) { + return mTethering; + } + + public Tethering getTethering() { + return mTethering; + } + + public class MockTetheringConnector extends Binder { + final IBinder mBase; + MockTetheringConnector(IBinder base) { + mBase = base; + } + + public ITetheringConnector getTetheringConnector() { + return ITetheringConnector.Stub.asInterface(mBase); + } + + public MockTetheringService getService() { + return MockTetheringService.this; + } + } +} diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java new file mode 100644 index 0000000000..d9d3e73eb4 --- /dev/null +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java @@ -0,0 +1,194 @@ +/* + * 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 com.android.server.connectivity.tethering; + +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.content.Intent; +import android.net.IIntResultListener; +import android.net.ITetheringConnector; +import android.net.ITetheringEventCallback; +import android.net.TetheringRequestParcel; +import android.os.ResultReceiver; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.rule.ServiceTestRule; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.connectivity.tethering.MockTetheringService.MockTetheringConnector; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class TetheringServiceTest { + private static final String TEST_IFACE_NAME = "test_wlan0"; + private static final String TEST_CALLER_PKG = "test_pkg"; + @Mock private ITetheringEventCallback mITetheringEventCallback; + @Rule public ServiceTestRule mServiceTestRule; + private Tethering mTethering; + private Intent mMockServiceIntent; + private ITetheringConnector mTetheringConnector; + + private class TestTetheringResult extends IIntResultListener.Stub { + private int mResult = -1; // Default value that does not match any result code. + @Override + public void onResult(final int resultCode) { + mResult = resultCode; + } + + public void assertResult(final int expected) { + assertEquals(expected, mResult); + } + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mServiceTestRule = new ServiceTestRule(); + mMockServiceIntent = new Intent( + InstrumentationRegistry.getTargetContext(), + MockTetheringService.class); + final MockTetheringConnector mockConnector = + (MockTetheringConnector) mServiceTestRule.bindService(mMockServiceIntent); + mTetheringConnector = mockConnector.getTetheringConnector(); + final MockTetheringService service = mockConnector.getService(); + mTethering = service.getTethering(); + verify(mTethering).startStateMachineUpdaters(); + when(mTethering.hasTetherableConfiguration()).thenReturn(true); + } + + @After + public void tearDown() throws Exception { + mServiceTestRule.unbindService(); + } + + @Test + public void testTether() throws Exception { + when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).tether(TEST_IFACE_NAME); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testUntether() throws Exception { + when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).untether(TEST_IFACE_NAME); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testSetUsbTethering() throws Exception { + when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR); + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).setUsbTethering(true /* enable */); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testStartTethering() throws Exception { + final TestTetheringResult result = new TestTetheringResult(); + final TetheringRequestParcel request = new TetheringRequestParcel(); + request.tetheringType = TETHERING_WIFI; + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).startTethering(eq(request), eq(result)); + verifyNoMoreInteractions(mTethering); + } + + @Test + public void testStopTethering() throws Exception { + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).stopTethering(TETHERING_WIFI); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testRequestLatestTetheringEntitlementResult() throws Exception { + final ResultReceiver result = new ResultReceiver(null); + mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, + true /* showEntitlementUi */, TEST_CALLER_PKG); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI), + eq(result), eq(true) /* showEntitlementUi */); + verifyNoMoreInteractions(mTethering); + } + + @Test + public void testRegisterTetheringEventCallback() throws Exception { + mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback)); + verifyNoMoreInteractions(mTethering); + } + + @Test + public void testUnregisterTetheringEventCallback() throws Exception { + mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mTethering).unregisterTetheringEventCallback( + eq(mITetheringEventCallback)); + verifyNoMoreInteractions(mTethering); + } + + @Test + public void testStopAllTethering() throws Exception { + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).untetherAll(); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testIsTetheringSupported() throws Exception { + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } +} diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index a418c4a880..38059fc9f2 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -141,7 +141,9 @@ import com.android.networkstack.tethering.R; import com.android.testutils.MiscAssertsKt; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -440,6 +442,18 @@ public class TetheringTest { return buildMobileUpstreamState(false, true, true); } + // See FakeSettingsProvider#clearSettingsProvider() that this needs to be called before and + // after use. + @BeforeClass + public static void setupOnce() { + FakeSettingsProvider.clearSettingsProvider(); + } + + @AfterClass + public static void tearDownOnce() { + FakeSettingsProvider.clearSettingsProvider(); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); From 49889dd4c0b4ed4fb24f0a8645676d2241ef65f4 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 3 Apr 2020 17:01:33 +0900 Subject: [PATCH 0895/1415] Rename IDhcpLeaseCallbacks to IDhcpEventCallbacks for more generic. Bug: 130741856 Test: atest TetheringTests Change-Id: I66614fbf67fba1e7dab0b8a2d41bc30a726e4f38 --- Tethering/src/android/net/ip/IpServer.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 82b17acae5..9db6a3516a 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -41,7 +41,7 @@ import android.net.dhcp.DhcpLeaseParcelable; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.DhcpServingParamsParcelExt; -import android.net.dhcp.IDhcpLeaseCallbacks; +import android.net.dhcp.IDhcpEventCallbacks; import android.net.dhcp.IDhcpServer; import android.net.ip.IpNeighborMonitor.NeighborEvent; import android.net.ip.RouterAdvertisementDaemon.RaParams; @@ -449,7 +449,7 @@ public class IpServer extends StateMachine { } } - private class DhcpLeaseCallback extends IDhcpLeaseCallbacks.Stub { + private class DhcpLeaseCallback extends IDhcpEventCallbacks.Stub { @Override public void onLeasesChanged(List leaseParcelables) { final ArrayList leases = new ArrayList<>(); @@ -482,6 +482,11 @@ public class IpServer extends StateMachine { }); } + @Override + public void onNewPrefixRequest(IpPrefix currentPrefix) { + //TODO: add specific implementation. + } + @Override public int getInterfaceVersion() { return this.VERSION; From 1b39a10c21505318c9ca2c1bcaeee35c2002055d Mon Sep 17 00:00:00 2001 From: markchien Date: Sun, 5 Apr 2020 22:26:40 +0800 Subject: [PATCH 0896/1415] Add IPv6TetheringCoordinator unit test Bug: 148636687 Test: atest IPv6TetheringCoordinatorTest Change-Id: I939323ce09adb9c66b1e2b83d58b0f892aa8f011 --- .../IPv6TetheringCoordinatorTest.java | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java new file mode 100644 index 0000000000..912124357c --- /dev/null +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java @@ -0,0 +1,156 @@ +/* + * 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 com.android.server.connectivity.tethering; + +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.ip.IpServer.STATE_LOCAL_ONLY; +import static android.net.ip.IpServer.STATE_TETHERED; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.RouteInfo; +import android.net.ip.IpServer; +import android.net.util.SharedLog; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IPv6TetheringCoordinatorTest { + private static final String TEST_DNS_SERVER = "2001:4860:4860::8888"; + private static final String TEST_INTERFACE = "test_rmnet0"; + private static final String TEST_IPV6_ADDRESS = "2001:db8::1/64"; + private static final String TEST_IPV4_ADDRESS = "192.168.100.1/24"; + + private IPv6TetheringCoordinator mIPv6TetheringCoordinator; + private ArrayList mNotifyList; + + @Mock private SharedLog mSharedLog; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); + mNotifyList = new ArrayList(); + mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mSharedLog); + } + + private UpstreamNetworkState createDualStackUpstream(final int transportType) { + final Network network = mock(Network.class); + final NetworkCapabilities netCap = + new NetworkCapabilities.Builder().addTransportType(transportType).build(); + final InetAddress dns = InetAddresses.parseNumericAddress(TEST_DNS_SERVER); + final LinkProperties linkProp = new LinkProperties(); + linkProp.setInterfaceName(TEST_INTERFACE); + linkProp.addLinkAddress(new LinkAddress(TEST_IPV6_ADDRESS)); + linkProp.addLinkAddress(new LinkAddress(TEST_IPV4_ADDRESS)); + linkProp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, TEST_INTERFACE, RTN_UNICAST)); + linkProp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, TEST_INTERFACE, + RTN_UNICAST)); + linkProp.addDnsServer(dns); + return new UpstreamNetworkState(linkProp, netCap, network); + } + + private void assertOnlyOneV6AddressAndNoV4(LinkProperties lp) { + assertEquals(lp.getInterfaceName(), TEST_INTERFACE); + assertFalse(lp.hasIpv4Address()); + final List addresses = lp.getLinkAddresses(); + assertEquals(addresses.size(), 1); + final LinkAddress v6Address = addresses.get(0); + assertEquals(v6Address, new LinkAddress(TEST_IPV6_ADDRESS)); + } + + @Test + public void testUpdateIpv6Upstream() throws Exception { + // 1. Add first IpServer. + final IpServer firstServer = mock(IpServer.class); + mNotifyList.add(firstServer); + mIPv6TetheringCoordinator.addActiveDownstream(firstServer, STATE_TETHERED); + verify(firstServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); + verifyNoMoreInteractions(firstServer); + + // 2. Add second IpServer and it would not have ipv6 tethering. + final IpServer secondServer = mock(IpServer.class); + mNotifyList.add(secondServer); + mIPv6TetheringCoordinator.addActiveDownstream(secondServer, STATE_LOCAL_ONLY); + verifyNoMoreInteractions(secondServer); + reset(firstServer, secondServer); + + // 3. No upstream. + mIPv6TetheringCoordinator.updateUpstreamNetworkState(null); + verify(secondServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); + reset(firstServer, secondServer); + + // 4. Update ipv6 mobile upstream. + final UpstreamNetworkState mobileUpstream = createDualStackUpstream(TRANSPORT_CELLULAR); + final ArgumentCaptor lp = ArgumentCaptor.forClass(LinkProperties.class); + mIPv6TetheringCoordinator.updateUpstreamNetworkState(mobileUpstream); + verify(firstServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(0), eq(0), + lp.capture()); + final LinkProperties v6OnlyLink = lp.getValue(); + assertOnlyOneV6AddressAndNoV4(v6OnlyLink); + verifyNoMoreInteractions(firstServer); + verifyNoMoreInteractions(secondServer); + reset(firstServer, secondServer); + + // 5. Remove first IpServer. + mNotifyList.remove(firstServer); + mIPv6TetheringCoordinator.removeActiveDownstream(firstServer); + verify(firstServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); + verify(secondServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(0), eq(0), + lp.capture()); + final LinkProperties localOnlyLink = lp.getValue(); + assertNotNull(localOnlyLink); + assertNotEquals(localOnlyLink, v6OnlyLink); + reset(firstServer, secondServer); + + // 6. Remove second IpServer. + mNotifyList.remove(secondServer); + mIPv6TetheringCoordinator.removeActiveDownstream(secondServer); + verifyNoMoreInteractions(firstServer); + verify(secondServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); + } +} From b03df59c70d09bb8f4e41994e944ad49be9be626 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 21 Nov 2019 21:37:22 +0800 Subject: [PATCH 0897/1415] Add ProxyInfoTest to test public APIs Add cts to test current public APIs and new public APIs. Bug: 151110319 Bug: 152617305 Test: atest CtsNetTestCasesLatestSdk:ProxyInfoTest Change-Id: I451989f7312fb98ec2fa0b7b9ddc856ecf2087be --- .../src/android/net/cts/ProxyInfoTest.java | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/ProxyInfoTest.java diff --git a/tests/cts/net/src/android/net/cts/ProxyInfoTest.java b/tests/cts/net/src/android/net/cts/ProxyInfoTest.java new file mode 100644 index 0000000000..1c5624ce38 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ProxyInfoTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2019 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 org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.ProxyInfo; +import android.net.Uri; +import android.os.Build; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +@RunWith(AndroidJUnit4.class) +public final class ProxyInfoTest { + private static final String TEST_HOST = "test.example.com"; + private static final int TEST_PORT = 5566; + private static final Uri TEST_URI = Uri.parse("https://test.example.com"); + // This matches android.net.ProxyInfo#LOCAL_EXCL_LIST + private static final String LOCAL_EXCL_LIST = ""; + // This matches android.net.ProxyInfo#LOCAL_HOST + private static final String LOCAL_HOST = "localhost"; + // This matches android.net.ProxyInfo#LOCAL_PORT + private static final int LOCAL_PORT = -1; + + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + + @Test + public void testConstructor() { + final ProxyInfo proxy = new ProxyInfo((ProxyInfo) null); + checkEmpty(proxy); + + assertEquals(proxy, new ProxyInfo(proxy)); + } + + @Test + public void testBuildDirectProxy() { + final ProxyInfo proxy1 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT); + + assertEquals(TEST_HOST, proxy1.getHost()); + assertEquals(TEST_PORT, proxy1.getPort()); + assertArrayEquals(new String[0], proxy1.getExclusionList()); + assertEquals(Uri.EMPTY, proxy1.getPacFileUrl()); + + final List exclList = new ArrayList<>(); + exclList.add("localhost"); + exclList.add("*.exclusion.com"); + final ProxyInfo proxy2 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT, exclList); + + assertEquals(TEST_HOST, proxy2.getHost()); + assertEquals(TEST_PORT, proxy2.getPort()); + assertArrayEquals(exclList.toArray(new String[0]), proxy2.getExclusionList()); + assertEquals(Uri.EMPTY, proxy2.getPacFileUrl()); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testBuildPacProxy() { + final ProxyInfo proxy1 = ProxyInfo.buildPacProxy(TEST_URI); + + assertEquals(LOCAL_HOST, proxy1.getHost()); + assertEquals(LOCAL_PORT, proxy1.getPort()); + assertArrayEquals(LOCAL_EXCL_LIST.toLowerCase(Locale.ROOT).split(","), + proxy1.getExclusionList()); + assertEquals(TEST_URI, proxy1.getPacFileUrl()); + + final ProxyInfo proxy2 = ProxyInfo.buildPacProxy(TEST_URI, TEST_PORT); + + assertEquals(LOCAL_HOST, proxy2.getHost()); + assertEquals(TEST_PORT, proxy2.getPort()); + assertArrayEquals(LOCAL_EXCL_LIST.toLowerCase(Locale.ROOT).split(","), + proxy2.getExclusionList()); + assertEquals(TEST_URI, proxy2.getPacFileUrl()); + } + + @Test + public void testIsValid() { + final ProxyInfo proxy1 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT); + assertTrue(proxy1.isValid()); + + // Given empty host + final ProxyInfo proxy2 = ProxyInfo.buildDirectProxy("", TEST_PORT); + assertFalse(proxy2.isValid()); + // Given invalid host + final ProxyInfo proxy3 = ProxyInfo.buildDirectProxy(".invalid.com", TEST_PORT); + assertFalse(proxy3.isValid()); + // Given invalid port. + final ProxyInfo proxy4 = ProxyInfo.buildDirectProxy(TEST_HOST, 0); + assertFalse(proxy4.isValid()); + // Given another invalid port + final ProxyInfo proxy5 = ProxyInfo.buildDirectProxy(TEST_HOST, 65536); + assertFalse(proxy5.isValid()); + // Given invalid exclusion list + final List exclList = new ArrayList<>(); + exclList.add(".invalid.com"); + exclList.add("%.test.net"); + final ProxyInfo proxy6 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT, exclList); + assertFalse(proxy6.isValid()); + } + + private void checkEmpty(ProxyInfo proxy) { + assertNull(proxy.getHost()); + assertEquals(0, proxy.getPort()); + assertNull(proxy.getExclusionList()); + assertEquals(Uri.EMPTY, proxy.getPacFileUrl()); + } +} From 64522ba4eae63b8daf37197a2aec357732b9a75d Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 6 Mar 2020 10:37:21 +0800 Subject: [PATCH 0898/1415] Add testRegisterTetheringEventCallback for CtsTetheringTest Bug: 150632712 Bug: 150631563 Test: atest CtsTetheringTest Change-Id: I55895c8b26acb7ec905d75d1f4b2a8964b13187a --- .../tethering/cts/TetheringManagerTest.java | 181 +++++++++++++++++- 1 file changed, 179 insertions(+), 2 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 86fe54ce54..b132982e1a 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -29,9 +29,14 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.LinkAddress; +import android.net.Network; +import android.net.TetheredClient; import android.net.TetheringManager; +import android.net.TetheringManager.TetheringEventCallback; +import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; +import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -42,6 +47,8 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -195,8 +202,12 @@ public class TetheringManagerTest { } } - private static boolean isIfaceMatch(final String[] ifaceRegexs, - final ArrayList ifaces) { + private static boolean isIfaceMatch(final List ifaceRegexs, + final List ifaces) { + return isIfaceMatch(ifaceRegexs.toArray(new String[0]), ifaces); + } + + private static boolean isIfaceMatch(final String[] ifaceRegexs, final List ifaces) { if (ifaceRegexs == null) fail("ifaceRegexs should not be null"); if (ifaces == null) return false; @@ -251,4 +262,170 @@ public class TetheringManagerTest { assertTrue(tr2.isExemptFromEntitlementCheck()); assertFalse(tr2.getShouldShowEntitlementUi()); } + + // Must poll the callback before looking at the member. + private static class TestTetheringEventCallback implements TetheringEventCallback { + public enum CallbackType { + ON_SUPPORTED, + ON_UPSTREAM, + ON_TETHERABLE_REGEX, + ON_TETHERABLE_IFACES, + ON_TETHERED_IFACES, + ON_ERROR, + ON_CLIENTS, + }; + + public static class CallbackValue { + public final CallbackType callbackType; + public final Object callbackParam; + public final int callbackParam2; + + private CallbackValue(final CallbackType type, final Object param, final int param2) { + this.callbackType = type; + this.callbackParam = param; + this.callbackParam2 = param2; + } + } + private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + private TetheringInterfaceRegexps mTetherableRegex; + private List mTetherableIfaces; + private List mTetheredIfaces; + + @Override + public void onTetheringSupported(boolean supported) { + mCallbacks.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); + } + + @Override + public void onUpstreamChanged(Network network) { + mCallbacks.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); + } + + @Override + public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { + mTetherableRegex = reg; + mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); + } + + @Override + public void onTetherableInterfacesChanged(List interfaces) { + mTetherableIfaces = interfaces; + mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); + } + + @Override + public void onTetheredInterfacesChanged(List interfaces) { + mTetheredIfaces = interfaces; + mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); + } + + @Override + public void onError(String ifName, int error) { + mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); + } + + @Override + public void onClientsChanged(Collection clients) { + mCallbacks.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); + } + + public CallbackValue pollCallback() { + try { + return mCallbacks.poll(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + fail("Callback not seen"); + } + return null; + } + + public void expectTetherableInterfacesChanged(@NonNull List regexs) { + while (true) { + final CallbackValue cv = pollCallback(); + if (cv == null) fail("No expected tetherable ifaces callback"); + if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) continue; + + final List interfaces = (List) cv.callbackParam; + if (isIfaceMatch(regexs, interfaces)) break; + } + } + + public void expectTetheredInterfacesChanged(@NonNull List regexs) { + while (true) { + final CallbackValue cv = pollCallback(); + if (cv == null) fail("No expected tethered ifaces callback"); + if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) continue; + + final List interfaces = (List) cv.callbackParam; + + // Null regexs means no active tethering. + if (regexs == null) { + if (interfaces.size() == 0) break; + } else if (isIfaceMatch(regexs, interfaces)) { + break; + } + } + } + + public void expectCallbackStarted() { + // The each bit represent a type from CallbackType.ON_*. + // Expect all of callbacks except for ON_ERROR. + final int expectedBitMap = 0x7f ^ (1 << CallbackType.ON_ERROR.ordinal()); + int receivedBitMap = 0; + while (receivedBitMap != expectedBitMap) { + final CallbackValue cv = pollCallback(); + if (cv == null) { + fail("No expected callbacks, " + "expected bitmap: " + + expectedBitMap + ", actual: " + receivedBitMap); + } + receivedBitMap = receivedBitMap | (1 << cv.callbackType.ordinal()); + } + } + + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { + return mTetherableRegex; + } + + public List getTetherableInterfaces() { + return mTetherableIfaces; + } + + public List getTetheredInterfaces() { + return mTetheredIfaces; + } + } + + @Test + public void testRegisterTetheringEventCallback() throws Exception { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); + + mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); + tetherEventCallback.expectCallbackStarted(); + + final TetheringInterfaceRegexps tetherableRegexs = + tetherEventCallback.getTetheringInterfaceRegexps(); + final List wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); + if (wifiRegexs.size() == 0) return; + + final boolean isIfaceAvailWhenNoTethering = + isIfaceMatch(wifiRegexs, tetherEventCallback.getTetherableInterfaces()); + + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(), + new StartTetheringCallback()); + + // If interface is already available before starting tethering, the available callback may + // not be sent after tethering enabled. + if (!isIfaceAvailWhenNoTethering) { + tetherEventCallback.expectTetherableInterfacesChanged(wifiRegexs); + } + + tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); + + mTM.stopTethering(TETHERING_WIFI); + + tetherEventCallback.expectTetheredInterfacesChanged(null); + mTM.unregisterTetheringEventCallback(tetherEventCallback); + } } From a18f6094e1bbe992bb7659fe34a56e7a6e90dfa2 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Dec 2019 22:23:01 +0900 Subject: [PATCH 0899/1415] CTS test for NetworkRequest#getSpecifier Bug: 135998869 Test: this Change-Id: I339c62f0ce68cc3c19abbaef7f99d216362db4cb --- .../android/net/cts/NetworkRequestTest.java | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index c862c77bc7..8b97c8cb92 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -18,11 +18,42 @@ package android.net.cts; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.MacAddress; import android.net.NetworkRequest; -import android.test.AndroidTestCase; +import android.net.NetworkSpecifier; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiNetworkSpecifier; +import android.os.Build; +import android.os.PatternMatcher; +import android.util.Pair; -public class NetworkRequestTest extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class NetworkRequestTest { + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + + private static final String TEST_SSID = "TestSSID"; + private static final int TEST_UID = 2097; + private static final String TEST_PACKAGE_NAME = "test.package.name"; + private static final MacAddress ARBITRARY_ADDRESS = MacAddress.fromString("3:5:8:12:9:2"); + + @Test public void testCapabilities() { assertTrue(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build() .hasCapability(NET_CAPABILITY_MMS)); @@ -30,10 +61,27 @@ public class NetworkRequestTest extends AndroidTestCase { .hasCapability(NET_CAPABILITY_MMS)); } + @Test public void testTransports() { assertTrue(new NetworkRequest.Builder().addTransportType(TRANSPORT_BLUETOOTH).build() .hasTransport(TRANSPORT_BLUETOOTH)); assertFalse(new NetworkRequest.Builder().removeTransportType(TRANSPORT_BLUETOOTH).build() .hasTransport(TRANSPORT_BLUETOOTH)); } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testSpecifier() { + assertNull(new NetworkRequest.Builder().build().getNetworkSpecifier()); + final WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL)) + .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + .build(); + final NetworkSpecifier obtainedSpecifier = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .setNetworkSpecifier(specifier) + .build() + .getNetworkSpecifier(); + assertEquals(obtainedSpecifier, specifier); + } } From 2648ad46fe74d402f980f0fb315728c827f15d01 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 8 Nov 2019 21:19:51 +0800 Subject: [PATCH 0900/1415] CTS test for DhcpInfo parcel/unparcel Bug: 139268426 Bug: 135998869 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.DhcpInfoTest Change-Id: I076241072688fca37b8451873183f9597bc5fe79 --- .../net/src/android/net/cts/DhcpInfoTest.java | 105 +++++++++++++----- 1 file changed, 78 insertions(+), 27 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java index 085fdd9132..b8d239272a 100644 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -16,48 +16,99 @@ package android.net.cts; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL; + +import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; +import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.annotation.Nullable; import android.net.DhcpInfo; -import android.test.AndroidTestCase; -public class DhcpInfoTest extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; - public void testConstructor() { - new DhcpInfo(); +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.InetAddress; + +@RunWith(AndroidJUnit4.class) +public class DhcpInfoTest { + private static final String STR_ADDR1 = "255.255.255.255"; + private static final String STR_ADDR2 = "127.0.0.1"; + private static final String STR_ADDR3 = "192.168.1.1"; + private static final String STR_ADDR4 = "192.168.1.0"; + private static final int LEASE_TIME = 9999; + + private int ipToInteger(String ipString) throws Exception { + return inet4AddressToIntHTL((Inet4Address) InetAddress.getByName(ipString)); } - public void testToString() { - String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 dns1 0.0.0.0 " - + "dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; - String STR_ADDR1 = "255.255.255.255"; - String STR_ADDR2 = "127.0.0.1"; - String STR_ADDR3 = "192.168.1.1"; - String STR_ADDR4 = "192.168.1.0"; - int leaseTime = 9999; - String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask " - + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server " - + STR_ADDR2 + " lease " + leaseTime + " seconds"; - - DhcpInfo dhcpInfo = new DhcpInfo(); - - // Test default string. - assertEquals(expectedDefault, dhcpInfo.toString()); - + private DhcpInfo createDhcpInfoObject() throws Exception { + final DhcpInfo dhcpInfo = new DhcpInfo(); dhcpInfo.ipAddress = ipToInteger(STR_ADDR1); dhcpInfo.gateway = ipToInteger(STR_ADDR2); dhcpInfo.netmask = ipToInteger(STR_ADDR3); dhcpInfo.dns1 = ipToInteger(STR_ADDR4); dhcpInfo.dns2 = ipToInteger(STR_ADDR4); dhcpInfo.serverAddress = ipToInteger(STR_ADDR2); - dhcpInfo.leaseDuration = leaseTime; + dhcpInfo.leaseDuration = LEASE_TIME; + return dhcpInfo; + } + @Test + public void testConstructor() { + new DhcpInfo(); + } + + @Test + public void testToString() throws Exception { + final String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 " + + "dns1 0.0.0.0 dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; + + DhcpInfo dhcpInfo = new DhcpInfo(); + + // Test default string. + assertEquals(expectedDefault, dhcpInfo.toString()); + + dhcpInfo = createDhcpInfoObject(); + + final String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask " + + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server " + + STR_ADDR2 + " lease " + LEASE_TIME + " seconds"; // Test with new values assertEquals(expected, dhcpInfo.toString()); } - private int ipToInteger(String ipString) { - String ipSegs[] = ipString.split("[.]"); - int tmp = Integer.parseInt(ipSegs[3]) << 24 | Integer.parseInt(ipSegs[2]) << 16 | - Integer.parseInt(ipSegs[1]) << 8 | Integer.parseInt(ipSegs[0]); - return tmp; + private boolean dhcpInfoEquals(@Nullable DhcpInfo left, @Nullable DhcpInfo right) { + if (left == null && right == null) return true; + + if (left == null || right == null) return false; + + return left.ipAddress == right.ipAddress + && left.gateway == right.gateway + && left.netmask == right.netmask + && left.dns1 == right.dns1 + && left.dns2 == right.dns2 + && left.serverAddress == right.serverAddress + && left.leaseDuration == right.leaseDuration; + } + + @Test + public void testParcelDhcpInfo() throws Exception { + // Cannot use assertParcelSane() here because this requires .equals() to work as + // defined, but DhcpInfo has a different legacy behavior that we cannot change. + final DhcpInfo dhcpInfo = createDhcpInfoObject(); + assertFieldCountEquals(7, DhcpInfo.class); + + final DhcpInfo dhcpInfoRoundTrip = parcelingRoundTrip(dhcpInfo); + assertTrue(dhcpInfoEquals(null, null)); + assertFalse(dhcpInfoEquals(null, dhcpInfoRoundTrip)); + assertFalse(dhcpInfoEquals(dhcpInfo, null)); + assertTrue(dhcpInfoEquals(dhcpInfo, dhcpInfoRoundTrip)); } } From 31a7f20c49a7297fbf506710db65b1d6476bb1d0 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 7 Apr 2020 06:59:29 +0000 Subject: [PATCH 0901/1415] CTS test for NetworkRequest#getSpecifier Bug: 135998869 Test: this Change-Id: I1ca9ecff8ed93164855686e4c76a070e6fa757c7 Merged-In: I339c62f0ce68cc3c19abbaef7f99d216362db4cb (cherry picked from commit 8fba41c86d92460a80cd58beb131528ce6e147d8, aosp/1188840) --- .../android/net/cts/NetworkRequestTest.java | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index c862c77bc7..8b97c8cb92 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -18,11 +18,42 @@ package android.net.cts; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.MacAddress; import android.net.NetworkRequest; -import android.test.AndroidTestCase; +import android.net.NetworkSpecifier; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiNetworkSpecifier; +import android.os.Build; +import android.os.PatternMatcher; +import android.util.Pair; -public class NetworkRequestTest extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class NetworkRequestTest { + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + + private static final String TEST_SSID = "TestSSID"; + private static final int TEST_UID = 2097; + private static final String TEST_PACKAGE_NAME = "test.package.name"; + private static final MacAddress ARBITRARY_ADDRESS = MacAddress.fromString("3:5:8:12:9:2"); + + @Test public void testCapabilities() { assertTrue(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build() .hasCapability(NET_CAPABILITY_MMS)); @@ -30,10 +61,27 @@ public class NetworkRequestTest extends AndroidTestCase { .hasCapability(NET_CAPABILITY_MMS)); } + @Test public void testTransports() { assertTrue(new NetworkRequest.Builder().addTransportType(TRANSPORT_BLUETOOTH).build() .hasTransport(TRANSPORT_BLUETOOTH)); assertFalse(new NetworkRequest.Builder().removeTransportType(TRANSPORT_BLUETOOTH).build() .hasTransport(TRANSPORT_BLUETOOTH)); } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testSpecifier() { + assertNull(new NetworkRequest.Builder().build().getNetworkSpecifier()); + final WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL)) + .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + .build(); + final NetworkSpecifier obtainedSpecifier = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .setNetworkSpecifier(specifier) + .build() + .getNetworkSpecifier(); + assertEquals(obtainedSpecifier, specifier); + } } From 6ca4ec97d2ba533621386dadde51dc26a33b0357 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 1 Apr 2020 00:30:22 +0800 Subject: [PATCH 0902/1415] Use the lastest frozen netd_aidl_interface in framework Bug: 140541991 Test: build Change-Id: I984969e09f8d5196945a7412c51bd8880223ad9e --- Tethering/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 0cfd8843c0..27297c4457 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -25,7 +25,7 @@ java_defaults { ], static_libs: [ "androidx.annotation_annotation", - "netd_aidl_interface-unstable-java", + "netd_aidl_interface-V3-java", "netlink-client", "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.config-V1.0-java", From d24f495dc4d86e305c4837205064baa9df2e3570 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 7 Apr 2020 14:04:44 -0700 Subject: [PATCH 0903/1415] Remove tests from vts suite After vts-core is renamed to vts, the CTS tests won't be needed in vts suite. Bug: 151896491 Test: local build Exempt-From-Owner-Approval: This CL removes all CTS tests in vts suite, as vts is renamed to vts10. This CL won't change test logic or behavior. Change-Id: Idc9e9cc1d1080ff689823671a736bbb78bd7a740 Merged-In: Idc9e9cc1d1080ff689823671a736bbb78bd7a740 --- tests/cts/hostside/Android.bp | 1 - tests/cts/hostside/app/Android.bp | 1 - tests/cts/hostside/app2/Android.bp | 1 - tests/cts/net/Android.bp | 1 - tests/cts/net/api23Test/Android.bp | 1 - tests/cts/net/appForApi23/Android.bp | 1 - tests/cts/net/ipsec/Android.bp | 1 - tests/cts/net/native/qtaguid/Android.bp | 1 - 8 files changed, 8 deletions(-) diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp index a8cc95ba5f..741c961e5f 100644 --- a/tests/cts/hostside/Android.bp +++ b/tests/cts/hostside/Android.bp @@ -24,7 +24,6 @@ java_test_host { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index 49aacd91a9..2362389578 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp @@ -33,7 +33,6 @@ android_test_helper_app { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp index 0bb0d2f631..a6e9b118ff 100644 --- a/tests/cts/hostside/app2/Android.bp +++ b/tests/cts/hostside/app2/Android.bp @@ -23,7 +23,6 @@ android_test_helper_app { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index d77f416557..76bb27e448 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -64,7 +64,6 @@ android_test { defaults: ["CtsNetTestCasesDefaults"], test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index 614a5a2a76..ffeef48a88 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -45,7 +45,6 @@ android_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/net/appForApi23/Android.bp b/tests/cts/net/appForApi23/Android.bp index 17cfe3821b..399c199508 100644 --- a/tests/cts/net/appForApi23/Android.bp +++ b/tests/cts/net/appForApi23/Android.bp @@ -26,7 +26,6 @@ android_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", "general-tests", ], diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp index 86969c31ae..8c073c9602 100644 --- a/tests/cts/net/ipsec/Android.bp +++ b/tests/cts/net/ipsec/Android.bp @@ -40,7 +40,6 @@ android_test { test_suites: [ "cts", "mts", - "vts", "general-tests", ], } diff --git a/tests/cts/net/native/qtaguid/Android.bp b/tests/cts/net/native/qtaguid/Android.bp index 054937b4fa..23a0cf764d 100644 --- a/tests/cts/net/native/qtaguid/Android.bp +++ b/tests/cts/net/native/qtaguid/Android.bp @@ -42,7 +42,6 @@ cc_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts", "vts10", ], From d584d2fa36e356873166c972883dddb6293c1b4e Mon Sep 17 00:00:00 2001 From: paulhu Date: Wed, 8 Apr 2020 09:57:57 +0800 Subject: [PATCH 0904/1415] Fix TetheringIntegrationTests failure Bug: 150644681 Test: atest TetheringIntegrationTests Change-Id: I5a537eca9b1aab3694a11a2dab147a31f289314c --- Tethering/tests/integration/Android.bp | 5 +++++ .../integration/src/android/net/EthernetTetheringTest.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp index 1a1c30d1d5..620261b375 100644 --- a/Tethering/tests/integration/Android.bp +++ b/Tethering/tests/integration/Android.bp @@ -39,4 +39,9 @@ android_test { "android.test.base", "android.test.mock", ], + jni_libs: [ + // For mockito extended + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], } diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index dbd68ef77c..b02bb23f98 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -205,7 +205,7 @@ public class EthernetTetheringTest { requestWithStaticIpv4(localAddr, clientAddr)); mTetheringEventCallback.awaitInterfaceTethered(); - assertInterfaceHasIpAddress(iface, clientAddr); + assertInterfaceHasIpAddress(iface, localAddr); byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray(); byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray(); From eaa2b0e30af4454f6632b8476913a5c3ebcb13fa Mon Sep 17 00:00:00 2001 From: paulhu Date: Wed, 8 Apr 2020 10:37:54 +0800 Subject: [PATCH 0905/1415] Address aosp/1274403 leftover comment Bug: 152828142 Test: atest EntitlementManagerTest Change-Id: I81f2d268c9f26bc4488b06032477a73d071f73f8 --- .../tethering/EntitlementManagerTest.java | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java index b3a30abca6..6695eed0ff 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -33,7 +33,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; @@ -72,8 +71,6 @@ import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest @@ -255,19 +252,16 @@ public final class EntitlementManagerTest { @Test public void testRequestLastEntitlementCacheValue() throws Exception { - final CountDownLatch mCallbacklatch = new CountDownLatch(1); // 1. Entitlement check is not required. mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; ResultReceiver receiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_NO_ERROR, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); @@ -277,12 +271,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 3. No cache value and ui entitlement check is needed. @@ -291,12 +283,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_PROVISIONING_FAILED, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(1, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 4. Cache value is TETHER_ERROR_PROVISIONING_FAILED and don't need to run entitlement @@ -306,12 +296,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_PROVISIONING_FAILED, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 5. Cache value is TETHER_ERROR_PROVISIONING_FAILED and ui entitlement check is needed. @@ -320,12 +308,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_NO_ERROR, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(1, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 6. Cache value is TETHER_ERROR_NO_ERROR. @@ -334,12 +320,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_NO_ERROR, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 7. Test get value for other downstream type. @@ -347,12 +331,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_USB, receiver, false); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 8. Test get value for invalid downstream type. @@ -361,22 +343,14 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI_P2P, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); } - void callbackTimeoutHelper(final CountDownLatch latch) throws Exception { - if (!latch.await(1, TimeUnit.SECONDS)) { - fail("Timout, fail to receive callback"); - } - } - @Test public void verifyPermissionResult() { setupForRequiredProvisioning(); From f483cc96799dce6410e004733fcbd0117c50fb6f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 23 Dec 2019 16:14:20 +0800 Subject: [PATCH 0906/1415] Add cts test for traffic stats APIs This change adds test for new public APIs. Bug: 135998869 Test: atest CtsNetTestCasesLatestSdk:TrafficStatsTest Change-Id: I6b4a6773e22a204b6267d28638b9f57a0d0eb65a --- .../src/android/net/cts/TrafficStatsTest.java | 58 ++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 12ab3702d4..577e24ac29 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -61,6 +61,11 @@ public class TrafficStatsTest extends AndroidTestCase { assertTrue(TrafficStats.getTotalRxBytes() >= 0); } + public void testValidPacketStats() { + assertTrue(TrafficStats.getTxPackets("lo") >= 0); + assertTrue(TrafficStats.getRxPackets("lo") >= 0); + } + public void testThreadStatsTag() throws Exception { TrafficStats.setThreadStatsTag(0xf00d); assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xf00d); @@ -104,6 +109,8 @@ public class TrafficStatsTest extends AndroidTestCase { final long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); final long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid()); final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid()); + final long ifaceTxPacketsBefore = TrafficStats.getTxPackets("lo"); + final long ifaceRxPacketsBefore = TrafficStats.getRxPackets("lo"); // Transfer 1MB of data across an explicitly localhost socket. final int byteCount = 1024; @@ -182,6 +189,10 @@ public class TrafficStatsTest extends AndroidTestCase { final long uidTxDeltaPackets = uidTxPacketsAfter - uidTxPacketsBefore; final long uidRxDeltaBytes = uidRxBytesAfter - uidRxBytesBefore; final long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore; + final long ifaceTxPacketsAfter = TrafficStats.getTxPackets("lo"); + final long ifaceRxPacketsAfter = TrafficStats.getRxPackets("lo"); + final long ifaceTxDeltaPackets = ifaceTxPacketsAfter - ifaceTxPacketsBefore; + final long ifaceRxDeltaPackets = ifaceRxPacketsAfter - ifaceRxPacketsBefore; // Localhost traffic *does* count against per-UID stats. /* @@ -209,34 +220,37 @@ public class TrafficStatsTest extends AndroidTestCase { + deltaRxOtherPackets); } - // Check the per uid stats read from data profiling have the stats expected. The data - // profiling snapshot is generated from readNetworkStatsDetail() method in - // networkStatsService and in this way we can verify the detail networkStats of a given uid - // is correct. - NetworkStats.Entry entry = testStats.getTotal(null, Process.myUid()); + // Check that the per-uid stats obtained from data profiling contain the expected values. + // The data profiling snapshot is generated from the readNetworkStatsDetail() method in + // networkStatsService, so it's possible to verify that the detailed stats for a given + // uid are correct. + final NetworkStats.Entry entry = testStats.getTotal(null, Process.myUid()); + final long pktBytes = tcpPacketToIpBytes(packetCount, byteCount); + final long pktWithNoDataBytes = tcpPacketToIpBytes(packetCount, 0); + final long minExpExtraPktBytes = tcpPacketToIpBytes(minExpectedExtraPackets, 0); + final long maxExpExtraPktBytes = tcpPacketToIpBytes(maxExpectedExtraPackets, 0); + final long deltaTxOtherPktBytes = tcpPacketToIpBytes(deltaTxOtherPackets, 0); + final long deltaRxOtherPktBytes = tcpPacketToIpBytes(deltaRxOtherPackets, 0); assertInRange("txPackets detail", entry.txPackets, packetCount + minExpectedExtraPackets, uidTxDeltaPackets); assertInRange("rxPackets detail", entry.rxPackets, packetCount + minExpectedExtraPackets, uidRxDeltaPackets); - assertInRange("txBytes detail", entry.txBytes, tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0), uidTxDeltaBytes); - assertInRange("rxBytes detail", entry.rxBytes, tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0), uidRxDeltaBytes); - + assertInRange("txBytes detail", entry.txBytes, pktBytes + minExpExtraPktBytes, + uidTxDeltaBytes); + assertInRange("rxBytes detail", entry.rxBytes, pktBytes + minExpExtraPktBytes, + uidRxDeltaBytes); assertInRange("uidtxp", uidTxDeltaPackets, packetCount + minExpectedExtraPackets, packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); assertInRange("uidrxp", uidRxDeltaPackets, packetCount + minExpectedExtraPackets, packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); - assertInRange("uidtxb", uidTxDeltaBytes, tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0), - tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets - + deltaTxOtherPackets, 0)); - assertInRange("uidrxb", uidRxDeltaBytes, tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0), - tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets - + deltaRxOtherPackets, 0)); + assertInRange("uidtxb", uidTxDeltaBytes, pktBytes + minExpExtraPktBytes, + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaTxOtherPktBytes); + assertInRange("uidrxb", uidRxDeltaBytes, pktBytes + minExpExtraPktBytes, + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaRxOtherPktBytes); + assertInRange("iftxp", ifaceTxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); + assertInRange("ifrxp", ifaceRxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); // Localhost traffic *does* count against total stats. // Check the total stats increased after test data transfer over localhost has been made. @@ -248,6 +262,10 @@ public class TrafficStatsTest extends AndroidTestCase { totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes); assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes); + assertTrue("iftxp: " + ifaceTxPacketsBefore + " -> " + ifaceTxPacketsAfter, + totalTxPacketsAfter >= totalTxPacketsBefore + ifaceTxDeltaPackets); + assertTrue("ifrxp: " + ifaceRxPacketsBefore + " -> " + ifaceRxPacketsAfter, + totalRxPacketsAfter >= totalRxPacketsBefore + ifaceRxDeltaPackets); // If the adb TCP port is opened, this test may be run by adb over network. // Huge amount of data traffic might go through the network and accounted into total packets From 0e7d08e2b2f8a7e18e63d470d7c709879d0690b0 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 7 Apr 2020 05:57:56 +0000 Subject: [PATCH 0907/1415] Add a first NetworkAgent CTS test This is a basic test that only tests register(), markConnected(), unregister and onNetworkUnwanted. It provides the backbone for the tests, a harness to test callbacks on NetworkAgent, and demonstrates how the instrumentation in ConnectivityService can be used to test this API. Test: this Bug: 139268426 Change-Id: I859208f381ccc22a85d6bccb44c0d5d84c3380c6 Merged-In: I022c9e237fdaec27338047c171c04e5a96cf89e3 (cherry picked from commit 723b519dc2de077c37db510850a590188591a80b, aosp/1253423) --- tests/cts/net/AndroidManifest.xml | 5 + .../net/cts/IpSecManagerTunnelTest.java | 3 +- .../src/android/net/cts/NetworkAgentTest.kt | 142 ++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/NetworkAgentTest.kt diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index c2b3bf77ad..baf914f1ac 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -35,6 +35,11 @@ + + diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 999d2f187b..1d83dda33c 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -192,9 +192,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Build a network request NetworkRequest nr = new NetworkRequest.Builder() + .clearCapabilities() .addTransportType(TRANSPORT_TEST) - .removeCapability(NET_CAPABILITY_TRUSTED) - .removeCapability(NET_CAPABILITY_NOT_VPN) .setNetworkSpecifier(ifname) .build(); diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt new file mode 100644 index 0000000000..85c94e7db2 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -0,0 +1,142 @@ +/* + * 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 android.app.Instrumentation +import android.content.Context +import android.net.ConnectivityManager +import android.net.LinkProperties +import android.net.NetworkAgent +import android.net.NetworkAgentConfig +import android.net.NetworkCapabilities +import android.net.NetworkProvider +import android.net.NetworkRequest +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted +import android.os.Build +import android.os.HandlerThread +import android.os.Looper +import androidx.test.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.ArrayTrackRecord +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.RecorderCallback.CallbackEntry.Lost +import com.android.testutils.TestableNetworkCallback +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +// This test doesn't really have a constraint on how fast the methods should return. If it's +// going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio +// without affecting the run time of successful runs. Thus, set a very high timeout. +private const val DEFAULT_TIMEOUT_MS = 5000L +// Any legal score (0~99) for the test network would do, as it is going to be kept up by the +// requests filed by the test and should never match normal internet requests. 70 is the default +// score of Ethernet networks, it's as good a value as any other. +private const val TEST_NETWORK_SCORE = 70 +private val instrumentation: Instrumentation + get() = InstrumentationRegistry.getInstrumentation() +private val context: Context + get() = InstrumentationRegistry.getContext() + +@RunWith(AndroidJUnit4::class) +class NetworkAgentTest { + @Rule @JvmField + val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) + + private val mCM = context.getSystemService(ConnectivityManager::class.java) + private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") + + private class Provider(context: Context, looper: Looper) : + NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") + + @Before + fun setUp() { + instrumentation.getUiAutomation().adoptShellPermissionIdentity() + mHandlerThread.start() + } + + @After + fun tearDown() { + mHandlerThread.quitSafely() + instrumentation.getUiAutomation().dropShellPermissionIdentity() + } + + internal class TestableNetworkAgent( + looper: Looper, + nc: NetworkCapabilities, + lp: LinkProperties, + conf: NetworkAgentConfig + ) : NetworkAgent(context, looper, TestableNetworkAgent::class.java.simpleName /* tag */, + nc, lp, TEST_NETWORK_SCORE, conf, Provider(context, looper)) { + private val history = ArrayTrackRecord().newReadHead() + + sealed class CallbackEntry { + object OnNetworkUnwanted : CallbackEntry() + } + + override fun onNetworkUnwanted() { + super.onNetworkUnwanted() + history.add(OnNetworkUnwanted) + } + + inline fun expectCallback() { + val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) + assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") + } + } + + private fun createNetworkAgent(): TestableNetworkAgent { + val nc = NetworkCapabilities().apply { + addTransportType(NetworkCapabilities.TRANSPORT_TEST) + removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + } + val lp = LinkProperties() + val config = NetworkAgentConfig.Builder().build() + return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config) + } + + private fun createConnectedNetworkAgent(): Pair { + val request: NetworkRequest = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) + mCM.requestNetwork(request, callback) + val agent = createNetworkAgent().also { it.register() } + agent.markConnected() + return agent to callback + } + + @Test + fun testConnectAndUnregister() { + val (agent, callback) = createConnectedNetworkAgent() + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.unregister() + callback.expectCallback(agent.network) + agent.expectCallback() + assertFailsWith("Must not be able to register an agent twice") { + agent.register() + } + } +} From abf9bc0843c7168a6d7ab91095558b7bd4a4d9e9 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 8 Apr 2020 07:58:02 +0000 Subject: [PATCH 0908/1415] Add ProxyInfoTest to test public APIs Add cts to test current public APIs and new public APIs. Bug: 151110319 Bug: 152617305 Test: atest CtsNetTestCasesLatestSdk:ProxyInfoTest Change-Id: I3e7d2cb7b4c5e47fc85d418aa8ef504367b3d8db Merged-In: I451989f7312fb98ec2fa0b7b9ddc856ecf2087be (cherry picked from commit 0a4d5ecc83d56c2c3f400927a2b8af6e26eb8db8) --- .../src/android/net/cts/ProxyInfoTest.java | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/ProxyInfoTest.java diff --git a/tests/cts/net/src/android/net/cts/ProxyInfoTest.java b/tests/cts/net/src/android/net/cts/ProxyInfoTest.java new file mode 100644 index 0000000000..1c5624ce38 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ProxyInfoTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2019 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 org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.ProxyInfo; +import android.net.Uri; +import android.os.Build; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +@RunWith(AndroidJUnit4.class) +public final class ProxyInfoTest { + private static final String TEST_HOST = "test.example.com"; + private static final int TEST_PORT = 5566; + private static final Uri TEST_URI = Uri.parse("https://test.example.com"); + // This matches android.net.ProxyInfo#LOCAL_EXCL_LIST + private static final String LOCAL_EXCL_LIST = ""; + // This matches android.net.ProxyInfo#LOCAL_HOST + private static final String LOCAL_HOST = "localhost"; + // This matches android.net.ProxyInfo#LOCAL_PORT + private static final int LOCAL_PORT = -1; + + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + + @Test + public void testConstructor() { + final ProxyInfo proxy = new ProxyInfo((ProxyInfo) null); + checkEmpty(proxy); + + assertEquals(proxy, new ProxyInfo(proxy)); + } + + @Test + public void testBuildDirectProxy() { + final ProxyInfo proxy1 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT); + + assertEquals(TEST_HOST, proxy1.getHost()); + assertEquals(TEST_PORT, proxy1.getPort()); + assertArrayEquals(new String[0], proxy1.getExclusionList()); + assertEquals(Uri.EMPTY, proxy1.getPacFileUrl()); + + final List exclList = new ArrayList<>(); + exclList.add("localhost"); + exclList.add("*.exclusion.com"); + final ProxyInfo proxy2 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT, exclList); + + assertEquals(TEST_HOST, proxy2.getHost()); + assertEquals(TEST_PORT, proxy2.getPort()); + assertArrayEquals(exclList.toArray(new String[0]), proxy2.getExclusionList()); + assertEquals(Uri.EMPTY, proxy2.getPacFileUrl()); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testBuildPacProxy() { + final ProxyInfo proxy1 = ProxyInfo.buildPacProxy(TEST_URI); + + assertEquals(LOCAL_HOST, proxy1.getHost()); + assertEquals(LOCAL_PORT, proxy1.getPort()); + assertArrayEquals(LOCAL_EXCL_LIST.toLowerCase(Locale.ROOT).split(","), + proxy1.getExclusionList()); + assertEquals(TEST_URI, proxy1.getPacFileUrl()); + + final ProxyInfo proxy2 = ProxyInfo.buildPacProxy(TEST_URI, TEST_PORT); + + assertEquals(LOCAL_HOST, proxy2.getHost()); + assertEquals(TEST_PORT, proxy2.getPort()); + assertArrayEquals(LOCAL_EXCL_LIST.toLowerCase(Locale.ROOT).split(","), + proxy2.getExclusionList()); + assertEquals(TEST_URI, proxy2.getPacFileUrl()); + } + + @Test + public void testIsValid() { + final ProxyInfo proxy1 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT); + assertTrue(proxy1.isValid()); + + // Given empty host + final ProxyInfo proxy2 = ProxyInfo.buildDirectProxy("", TEST_PORT); + assertFalse(proxy2.isValid()); + // Given invalid host + final ProxyInfo proxy3 = ProxyInfo.buildDirectProxy(".invalid.com", TEST_PORT); + assertFalse(proxy3.isValid()); + // Given invalid port. + final ProxyInfo proxy4 = ProxyInfo.buildDirectProxy(TEST_HOST, 0); + assertFalse(proxy4.isValid()); + // Given another invalid port + final ProxyInfo proxy5 = ProxyInfo.buildDirectProxy(TEST_HOST, 65536); + assertFalse(proxy5.isValid()); + // Given invalid exclusion list + final List exclList = new ArrayList<>(); + exclList.add(".invalid.com"); + exclList.add("%.test.net"); + final ProxyInfo proxy6 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT, exclList); + assertFalse(proxy6.isValid()); + } + + private void checkEmpty(ProxyInfo proxy) { + assertNull(proxy.getHost()); + assertEquals(0, proxy.getPort()); + assertNull(proxy.getExclusionList()); + assertEquals(Uri.EMPTY, proxy.getPacFileUrl()); + } +} From 1522b023d0cb083371e635312b57a8d20da27b79 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 8 Apr 2020 07:58:15 +0000 Subject: [PATCH 0909/1415] CTS test for DhcpInfo parcel/unparcel Bug: 139268426 Bug: 135998869 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.DhcpInfoTest Change-Id: I20d9faba899c7eef026e155e329c5c3a89253209 Merged-In: I076241072688fca37b8451873183f9597bc5fe79 (cherry picked from commit 130479fb2aa2457eb590202382ed31f72cc5386e) --- .../net/src/android/net/cts/DhcpInfoTest.java | 105 +++++++++++++----- 1 file changed, 78 insertions(+), 27 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java index 085fdd9132..b8d239272a 100644 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java @@ -16,48 +16,99 @@ package android.net.cts; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL; + +import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; +import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.annotation.Nullable; import android.net.DhcpInfo; -import android.test.AndroidTestCase; -public class DhcpInfoTest extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; - public void testConstructor() { - new DhcpInfo(); +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.InetAddress; + +@RunWith(AndroidJUnit4.class) +public class DhcpInfoTest { + private static final String STR_ADDR1 = "255.255.255.255"; + private static final String STR_ADDR2 = "127.0.0.1"; + private static final String STR_ADDR3 = "192.168.1.1"; + private static final String STR_ADDR4 = "192.168.1.0"; + private static final int LEASE_TIME = 9999; + + private int ipToInteger(String ipString) throws Exception { + return inet4AddressToIntHTL((Inet4Address) InetAddress.getByName(ipString)); } - public void testToString() { - String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 dns1 0.0.0.0 " - + "dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; - String STR_ADDR1 = "255.255.255.255"; - String STR_ADDR2 = "127.0.0.1"; - String STR_ADDR3 = "192.168.1.1"; - String STR_ADDR4 = "192.168.1.0"; - int leaseTime = 9999; - String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask " - + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server " - + STR_ADDR2 + " lease " + leaseTime + " seconds"; - - DhcpInfo dhcpInfo = new DhcpInfo(); - - // Test default string. - assertEquals(expectedDefault, dhcpInfo.toString()); - + private DhcpInfo createDhcpInfoObject() throws Exception { + final DhcpInfo dhcpInfo = new DhcpInfo(); dhcpInfo.ipAddress = ipToInteger(STR_ADDR1); dhcpInfo.gateway = ipToInteger(STR_ADDR2); dhcpInfo.netmask = ipToInteger(STR_ADDR3); dhcpInfo.dns1 = ipToInteger(STR_ADDR4); dhcpInfo.dns2 = ipToInteger(STR_ADDR4); dhcpInfo.serverAddress = ipToInteger(STR_ADDR2); - dhcpInfo.leaseDuration = leaseTime; + dhcpInfo.leaseDuration = LEASE_TIME; + return dhcpInfo; + } + @Test + public void testConstructor() { + new DhcpInfo(); + } + + @Test + public void testToString() throws Exception { + final String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 " + + "dns1 0.0.0.0 dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; + + DhcpInfo dhcpInfo = new DhcpInfo(); + + // Test default string. + assertEquals(expectedDefault, dhcpInfo.toString()); + + dhcpInfo = createDhcpInfoObject(); + + final String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask " + + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server " + + STR_ADDR2 + " lease " + LEASE_TIME + " seconds"; // Test with new values assertEquals(expected, dhcpInfo.toString()); } - private int ipToInteger(String ipString) { - String ipSegs[] = ipString.split("[.]"); - int tmp = Integer.parseInt(ipSegs[3]) << 24 | Integer.parseInt(ipSegs[2]) << 16 | - Integer.parseInt(ipSegs[1]) << 8 | Integer.parseInt(ipSegs[0]); - return tmp; + private boolean dhcpInfoEquals(@Nullable DhcpInfo left, @Nullable DhcpInfo right) { + if (left == null && right == null) return true; + + if (left == null || right == null) return false; + + return left.ipAddress == right.ipAddress + && left.gateway == right.gateway + && left.netmask == right.netmask + && left.dns1 == right.dns1 + && left.dns2 == right.dns2 + && left.serverAddress == right.serverAddress + && left.leaseDuration == right.leaseDuration; + } + + @Test + public void testParcelDhcpInfo() throws Exception { + // Cannot use assertParcelSane() here because this requires .equals() to work as + // defined, but DhcpInfo has a different legacy behavior that we cannot change. + final DhcpInfo dhcpInfo = createDhcpInfoObject(); + assertFieldCountEquals(7, DhcpInfo.class); + + final DhcpInfo dhcpInfoRoundTrip = parcelingRoundTrip(dhcpInfo); + assertTrue(dhcpInfoEquals(null, null)); + assertFalse(dhcpInfoEquals(null, dhcpInfoRoundTrip)); + assertFalse(dhcpInfoEquals(dhcpInfo, null)); + assertTrue(dhcpInfoEquals(dhcpInfo, dhcpInfoRoundTrip)); } } From f3d18d43fc992e4a76a5255eb5f3946d6644fe0d Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Wed, 8 Apr 2020 23:37:10 -0700 Subject: [PATCH 0910/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I5fad2cb9cbe12cf0eb1d046317d420667a262b8e --- Tethering/res/values-ky/strings.xml | 6 +++--- Tethering/res/values-mcc204-mnc04-ar/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-bn/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-bs/strings.xml | 2 +- .../res/values-mcc204-mnc04-es-rUS/strings.xml | 4 ++-- Tethering/res/values-mcc204-mnc04-es/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-eu/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-gu/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-in/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-it/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-kn/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-ky/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-lo/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-ml/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-ne/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-or/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-pa/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-ru/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-sw/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-ta/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-te/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-uz/strings.xml | 15 +++++---------- .../res/values-mcc204-mnc04-zh-rCN/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-ar/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-bn/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-bs/strings.xml | 2 +- .../res/values-mcc310-mnc004-es-rUS/strings.xml | 4 ++-- Tethering/res/values-mcc310-mnc004-es/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-eu/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-gu/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-in/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-it/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-kn/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-ky/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-lo/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-ml/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-or/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-pa/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-ru/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-sw/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-ta/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-te/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-uz/strings.xml | 15 +++++---------- .../res/values-mcc310-mnc004-zh-rCN/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-ar/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-bn/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-bs/strings.xml | 2 +- .../res/values-mcc311-mnc480-es-rUS/strings.xml | 4 ++-- Tethering/res/values-mcc311-mnc480-es/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-eu/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-gu/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-in/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-it/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-kn/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-ky/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-lo/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-ml/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-or/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-pa/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-ru/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-sw/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-ta/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-te/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-uz/strings.xml | 15 +++++---------- .../res/values-mcc311-mnc480-zh-rCN/strings.xml | 2 +- Tethering/res/values-vi/strings.xml | 6 +++--- 68 files changed, 219 insertions(+), 399 deletions(-) diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index f763bf3ff0..7b9c0f5714 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -16,12 +16,12 @@ - "Жалгаштыруу же хотспот жандырылган" + "Модем режими күйүп турат" "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" + "Телефонду модем катары колдонууга болбойт" "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" - "Хотспот жана байланыш түйүнүүн статусу" + "Байланыш түйүнүнүн жана модем режиминин статусу" diff --git a/Tethering/res/values-mcc204-mnc04-ar/strings.xml b/Tethering/res/values-mcc204-mnc04-ar/strings.xml index 40eb9a741c..e6d8423f46 100644 --- a/Tethering/res/values-mcc204-mnc04-ar/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ar/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "نقطة الاتصال غير متصلة بالإنترنت." + "لا يمكن للأجهزة الاتصال بالإنترنت." + "إيقاف نقطة الاتصال" + "نقطة الاتصال مفعّلة" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." "متابعة" diff --git a/Tethering/res/values-mcc204-mnc04-bn/strings.xml b/Tethering/res/values-mcc204-mnc04-bn/strings.xml index 7f9efba7f0..9a3033c94d 100644 --- a/Tethering/res/values-mcc204-mnc04-bn/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-bn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" + "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" + "হটস্পট বন্ধ করুন" + "হটস্পট চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" "চালিয়ে যান" diff --git a/Tethering/res/values-mcc204-mnc04-bs/strings.xml b/Tethering/res/values-mcc204-mnc04-bs/strings.xml index 7539736415..57f6d88a4e 100644 --- a/Tethering/res/values-mcc204-mnc04-bs/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-bs/strings.xml @@ -20,6 +20,6 @@ "Uređaji se ne mogu povezati na internet" "Isključi pristupnu tačku" "Pristupna tačka je uključena" - "Primjenjuju se dodatne tarife u romingu" + "Mogu nastati dodatni troškovi u romingu" "Nastavi" diff --git a/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml index 196303fa83..956547cc6d 100644 --- a/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml @@ -16,10 +16,10 @@ - "El hotspot no tiene Internet" + "El hotspot no tiene conexión a Internet" "Los dispositivos no pueden conectarse a Internet" "Desactiva el hotspot" "El hotspot está activado" - "Es posible que apliquen cargos adicionales por roaming" + "Es posible que se apliquen cargos adicionales por roaming" "Continuar" diff --git a/Tethering/res/values-mcc204-mnc04-es/strings.xml b/Tethering/res/values-mcc204-mnc04-es/strings.xml index cac5b23bd9..831ec1fb1e 100644 --- a/Tethering/res/values-mcc204-mnc04-es/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-es/strings.xml @@ -19,7 +19,7 @@ "El punto de acceso no tiene conexión a Internet" "Los dispositivos no se pueden conectar a Internet" "Desactivar punto de acceso" - "Zona Wi-Fi activada" + "Punto de acceso activado" "Puede que se apliquen cargos adicionales en itinerancia" "Continuar" diff --git a/Tethering/res/values-mcc204-mnc04-eu/strings.xml b/Tethering/res/values-mcc204-mnc04-eu/strings.xml index 1758a4fada..c4f70a3eb4 100644 --- a/Tethering/res/values-mcc204-mnc04-eu/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-eu/strings.xml @@ -20,6 +20,6 @@ "Gailuak ezin dira konektatu Internetera" "Desaktibatu sare publikoa" "Sare publikoa aktibatuta dago" - "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" "Egin aurrera" diff --git a/Tethering/res/values-mcc204-mnc04-gu/strings.xml b/Tethering/res/values-mcc204-mnc04-gu/strings.xml index 0f4d26afdd..796d42ec52 100644 --- a/Tethering/res/values-mcc204-mnc04-gu/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-gu/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" + "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" + "હૉટસ્પૉટ બંધ કરો" + "હૉટસ્પૉટ ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" "આગળ વધો" diff --git a/Tethering/res/values-mcc204-mnc04-in/strings.xml b/Tethering/res/values-mcc204-mnc04-in/strings.xml index 4998474a36..1243d22d19 100644 --- a/Tethering/res/values-mcc204-mnc04-in/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-in/strings.xml @@ -16,7 +16,7 @@ - "Hotspot tidak memiliki internet" + "Hotspot tidak memiliki koneksi internet" "Perangkat tidak dapat tersambung ke internet" "Nonaktifkan hotspot" "Hotspot aktif" diff --git a/Tethering/res/values-mcc204-mnc04-it/strings.xml b/Tethering/res/values-mcc204-mnc04-it/strings.xml index a10d511c17..a0f52dc89b 100644 --- a/Tethering/res/values-mcc204-mnc04-it/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-it/strings.xml @@ -20,6 +20,6 @@ "I dispositivi non possono connettersi a Internet" "Disattiva l\'hotspot" "Hotspot attivo" - "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" "Continua" diff --git a/Tethering/res/values-mcc204-mnc04-kn/strings.xml b/Tethering/res/values-mcc204-mnc04-kn/strings.xml index 0427a77659..f0adad8e21 100644 --- a/Tethering/res/values-mcc204-mnc04-kn/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-kn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" + "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc204-mnc04-ky/strings.xml b/Tethering/res/values-mcc204-mnc04-ky/strings.xml index bc3d555597..35a060aa24 100644 --- a/Tethering/res/values-mcc204-mnc04-ky/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ky/strings.xml @@ -16,7 +16,7 @@ - "Хотспоттун Интернети жок" + "Байланыш түйүнүндө Интернет жок" "Түзмөктөр Интернетке туташпай жатат" "Туташуу түйүнүн өчүрүү" "Кошулуу түйүнү күйүк" diff --git a/Tethering/res/values-mcc204-mnc04-lo/strings.xml b/Tethering/res/values-mcc204-mnc04-lo/strings.xml index 06dcbcbccc..1d9203b369 100644 --- a/Tethering/res/values-mcc204-mnc04-lo/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-lo/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" + "ປິດຮັອດສະປອດ" + "ຮັອດສະປອດເປີດຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc204-mnc04-ml/strings.xml b/Tethering/res/values-mcc204-mnc04-ml/strings.xml index 0ef956a5a4..d376fe5870 100644 --- a/Tethering/res/values-mcc204-mnc04-ml/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ml/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" + "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" + "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" + "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" "തുടരുക" diff --git a/Tethering/res/values-mcc204-mnc04-ne/strings.xml b/Tethering/res/values-mcc204-mnc04-ne/strings.xml index fadd357ebf..63ce155034 100644 --- a/Tethering/res/values-mcc204-mnc04-ne/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ne/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "हटस्पटमा इन्टरनेट छैन" + "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" + "हटस्पट निष्क्रिय पार्नुहोस्" + "हटस्पट सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc204-mnc04-or/strings.xml b/Tethering/res/values-mcc204-mnc04-or/strings.xml index 1cdfce04d8..ab87b76caf 100644 --- a/Tethering/res/values-mcc204-mnc04-or/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-or/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc204-mnc04-pa/strings.xml b/Tethering/res/values-mcc204-mnc04-pa/strings.xml index 93402c35d0..b09f285c2d 100644 --- a/Tethering/res/values-mcc204-mnc04-pa/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-pa/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" + "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc204-mnc04-ru/strings.xml b/Tethering/res/values-mcc204-mnc04-ru/strings.xml index 69f8c59613..a2b1640cb2 100644 --- a/Tethering/res/values-mcc204-mnc04-ru/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ru/strings.xml @@ -17,7 +17,7 @@ "Точка доступа не подключена к Интернету" - "Не удается подключить устройства к Интернету" + "Устройства не могут подключаться к Интернету" "Отключить точку доступа" "Точка доступа включена" "За использование услуг связи в роуминге может взиматься дополнительная плата." diff --git a/Tethering/res/values-mcc204-mnc04-sw/strings.xml b/Tethering/res/values-mcc204-mnc04-sw/strings.xml index 3fe09fc22a..18ee457d03 100644 --- a/Tethering/res/values-mcc204-mnc04-sw/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-sw/strings.xml @@ -19,7 +19,7 @@ "Mtandao pepe hauna intaneti" "Vifaa vimeshindwa kuunganisha kwenye intaneti" "Zima mtandao pepe" - "Mtandaopepe umewashwa" + "Mtandao pepe umewashwa" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" "Endelea" diff --git a/Tethering/res/values-mcc204-mnc04-ta/strings.xml b/Tethering/res/values-mcc204-mnc04-ta/strings.xml index 63c28c6702..7eebd6784a 100644 --- a/Tethering/res/values-mcc204-mnc04-ta/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ta/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" + "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" + "ஹாட்ஸ்பாட்டை ஆஃப் செய்" + "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" "தொடர்க" diff --git a/Tethering/res/values-mcc204-mnc04-te/strings.xml b/Tethering/res/values-mcc204-mnc04-te/strings.xml index 2cf579ca0e..0986534fc7 100644 --- a/Tethering/res/values-mcc204-mnc04-te/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-te/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" + "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" + "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" + "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" "కొనసాగించు" diff --git a/Tethering/res/values-mcc204-mnc04-uz/strings.xml b/Tethering/res/values-mcc204-mnc04-uz/strings.xml index 5231c5fff5..715d34808b 100644 --- a/Tethering/res/values-mcc204-mnc04-uz/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-uz/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "Hotspot internetga ulanmagan" + "Qurilmalar internetga ulana olmayapti" + "Hotspotni faolsizlantirish" + "Hotspot yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" "Davom etish" diff --git a/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml index 38c2563638..cdb4224bf3 100644 --- a/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml @@ -16,7 +16,7 @@ - "热点无法访问互联网" + "热点没有网络连接" "设备无法连接到互联网" "关闭热点" "热点已开启" diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml index e5e7e5e03d..f4b4c176e7 100644 --- a/Tethering/res/values-mcc310-mnc004-ar/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "نقطة الاتصال غير متصلة بالإنترنت." + "لا يمكن للأجهزة الاتصال بالإنترنت." + "إيقاف نقطة الاتصال" + "نقطة الاتصال مفعّلة" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." "متابعة" diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml index d5ee1a91ce..7a8d1e173e 100644 --- a/Tethering/res/values-mcc310-mnc004-bn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" + "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" + "হটস্পট বন্ধ করুন" + "হটস্পট চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" "চালিয়ে যান" diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml index ae86e0aa8e..a4ec581fe9 100644 --- a/Tethering/res/values-mcc310-mnc004-bs/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -20,6 +20,6 @@ "Uređaji se ne mogu povezati na internet" "Isključi pristupnu tačku" "Pristupna tačka je uključena" - "Primjenjuju se dodatne tarife u romingu" + "Mogu nastati dodatni troškovi u romingu" "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml index d4b6937881..91368bf011 100644 --- a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -16,10 +16,10 @@ - "El hotspot no tiene Internet" + "El hotspot no tiene conexión a Internet" "Los dispositivos no pueden conectarse a Internet" "Desactiva el hotspot" "El hotspot está activado" - "Es posible que apliquen cargos adicionales por roaming" + "Es posible que se apliquen cargos adicionales por roaming" "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml index 158fd86296..c717033145 100644 --- a/Tethering/res/values-mcc310-mnc004-es/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -19,7 +19,7 @@ "El punto de acceso no tiene conexión a Internet" "Los dispositivos no se pueden conectar a Internet" "Desactivar punto de acceso" - "Zona Wi-Fi activada" + "Punto de acceso activado" "Puede que se apliquen cargos adicionales en itinerancia" "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml index 7a2b99e028..09de71f8bc 100644 --- a/Tethering/res/values-mcc310-mnc004-eu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -20,6 +20,6 @@ "Gailuak ezin dira konektatu Internetera" "Desaktibatu sare publikoa" "Sare publikoa aktibatuta dago" - "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" "Egin aurrera" diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml index e85c00c648..580f3c5cbf 100644 --- a/Tethering/res/values-mcc310-mnc004-gu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" + "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" + "હૉટસ્પૉટ બંધ કરો" + "હૉટસ્પૉટ ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" "આગળ વધો" diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml index 513d2fb040..bef3fc59d3 100644 --- a/Tethering/res/values-mcc310-mnc004-in/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -16,7 +16,7 @@ - "Hotspot tidak memiliki internet" + "Hotspot tidak memiliki koneksi internet" "Perangkat tidak dapat tersambung ke internet" "Nonaktifkan hotspot" "Hotspot aktif" diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml index b82363270b..cc5a6a5cda 100644 --- a/Tethering/res/values-mcc310-mnc004-it/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -20,6 +20,6 @@ "I dispositivi non possono connettersi a Internet" "Disattiva l\'hotspot" "Hotspot attivo" - "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" "Continua" diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml index 3e8aaebbe9..8044c9f5f6 100644 --- a/Tethering/res/values-mcc310-mnc004-kn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" + "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml index 7ecb6970e7..860c3e41f1 100644 --- a/Tethering/res/values-mcc310-mnc004-ky/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -16,7 +16,7 @@ - "Хотспоттун Интернети жок" + "Байланыш түйүнүндө Интернет жок" "Түзмөктөр Интернетке туташпай жатат" "Туташуу түйүнүн өчүрүү" "Кошулуу түйүнү күйүк" diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml index 5d1766707c..b6b8252164 100644 --- a/Tethering/res/values-mcc310-mnc004-lo/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" + "ປິດຮັອດສະປອດ" + "ຮັອດສະປອດເປີດຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml index 930ffa184e..b8fdda0991 100644 --- a/Tethering/res/values-mcc310-mnc004-ml/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" + "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" + "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" + "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" "തുടരുക" diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index e1770b3f77..86c070500f 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "हटस्पटमा इन्टरनेट छैन" + "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" + "हटस्पट निष्क्रिय पार्नुहोस्" + "हटस्पट सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml index 6a842428e0..5509a54b2f 100644 --- a/Tethering/res/values-mcc310-mnc004-or/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml index bb1479d3fb..790fced58e 100644 --- a/Tethering/res/values-mcc310-mnc004-pa/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" + "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml index 6ab396d50d..1ff63cf967 100644 --- a/Tethering/res/values-mcc310-mnc004-ru/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -17,7 +17,7 @@ "Точка доступа не подключена к Интернету" - "Не удается подключить устройства к Интернету" + "Устройства не могут подключаться к Интернету" "Отключить точку доступа" "Точка доступа включена" "За использование услуг связи в роуминге может взиматься дополнительная плата." diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml index 0eb922fff6..00e99bdf5f 100644 --- a/Tethering/res/values-mcc310-mnc004-sw/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -19,7 +19,7 @@ "Mtandao pepe hauna intaneti" "Vifaa vimeshindwa kuunganisha kwenye intaneti" "Zima mtandao pepe" - "Mtandaopepe umewashwa" + "Mtandao pepe umewashwa" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" "Endelea" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index 1d66c6d689..416d73f2d7 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" + "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" + "ஹாட்ஸ்பாட்டை ஆஃப் செய்" + "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" "தொடர்க" diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml index 2ee0fa8dda..864f726b94 100644 --- a/Tethering/res/values-mcc310-mnc004-te/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" + "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" + "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" + "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" "కొనసాగించు" diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml index 9def0a1b06..167b41a7ed 100644 --- a/Tethering/res/values-mcc310-mnc004-uz/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "Hotspot internetga ulanmagan" + "Qurilmalar internetga ulana olmayapti" + "Hotspotni faolsizlantirish" + "Hotspot yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" "Davom etish" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml index cee4682e7d..570d793c44 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -16,7 +16,7 @@ - "热点无法访问互联网" + "热点没有网络连接" "设备无法连接到互联网" "关闭热点" "热点已开启" diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml index 9460023663..15e5605d13 100644 --- a/Tethering/res/values-mcc311-mnc480-ar/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "نقطة الاتصال غير متصلة بالإنترنت." + "لا يمكن للأجهزة الاتصال بالإنترنت." + "إيقاف نقطة الاتصال" + "نقطة الاتصال مفعّلة" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." "متابعة" diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml index 00bac782ed..4058f719c9 100644 --- a/Tethering/res/values-mcc311-mnc480-bn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" + "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" + "হটস্পট বন্ধ করুন" + "হটস্পট চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" "চালিয়ে যান" diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml index 907821260b..ccfb199cee 100644 --- a/Tethering/res/values-mcc311-mnc480-bs/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -20,6 +20,6 @@ "Uređaji se ne mogu povezati na internet" "Isključi pristupnu tačku" "Pristupna tačka je uključena" - "Primjenjuju se dodatne tarife u romingu" + "Mogu nastati dodatni troškovi u romingu" "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml index 68d5fc26de..522fb5fc72 100644 --- a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -16,10 +16,10 @@ - "El hotspot no tiene Internet" + "El hotspot no tiene conexión a Internet" "Los dispositivos no pueden conectarse a Internet" "Desactiva el hotspot" "El hotspot está activado" - "Es posible que apliquen cargos adicionales por roaming" + "Es posible que se apliquen cargos adicionales por roaming" "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml index 930e088642..e2e30ee934 100644 --- a/Tethering/res/values-mcc311-mnc480-es/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -19,7 +19,7 @@ "El punto de acceso no tiene conexión a Internet" "Los dispositivos no se pueden conectar a Internet" "Desactivar punto de acceso" - "Zona Wi-Fi activada" + "Punto de acceso activado" "Puede que se apliquen cargos adicionales en itinerancia" "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml index 4358266323..34c36bb056 100644 --- a/Tethering/res/values-mcc311-mnc480-eu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -20,6 +20,6 @@ "Gailuak ezin dira konektatu Internetera" "Desaktibatu sare publikoa" "Sare publikoa aktibatuta dago" - "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" "Egin aurrera" diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml index c2af9a6688..13f74ac93d 100644 --- a/Tethering/res/values-mcc311-mnc480-gu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" + "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" + "હૉટસ્પૉટ બંધ કરો" + "હૉટસ્પૉટ ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" "આગળ વધો" diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml index e2538328cf..16efe936ef 100644 --- a/Tethering/res/values-mcc311-mnc480-in/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -16,7 +16,7 @@ - "Hotspot tidak memiliki internet" + "Hotspot tidak memiliki koneksi internet" "Perangkat tidak dapat tersambung ke internet" "Nonaktifkan hotspot" "Hotspot aktif" diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml index 388aa7a2c5..6ffa05bf93 100644 --- a/Tethering/res/values-mcc311-mnc480-it/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -20,6 +20,6 @@ "I dispositivi non possono connettersi a Internet" "Disattiva l\'hotspot" "Hotspot attivo" - "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" "Continua" diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml index 3c75b1205b..cc401b1775 100644 --- a/Tethering/res/values-mcc311-mnc480-kn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" + "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml index 85e92e0a3c..cbae0056fe 100644 --- a/Tethering/res/values-mcc311-mnc480-ky/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -16,7 +16,7 @@ - "Хотспоттун Интернети жок" + "Байланыш түйүнүндө Интернет жок" "Түзмөктөр Интернетке туташпай жатат" "Туташуу түйүнүн өчүрүү" "Кошулуу түйүнү күйүк" diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml index 881e05c5e0..33b03f8690 100644 --- a/Tethering/res/values-mcc311-mnc480-lo/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" + "ປິດຮັອດສະປອດ" + "ຮັອດສະປອດເປີດຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml index c9b12cd706..9e5336e46d 100644 --- a/Tethering/res/values-mcc311-mnc480-ml/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" + "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" + "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" + "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" "തുടരുക" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 9b2256abfc..2d7cf4d316 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "हटस्पटमा इन्टरनेट छैन" + "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" + "हटस्पट निष्क्रिय पार्नुहोस्" + "हटस्पट सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml index b478d1393b..e4c2458f44 100644 --- a/Tethering/res/values-mcc311-mnc480-or/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml index e0940a518d..642befbd64 100644 --- a/Tethering/res/values-mcc311-mnc480-pa/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" + "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml index 22dcfcf42d..fb2caa9428 100644 --- a/Tethering/res/values-mcc311-mnc480-ru/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -17,7 +17,7 @@ "Точка доступа не подключена к Интернету" - "Не удается подключить устройства к Интернету" + "Устройства не могут подключаться к Интернету" "Отключить точку доступа" "Точка доступа включена" "За использование услуг связи в роуминге может взиматься дополнительная плата." diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml index 5a812e3f0c..e3bb799a6b 100644 --- a/Tethering/res/values-mcc311-mnc480-sw/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -19,7 +19,7 @@ "Mtandao pepe hauna intaneti" "Vifaa vimeshindwa kuunganisha kwenye intaneti" "Zima mtandao pepe" - "Mtandaopepe umewashwa" + "Mtandao pepe umewashwa" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" "Endelea" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 315403135d..4fa3f03e82 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" + "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" + "ஹாட்ஸ்பாட்டை ஆஃப் செய்" + "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" "தொடர்க" diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml index 414def5963..49d7687178 100644 --- a/Tethering/res/values-mcc311-mnc480-te/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" + "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" + "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" + "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" "కొనసాగించు" diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml index 769cc2c385..c6bd803e3f 100644 --- a/Tethering/res/values-mcc311-mnc480-uz/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "Hotspot internetga ulanmagan" + "Qurilmalar internetga ulana olmayapti" + "Hotspotni faolsizlantirish" + "Hotspot yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" "Davom etish" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml index 75786086b6..eae5865b0c 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -16,7 +16,7 @@ - "热点无法访问互联网" + "热点没有网络连接" "设备无法连接到互联网" "关闭热点" "热点已开启" diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 19240700ee..156ab2d383 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -16,12 +16,12 @@ - "Tính năng chia sẻ kết nối hoặc điểm phát sóng đang hoạt động" + "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" "Hãy nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" + "Đã tắt tính năng chia sẻ Internet" "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" - "Trạng thái điểm phát sóng và trạng thái chia sẻ kết nối" + "Trạng thái điểm phát sóng và chia sẻ Internet" From 4475b7fc934eb2de9bfb05af7d82997c83e54ac6 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Mon, 30 Mar 2020 13:23:01 +0900 Subject: [PATCH 0911/1415] Add min_sdk_version:R to updatable apexes APEXes introduced in R need to set min_sdk_version to ensure that they are built against correct version of stubs (libc/liblog/...). Bug: 152655956 Test: m Merged-In: I4a893c34b09334eea124266287301e479b9e8a59 Change-Id: I4a893c34b09334eea124266287301e479b9e8a59 (cherry picked from commit f1460fad5252dfea1031c463a40e4202cf1d24e9) --- Tethering/apex/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp index 96a4d20077..24df5f6960 100644 --- a/Tethering/apex/Android.bp +++ b/Tethering/apex/Android.bp @@ -17,6 +17,7 @@ apex { name: "com.android.tethering", updatable: true, + min_sdk_version: "R", java_libs: ["framework-tethering"], apps: ["Tethering"], manifest: "manifest.json", From 2b1fbd6404b9261d119da5ca34eabba413284be7 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 24 Mar 2020 05:32:24 +0000 Subject: [PATCH 0912/1415] Refactor assertion into assertInRange() method It's hard to read in current design, refactor the assertion into assertInRange() for readability. Bug: 153614624 Test: atest android.net.cts.TrafficStatsTest Change-Id: I6d939dd62cad3d6ba23a3c5ca7b1e6a8b4131a90 Merged-In: I6d939dd62cad3d6ba23a3c5ca7b1e6a8b4131a90 (cherry picked from commit af3469bdc7031d80f3d3838518fd7518b3e8eb9c) --- .../src/android/net/cts/TrafficStatsTest.java | 137 +++++++++--------- 1 file changed, 67 insertions(+), 70 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 5bd1e208a8..12ab3702d4 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -24,6 +24,7 @@ import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; import android.util.Log; +import android.util.Range; import java.io.IOException; import java.io.InputStream; @@ -36,6 +37,13 @@ import java.util.concurrent.TimeUnit; public class TrafficStatsTest extends AndroidTestCase { private static final String LOG_TAG = "TrafficStatsTest"; + /** Verify the given value is in range [lower, upper] */ + private void assertInRange(String tag, long value, long lower, long upper) { + final Range range = new Range(lower, upper); + assertTrue(tag + ": " + value + " is not within range [" + lower + ", " + upper + "]", + range.contains(value)); + } + public void testValidMobileStats() { // We can't assume a mobile network is even present in this test, so // we simply assert that a valid value is returned. @@ -107,12 +115,12 @@ public class TrafficStatsTest extends AndroidTestCase { @Override public void run() { try { - Socket socket = new Socket("localhost", server.getLocalPort()); + final Socket socket = new Socket("localhost", server.getLocalPort()); // Make sure that each write()+flush() turns into a packet: // disable Nagle. socket.setTcpNoDelay(true); - OutputStream out = socket.getOutputStream(); - byte[] buf = new byte[byteCount]; + final OutputStream out = socket.getOutputStream(); + final byte[] buf = new byte[byteCount]; TrafficStats.setThreadStatsTag(0x42); TrafficStats.tagSocket(socket); for (int i = 0; i < packetCount; i++) { @@ -135,12 +143,12 @@ public class TrafficStatsTest extends AndroidTestCase { int read = 0; try { - Socket socket = server.accept(); + final Socket socket = server.accept(); socket.setTcpNoDelay(true); TrafficStats.setThreadStatsTag(0x43); TrafficStats.tagSocket(socket); - InputStream in = socket.getInputStream(); - byte[] buf = new byte[byteCount]; + final InputStream in = socket.getInputStream(); + final byte[] buf = new byte[byteCount]; while (read < byteCount * packetCount) { int n = in.read(buf); assertTrue("Unexpected EOF", n > 0); @@ -156,24 +164,24 @@ public class TrafficStatsTest extends AndroidTestCase { Thread.sleep(1000); } catch (InterruptedException e) { } - NetworkStats testStats = TrafficStats.stopDataProfiling(null); + final NetworkStats testStats = TrafficStats.stopDataProfiling(null); - long mobileTxPacketsAfter = TrafficStats.getMobileTxPackets(); - long mobileRxPacketsAfter = TrafficStats.getMobileRxPackets(); - long mobileTxBytesAfter = TrafficStats.getMobileTxBytes(); - long mobileRxBytesAfter = TrafficStats.getMobileRxBytes(); - long totalTxPacketsAfter = TrafficStats.getTotalTxPackets(); - long totalRxPacketsAfter = TrafficStats.getTotalRxPackets(); - long totalTxBytesAfter = TrafficStats.getTotalTxBytes(); - long totalRxBytesAfter = TrafficStats.getTotalRxBytes(); - long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid()); - long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid()); - long uidTxPacketsAfter = TrafficStats.getUidTxPackets(Process.myUid()); - long uidRxPacketsAfter = TrafficStats.getUidRxPackets(Process.myUid()); - long uidTxDeltaBytes = uidTxBytesAfter - uidTxBytesBefore; - long uidTxDeltaPackets = uidTxPacketsAfter - uidTxPacketsBefore; - long uidRxDeltaBytes = uidRxBytesAfter - uidRxBytesBefore; - long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore; + final long mobileTxPacketsAfter = TrafficStats.getMobileTxPackets(); + final long mobileRxPacketsAfter = TrafficStats.getMobileRxPackets(); + final long mobileTxBytesAfter = TrafficStats.getMobileTxBytes(); + final long mobileRxBytesAfter = TrafficStats.getMobileRxBytes(); + final long totalTxPacketsAfter = TrafficStats.getTotalTxPackets(); + final long totalRxPacketsAfter = TrafficStats.getTotalRxPackets(); + final long totalTxBytesAfter = TrafficStats.getTotalTxBytes(); + final long totalRxBytesAfter = TrafficStats.getTotalRxBytes(); + final long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid()); + final long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid()); + final long uidTxPacketsAfter = TrafficStats.getUidTxPackets(Process.myUid()); + final long uidRxPacketsAfter = TrafficStats.getUidRxPackets(Process.myUid()); + final long uidTxDeltaBytes = uidTxBytesAfter - uidTxBytesBefore; + final long uidTxDeltaPackets = uidTxPacketsAfter - uidTxPacketsBefore; + final long uidRxDeltaBytes = uidRxBytesAfter - uidRxBytesBefore; + final long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore; // Localhost traffic *does* count against per-UID stats. /* @@ -192,10 +200,13 @@ public class TrafficStatsTest extends AndroidTestCase { // Some other tests don't cleanup connections correctly. // They have the same UID, so we discount their lingering traffic // which happens only on non-localhost, such as TCP FIN retranmission packets - long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore) - uidTxDeltaPackets; - long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) - uidRxDeltaPackets; + final long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore) + - uidTxDeltaPackets; + final long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) + - uidRxDeltaPackets; if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { - Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); + Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + + deltaRxOtherPackets); } // Check the per uid stats read from data profiling have the stats expected. The data @@ -203,39 +214,29 @@ public class TrafficStatsTest extends AndroidTestCase { // networkStatsService and in this way we can verify the detail networkStats of a given uid // is correct. NetworkStats.Entry entry = testStats.getTotal(null, Process.myUid()); - assertTrue("txPackets detail: " + entry.txPackets + " uidTxPackets: " + uidTxDeltaPackets, - entry.txPackets >= packetCount + minExpectedExtraPackets - && entry.txPackets <= uidTxDeltaPackets); - assertTrue("rxPackets detail: " + entry.rxPackets + " uidRxPackets: " + uidRxDeltaPackets, - entry.rxPackets >= packetCount + minExpectedExtraPackets - && entry.rxPackets <= uidRxDeltaPackets); - assertTrue("txBytes detail: " + entry.txBytes + " uidTxDeltaBytes: " + uidTxDeltaBytes, - entry.txBytes >= tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && entry.txBytes <= uidTxDeltaBytes); - assertTrue("rxBytes detail: " + entry.rxBytes + " uidRxDeltaBytes: " + uidRxDeltaBytes, - entry.rxBytes >= tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && entry.rxBytes <= uidRxDeltaBytes); + assertInRange("txPackets detail", entry.txPackets, packetCount + minExpectedExtraPackets, + uidTxDeltaPackets); + assertInRange("rxPackets detail", entry.rxPackets, packetCount + minExpectedExtraPackets, + uidRxDeltaPackets); + assertInRange("txBytes detail", entry.txBytes, tcpPacketToIpBytes(packetCount, byteCount) + + tcpPacketToIpBytes(minExpectedExtraPackets, 0), uidTxDeltaBytes); + assertInRange("rxBytes detail", entry.rxBytes, tcpPacketToIpBytes(packetCount, byteCount) + + tcpPacketToIpBytes(minExpectedExtraPackets, 0), uidRxDeltaBytes); - assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + - " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + - uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets + "+" + deltaTxOtherPackets, - uidTxDeltaPackets >= packetCount + minExpectedExtraPackets && - uidTxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); - assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets + - " Wanted: " + uidRxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + - uidRxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets, - uidRxDeltaPackets >= packetCount + minExpectedExtraPackets && - uidRxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); - assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes + - " Wanted: " + uidTxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + - uidTxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), - uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && - uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaTxOtherPackets, 0)); - assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes + - " Wanted: " + uidRxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + - uidRxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), - uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && - uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaRxOtherPackets, 0)); + assertInRange("uidtxp", uidTxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); + assertInRange("uidrxp", uidRxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); + assertInRange("uidtxb", uidTxDeltaBytes, tcpPacketToIpBytes(packetCount, byteCount) + + tcpPacketToIpBytes(minExpectedExtraPackets, 0), + tcpPacketToIpBytes(packetCount, byteCount) + + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + + deltaTxOtherPackets, 0)); + assertInRange("uidrxb", uidRxDeltaBytes, tcpPacketToIpBytes(packetCount, byteCount) + + tcpPacketToIpBytes(minExpectedExtraPackets, 0), + tcpPacketToIpBytes(packetCount, byteCount) + + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + + deltaRxOtherPackets, 0)); // Localhost traffic *does* count against total stats. // Check the total stats increased after test data transfer over localhost has been made. @@ -272,17 +273,13 @@ public class TrafficStatsTest extends AndroidTestCase { // Localhost traffic should *not* count against mobile stats, // There might be some other traffic, but nowhere near 1MB. - assertTrue("mtxp: " + mobileTxPacketsBefore + " -> " + mobileTxPacketsAfter, - mobileTxPacketsAfter >= mobileTxPacketsBefore && - mobileTxPacketsAfter <= mobileTxPacketsBefore + 500); - assertTrue("mrxp: " + mobileRxPacketsBefore + " -> " + mobileRxPacketsAfter, - mobileRxPacketsAfter >= mobileRxPacketsBefore && - mobileRxPacketsAfter <= mobileRxPacketsBefore + 500); - assertTrue("mtxb: " + mobileTxBytesBefore + " -> " + mobileTxBytesAfter, - mobileTxBytesAfter >= mobileTxBytesBefore && - mobileTxBytesAfter <= mobileTxBytesBefore + 200000); - assertTrue("mrxb: " + mobileRxBytesBefore + " -> " + mobileRxBytesAfter, - mobileRxBytesAfter >= mobileRxBytesBefore && - mobileRxBytesAfter <= mobileRxBytesBefore + 200000); + assertInRange("mtxp", mobileTxPacketsAfter, mobileTxPacketsBefore, + mobileTxPacketsBefore + 500); + assertInRange("mrxp", mobileRxPacketsAfter, mobileRxPacketsBefore, + mobileRxPacketsBefore + 500); + assertInRange("mtxb", mobileTxBytesAfter, mobileTxBytesBefore, + mobileTxBytesBefore + 200000); + assertInRange("mrxb", mobileRxBytesAfter, mobileRxBytesBefore, + mobileRxBytesBefore + 200000); } } From ed041b098a610e624cffc32b221234bfe54c54e7 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 10 Apr 2020 09:21:41 +0800 Subject: [PATCH 0913/1415] Add TetherableInterfaceRegexps CTS tests Test APIs below: getTetherableWifiRegexs() getTetherableUsbRegexs() getTetherableBluetoothRegexs() TetheringInterfaceRegexps.getTetherableWifiRegexs() TetheringInterfaceRegexps.getTetherableUsbRegexs() TetheringInterfaceRegexps.getTetherableBluetoothRegexs() Bug: 152737526 Test: atest CtsTetheringTest Change-Id: Icb7d8718d0aa6574b4c9dd1e17d7feb300fad2aa --- .../tethering/cts/TetheringManagerTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index b132982e1a..193a5dc3a4 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -428,4 +428,30 @@ public class TetheringManagerTest { tetherEventCallback.expectTetheredInterfacesChanged(null); mTM.unregisterTetheringEventCallback(tetherEventCallback); } + + @Test + public void testGetTetherableInterfaceRegexps() { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); + mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); + tetherEventCallback.expectCallbackStarted(); + + final TetheringInterfaceRegexps tetherableRegexs = + tetherEventCallback.getTetheringInterfaceRegexps(); + final List wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); + final List usbRegexs = tetherableRegexs.getTetherableUsbRegexs(); + final List btRegexs = tetherableRegexs.getTetherableBluetoothRegexs(); + + assertEquals(wifiRegexs, Arrays.asList(mTM.getTetherableWifiRegexs())); + assertEquals(usbRegexs, Arrays.asList(mTM.getTetherableUsbRegexs())); + assertEquals(btRegexs, Arrays.asList(mTM.getTetherableBluetoothRegexs())); + + //Verify that any of interface name should only contain in one array. + wifiRegexs.forEach(s -> assertFalse(usbRegexs.contains(s))); + wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); + usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); + + mTM.unregisterTetheringEventCallback(tetherEventCallback); + } } From ab9f1262702da216e9fa6cf798192ad1fb15a006 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Mar 2020 21:08:39 +0900 Subject: [PATCH 0914/1415] Test onBandwidthUpdateRequested Test: this Bug: 139268426 Change-Id: I427ae6ac2c8910683e47f503ba71a05e35507571 --- .../net/src/android/net/cts/NetworkAgentTest.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 85c94e7db2..2fdd5fb201 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -24,6 +24,7 @@ import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkProvider import android.net.NetworkRequest +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted import android.os.Build import android.os.HandlerThread @@ -88,9 +89,15 @@ class NetworkAgentTest { private val history = ArrayTrackRecord().newReadHead() sealed class CallbackEntry { + object OnBandwidthUpdateRequested : CallbackEntry() object OnNetworkUnwanted : CallbackEntry() } + override fun onBandwidthUpdateRequested() { + super.onBandwidthUpdateRequested() + history.add(OnBandwidthUpdateRequested) + } + override fun onNetworkUnwanted() { super.onNetworkUnwanted() history.add(OnNetworkUnwanted) @@ -139,4 +146,13 @@ class NetworkAgentTest { agent.register() } } + + @Test + fun testOnBandwidthUpdateRequested() { + val (agent, callback) = createConnectedNetworkAgent() + callback.expectAvailableThenValidatedCallbacks(agent.network) + mCM.requestBandwidthUpdate(agent.network) + agent.expectCallback() + agent.unregister() + } } From bbd10f21a0b7ffa4584f1066170d34ffb2856cc8 Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Wed, 8 Apr 2020 13:10:26 +0000 Subject: [PATCH 0915/1415] Add testRegisterTetheringEventCallback for CtsTetheringTest Bug: 150632712 Bug: 150631563 Test: atest CtsTetheringTest Merged-In: I55895c8b26acb7ec905d75d1f4b2a8964b13187a Change-Id: I55895c8b26acb7ec905d75d1f4b2a8964b13187a --- .../tethering/cts/TetheringManagerTest.java | 181 +++++++++++++++++- 1 file changed, 179 insertions(+), 2 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 86fe54ce54..b132982e1a 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -29,9 +29,14 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.LinkAddress; +import android.net.Network; +import android.net.TetheredClient; import android.net.TetheringManager; +import android.net.TetheringManager.TetheringEventCallback; +import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; +import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -42,6 +47,8 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -195,8 +202,12 @@ public class TetheringManagerTest { } } - private static boolean isIfaceMatch(final String[] ifaceRegexs, - final ArrayList ifaces) { + private static boolean isIfaceMatch(final List ifaceRegexs, + final List ifaces) { + return isIfaceMatch(ifaceRegexs.toArray(new String[0]), ifaces); + } + + private static boolean isIfaceMatch(final String[] ifaceRegexs, final List ifaces) { if (ifaceRegexs == null) fail("ifaceRegexs should not be null"); if (ifaces == null) return false; @@ -251,4 +262,170 @@ public class TetheringManagerTest { assertTrue(tr2.isExemptFromEntitlementCheck()); assertFalse(tr2.getShouldShowEntitlementUi()); } + + // Must poll the callback before looking at the member. + private static class TestTetheringEventCallback implements TetheringEventCallback { + public enum CallbackType { + ON_SUPPORTED, + ON_UPSTREAM, + ON_TETHERABLE_REGEX, + ON_TETHERABLE_IFACES, + ON_TETHERED_IFACES, + ON_ERROR, + ON_CLIENTS, + }; + + public static class CallbackValue { + public final CallbackType callbackType; + public final Object callbackParam; + public final int callbackParam2; + + private CallbackValue(final CallbackType type, final Object param, final int param2) { + this.callbackType = type; + this.callbackParam = param; + this.callbackParam2 = param2; + } + } + private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + private TetheringInterfaceRegexps mTetherableRegex; + private List mTetherableIfaces; + private List mTetheredIfaces; + + @Override + public void onTetheringSupported(boolean supported) { + mCallbacks.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); + } + + @Override + public void onUpstreamChanged(Network network) { + mCallbacks.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); + } + + @Override + public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { + mTetherableRegex = reg; + mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); + } + + @Override + public void onTetherableInterfacesChanged(List interfaces) { + mTetherableIfaces = interfaces; + mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); + } + + @Override + public void onTetheredInterfacesChanged(List interfaces) { + mTetheredIfaces = interfaces; + mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); + } + + @Override + public void onError(String ifName, int error) { + mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); + } + + @Override + public void onClientsChanged(Collection clients) { + mCallbacks.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); + } + + public CallbackValue pollCallback() { + try { + return mCallbacks.poll(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + fail("Callback not seen"); + } + return null; + } + + public void expectTetherableInterfacesChanged(@NonNull List regexs) { + while (true) { + final CallbackValue cv = pollCallback(); + if (cv == null) fail("No expected tetherable ifaces callback"); + if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) continue; + + final List interfaces = (List) cv.callbackParam; + if (isIfaceMatch(regexs, interfaces)) break; + } + } + + public void expectTetheredInterfacesChanged(@NonNull List regexs) { + while (true) { + final CallbackValue cv = pollCallback(); + if (cv == null) fail("No expected tethered ifaces callback"); + if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) continue; + + final List interfaces = (List) cv.callbackParam; + + // Null regexs means no active tethering. + if (regexs == null) { + if (interfaces.size() == 0) break; + } else if (isIfaceMatch(regexs, interfaces)) { + break; + } + } + } + + public void expectCallbackStarted() { + // The each bit represent a type from CallbackType.ON_*. + // Expect all of callbacks except for ON_ERROR. + final int expectedBitMap = 0x7f ^ (1 << CallbackType.ON_ERROR.ordinal()); + int receivedBitMap = 0; + while (receivedBitMap != expectedBitMap) { + final CallbackValue cv = pollCallback(); + if (cv == null) { + fail("No expected callbacks, " + "expected bitmap: " + + expectedBitMap + ", actual: " + receivedBitMap); + } + receivedBitMap = receivedBitMap | (1 << cv.callbackType.ordinal()); + } + } + + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { + return mTetherableRegex; + } + + public List getTetherableInterfaces() { + return mTetherableIfaces; + } + + public List getTetheredInterfaces() { + return mTetheredIfaces; + } + } + + @Test + public void testRegisterTetheringEventCallback() throws Exception { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); + + mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); + tetherEventCallback.expectCallbackStarted(); + + final TetheringInterfaceRegexps tetherableRegexs = + tetherEventCallback.getTetheringInterfaceRegexps(); + final List wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); + if (wifiRegexs.size() == 0) return; + + final boolean isIfaceAvailWhenNoTethering = + isIfaceMatch(wifiRegexs, tetherEventCallback.getTetherableInterfaces()); + + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(), + new StartTetheringCallback()); + + // If interface is already available before starting tethering, the available callback may + // not be sent after tethering enabled. + if (!isIfaceAvailWhenNoTethering) { + tetherEventCallback.expectTetherableInterfacesChanged(wifiRegexs); + } + + tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); + + mTM.stopTethering(TETHERING_WIFI); + + tetherEventCallback.expectTetheredInterfacesChanged(null); + mTM.unregisterTetheringEventCallback(tetherEventCallback); + } } From 853c428964aa6d607c65132080f8986541191bd0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 10 Apr 2020 11:34:58 -0600 Subject: [PATCH 0916/1415] Fix logic inversion bug from Android 1.0. Bug: 73822755 Test: atest CtsNetTestCases:android.net.cts.UrlQuerySanitizerTest Change-Id: Ice98bb0813918341d8cffd3197cd9758d0cbf285 --- .../android/net/cts/UrlQuerySanitizerTest.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java index 2d615bbe86..82b3b14d34 100644 --- a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -16,14 +16,15 @@ package android.net.cts; -import java.util.List; -import java.util.Set; import android.net.UrlQuerySanitizer; import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; import android.net.UrlQuerySanitizer.ParameterValuePair; import android.net.UrlQuerySanitizer.ValueSanitizer; import android.test.AndroidTestCase; +import java.util.List; +import java.util.Set; + public class UrlQuerySanitizerTest extends AndroidTestCase { private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; @@ -209,6 +210,17 @@ public class UrlQuerySanitizerTest extends AndroidTestCase { } + public void testScriptUrlOk_73822755() { + ValueSanitizer sanitizer = new UrlQuerySanitizer.IllegalCharacterValueSanitizer( + UrlQuerySanitizer.IllegalCharacterValueSanitizer.SCRIPT_URL_OK); + assertEquals("javascript:alert()", sanitizer.sanitize("javascript:alert()")); + } + + public void testScriptUrlBlocked_73822755() { + ValueSanitizer sanitizer = UrlQuerySanitizer.getUrlAndSpaceLegal(); + assertEquals("", sanitizer.sanitize("javascript:alert()")); + } + private static class MockValueSanitizer implements ValueSanitizer{ public String sanitize(String value) { From 848b78d9fb307336337560aff274ca8c8ef51543 Mon Sep 17 00:00:00 2001 From: evitayan Date: Sun, 8 Mar 2020 18:41:02 -0700 Subject: [PATCH 0917/1415] Add CTS for building IKE and Child SaProposal Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ic50d70f35216a065ff398c38262f2de0b370c5ef --- .../net/ipsec/ike/cts/SaProposalTest.java | 232 +++++++++++++++++- 1 file changed, 229 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java index 47e8f0174d..e0d3be0540 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java @@ -16,15 +16,241 @@ package android.net.ipsec.ike.cts; +import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP; +import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; +import static android.net.ipsec.ike.SaProposal.DH_GROUP_NONE; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeSaProposal; +import android.util.Pair; + import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + @RunWith(AndroidJUnit4.class) public class SaProposalTest { - @Test - public void testBuildIkeSaProposal() { - // TODO(b/148689509): Add real tests here + private static final List> NORMAL_MODE_CIPHERS = new ArrayList<>(); + private static final List> COMBINED_MODE_CIPHERS = new ArrayList<>(); + private static final List INTEGRITY_ALGOS = new ArrayList<>(); + private static final List DH_GROUPS = new ArrayList<>(); + private static final List DH_GROUPS_WITH_NONE = new ArrayList<>(); + private static final List PRFS = new ArrayList<>(); + + static { + NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)); + NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128)); + NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192)); + NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)); + + COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128)); + COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192)); + COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256)); + + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96); + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_AES_XCBC_96); + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128); + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192); + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256); + + DH_GROUPS.add(DH_GROUP_1024_BIT_MODP); + DH_GROUPS.add(DH_GROUP_2048_BIT_MODP); + + DH_GROUPS_WITH_NONE.add(DH_GROUP_NONE); + DH_GROUPS_WITH_NONE.addAll(DH_GROUPS); + + PRFS.add(PSEUDORANDOM_FUNCTION_HMAC_SHA1); + PRFS.add(PSEUDORANDOM_FUNCTION_AES128_XCBC); + PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_256); + PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_384); + PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_512); } + + // Package private + static IkeSaProposal buildIkeSaProposalWithNormalModeCipher() { + return buildIkeSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, PRFS, DH_GROUPS); + } + + // Package private + static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher() { + return buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); + } + + private static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher( + boolean hasIntegrityNone) { + List integerAlgos = new ArrayList<>(); + if (hasIntegrityNone) { + integerAlgos.add(INTEGRITY_ALGORITHM_NONE); + } + return buildIkeSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, PRFS, DH_GROUPS); + } + + private static IkeSaProposal buildIkeSaProposal( + List> ciphers, + List integrityAlgos, + List prfs, + List dhGroups) { + IkeSaProposal.Builder builder = new IkeSaProposal.Builder(); + + for (Pair pair : ciphers) { + builder.addEncryptionAlgorithm(pair.first, pair.second); + } + for (int algo : integrityAlgos) { + builder.addIntegrityAlgorithm(algo); + } + for (int algo : prfs) { + builder.addPseudorandomFunction(algo); + } + for (int algo : dhGroups) { + builder.addDhGroup(algo); + } + + return builder.build(); + } + + // Package private + static ChildSaProposal buildChildSaProposalWithNormalModeCipher() { + return buildChildSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, DH_GROUPS_WITH_NONE); + } + + // Package private + static ChildSaProposal buildChildSaProposalWithCombinedModeCipher() { + return buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); + } + + private static ChildSaProposal buildChildSaProposalWithCombinedModeCipher( + boolean hasIntegrityNone) { + List integerAlgos = new ArrayList<>(); + if (hasIntegrityNone) { + integerAlgos.add(INTEGRITY_ALGORITHM_NONE); + } + + return buildChildSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, DH_GROUPS_WITH_NONE); + } + + private static ChildSaProposal buildChildSaProposal( + List> ciphers, + List integrityAlgos, + List dhGroups) { + ChildSaProposal.Builder builder = new ChildSaProposal.Builder(); + + for (Pair pair : ciphers) { + builder.addEncryptionAlgorithm(pair.first, pair.second); + } + for (int algo : integrityAlgos) { + builder.addIntegrityAlgorithm(algo); + } + for (int algo : dhGroups) { + builder.addDhGroup(algo); + } + + return builder.build(); + } + + // Package private + static ChildSaProposal buildChildSaProposalWithOnlyCiphers() { + return buildChildSaProposal( + COMBINED_MODE_CIPHERS, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + } + + @Test + public void testBuildIkeSaProposalWithNormalModeCipher() { + IkeSaProposal saProposal = buildIkeSaProposalWithNormalModeCipher(); + + assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms()); + assertEquals(PRFS, saProposal.getPseudorandomFunctions()); + assertEquals(DH_GROUPS, saProposal.getDhGroups()); + } + + @Test + public void testBuildIkeSaProposalWithCombinedModeCipher() { + IkeSaProposal saProposal = + buildIkeSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(PRFS, saProposal.getPseudorandomFunctions()); + assertEquals(DH_GROUPS, saProposal.getDhGroups()); + assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); + } + + @Test + public void testBuildIkeSaProposalWithCombinedModeCipherAndIntegrityNone() { + IkeSaProposal saProposal = + buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(PRFS, saProposal.getPseudorandomFunctions()); + assertEquals(DH_GROUPS, saProposal.getDhGroups()); + assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms()); + } + + @Test + public void testBuildChildSaProposalWithNormalModeCipher() { + ChildSaProposal saProposal = buildChildSaProposalWithNormalModeCipher(); + + assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms()); + assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); + } + + @Test + public void testBuildChildProposalWithCombinedModeCipher() { + ChildSaProposal saProposal = + buildChildSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); + assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); + } + + @Test + public void testBuildChildProposalWithCombinedModeCipherAndIntegrityNone() { + ChildSaProposal saProposal = + buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms()); + assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); + } + + @Test + public void testBuildChildSaProposalWithOnlyCiphers() { + ChildSaProposal saProposal = buildChildSaProposalWithOnlyCiphers(); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); + assertTrue(saProposal.getDhGroups().isEmpty()); + } + + // TODO(b/148689509): Test throwing exception when algorithm combination is invalid } From e1236aeae4627ec3b4b5a7b96891f2107fb4c34f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 9 Apr 2020 03:26:31 +0000 Subject: [PATCH 0918/1415] Add cts test for traffic stats APIs This change adds test for new public APIs. Bug: 135998869 Test: atest CtsNetTestCasesLatestSdk:TrafficStatsTest Change-Id: Iefc234fb85145b31a1f7842b93b4d6fc4425bab6 Merged-In: I6b4a6773e22a204b6267d28638b9f57a0d0eb65a (cherry picked from commit e5a3234c38c35aaec55029e369f2aac2ec4326cd) --- .../src/android/net/cts/TrafficStatsTest.java | 58 ++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 12ab3702d4..577e24ac29 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -61,6 +61,11 @@ public class TrafficStatsTest extends AndroidTestCase { assertTrue(TrafficStats.getTotalRxBytes() >= 0); } + public void testValidPacketStats() { + assertTrue(TrafficStats.getTxPackets("lo") >= 0); + assertTrue(TrafficStats.getRxPackets("lo") >= 0); + } + public void testThreadStatsTag() throws Exception { TrafficStats.setThreadStatsTag(0xf00d); assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xf00d); @@ -104,6 +109,8 @@ public class TrafficStatsTest extends AndroidTestCase { final long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); final long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid()); final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid()); + final long ifaceTxPacketsBefore = TrafficStats.getTxPackets("lo"); + final long ifaceRxPacketsBefore = TrafficStats.getRxPackets("lo"); // Transfer 1MB of data across an explicitly localhost socket. final int byteCount = 1024; @@ -182,6 +189,10 @@ public class TrafficStatsTest extends AndroidTestCase { final long uidTxDeltaPackets = uidTxPacketsAfter - uidTxPacketsBefore; final long uidRxDeltaBytes = uidRxBytesAfter - uidRxBytesBefore; final long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore; + final long ifaceTxPacketsAfter = TrafficStats.getTxPackets("lo"); + final long ifaceRxPacketsAfter = TrafficStats.getRxPackets("lo"); + final long ifaceTxDeltaPackets = ifaceTxPacketsAfter - ifaceTxPacketsBefore; + final long ifaceRxDeltaPackets = ifaceRxPacketsAfter - ifaceRxPacketsBefore; // Localhost traffic *does* count against per-UID stats. /* @@ -209,34 +220,37 @@ public class TrafficStatsTest extends AndroidTestCase { + deltaRxOtherPackets); } - // Check the per uid stats read from data profiling have the stats expected. The data - // profiling snapshot is generated from readNetworkStatsDetail() method in - // networkStatsService and in this way we can verify the detail networkStats of a given uid - // is correct. - NetworkStats.Entry entry = testStats.getTotal(null, Process.myUid()); + // Check that the per-uid stats obtained from data profiling contain the expected values. + // The data profiling snapshot is generated from the readNetworkStatsDetail() method in + // networkStatsService, so it's possible to verify that the detailed stats for a given + // uid are correct. + final NetworkStats.Entry entry = testStats.getTotal(null, Process.myUid()); + final long pktBytes = tcpPacketToIpBytes(packetCount, byteCount); + final long pktWithNoDataBytes = tcpPacketToIpBytes(packetCount, 0); + final long minExpExtraPktBytes = tcpPacketToIpBytes(minExpectedExtraPackets, 0); + final long maxExpExtraPktBytes = tcpPacketToIpBytes(maxExpectedExtraPackets, 0); + final long deltaTxOtherPktBytes = tcpPacketToIpBytes(deltaTxOtherPackets, 0); + final long deltaRxOtherPktBytes = tcpPacketToIpBytes(deltaRxOtherPackets, 0); assertInRange("txPackets detail", entry.txPackets, packetCount + minExpectedExtraPackets, uidTxDeltaPackets); assertInRange("rxPackets detail", entry.rxPackets, packetCount + minExpectedExtraPackets, uidRxDeltaPackets); - assertInRange("txBytes detail", entry.txBytes, tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0), uidTxDeltaBytes); - assertInRange("rxBytes detail", entry.rxBytes, tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0), uidRxDeltaBytes); - + assertInRange("txBytes detail", entry.txBytes, pktBytes + minExpExtraPktBytes, + uidTxDeltaBytes); + assertInRange("rxBytes detail", entry.rxBytes, pktBytes + minExpExtraPktBytes, + uidRxDeltaBytes); assertInRange("uidtxp", uidTxDeltaPackets, packetCount + minExpectedExtraPackets, packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); assertInRange("uidrxp", uidRxDeltaPackets, packetCount + minExpectedExtraPackets, packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); - assertInRange("uidtxb", uidTxDeltaBytes, tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0), - tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets - + deltaTxOtherPackets, 0)); - assertInRange("uidrxb", uidRxDeltaBytes, tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(minExpectedExtraPackets, 0), - tcpPacketToIpBytes(packetCount, byteCount) - + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets - + deltaRxOtherPackets, 0)); + assertInRange("uidtxb", uidTxDeltaBytes, pktBytes + minExpExtraPktBytes, + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaTxOtherPktBytes); + assertInRange("uidrxb", uidRxDeltaBytes, pktBytes + minExpExtraPktBytes, + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaRxOtherPktBytes); + assertInRange("iftxp", ifaceTxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); + assertInRange("ifrxp", ifaceRxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); // Localhost traffic *does* count against total stats. // Check the total stats increased after test data transfer over localhost has been made. @@ -248,6 +262,10 @@ public class TrafficStatsTest extends AndroidTestCase { totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes); assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes); + assertTrue("iftxp: " + ifaceTxPacketsBefore + " -> " + ifaceTxPacketsAfter, + totalTxPacketsAfter >= totalTxPacketsBefore + ifaceTxDeltaPackets); + assertTrue("ifrxp: " + ifaceRxPacketsBefore + " -> " + ifaceRxPacketsAfter, + totalRxPacketsAfter >= totalRxPacketsBefore + ifaceRxDeltaPackets); // If the adb TCP port is opened, this test may be run by adb over network. // Huge amount of data traffic might go through the network and accounted into total packets From 9e5d061d736663f99bf1548ac3f2044e43f8402e Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 13 Apr 2020 17:40:06 +0900 Subject: [PATCH 0919/1415] Add tethering CTS owners. Test: none Change-Id: I552b3bf8d79c4e4480396edc201b51ec5901b87b --- tests/cts/tethering/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/cts/tethering/OWNERS diff --git a/tests/cts/tethering/OWNERS b/tests/cts/tethering/OWNERS new file mode 100644 index 0000000000..cd6abeb6e8 --- /dev/null +++ b/tests/cts/tethering/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 31808 +lorenzo@google.com +satk@google.com + From 01f3fd3d80529fadc23d19683fc822a1f9746349 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Sun, 12 Apr 2020 21:34:11 +0900 Subject: [PATCH 0920/1415] Increase test independence If a test fails without unregistering an agent, other tests will see their requests match the old agent. That means any test failing will fail all subsequent tests, which is not very helpful. Solve this by making sure the agents are unregistered before the test ends. Also ensure the requests are unregistered. Test: NetworkAgentTest Change-Id: I2c167803d478d31fd85dc6e6e621f35d36c68fb4 --- .../src/android/net/cts/NetworkAgentTest.kt | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 2fdd5fb201..d0e3023db6 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -67,6 +67,9 @@ class NetworkAgentTest { private class Provider(context: Context, looper: Looper) : NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") + private val agentsToCleanUp = mutableListOf() + private val callbacksToCleanUp = mutableListOf() + @Before fun setUp() { instrumentation.getUiAutomation().adoptShellPermissionIdentity() @@ -75,11 +78,13 @@ class NetworkAgentTest { @After fun tearDown() { + agentsToCleanUp.forEach { it.unregister() } + callbacksToCleanUp.forEach { mCM.unregisterNetworkCallback(it) } mHandlerThread.quitSafely() instrumentation.getUiAutomation().dropShellPermissionIdentity() } - internal class TestableNetworkAgent( + private class TestableNetworkAgent( looper: Looper, nc: NetworkCapabilities, lp: LinkProperties, @@ -94,12 +99,10 @@ class NetworkAgentTest { } override fun onBandwidthUpdateRequested() { - super.onBandwidthUpdateRequested() history.add(OnBandwidthUpdateRequested) } override fun onNetworkUnwanted() { - super.onNetworkUnwanted() history.add(OnNetworkUnwanted) } @@ -109,6 +112,11 @@ class NetworkAgentTest { } } + private fun requestNetwork(request: NetworkRequest, callback: TestableNetworkCallback) { + mCM.requestNetwork(request, callback) + callbacksToCleanUp.add(callback) + } + private fun createNetworkAgent(): TestableNetworkAgent { val nc = NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) @@ -120,7 +128,9 @@ class NetworkAgentTest { } val lp = LinkProperties() val config = NetworkAgentConfig.Builder().build() - return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config) + return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config).also { + agentsToCleanUp.add(it) + } } private fun createConnectedNetworkAgent(): Pair { @@ -129,8 +139,9 @@ class NetworkAgentTest { .addTransportType(NetworkCapabilities.TRANSPORT_TEST) .build() val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) - mCM.requestNetwork(request, callback) - val agent = createNetworkAgent().also { it.register() } + requestNetwork(request, callback) + val agent = createNetworkAgent() + agent.register() agent.markConnected() return agent to callback } From 570b76b2735a49bc8008956e088e0f24297bbdcb Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Mar 2020 21:10:56 +0900 Subject: [PATCH 0921/1415] Test onStartSocketKeepalive Test: this Bug: 139268426 Change-Id: I4e251fa0203a1888badef9ed90495fe8b3340a1c --- .../src/android/net/cts/NetworkAgentTest.kt | 161 +++++++++++++++++- 1 file changed, 155 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index d0e3023db6..32f2bfafe2 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -18,29 +18,51 @@ package android.net.cts import android.app.Instrumentation import android.content.Context import android.net.ConnectivityManager +import android.net.KeepalivePacketData +import android.net.LinkAddress import android.net.LinkProperties +import android.net.Network import android.net.NetworkAgent +import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE +import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkProvider import android.net.NetworkRequest -import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested -import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted +import android.net.SocketKeepalive import android.os.Build +import android.os.Handler import android.os.HandlerThread import android.os.Looper +import android.os.Message +import android.os.Messenger +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import androidx.test.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.AsyncChannel import com.android.testutils.ArrayTrackRecord import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback import org.junit.After +import org.junit.Assert.fail import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import java.net.InetAddress +import java.time.Duration +import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertNotNull +import kotlin.test.assertNull import kotlin.test.assertTrue // This test doesn't really have a constraint on how fast the methods should return. If it's @@ -51,18 +73,29 @@ private const val DEFAULT_TIMEOUT_MS = 5000L // requests filed by the test and should never match normal internet requests. 70 is the default // score of Ethernet networks, it's as good a value as any other. private const val TEST_NETWORK_SCORE = 70 +private const val FAKE_NET_ID = 1098 private val instrumentation: Instrumentation get() = InstrumentationRegistry.getInstrumentation() private val context: Context get() = InstrumentationRegistry.getContext() +private fun Message(what: Int, arg1: Int, arg2: Int, obj: Any?) = Message.obtain().also { + it.what = what + it.arg1 = arg1 + it.arg2 = arg2 + it.obj = obj +} @RunWith(AndroidJUnit4::class) class NetworkAgentTest { @Rule @JvmField val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) + private val LOCAL_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.1") + private val REMOTE_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.2") + private val mCM = context.getSystemService(ConnectivityManager::class.java) private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") + private val mFakeConnectivityService by lazy { FakeConnectivityService(mHandlerThread.looper) } private class Provider(context: Context, looper: Looper) : NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") @@ -84,8 +117,37 @@ class NetworkAgentTest { instrumentation.getUiAutomation().dropShellPermissionIdentity() } - private class TestableNetworkAgent( - looper: Looper, + /** + * A fake that helps simulating ConnectivityService talking to a harnessed agent. + * This fake only supports speaking to one harnessed agent at a time because it + * only keeps track of one async channel. + */ + private class FakeConnectivityService(looper: Looper) { + private val msgHistory = ArrayTrackRecord().newReadHead() + private val asyncChannel = AsyncChannel() + private val handler = object : Handler(looper) { + override fun handleMessage(msg: Message) { + msgHistory.add(Message.obtain(msg)) // make a copy as the original will be recycled + when (msg.what) { + AsyncChannel.CMD_CHANNEL_HALF_CONNECTED -> + asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) + AsyncChannel.CMD_CHANNEL_DISCONNECT, AsyncChannel.CMD_CHANNEL_DISCONNECTED -> + fail("Agent unexpectedly disconnected") + } + } + } + + fun connect(agentMsngr: Messenger) = asyncChannel.connect(context, handler, agentMsngr) + + fun sendMessage(what: Int, arg1: Int = 0, arg2: Int = 0, obj: Any? = null) = + asyncChannel.sendMessage(Message(what, arg1, arg2, obj)) + + fun expectMessage(what: Int) = + assertNotNull(msgHistory.poll(DEFAULT_TIMEOUT_MS) { it.what == what }) + } + + private open class TestableNetworkAgent( + val looper: Looper, nc: NetworkCapabilities, lp: LinkProperties, conf: NetworkAgentConfig @@ -96,6 +158,17 @@ class NetworkAgentTest { sealed class CallbackEntry { object OnBandwidthUpdateRequested : CallbackEntry() object OnNetworkUnwanted : CallbackEntry() + data class OnAddKeepalivePacketFilter( + val slot: Int, + val packet: KeepalivePacketData + ) : CallbackEntry() + data class OnRemoveKeepalivePacketFilter(val slot: Int) : CallbackEntry() + data class OnStartSocketKeepalive( + val slot: Int, + val interval: Int, + val packet: KeepalivePacketData + ) : CallbackEntry() + data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry() } override fun onBandwidthUpdateRequested() { @@ -106,9 +179,35 @@ class NetworkAgentTest { history.add(OnNetworkUnwanted) } - inline fun expectCallback() { + override fun onAddKeepalivePacketFilter(slot: Int, packet: KeepalivePacketData) { + history.add(OnAddKeepalivePacketFilter(slot, packet)) + } + + override fun onRemoveKeepalivePacketFilter(slot: Int) { + history.add(OnRemoveKeepalivePacketFilter(slot)) + } + + override fun onStartSocketKeepalive( + slot: Int, + interval: Duration, + packet: KeepalivePacketData + ) { + history.add(OnStartSocketKeepalive(slot, interval.seconds.toInt(), packet)) + } + + override fun onStopSocketKeepalive(slot: Int) { + history.add(OnStopSocketKeepalive(slot)) + } + + inline fun expectCallback(): T { val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") + return foundCallback + } + + fun assertNoCallback() { + assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS), "Handler never became idle") + assertNull(history.peek()) } } @@ -126,7 +225,9 @@ class NetworkAgentTest { addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) } - val lp = LinkProperties() + val lp = LinkProperties().apply { + addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) + } val config = NetworkAgentConfig.Builder().build() return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config).also { agentsToCleanUp.add(it) @@ -146,6 +247,10 @@ class NetworkAgentTest { return agent to callback } + private fun createNetworkAgentWithFakeCS() = createNetworkAgent().also { + mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID))) + } + @Test fun testConnectAndUnregister() { val (agent, callback) = createConnectedNetworkAgent() @@ -166,4 +271,48 @@ class NetworkAgentTest { agent.expectCallback() agent.unregister() } + + @Test + fun testSocketKeepalive(): Unit = createNetworkAgentWithFakeCS().let { agent -> + val packet = object : KeepalivePacketData( + LOCAL_IPV4_ADDRESS /* srcAddress */, 1234 /* srcPort */, + REMOTE_IPV4_ADDRESS /* dstAddress */, 4567 /* dstPort */, + ByteArray(100 /* size */) { it.toByte() /* init */ }) {} + val slot = 4 + val interval = 37 + + mFakeConnectivityService.sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + arg1 = slot, obj = packet) + mFakeConnectivityService.sendMessage(CMD_START_SOCKET_KEEPALIVE, + arg1 = slot, arg2 = interval, obj = packet) + + agent.expectCallback().let { + assertEquals(it.slot, slot) + assertEquals(it.packet, packet) + } + agent.expectCallback().let { + assertEquals(it.slot, slot) + assertEquals(it.interval, interval) + assertEquals(it.packet, packet) + } + + agent.assertNoCallback() + + // Check that when the agent sends a keepalive event, ConnectivityService receives the + // expected message. + agent.sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED) + mFakeConnectivityService.expectMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE).let() { + assertEquals(slot, it.arg1) + assertEquals(SocketKeepalive.ERROR_UNSUPPORTED, it.arg2) + } + + mFakeConnectivityService.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, arg1 = slot) + mFakeConnectivityService.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, arg1 = slot) + agent.expectCallback().let { + assertEquals(it.slot, slot) + } + agent.expectCallback().let { + assertEquals(it.slot, slot) + } + } } From 3f138ef9d3d839b08a283c5498a7470dbf229610 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 13 Apr 2020 14:27:45 +0900 Subject: [PATCH 0922/1415] Test accept unvalidated Test: this Bug: 139268426 Change-Id: I3326a2119d66e67566fce0268ea4861729b1c64c --- .../src/android/net/cts/NetworkAgentTest.kt | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 32f2bfafe2..14f52e1e7c 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -24,7 +24,9 @@ import android.net.LinkProperties import android.net.Network import android.net.NetworkAgent import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE import android.net.NetworkAgentConfig @@ -39,9 +41,11 @@ import android.os.Looper import android.os.Message import android.os.Messenger import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import androidx.test.InstrumentationRegistry @@ -60,6 +64,7 @@ import org.junit.runner.RunWith import java.net.InetAddress import java.time.Duration import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertFailsWith import kotlin.test.assertNotNull import kotlin.test.assertNull @@ -123,27 +128,38 @@ class NetworkAgentTest { * only keeps track of one async channel. */ private class FakeConnectivityService(looper: Looper) { + private val CMD_EXPECT_DISCONNECT = 1 + private var disconnectExpected = false private val msgHistory = ArrayTrackRecord().newReadHead() private val asyncChannel = AsyncChannel() private val handler = object : Handler(looper) { override fun handleMessage(msg: Message) { msgHistory.add(Message.obtain(msg)) // make a copy as the original will be recycled when (msg.what) { + CMD_EXPECT_DISCONNECT -> disconnectExpected = true AsyncChannel.CMD_CHANNEL_HALF_CONNECTED -> asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) - AsyncChannel.CMD_CHANNEL_DISCONNECT, AsyncChannel.CMD_CHANNEL_DISCONNECTED -> - fail("Agent unexpectedly disconnected") + AsyncChannel.CMD_CHANNEL_DISCONNECTED -> + if (!disconnectExpected) { + fail("Agent unexpectedly disconnected") + } else { + disconnectExpected = false + } } } } fun connect(agentMsngr: Messenger) = asyncChannel.connect(context, handler, agentMsngr) + fun disconnect() = asyncChannel.disconnect() + fun sendMessage(what: Int, arg1: Int = 0, arg2: Int = 0, obj: Any? = null) = asyncChannel.sendMessage(Message(what, arg1, arg2, obj)) fun expectMessage(what: Int) = assertNotNull(msgHistory.poll(DEFAULT_TIMEOUT_MS) { it.what == what }) + + fun willExpectDisconnectOnce() = handler.sendEmptyMessage(CMD_EXPECT_DISCONNECT) } private open class TestableNetworkAgent( @@ -169,6 +185,8 @@ class NetworkAgentTest { val packet: KeepalivePacketData ) : CallbackEntry() data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry() + data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry() + object OnAutomaticReconnectDisabled : CallbackEntry() } override fun onBandwidthUpdateRequested() { @@ -199,6 +217,14 @@ class NetworkAgentTest { history.add(OnStopSocketKeepalive(slot)) } + override fun onSaveAcceptUnvalidated(accept: Boolean) { + history.add(OnSaveAcceptUnvalidated(accept)) + } + + override fun onAutomaticReconnectDisabled() { + history.add(OnAutomaticReconnectDisabled) + } + inline fun expectCallback(): T { val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") @@ -315,4 +341,40 @@ class NetworkAgentTest { assertEquals(it.slot, slot) } } + + @Test + fun testSetAcceptUnvalidated() { + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 1) + agent.expectCallback().let { + assertTrue(it.accept) + } + agent.assertNoCallback() + } + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 0) + mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + agent.expectCallback().let { + assertFalse(it.accept) + } + agent.expectCallback() + agent.assertNoCallback() + // When automatic reconnect is turned off, the network is torn down and + // ConnectivityService sends a disconnect. This in turn causes the agent + // to send a DISCONNECTED message to CS. + mFakeConnectivityService.willExpectDisconnectOnce() + mFakeConnectivityService.disconnect() + mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) + agent.expectCallback() + } + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + agent.expectCallback() + agent.assertNoCallback() + mFakeConnectivityService.willExpectDisconnectOnce() + mFakeConnectivityService.disconnect() + mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) + agent.expectCallback() + } + } } From 735047bf6ee9865de925dce9eda8aaca9bb82132 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 13 Apr 2020 21:13:00 +0800 Subject: [PATCH 0923/1415] Update tethering notification strings Update strings after converged with carrier. Bug: 145629001 Bug: 147818698 Test: atests TetheringTests Change-Id: I8ad34e8c93ba1547aa397a8e9c0ecc15286a2b0b --- Tethering/res/values-mcc204-mnc04/strings.xml | 16 ++++++++-------- Tethering/res/values-mcc310-mnc004/strings.xml | 16 ++++++++-------- Tethering/res/values-mcc311-mnc480/strings.xml | 16 ++++++++-------- Tethering/res/values/strings.xml | 8 ++++---- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Tethering/res/values-mcc204-mnc04/strings.xml b/Tethering/res/values-mcc204-mnc04/strings.xml index a996b4247a..9dadd49cf8 100644 --- a/Tethering/res/values-mcc204-mnc04/strings.xml +++ b/Tethering/res/values-mcc204-mnc04/strings.xml @@ -15,16 +15,16 @@ --> - Hotspot has no internet + Tethering has no internet - Devices can\u2019t connect to internet - - Turn off hotspot + Devices can\u2019t connect + + Turn off tethering - - Hotspot is on - + + Hotspot or tethering is on + Additional charges may apply while roaming - + Continue diff --git a/Tethering/res/values-mcc310-mnc004/strings.xml b/Tethering/res/values-mcc310-mnc004/strings.xml index a996b4247a..9dadd49cf8 100644 --- a/Tethering/res/values-mcc310-mnc004/strings.xml +++ b/Tethering/res/values-mcc310-mnc004/strings.xml @@ -15,16 +15,16 @@ --> - Hotspot has no internet + Tethering has no internet - Devices can\u2019t connect to internet - - Turn off hotspot + Devices can\u2019t connect + + Turn off tethering - - Hotspot is on - + + Hotspot or tethering is on + Additional charges may apply while roaming - + Continue diff --git a/Tethering/res/values-mcc311-mnc480/strings.xml b/Tethering/res/values-mcc311-mnc480/strings.xml index a996b4247a..9dadd49cf8 100644 --- a/Tethering/res/values-mcc311-mnc480/strings.xml +++ b/Tethering/res/values-mcc311-mnc480/strings.xml @@ -15,16 +15,16 @@ --> - Hotspot has no internet + Tethering has no internet - Devices can\u2019t connect to internet - - Turn off hotspot + Devices can\u2019t connect + + Turn off tethering - - Hotspot is on - + + Hotspot or tethering is on + Additional charges may apply while roaming - + Continue diff --git a/Tethering/res/values/strings.xml b/Tethering/res/values/strings.xml index 52a16545c2..4fa60d4125 100644 --- a/Tethering/res/values/strings.xml +++ b/Tethering/res/values/strings.xml @@ -40,13 +40,13 @@ - + - + - + - + From 788d19d376d0373f97e4c1c5cecc5917cdd0b1f7 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 10 Apr 2020 23:36:48 +0900 Subject: [PATCH 0924/1415] Test validation status Test: this Bug: 139268426 Change-Id: I8499d9da8643cf60c912570e7a2ac2207d662e16 --- .../src/android/net/cts/NetworkAgentTest.kt | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 14f52e1e7c..97a15ef634 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -26,15 +26,20 @@ import android.net.NetworkAgent import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER import android.net.NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS import android.net.NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE +import android.net.NetworkAgent.INVALID_NETWORK +import android.net.NetworkAgent.VALID_NETWORK import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkProvider import android.net.NetworkRequest import android.net.SocketKeepalive +import android.net.Uri import android.os.Build +import android.os.Bundle import android.os.Handler import android.os.HandlerThread import android.os.Looper @@ -48,6 +53,7 @@ import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRem import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus import androidx.test.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.AsyncChannel @@ -187,6 +193,7 @@ class NetworkAgentTest { data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry() data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry() object OnAutomaticReconnectDisabled : CallbackEntry() + data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry() } override fun onBandwidthUpdateRequested() { @@ -225,6 +232,23 @@ class NetworkAgentTest { history.add(OnAutomaticReconnectDisabled) } + override fun onValidationStatus(status: Int, uri: Uri?) { + history.add(OnValidationStatus(status, uri)) + } + + // Expects the initial validation event that always occurs immediately after registering + // a NetworkAgent whose network does not require validation (which test networks do + // not, since they lack the INTERNET capability). It always contains the default argument + // for the URI. + fun expectNoInternetValidationStatus() = expectCallback().let { + assertEquals(it.status, VALID_NETWORK) + // The returned Uri is parsed from the empty string, which means it's an + // instance of the (private) Uri.StringUri. There are no real good ways + // to check this, the least bad is to just convert it to a string and + // make sure it's empty. + assertEquals("", it.uri.toString()) + } + inline fun expectCallback(): T { val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") @@ -281,6 +305,7 @@ class NetworkAgentTest { fun testConnectAndUnregister() { val (agent, callback) = createConnectedNetworkAgent() callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectNoInternetValidationStatus() agent.unregister() callback.expectCallback(agent.network) agent.expectCallback() @@ -293,6 +318,7 @@ class NetworkAgentTest { fun testOnBandwidthUpdateRequested() { val (agent, callback) = createConnectedNetworkAgent() callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectNoInternetValidationStatus() mCM.requestBandwidthUpdate(agent.network) agent.expectCallback() agent.unregister() @@ -377,4 +403,25 @@ class NetworkAgentTest { agent.expectCallback() } } + + @Test + fun testValidationStatus() = createNetworkAgentWithFakeCS().let { agent -> + val uri = Uri.parse("http://www.google.com") + val bundle = Bundle().apply { + putString(NetworkAgent.REDIRECT_URL_KEY, uri.toString()) + } + mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, + arg1 = VALID_NETWORK, obj = bundle) + agent.expectCallback().let { + assertEquals(it.status, VALID_NETWORK) + assertEquals(it.uri, uri) + } + + mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, + arg1 = INVALID_NETWORK, obj = Bundle()) + agent.expectCallback().let { + assertEquals(it.status, INVALID_NETWORK) + assertNull(it.uri) + } + } } From d5f249c24c8824b57ae51d8eab1238580bd7667f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Sat, 11 Apr 2020 02:47:05 +0900 Subject: [PATCH 0925/1415] Test sendCaps and sendProps Test: this Bug: 139268426 Change-Id: Idefce1174b82668d23c53dd1bf95bc660cb21c28 --- .../src/android/net/cts/NetworkAgentTest.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 97a15ef634..4de3a086ce 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -84,6 +84,7 @@ private const val DEFAULT_TIMEOUT_MS = 5000L // requests filed by the test and should never match normal internet requests. 70 is the default // score of Ethernet networks, it's as good a value as any other. private const val TEST_NETWORK_SCORE = 70 +private const val BETTER_NETWORK_SCORE = 75 private const val FAKE_NET_ID = 1098 private val instrumentation: Instrumentation get() = InstrumentationRegistry.getInstrumentation() @@ -170,8 +171,8 @@ class NetworkAgentTest { private open class TestableNetworkAgent( val looper: Looper, - nc: NetworkCapabilities, - lp: LinkProperties, + val nc: NetworkCapabilities, + val lp: LinkProperties, conf: NetworkAgentConfig ) : NetworkAgent(context, looper, TestableNetworkAgent::class.java.simpleName /* tag */, nc, lp, TEST_NETWORK_SCORE, conf, Provider(context, looper)) { @@ -368,6 +369,25 @@ class NetworkAgentTest { } } + @Test + fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectNoInternetValidationStatus() + val ifaceName = "adhocIface" + val lp = LinkProperties(agent.lp) + lp.setInterfaceName(ifaceName) + agent.sendLinkProperties(lp) + callback.expectLinkPropertiesThat(agent.network) { + it.getInterfaceName() == ifaceName + } + val nc = NetworkCapabilities(agent.nc) + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + agent.sendNetworkCapabilities(nc) + callback.expectCapabilitiesThat(agent.network) { + it.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + } + } + @Test fun testSetAcceptUnvalidated() { createNetworkAgentWithFakeCS().let { agent -> From 80ee14e0e7215c04ba26924f5cbaa86551a2b0e1 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Sat, 11 Apr 2020 03:12:42 +0900 Subject: [PATCH 0926/1415] Test sendNetworkScore Test: this Bug: 139268426 Change-Id: I66cea443f0c6aa9235da577817787d764fbd030b --- .../src/android/net/cts/NetworkAgentTest.kt | 66 ++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 4de3a086ce..659950a0db 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -37,6 +37,7 @@ import android.net.NetworkCapabilities import android.net.NetworkProvider import android.net.NetworkRequest import android.net.SocketKeepalive +import android.net.StringNetworkSpecifier import android.net.Uri import android.os.Build import android.os.Bundle @@ -59,8 +60,10 @@ import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.AsyncChannel import com.android.testutils.ArrayTrackRecord import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback +import java.util.UUID import org.junit.After import org.junit.Assert.fail import org.junit.Before @@ -197,6 +200,8 @@ class NetworkAgentTest { data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry() } + fun getName(): String? = (nc.getNetworkSpecifier() as? StringNetworkSpecifier)?.specifier + override fun onBandwidthUpdateRequested() { history.add(OnBandwidthUpdateRequested) } @@ -267,7 +272,7 @@ class NetworkAgentTest { callbacksToCleanUp.add(callback) } - private fun createNetworkAgent(): TestableNetworkAgent { + private fun createNetworkAgent(name: String? = null): TestableNetworkAgent { val nc = NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) @@ -275,6 +280,9 @@ class NetworkAgentTest { addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + if (null != name) { + setNetworkSpecifier(StringNetworkSpecifier(name)) + } } val lp = LinkProperties().apply { addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) @@ -285,14 +293,15 @@ class NetworkAgentTest { } } - private fun createConnectedNetworkAgent(): Pair { + private fun createConnectedNetworkAgent(name: String? = null): + Pair { val request: NetworkRequest = NetworkRequest.Builder() .clearCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_TEST) .build() val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) requestNetwork(request, callback) - val agent = createNetworkAgent() + val agent = createNetworkAgent(name) agent.register() agent.markConnected() return agent to callback @@ -388,6 +397,57 @@ class NetworkAgentTest { } } + @Test + fun testSendScore() { + // This test will create two networks and check that the one with the stronger + // score wins out for a request that matches them both. + // First create requests to make sure both networks are kept up, using the + // specifier so they are specific to each network + val name1 = UUID.randomUUID().toString() + val name2 = UUID.randomUUID().toString() + val request1 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setNetworkSpecifier(StringNetworkSpecifier(name1)) + .build() + val request2 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setNetworkSpecifier(StringNetworkSpecifier(name2)) + .build() + val callback1 = TestableNetworkCallback() + val callback2 = TestableNetworkCallback() + requestNetwork(request1, callback1) + requestNetwork(request2, callback2) + + // Then file the interesting request + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback() + requestNetwork(request, callback) + + // Connect the first Network + createConnectedNetworkAgent(name1).let { (agent1, _) -> + callback.expectAvailableThenValidatedCallbacks(agent1.network) + // Upgrade agent1 to a better score so that there is no ambiguity when + // agent2 connects that agent1 is still better + agent1.sendNetworkScore(BETTER_NETWORK_SCORE - 1) + // Connect the second agent + createConnectedNetworkAgent(name2).let { (agent2, _) -> + agent2.markConnected() + // The callback should not see anything yet + callback.assertNoCallback(200) + // Now update the score and expect the callback now prefers agent2 + agent2.sendNetworkScore(BETTER_NETWORK_SCORE) + callback.expectCallback(agent2.network) + } + } + + // tearDown() will unregister the requests and agents + } + @Test fun testSetAcceptUnvalidated() { createNetworkAgentWithFakeCS().let { agent -> From da5800cc8687f13f2bcbae1c6e0fbde9a745142d Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 13 Apr 2020 16:32:39 +0900 Subject: [PATCH 0927/1415] Test Signal thresholds Test: this Bug: 139268426 Change-Id: I136f246d0e3ad6744989e7d6f4f8034cc6674def --- .../src/android/net/cts/NetworkAgentTest.kt | 81 ++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 659950a0db..9d1eee9da9 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -52,6 +52,7 @@ import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBan import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSignalStrengthThresholdsUpdated import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus @@ -65,6 +66,7 @@ import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback import java.util.UUID import org.junit.After +import org.junit.Assert.assertArrayEquals import org.junit.Assert.fail import org.junit.Before import org.junit.Rule @@ -83,6 +85,11 @@ import kotlin.test.assertTrue // going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio // without affecting the run time of successful runs. Thus, set a very high timeout. private const val DEFAULT_TIMEOUT_MS = 5000L +// When waiting for a NetworkCallback to determine there was no timeout, waiting is the +// only possible thing (the relevant handler is the one in the real ConnectivityService, +// and then there is the Binder call), so have a short timeout for this as it will be +// exhausted every time. +private const val NO_CALLBACK_TIMEOUT = 200L // Any legal score (0~99) for the test network would do, as it is going to be kept up by the // requests filed by the test and should never match normal internet requests. 70 is the default // score of Ethernet networks, it's as good a value as any other. @@ -198,6 +205,7 @@ class NetworkAgentTest { data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry() object OnAutomaticReconnectDisabled : CallbackEntry() data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry() + data class OnSignalStrengthThresholdsUpdated(val thresholds: IntArray) : CallbackEntry() } fun getName(): String? = (nc.getNetworkSpecifier() as? StringNetworkSpecifier)?.specifier @@ -238,6 +246,17 @@ class NetworkAgentTest { history.add(OnAutomaticReconnectDisabled) } + override fun onSignalStrengthThresholdsUpdated(thresholds: IntArray) { + history.add(OnSignalStrengthThresholdsUpdated(thresholds)) + } + + fun expectEmptySignalStrengths() { + expectCallback().let { + // intArrayOf() without arguments makes an empty array + assertArrayEquals(intArrayOf(), it.thresholds) + } + } + override fun onValidationStatus(status: Int, uri: Uri?) { history.add(OnValidationStatus(status, uri)) } @@ -272,6 +291,14 @@ class NetworkAgentTest { callbacksToCleanUp.add(callback) } + private fun registerNetworkCallback( + request: NetworkRequest, + callback: TestableNetworkCallback + ) { + mCM.registerNetworkCallback(request, callback) + callbacksToCleanUp.add(callback) + } + private fun createNetworkAgent(name: String? = null): TestableNetworkAgent { val nc = NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) @@ -315,6 +342,7 @@ class NetworkAgentTest { fun testConnectAndUnregister() { val (agent, callback) = createConnectedNetworkAgent() callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() agent.expectNoInternetValidationStatus() agent.unregister() callback.expectCallback(agent.network) @@ -328,12 +356,62 @@ class NetworkAgentTest { fun testOnBandwidthUpdateRequested() { val (agent, callback) = createConnectedNetworkAgent() callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() agent.expectNoInternetValidationStatus() mCM.requestBandwidthUpdate(agent.network) agent.expectCallback() agent.unregister() } + @Test + fun testSignalStrengthThresholds() { + val thresholds = intArrayOf(30, 50, 65) + val callbacks = thresholds.map { strength -> + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setSignalStrength(strength) + .build() + TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also { + registerNetworkCallback(request, it) + } + } + createConnectedNetworkAgent().let { (agent, callback) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectCallback().let { + assertArrayEquals(it.thresholds, thresholds) + } + agent.expectNoInternetValidationStatus() + + // Send signal strength and check that the callbacks are called appropriately. + val nc = NetworkCapabilities(agent.nc) + nc.setSignalStrength(20) + agent.sendNetworkCapabilities(nc) + callbacks.forEach { it.assertNoCallback(NO_CALLBACK_TIMEOUT) } + + nc.setSignalStrength(40) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectAvailableCallbacks(agent.network) + callbacks[1].assertNoCallback(NO_CALLBACK_TIMEOUT) + callbacks[2].assertNoCallback(NO_CALLBACK_TIMEOUT) + + nc.setSignalStrength(80) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 80 } + callbacks[1].expectAvailableCallbacks(agent.network) + callbacks[2].expectAvailableCallbacks(agent.network) + + nc.setSignalStrength(55) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 } + callbacks[1].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 } + callbacks[2].expectCallback(agent.network) + } + callbacks.forEach { + mCM.unregisterNetworkCallback(it) + } + } + @Test fun testSocketKeepalive(): Unit = createNetworkAgentWithFakeCS().let { agent -> val packet = object : KeepalivePacketData( @@ -381,6 +459,7 @@ class NetworkAgentTest { @Test fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) -> callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() agent.expectNoInternetValidationStatus() val ifaceName = "adhocIface" val lp = LinkProperties(agent.lp) @@ -438,7 +517,7 @@ class NetworkAgentTest { createConnectedNetworkAgent(name2).let { (agent2, _) -> agent2.markConnected() // The callback should not see anything yet - callback.assertNoCallback(200) + callback.assertNoCallback(NO_CALLBACK_TIMEOUT) // Now update the score and expect the callback now prefers agent2 agent2.sendNetworkScore(BETTER_NETWORK_SCORE) callback.expectCallback(agent2.network) From 2cef9f7da56fe0a723f930c33baabaaa48078f38 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 13 Apr 2020 22:18:48 +0900 Subject: [PATCH 0928/1415] Address comments from aosp/1284557 Test: this Bug: 139268426 Change-Id: I5edbff1d7eed2f939ba26f1ebd7ead49ac67b978 --- tests/cts/net/src/android/net/cts/NetworkAgentTest.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 9d1eee9da9..89d3dff66c 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -281,7 +281,8 @@ class NetworkAgentTest { } fun assertNoCallback() { - assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS), "Handler never became idle") + assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS), + "Handler didn't became idle after ${DEFAULT_TIMEOUT_MS}ms") assertNull(history.peek()) } } @@ -536,6 +537,10 @@ class NetworkAgentTest { } agent.assertNoCallback() } + } + + @Test + fun testSetAcceptUnvalidatedPreventAutomaticReconnect() { createNetworkAgentWithFakeCS().let { agent -> mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 0) mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) @@ -552,6 +557,10 @@ class NetworkAgentTest { mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) agent.expectCallback() } + } + + @Test + fun testPreventAutomaticReconnect() { createNetworkAgentWithFakeCS().let { agent -> mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) agent.expectCallback() From 910a0b44ddc1ccefad22ffb5bcf58f2c5a4b8293 Mon Sep 17 00:00:00 2001 From: Ashwini Oruganti Date: Tue, 10 Mar 2020 13:49:18 -0700 Subject: [PATCH 0929/1415] Tethering: Add an exported flag in manifest With b/150232615, we will need an explicit value set for the exported flag when intent filters are present, as the default behavior is changing for S+. This change adds the value reflecting the previous default to the manifest. Bug: 150232615 Test: TH Change-Id: I25b55378df393cd4fb8932b7ae64f97eb9f1aa8e Merged-In: I25b55378df393cd4fb8932b7ae64f97eb9f1aa8e (cherry picked from commit dc03d15189b3d6914bb75374bfa616662ed5ac26) --- Tethering/AndroidManifest.xml | 3 ++- Tethering/AndroidManifest_InProcess.xml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index 9328611f5d..ab257475ca 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml @@ -44,7 +44,8 @@ android:extractNativeLibs="false" android:persistent="true"> + android:permission="android.permission.MAINLINE_NETWORK_STACK" + android:exported="true"> diff --git a/Tethering/AndroidManifest_InProcess.xml b/Tethering/AndroidManifest_InProcess.xml index 02ea551254..bf1f001e03 100644 --- a/Tethering/AndroidManifest_InProcess.xml +++ b/Tethering/AndroidManifest_InProcess.xml @@ -24,7 +24,8 @@ + android:permission="android.permission.MAINLINE_NETWORK_STACK" + android:exported="true"> From 6f4d0a0d64f0e035a4b4fb740e1d58599e9f1d25 Mon Sep 17 00:00:00 2001 From: evitayan Date: Thu, 2 Apr 2020 18:19:56 -0700 Subject: [PATCH 0930/1415] Test setting proposal, TS and lifetime for ChildSessionParams Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: If19fb12c92f65d487478fda172acb21f6cfb1717 --- .../ipsec/ike/cts/ChildSessionParamsTest.java | 140 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 83 +++++++++++ 2 files changed, 223 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java new file mode 100644 index 0000000000..316355252a --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java @@ -0,0 +1,140 @@ +/* + * 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.ipsec.ike.cts; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.ChildSessionParams; +import android.net.ipsec.ike.TransportModeChildSessionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class ChildSessionParamsTest extends IkeTestBase { + private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(3L); + private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(1L); + + // Random proposal. Content doesn't matter + private final ChildSaProposal mSaProposal = + SaProposalTest.buildChildSaProposalWithCombinedModeCipher(); + + private void verifyTunnelModeChildParamsWithDefaultValues(ChildSessionParams childParams) { + assertTrue(childParams instanceof TunnelModeChildSessionParams); + verifyChildParamsWithDefaultValues(childParams); + } + + private void verifyTunnelModeChildParamsWithCustomizedValues(ChildSessionParams childParams) { + assertTrue(childParams instanceof TunnelModeChildSessionParams); + verifyChildParamsWithCustomizedValues(childParams); + } + + private void verifyTransportModeChildParamsWithDefaultValues(ChildSessionParams childParams) { + assertTrue(childParams instanceof TransportModeChildSessionParams); + verifyChildParamsWithDefaultValues(childParams); + } + + private void verifyTransportModeChildParamsWithCustomizedValues( + ChildSessionParams childParams) { + assertTrue(childParams instanceof TransportModeChildSessionParams); + verifyChildParamsWithCustomizedValues(childParams); + } + + private void verifyChildParamsWithDefaultValues(ChildSessionParams childParams) { + assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals()); + + // Do not do assertEquals to the default values to be avoid being a change-detector test + assertTrue(childParams.getHardLifetimeSeconds() > childParams.getSoftLifetimeSeconds()); + assertTrue(childParams.getSoftLifetimeSeconds() > 0); + + assertEquals( + Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS), + childParams.getInboundTrafficSelectors()); + assertEquals( + Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS), + childParams.getOutboundTrafficSelectors()); + } + + private void verifyChildParamsWithCustomizedValues(ChildSessionParams childParams) { + assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals()); + + assertEquals(HARD_LIFETIME_SECONDS, childParams.getHardLifetimeSeconds()); + assertEquals(SOFT_LIFETIME_SECONDS, childParams.getSoftLifetimeSeconds()); + + assertEquals( + Arrays.asList(INBOUND_V4_TS, INBOUND_V6_TS), + childParams.getInboundTrafficSelectors()); + assertEquals( + Arrays.asList(OUTBOUND_V4_TS, OUTBOUND_V6_TS), + childParams.getOutboundTrafficSelectors()); + } + + @Test + public void testBuildTransportModeParamsWithDefaultValues() { + TransportModeChildSessionParams childParams = + new TransportModeChildSessionParams.Builder().addSaProposal(mSaProposal).build(); + + verifyTransportModeChildParamsWithDefaultValues(childParams); + } + + @Test + public void testBuildTunnelModeParamsWithDefaultValues() { + TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder().addSaProposal(mSaProposal).build(); + + verifyTunnelModeChildParamsWithDefaultValues(childParams); + assertTrue(childParams.getConfigurationRequests().isEmpty()); + } + + @Test + public void testBuildTransportModeParamsWithCustomizedValues() { + TransportModeChildSessionParams childParams = + new TransportModeChildSessionParams.Builder() + .addSaProposal(mSaProposal) + .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) + .addInboundTrafficSelectors(INBOUND_V4_TS) + .addInboundTrafficSelectors(INBOUND_V6_TS) + .addOutboundTrafficSelectors(OUTBOUND_V4_TS) + .addOutboundTrafficSelectors(OUTBOUND_V6_TS) + .build(); + + verifyTransportModeChildParamsWithCustomizedValues(childParams); + } + + @Test + public void testBuildTunnelModeParamsWithCustomizedValues() { + TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder() + .addSaProposal(mSaProposal) + .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) + .addInboundTrafficSelectors(INBOUND_V4_TS) + .addInboundTrafficSelectors(INBOUND_V6_TS) + .addOutboundTrafficSelectors(OUTBOUND_V4_TS) + .addOutboundTrafficSelectors(OUTBOUND_V6_TS) + .build(); + + verifyTunnelModeChildParamsWithCustomizedValues(childParams); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java new file mode 100644 index 0000000000..d4b431e837 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -0,0 +1,83 @@ +/* + * 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.ipsec.ike.cts; + +import android.net.InetAddresses; +import android.net.ipsec.ike.IkeTrafficSelector; + +import java.net.Inet4Address; +import java.net.Inet6Address; + +/** Shared parameters and util methods for testing different components of IKE */ +abstract class IkeTestBase { + private static final int MIN_PORT = 0; + private static final int MAX_PORT = 65535; + private static final int INBOUND_TS_START_PORT = MIN_PORT; + private static final int INBOUND_TS_END_PORT = 65520; + private static final int OUTBOUND_TS_START_PORT = 16; + private static final int OUTBOUND_TS_END_PORT = MAX_PORT; + + static final int IP4_PREFIX_LEN = 32; + static final int IP6_PREFIX_LEN = 64; + + static final Inet4Address IPV4_ADDRESS_LOCAL = + (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); + static final Inet4Address IPV4_ADDRESS_REMOTE = + (Inet4Address) (InetAddresses.parseNumericAddress("198.51.100.100")); + static final Inet6Address IPV6_ADDRESS_LOCAL = + (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8::100")); + static final Inet6Address IPV6_ADDRESS_REMOTE = + (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8:255::100")); + + static final IkeTrafficSelector DEFAULT_V4_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("0.0.0.0"), + InetAddresses.parseNumericAddress("255.255.255.255")); + static final IkeTrafficSelector DEFAULT_V6_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("::"), + InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); + static final IkeTrafficSelector INBOUND_V4_TS = + new IkeTrafficSelector( + INBOUND_TS_START_PORT, + INBOUND_TS_END_PORT, + InetAddresses.parseNumericAddress("192.0.2.10"), + InetAddresses.parseNumericAddress("192.0.2.20")); + static final IkeTrafficSelector OUTBOUND_V4_TS = + new IkeTrafficSelector( + OUTBOUND_TS_START_PORT, + OUTBOUND_TS_END_PORT, + InetAddresses.parseNumericAddress("198.51.100.0"), + InetAddresses.parseNumericAddress("198.51.100.255")); + + static final IkeTrafficSelector INBOUND_V6_TS = + new IkeTrafficSelector( + INBOUND_TS_START_PORT, + INBOUND_TS_END_PORT, + InetAddresses.parseNumericAddress("2001:db8::10"), + InetAddresses.parseNumericAddress("2001:db8::128")); + static final IkeTrafficSelector OUTBOUND_V6_TS = + new IkeTrafficSelector( + OUTBOUND_TS_START_PORT, + OUTBOUND_TS_END_PORT, + InetAddresses.parseNumericAddress("2001:db8:255::64"), + InetAddresses.parseNumericAddress("2001:db8:255::255")); +} From 4e7d4a611ea73f75f0f64fd7df8ac8a0e4f95d67 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Mon, 13 Apr 2020 10:43:20 -0700 Subject: [PATCH 0931/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I562307bd38d87a0ccd16db99a41d3101f3f37670 --- Tethering/res/values-ky/strings.xml | 6 +++--- Tethering/res/values-mcc204-mnc04-ar/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-bn/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-bs/strings.xml | 2 +- .../res/values-mcc204-mnc04-es-rUS/strings.xml | 4 ++-- Tethering/res/values-mcc204-mnc04-es/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-eu/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-gu/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-in/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-it/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-kn/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-ky/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-lo/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-ml/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-ne/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-or/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-pa/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-ru/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-sw/strings.xml | 2 +- Tethering/res/values-mcc204-mnc04-ta/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-te/strings.xml | 15 +++++---------- Tethering/res/values-mcc204-mnc04-uz/strings.xml | 15 +++++---------- .../res/values-mcc204-mnc04-zh-rCN/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-ar/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-bn/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-bs/strings.xml | 2 +- .../res/values-mcc310-mnc004-es-rUS/strings.xml | 4 ++-- Tethering/res/values-mcc310-mnc004-es/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-eu/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-gu/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-in/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-it/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-kn/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-ky/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-lo/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-ml/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-or/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-pa/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-ru/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-sw/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-ta/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-te/strings.xml | 15 +++++---------- Tethering/res/values-mcc310-mnc004-uz/strings.xml | 15 +++++---------- .../res/values-mcc310-mnc004-zh-rCN/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-ar/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-bn/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-bs/strings.xml | 2 +- .../res/values-mcc311-mnc480-es-rUS/strings.xml | 4 ++-- Tethering/res/values-mcc311-mnc480-es/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-eu/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-gu/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-in/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-it/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-kn/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-ky/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-lo/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-ml/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-or/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-pa/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-ru/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-sw/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-ta/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-te/strings.xml | 15 +++++---------- Tethering/res/values-mcc311-mnc480-uz/strings.xml | 15 +++++---------- .../res/values-mcc311-mnc480-zh-rCN/strings.xml | 2 +- Tethering/res/values-vi/strings.xml | 6 +++--- 68 files changed, 219 insertions(+), 399 deletions(-) diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index f763bf3ff0..7b9c0f5714 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -16,12 +16,12 @@ - "Жалгаштыруу же хотспот жандырылган" + "Модем режими күйүп турат" "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" + "Телефонду модем катары колдонууга болбойт" "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" - "Хотспот жана байланыш түйүнүүн статусу" + "Байланыш түйүнүнүн жана модем режиминин статусу" diff --git a/Tethering/res/values-mcc204-mnc04-ar/strings.xml b/Tethering/res/values-mcc204-mnc04-ar/strings.xml index 40eb9a741c..e6d8423f46 100644 --- a/Tethering/res/values-mcc204-mnc04-ar/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ar/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "نقطة الاتصال غير متصلة بالإنترنت." + "لا يمكن للأجهزة الاتصال بالإنترنت." + "إيقاف نقطة الاتصال" + "نقطة الاتصال مفعّلة" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." "متابعة" diff --git a/Tethering/res/values-mcc204-mnc04-bn/strings.xml b/Tethering/res/values-mcc204-mnc04-bn/strings.xml index 7f9efba7f0..9a3033c94d 100644 --- a/Tethering/res/values-mcc204-mnc04-bn/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-bn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" + "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" + "হটস্পট বন্ধ করুন" + "হটস্পট চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" "চালিয়ে যান" diff --git a/Tethering/res/values-mcc204-mnc04-bs/strings.xml b/Tethering/res/values-mcc204-mnc04-bs/strings.xml index 7539736415..57f6d88a4e 100644 --- a/Tethering/res/values-mcc204-mnc04-bs/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-bs/strings.xml @@ -20,6 +20,6 @@ "Uređaji se ne mogu povezati na internet" "Isključi pristupnu tačku" "Pristupna tačka je uključena" - "Primjenjuju se dodatne tarife u romingu" + "Mogu nastati dodatni troškovi u romingu" "Nastavi" diff --git a/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml index 196303fa83..956547cc6d 100644 --- a/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-es-rUS/strings.xml @@ -16,10 +16,10 @@ - "El hotspot no tiene Internet" + "El hotspot no tiene conexión a Internet" "Los dispositivos no pueden conectarse a Internet" "Desactiva el hotspot" "El hotspot está activado" - "Es posible que apliquen cargos adicionales por roaming" + "Es posible que se apliquen cargos adicionales por roaming" "Continuar" diff --git a/Tethering/res/values-mcc204-mnc04-es/strings.xml b/Tethering/res/values-mcc204-mnc04-es/strings.xml index cac5b23bd9..831ec1fb1e 100644 --- a/Tethering/res/values-mcc204-mnc04-es/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-es/strings.xml @@ -19,7 +19,7 @@ "El punto de acceso no tiene conexión a Internet" "Los dispositivos no se pueden conectar a Internet" "Desactivar punto de acceso" - "Zona Wi-Fi activada" + "Punto de acceso activado" "Puede que se apliquen cargos adicionales en itinerancia" "Continuar" diff --git a/Tethering/res/values-mcc204-mnc04-eu/strings.xml b/Tethering/res/values-mcc204-mnc04-eu/strings.xml index 1758a4fada..c4f70a3eb4 100644 --- a/Tethering/res/values-mcc204-mnc04-eu/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-eu/strings.xml @@ -20,6 +20,6 @@ "Gailuak ezin dira konektatu Internetera" "Desaktibatu sare publikoa" "Sare publikoa aktibatuta dago" - "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" "Egin aurrera" diff --git a/Tethering/res/values-mcc204-mnc04-gu/strings.xml b/Tethering/res/values-mcc204-mnc04-gu/strings.xml index 0f4d26afdd..796d42ec52 100644 --- a/Tethering/res/values-mcc204-mnc04-gu/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-gu/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" + "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" + "હૉટસ્પૉટ બંધ કરો" + "હૉટસ્પૉટ ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" "આગળ વધો" diff --git a/Tethering/res/values-mcc204-mnc04-in/strings.xml b/Tethering/res/values-mcc204-mnc04-in/strings.xml index 4998474a36..1243d22d19 100644 --- a/Tethering/res/values-mcc204-mnc04-in/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-in/strings.xml @@ -16,7 +16,7 @@ - "Hotspot tidak memiliki internet" + "Hotspot tidak memiliki koneksi internet" "Perangkat tidak dapat tersambung ke internet" "Nonaktifkan hotspot" "Hotspot aktif" diff --git a/Tethering/res/values-mcc204-mnc04-it/strings.xml b/Tethering/res/values-mcc204-mnc04-it/strings.xml index a10d511c17..a0f52dc89b 100644 --- a/Tethering/res/values-mcc204-mnc04-it/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-it/strings.xml @@ -20,6 +20,6 @@ "I dispositivi non possono connettersi a Internet" "Disattiva l\'hotspot" "Hotspot attivo" - "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" "Continua" diff --git a/Tethering/res/values-mcc204-mnc04-kn/strings.xml b/Tethering/res/values-mcc204-mnc04-kn/strings.xml index 0427a77659..f0adad8e21 100644 --- a/Tethering/res/values-mcc204-mnc04-kn/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-kn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" + "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc204-mnc04-ky/strings.xml b/Tethering/res/values-mcc204-mnc04-ky/strings.xml index bc3d555597..35a060aa24 100644 --- a/Tethering/res/values-mcc204-mnc04-ky/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ky/strings.xml @@ -16,7 +16,7 @@ - "Хотспоттун Интернети жок" + "Байланыш түйүнүндө Интернет жок" "Түзмөктөр Интернетке туташпай жатат" "Туташуу түйүнүн өчүрүү" "Кошулуу түйүнү күйүк" diff --git a/Tethering/res/values-mcc204-mnc04-lo/strings.xml b/Tethering/res/values-mcc204-mnc04-lo/strings.xml index 06dcbcbccc..1d9203b369 100644 --- a/Tethering/res/values-mcc204-mnc04-lo/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-lo/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" + "ປິດຮັອດສະປອດ" + "ຮັອດສະປອດເປີດຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc204-mnc04-ml/strings.xml b/Tethering/res/values-mcc204-mnc04-ml/strings.xml index 0ef956a5a4..d376fe5870 100644 --- a/Tethering/res/values-mcc204-mnc04-ml/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ml/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" + "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" + "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" + "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" "തുടരുക" diff --git a/Tethering/res/values-mcc204-mnc04-ne/strings.xml b/Tethering/res/values-mcc204-mnc04-ne/strings.xml index fadd357ebf..63ce155034 100644 --- a/Tethering/res/values-mcc204-mnc04-ne/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ne/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "हटस्पटमा इन्टरनेट छैन" + "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" + "हटस्पट निष्क्रिय पार्नुहोस्" + "हटस्पट सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc204-mnc04-or/strings.xml b/Tethering/res/values-mcc204-mnc04-or/strings.xml index 1cdfce04d8..ab87b76caf 100644 --- a/Tethering/res/values-mcc204-mnc04-or/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-or/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc204-mnc04-pa/strings.xml b/Tethering/res/values-mcc204-mnc04-pa/strings.xml index 93402c35d0..b09f285c2d 100644 --- a/Tethering/res/values-mcc204-mnc04-pa/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-pa/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" + "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc204-mnc04-ru/strings.xml b/Tethering/res/values-mcc204-mnc04-ru/strings.xml index 69f8c59613..a2b1640cb2 100644 --- a/Tethering/res/values-mcc204-mnc04-ru/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ru/strings.xml @@ -17,7 +17,7 @@ "Точка доступа не подключена к Интернету" - "Не удается подключить устройства к Интернету" + "Устройства не могут подключаться к Интернету" "Отключить точку доступа" "Точка доступа включена" "За использование услуг связи в роуминге может взиматься дополнительная плата." diff --git a/Tethering/res/values-mcc204-mnc04-sw/strings.xml b/Tethering/res/values-mcc204-mnc04-sw/strings.xml index 3fe09fc22a..18ee457d03 100644 --- a/Tethering/res/values-mcc204-mnc04-sw/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-sw/strings.xml @@ -19,7 +19,7 @@ "Mtandao pepe hauna intaneti" "Vifaa vimeshindwa kuunganisha kwenye intaneti" "Zima mtandao pepe" - "Mtandaopepe umewashwa" + "Mtandao pepe umewashwa" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" "Endelea" diff --git a/Tethering/res/values-mcc204-mnc04-ta/strings.xml b/Tethering/res/values-mcc204-mnc04-ta/strings.xml index 63c28c6702..7eebd6784a 100644 --- a/Tethering/res/values-mcc204-mnc04-ta/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-ta/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" + "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" + "ஹாட்ஸ்பாட்டை ஆஃப் செய்" + "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" "தொடர்க" diff --git a/Tethering/res/values-mcc204-mnc04-te/strings.xml b/Tethering/res/values-mcc204-mnc04-te/strings.xml index 2cf579ca0e..0986534fc7 100644 --- a/Tethering/res/values-mcc204-mnc04-te/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-te/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" + "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" + "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" + "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" "కొనసాగించు" diff --git a/Tethering/res/values-mcc204-mnc04-uz/strings.xml b/Tethering/res/values-mcc204-mnc04-uz/strings.xml index 5231c5fff5..715d34808b 100644 --- a/Tethering/res/values-mcc204-mnc04-uz/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-uz/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "Hotspot internetga ulanmagan" + "Qurilmalar internetga ulana olmayapti" + "Hotspotni faolsizlantirish" + "Hotspot yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" "Davom etish" diff --git a/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml index 38c2563638..cdb4224bf3 100644 --- a/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc204-mnc04-zh-rCN/strings.xml @@ -16,7 +16,7 @@ - "热点无法访问互联网" + "热点没有网络连接" "设备无法连接到互联网" "关闭热点" "热点已开启" diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml index e5e7e5e03d..f4b4c176e7 100644 --- a/Tethering/res/values-mcc310-mnc004-ar/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "نقطة الاتصال غير متصلة بالإنترنت." + "لا يمكن للأجهزة الاتصال بالإنترنت." + "إيقاف نقطة الاتصال" + "نقطة الاتصال مفعّلة" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." "متابعة" diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml index d5ee1a91ce..7a8d1e173e 100644 --- a/Tethering/res/values-mcc310-mnc004-bn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" + "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" + "হটস্পট বন্ধ করুন" + "হটস্পট চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" "চালিয়ে যান" diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml index ae86e0aa8e..a4ec581fe9 100644 --- a/Tethering/res/values-mcc310-mnc004-bs/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -20,6 +20,6 @@ "Uređaji se ne mogu povezati na internet" "Isključi pristupnu tačku" "Pristupna tačka je uključena" - "Primjenjuju se dodatne tarife u romingu" + "Mogu nastati dodatni troškovi u romingu" "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml index d4b6937881..91368bf011 100644 --- a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -16,10 +16,10 @@ - "El hotspot no tiene Internet" + "El hotspot no tiene conexión a Internet" "Los dispositivos no pueden conectarse a Internet" "Desactiva el hotspot" "El hotspot está activado" - "Es posible que apliquen cargos adicionales por roaming" + "Es posible que se apliquen cargos adicionales por roaming" "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml index 158fd86296..c717033145 100644 --- a/Tethering/res/values-mcc310-mnc004-es/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -19,7 +19,7 @@ "El punto de acceso no tiene conexión a Internet" "Los dispositivos no se pueden conectar a Internet" "Desactivar punto de acceso" - "Zona Wi-Fi activada" + "Punto de acceso activado" "Puede que se apliquen cargos adicionales en itinerancia" "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml index 7a2b99e028..09de71f8bc 100644 --- a/Tethering/res/values-mcc310-mnc004-eu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -20,6 +20,6 @@ "Gailuak ezin dira konektatu Internetera" "Desaktibatu sare publikoa" "Sare publikoa aktibatuta dago" - "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" "Egin aurrera" diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml index e85c00c648..580f3c5cbf 100644 --- a/Tethering/res/values-mcc310-mnc004-gu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" + "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" + "હૉટસ્પૉટ બંધ કરો" + "હૉટસ્પૉટ ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" "આગળ વધો" diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml index 513d2fb040..bef3fc59d3 100644 --- a/Tethering/res/values-mcc310-mnc004-in/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -16,7 +16,7 @@ - "Hotspot tidak memiliki internet" + "Hotspot tidak memiliki koneksi internet" "Perangkat tidak dapat tersambung ke internet" "Nonaktifkan hotspot" "Hotspot aktif" diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml index b82363270b..cc5a6a5cda 100644 --- a/Tethering/res/values-mcc310-mnc004-it/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -20,6 +20,6 @@ "I dispositivi non possono connettersi a Internet" "Disattiva l\'hotspot" "Hotspot attivo" - "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" "Continua" diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml index 3e8aaebbe9..8044c9f5f6 100644 --- a/Tethering/res/values-mcc310-mnc004-kn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" + "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml index 7ecb6970e7..860c3e41f1 100644 --- a/Tethering/res/values-mcc310-mnc004-ky/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -16,7 +16,7 @@ - "Хотспоттун Интернети жок" + "Байланыш түйүнүндө Интернет жок" "Түзмөктөр Интернетке туташпай жатат" "Туташуу түйүнүн өчүрүү" "Кошулуу түйүнү күйүк" diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml index 5d1766707c..b6b8252164 100644 --- a/Tethering/res/values-mcc310-mnc004-lo/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" + "ປິດຮັອດສະປອດ" + "ຮັອດສະປອດເປີດຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml index 930ffa184e..b8fdda0991 100644 --- a/Tethering/res/values-mcc310-mnc004-ml/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" + "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" + "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" + "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" "തുടരുക" diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index e1770b3f77..86c070500f 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "हटस्पटमा इन्टरनेट छैन" + "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" + "हटस्पट निष्क्रिय पार्नुहोस्" + "हटस्पट सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml index 6a842428e0..5509a54b2f 100644 --- a/Tethering/res/values-mcc310-mnc004-or/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml index bb1479d3fb..790fced58e 100644 --- a/Tethering/res/values-mcc310-mnc004-pa/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" + "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml index 6ab396d50d..1ff63cf967 100644 --- a/Tethering/res/values-mcc310-mnc004-ru/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -17,7 +17,7 @@ "Точка доступа не подключена к Интернету" - "Не удается подключить устройства к Интернету" + "Устройства не могут подключаться к Интернету" "Отключить точку доступа" "Точка доступа включена" "За использование услуг связи в роуминге может взиматься дополнительная плата." diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml index 0eb922fff6..00e99bdf5f 100644 --- a/Tethering/res/values-mcc310-mnc004-sw/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -19,7 +19,7 @@ "Mtandao pepe hauna intaneti" "Vifaa vimeshindwa kuunganisha kwenye intaneti" "Zima mtandao pepe" - "Mtandaopepe umewashwa" + "Mtandao pepe umewashwa" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" "Endelea" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index 1d66c6d689..416d73f2d7 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" + "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" + "ஹாட்ஸ்பாட்டை ஆஃப் செய்" + "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" "தொடர்க" diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml index 2ee0fa8dda..864f726b94 100644 --- a/Tethering/res/values-mcc310-mnc004-te/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" + "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" + "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" + "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" "కొనసాగించు" diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml index 9def0a1b06..167b41a7ed 100644 --- a/Tethering/res/values-mcc310-mnc004-uz/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "Hotspot internetga ulanmagan" + "Qurilmalar internetga ulana olmayapti" + "Hotspotni faolsizlantirish" + "Hotspot yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" "Davom etish" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml index cee4682e7d..570d793c44 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -16,7 +16,7 @@ - "热点无法访问互联网" + "热点没有网络连接" "设备无法连接到互联网" "关闭热点" "热点已开启" diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml index 9460023663..15e5605d13 100644 --- a/Tethering/res/values-mcc311-mnc480-ar/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "نقطة الاتصال غير متصلة بالإنترنت." + "لا يمكن للأجهزة الاتصال بالإنترنت." + "إيقاف نقطة الاتصال" + "نقطة الاتصال مفعّلة" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." "متابعة" diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml index 00bac782ed..4058f719c9 100644 --- a/Tethering/res/values-mcc311-mnc480-bn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" + "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" + "হটস্পট বন্ধ করুন" + "হটস্পট চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" "চালিয়ে যান" diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml index 907821260b..ccfb199cee 100644 --- a/Tethering/res/values-mcc311-mnc480-bs/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -20,6 +20,6 @@ "Uređaji se ne mogu povezati na internet" "Isključi pristupnu tačku" "Pristupna tačka je uključena" - "Primjenjuju se dodatne tarife u romingu" + "Mogu nastati dodatni troškovi u romingu" "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml index 68d5fc26de..522fb5fc72 100644 --- a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -16,10 +16,10 @@ - "El hotspot no tiene Internet" + "El hotspot no tiene conexión a Internet" "Los dispositivos no pueden conectarse a Internet" "Desactiva el hotspot" "El hotspot está activado" - "Es posible que apliquen cargos adicionales por roaming" + "Es posible que se apliquen cargos adicionales por roaming" "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml index 930e088642..e2e30ee934 100644 --- a/Tethering/res/values-mcc311-mnc480-es/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -19,7 +19,7 @@ "El punto de acceso no tiene conexión a Internet" "Los dispositivos no se pueden conectar a Internet" "Desactivar punto de acceso" - "Zona Wi-Fi activada" + "Punto de acceso activado" "Puede que se apliquen cargos adicionales en itinerancia" "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml index 4358266323..34c36bb056 100644 --- a/Tethering/res/values-mcc311-mnc480-eu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -20,6 +20,6 @@ "Gailuak ezin dira konektatu Internetera" "Desaktibatu sare publikoa" "Sare publikoa aktibatuta dago" - "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" "Egin aurrera" diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml index c2af9a6688..13f74ac93d 100644 --- a/Tethering/res/values-mcc311-mnc480-gu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" + "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" + "હૉટસ્પૉટ બંધ કરો" + "હૉટસ્પૉટ ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" "આગળ વધો" diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml index e2538328cf..16efe936ef 100644 --- a/Tethering/res/values-mcc311-mnc480-in/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -16,7 +16,7 @@ - "Hotspot tidak memiliki internet" + "Hotspot tidak memiliki koneksi internet" "Perangkat tidak dapat tersambung ke internet" "Nonaktifkan hotspot" "Hotspot aktif" diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml index 388aa7a2c5..6ffa05bf93 100644 --- a/Tethering/res/values-mcc311-mnc480-it/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -20,6 +20,6 @@ "I dispositivi non possono connettersi a Internet" "Disattiva l\'hotspot" "Hotspot attivo" - "Potrebbero essere addebitati costi aggiuntivi durante il roaming" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" "Continua" diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml index 3c75b1205b..cc401b1775 100644 --- a/Tethering/res/values-mcc311-mnc480-kn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" + "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml index 85e92e0a3c..cbae0056fe 100644 --- a/Tethering/res/values-mcc311-mnc480-ky/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -16,7 +16,7 @@ - "Хотспоттун Интернети жок" + "Байланыш түйүнүндө Интернет жок" "Түзмөктөр Интернетке туташпай жатат" "Туташуу түйүнүн өчүрүү" "Кошулуу түйүнү күйүк" diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml index 881e05c5e0..33b03f8690 100644 --- a/Tethering/res/values-mcc311-mnc480-lo/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" + "ປິດຮັອດສະປອດ" + "ຮັອດສະປອດເປີດຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml index c9b12cd706..9e5336e46d 100644 --- a/Tethering/res/values-mcc311-mnc480-ml/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" + "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" + "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" + "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" "തുടരുക" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 9b2256abfc..2d7cf4d316 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "हटस्पटमा इन्टरनेट छैन" + "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" + "हटस्पट निष्क्रिय पार्नुहोस्" + "हटस्पट सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml index b478d1393b..e4c2458f44 100644 --- a/Tethering/res/values-mcc311-mnc480-or/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml index e0940a518d..642befbd64 100644 --- a/Tethering/res/values-mcc311-mnc480-pa/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" + "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml index 22dcfcf42d..fb2caa9428 100644 --- a/Tethering/res/values-mcc311-mnc480-ru/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -17,7 +17,7 @@ "Точка доступа не подключена к Интернету" - "Не удается подключить устройства к Интернету" + "Устройства не могут подключаться к Интернету" "Отключить точку доступа" "Точка доступа включена" "За использование услуг связи в роуминге может взиматься дополнительная плата." diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml index 5a812e3f0c..e3bb799a6b 100644 --- a/Tethering/res/values-mcc311-mnc480-sw/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -19,7 +19,7 @@ "Mtandao pepe hauna intaneti" "Vifaa vimeshindwa kuunganisha kwenye intaneti" "Zima mtandao pepe" - "Mtandaopepe umewashwa" + "Mtandao pepe umewashwa" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" "Endelea" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 315403135d..4fa3f03e82 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" + "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" + "ஹாட்ஸ்பாட்டை ஆஃப் செய்" + "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" "தொடர்க" diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml index 414def5963..49d7687178 100644 --- a/Tethering/res/values-mcc311-mnc480-te/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" + "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" + "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" + "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" "కొనసాగించు" diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml index 769cc2c385..c6bd803e3f 100644 --- a/Tethering/res/values-mcc311-mnc480-uz/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -16,15 +16,10 @@ - - - - - - - - - - + "Hotspot internetga ulanmagan" + "Qurilmalar internetga ulana olmayapti" + "Hotspotni faolsizlantirish" + "Hotspot yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" "Davom etish" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml index 75786086b6..eae5865b0c 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -16,7 +16,7 @@ - "热点无法访问互联网" + "热点没有网络连接" "设备无法连接到互联网" "关闭热点" "热点已开启" diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 19240700ee..156ab2d383 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -16,12 +16,12 @@ - "Tính năng chia sẻ kết nối hoặc điểm phát sóng đang hoạt động" + "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" "Hãy nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" + "Đã tắt tính năng chia sẻ Internet" "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" - "Trạng thái điểm phát sóng và trạng thái chia sẻ kết nối" + "Trạng thái điểm phát sóng và chia sẻ Internet" From d995566700fbc4835f2f51b9d4ec40c5a89093f3 Mon Sep 17 00:00:00 2001 From: markchien Date: Sun, 12 Apr 2020 21:41:29 +0800 Subject: [PATCH 0932/1415] Change tethering file structure to respect its package name Bug: 145099347 Test: atest TetheringTests atest CtsTetheringTest Change-Id: I7401c550fbafd17a5ed2d925b5d0e17e358af467 --- Tethering/AndroidManifest.xml | 2 +- Tethering/AndroidManifest_InProcess.xml | 2 +- Tethering/proguard.flags | 2 +- Tethering/res/values/config.xml | 2 +- .../tethering/ConnectedClientsTracker.java | 2 +- .../tethering/EntitlementManager.java | 5 ++--- .../tethering/IPv6TetheringCoordinator.java | 2 +- .../tethering/OffloadController.java | 4 ++-- .../tethering/OffloadHardwareInterface.java | 2 +- .../tethering/Tethering.java | 4 ++-- .../tethering/TetheringConfiguration.java | 3 +-- .../tethering/TetheringDependencies.java | 2 +- .../tethering/TetheringInterfaceUtils.java | 2 +- .../tethering/TetheringNotificationUpdater.java | 3 +-- .../tethering/TetheringService.java | 2 +- .../tethering/UpstreamNetworkMonitor.java | 2 +- .../tethering/UpstreamNetworkState.java | 2 +- Tethering/tests/unit/AndroidManifest.xml | 4 ++-- .../tethering/ConnectedClientsTrackerTest.kt | 4 ++-- .../tethering/EntitlementManagerTest.java | 3 +-- .../tethering/IPv6TetheringCoordinatorTest.java | 2 +- .../tethering/MockTetheringService.java | 2 +- .../tethering/OffloadControllerTest.java | 8 ++++---- .../tethering/TetheringConfigurationTest.java | 3 +-- .../tethering/TetheringNotificationUpdaterTest.kt | 7 +++---- .../tethering/TetheringServiceTest.java | 4 ++-- .../tethering/TetheringTest.java | 5 ++--- .../tethering/UpstreamNetworkMonitorTest.java | 4 ++-- 28 files changed, 41 insertions(+), 48 deletions(-) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/ConnectedClientsTracker.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/EntitlementManager.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/IPv6TetheringCoordinator.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/OffloadController.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/OffloadHardwareInterface.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/Tethering.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringConfiguration.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringDependencies.java (98%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringInterfaceUtils.java (98%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringNotificationUpdater.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringService.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/UpstreamNetworkMonitor.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/UpstreamNetworkState.java (97%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/ConnectedClientsTrackerTest.kt (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/EntitlementManagerTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/IPv6TetheringCoordinatorTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/MockTetheringService.java (96%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/OffloadControllerTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/TetheringConfigurationTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/TetheringNotificationUpdaterTest.kt (98%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/TetheringServiceTest.java (98%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/TetheringTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/UpstreamNetworkMonitorTest.java (99%) diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index ab257475ca..1dc8227e81 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml @@ -43,7 +43,7 @@ android:process="com.android.networkstack.process" android:extractNativeLibs="false" android:persistent="true"> - diff --git a/Tethering/AndroidManifest_InProcess.xml b/Tethering/AndroidManifest_InProcess.xml index bf1f001e03..b1f124097c 100644 --- a/Tethering/AndroidManifest_InProcess.xml +++ b/Tethering/AndroidManifest_InProcess.xml @@ -22,7 +22,7 @@ android:process="system"> - diff --git a/Tethering/proguard.flags b/Tethering/proguard.flags index 1f83a66382..051fbd19fc 100644 --- a/Tethering/proguard.flags +++ b/Tethering/proguard.flags @@ -1,5 +1,5 @@ # Keep class's integer static field for MessageUtils to parsing their name. --keep class com.android.server.connectivity.tethering.Tethering$TetherMasterSM { +-keep class com.android.networkstack.tethering.Tethering$TetherMasterSM { static final int CMD_*; static final int EVENT_*; } diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index f825d6b07f..3a2084ac92 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -87,7 +87,7 @@ TYPE_MOBILE_HIPRI is appended. For other changes applied to this list, now and in the future, see - com.android.server.connectivity.tethering.TetheringConfiguration. + com.android.networkstack.tethering.TetheringConfiguration. Note also: the order of this is important. The first upstream type for which a satisfying network exists is used. diff --git a/Tethering/src/com/android/server/connectivity/tethering/ConnectedClientsTracker.java b/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/ConnectedClientsTracker.java rename to Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java index cdd1a5d978..8a96988ae1 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/ConnectedClientsTracker.java +++ b/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_WIFI; diff --git a/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java rename to Tethering/src/com/android/networkstack/tethering/EntitlementManager.java index 639cf65d79..4c7b2d49ee 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; @@ -52,7 +52,6 @@ import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; -import com.android.networkstack.tethering.R; import java.io.PrintWriter; @@ -71,7 +70,7 @@ public class EntitlementManager { @VisibleForTesting protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning"; private static final String ACTION_PROVISIONING_ALARM = - "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"; + "com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM"; private static final String EXTRA_SUBID = "subId"; private final ComponentName mSilentProvisioningService; diff --git a/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java rename to Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java index 66b9ade810..d450c46de7 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.net.IpPrefix; import android.net.LinkAddress; diff --git a/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/OffloadController.java rename to Tethering/src/com/android/networkstack/tethering/OffloadController.java index 15cdb6ad7a..c007c174fe 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; @@ -50,7 +50,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; +import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import java.net.Inet4Address; import java.net.Inet6Address; diff --git a/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java rename to Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index b545717208..85a23fb83f 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.util.TetheringUtils.uint16; diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/Tethering.java rename to Tethering/src/com/android/networkstack/tethering/Tethering.java index 343ed4b16c..601a9dbe9e 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STACK; @@ -60,7 +60,7 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; +import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothAdapter; diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java rename to Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 7e9e26f5af..aeac437e24 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.content.Context.TELEPHONY_SERVICE; import static android.net.ConnectivityManager.TYPE_ETHERNET; @@ -33,7 +33,6 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; -import com.android.networkstack.tethering.R; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java similarity index 98% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java rename to Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 0330dad6a1..893c5823dc 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.bluetooth.BluetoothAdapter; import android.content.Context; diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java similarity index 98% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java rename to Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java index 4dd68301f9..ff38f717a1 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.annotation.Nullable; import android.net.LinkProperties; diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java rename to Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index 992cdd8de6..42870560cb 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_USB; @@ -41,7 +41,6 @@ import androidx.annotation.IntRange; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; -import com.android.networkstack.tethering.R; /** * A class to display tethering-related notifications. diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringService.java rename to Tethering/src/com/android/networkstack/tethering/TetheringService.java index c30be25dbd..3ed211520d 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; diff --git a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java rename to Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java index 45bb4ab6e5..25ddce4404 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; diff --git a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkState.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java similarity index 97% rename from Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkState.java rename to Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java index 68bb837593..bab9f84cf7 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkState.java +++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.net.LinkProperties; import android.net.Network; diff --git a/Tethering/tests/unit/AndroidManifest.xml b/Tethering/tests/unit/AndroidManifest.xml index 4ff1d3777f..55640db693 100644 --- a/Tethering/tests/unit/AndroidManifest.xml +++ b/Tethering/tests/unit/AndroidManifest.xml @@ -21,11 +21,11 @@ - + diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt rename to Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt index 1cdc3bbb99..d915354b0c 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering +package com.android.networkstack.tethering import android.net.LinkAddress import android.net.MacAddress @@ -159,4 +159,4 @@ class ConnectedClientsTrackerTest { return time } } -} \ No newline at end of file +} diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java index 6695eed0ff..8bd0edc249 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_ETHERNET; @@ -59,7 +59,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java index 912124357c..820f255145 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.RouteInfo.RTN_UNICAST; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java similarity index 96% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java index 355ece9a44..1c81c1247d 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static org.mockito.Mockito.mock; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index fe840864fb..65797200fa 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; @@ -26,9 +26,9 @@ import static android.net.NetworkStats.UID_TETHERING; import static android.net.RouteInfo.RTN_UNICAST; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; -import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_IFACE; -import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_UID; -import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; +import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE; +import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; +import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index 3635964dd6..07ddea43f4 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; @@ -44,7 +44,6 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt similarity index 98% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt rename to Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index b86949185c..7bff74b25d 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering +package com.android.networkstack.tethering import android.app.Notification import android.app.NotificationManager @@ -29,8 +29,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.test.BroadcastInterceptingContext -import com.android.networkstack.tethering.R -import com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE +import com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -259,4 +258,4 @@ class TetheringNotificationUpdaterTest { notificationUpdater.notifyTetheringDisabledByRestriction() verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage) } -} \ No newline at end of file +} diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java similarity index 98% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index d9d3e73eb4..51bad9af23 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; @@ -37,7 +37,7 @@ import androidx.test.filters.SmallTest; import androidx.test.rule.ServiceTestRule; import androidx.test.runner.AndroidJUnit4; -import com.android.server.connectivity.tethering.MockTetheringService.MockTetheringConnector; +import com.android.networkstack.tethering.MockTetheringService.MockTetheringConnector; import org.junit.After; import org.junit.Before; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 38059fc9f2..5bec513322 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; @@ -47,7 +47,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; +import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -137,7 +137,6 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.networkstack.tethering.R; import com.android.testutils.MiscAssertsKt; import org.junit.After; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java index 7c98f626a4..232588c7ee 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; @@ -24,7 +24,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static com.android.server.connectivity.tethering.UpstreamNetworkMonitor.TYPE_NONE; +import static com.android.networkstack.tethering.UpstreamNetworkMonitor.TYPE_NONE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; From 5eaf009a929d4f7a4bdd1f53767e6ec95cb0cee4 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Mon, 13 Apr 2020 15:02:00 +0000 Subject: [PATCH 0933/1415] Add tethering CTS owners. Test: none Bug: 153921802 Change-Id: I0651e7fa2a705b553f2d24ca573936c28591bb84 Merged-In: I552b3bf8d79c4e4480396edc201b51ec5901b87b (cherry picked from commit 7f210a41827742b1448a82d093a651898f40ad2e) --- tests/cts/tethering/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/cts/tethering/OWNERS diff --git a/tests/cts/tethering/OWNERS b/tests/cts/tethering/OWNERS new file mode 100644 index 0000000000..cd6abeb6e8 --- /dev/null +++ b/tests/cts/tethering/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 31808 +lorenzo@google.com +satk@google.com + From 524f93613fdb5f8ad180681be593133cf77474fb Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Sun, 12 Apr 2020 14:53:45 +0000 Subject: [PATCH 0934/1415] Test onBandwidthUpdateRequested Test: this Bug: 139268426 Change-Id: I5f4b42dc68fdd13f26e59b4e2217d39dcee8f2a1 Merged-In: I427ae6ac2c8910683e47f503ba71a05e35507571 (cherry picked from commit bbe53cd710440468520d5d5713eaa503b6c9d8b9, aosp/1258136) --- .../net/src/android/net/cts/NetworkAgentTest.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 85c94e7db2..2fdd5fb201 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -24,6 +24,7 @@ import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkProvider import android.net.NetworkRequest +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted import android.os.Build import android.os.HandlerThread @@ -88,9 +89,15 @@ class NetworkAgentTest { private val history = ArrayTrackRecord().newReadHead() sealed class CallbackEntry { + object OnBandwidthUpdateRequested : CallbackEntry() object OnNetworkUnwanted : CallbackEntry() } + override fun onBandwidthUpdateRequested() { + super.onBandwidthUpdateRequested() + history.add(OnBandwidthUpdateRequested) + } + override fun onNetworkUnwanted() { super.onNetworkUnwanted() history.add(OnNetworkUnwanted) @@ -139,4 +146,13 @@ class NetworkAgentTest { agent.register() } } + + @Test + fun testOnBandwidthUpdateRequested() { + val (agent, callback) = createConnectedNetworkAgent() + callback.expectAvailableThenValidatedCallbacks(agent.network) + mCM.requestBandwidthUpdate(agent.network) + agent.expectCallback() + agent.unregister() + } } From 330a9b9fa74aaa96b4c17c514a73e11841102b66 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 14 Apr 2020 14:57:30 +0900 Subject: [PATCH 0935/1415] Don't crash when receiving an RTM_DELNEIGH or NUD_FAILED. These events don't have MAC addresses, so the code attempts to create an Ipv6ForwardingRule with a null MAC address. This crashes when attempting to get the raw MAC address bytes to send to netd in the TetherOffloadRuleParcel. This was not caught by unit tests because the test exercise this code path in a way that is not correct (by sending RTM_DELNEIGH and NUD_FAILED events with MAC addresses). Fix the unit tests to properly pass in null MAC addresses for these events. Bug: 153697068 Test: fixed existing tests to be more realistic Change-Id: I26d89a81f1c448d9b4809652b079a5f5eace3924 --- Tethering/src/android/net/ip/IpServer.java | 9 +++++++-- .../tests/unit/src/android/net/ip/IpServerTest.java | 8 +++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 1dac5b7846..83727bcdc6 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -122,6 +122,8 @@ public class IpServer extends StateMachine { // TODO: have this configurable private static final int DHCP_LEASE_TIME_SECS = 3600; + private static final MacAddress NULL_MAC_ADDRESS = MacAddress.fromString("00:00:00:00:00:00"); + private static final String TAG = "IpServer"; private static final boolean DBG = false; private static final boolean VDBG = false; @@ -902,9 +904,12 @@ public class IpServer extends StateMachine { return; } + // When deleting rules, we still need to pass a non-null MAC, even though it's ignored. + // Do this here instead of in the Ipv6ForwardingRule constructor to ensure that we never + // add rules with a null MAC, only delete them. + MacAddress dstMac = e.isValid() ? e.macAddr : NULL_MAC_ADDRESS; Ipv6ForwardingRule rule = new Ipv6ForwardingRule(upstreamIfindex, - mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, - e.macAddr); + mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, dstMac); if (e.isValid()) { addIpv6ForwardingRule(rule); } else { diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index fdfdae837d..f9be7b9d36 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -587,6 +587,7 @@ public class IpServerTest { final InetAddress neighB = InetAddresses.parseNumericAddress("2001:db8::2"); final InetAddress neighLL = InetAddresses.parseNumericAddress("fe80::1"); final InetAddress neighMC = InetAddresses.parseNumericAddress("ff02::1234"); + final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00"); final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b"); @@ -612,13 +613,14 @@ public class IpServerTest { verifyNoMoreInteractions(mNetd); // A neighbor that is no longer valid causes the rule to be removed. - recvNewNeigh(myIfindex, neighA, NUD_FAILED, macA); - verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); + // NUD_FAILED events do not have a MAC address. + recvNewNeigh(myIfindex, neighA, NUD_FAILED, null); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macNull)); reset(mNetd); // A neighbor that is deleted causes the rule to be removed. recvDelNeigh(myIfindex, neighB, NUD_STALE, macB); - verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macNull)); reset(mNetd); // Upstream changes result in deleting and re-adding the rules. From bdf1003c3bfa9486515c207067c5c25218c2a47d Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 14 Apr 2020 16:57:55 +0800 Subject: [PATCH 0936/1415] Do not stop IpServer when recieve wifi ap disabling state. This is used to fix the race when quickly OFF/ON wifi tethering. When IpServer is started/stopped, there is callback update tethering interface status. Before this change, IpServer is stopped when wifi ap is disabling. Then the next startTethering may fail in wifi because wifi is in disabling state. Error pattern: WifiService: Tethering is already active. No unitest for this CL but it fixed the CtsTetheringTest flakty rate than around 30% to 0 for more than 100 runs. Bug: 153925821 Test: atest CtsTetheringTest --iteration 100 Change-Id: I8b65f621abe20799a3a0d410ba1f06368746ee49 --- .../src/com/android/networkstack/tethering/Tethering.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 601a9dbe9e..14abfdc0cc 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -922,8 +922,10 @@ public class Tethering { case WifiManager.WIFI_AP_STATE_ENABLED: enableWifiIpServingLocked(ifname, ipmode); break; - case WifiManager.WIFI_AP_STATE_DISABLED: case WifiManager.WIFI_AP_STATE_DISABLING: + // We can see this state on the way to disabled. + break; + case WifiManager.WIFI_AP_STATE_DISABLED: case WifiManager.WIFI_AP_STATE_FAILED: default: disableWifiIpServingLocked(ifname, curState); From 7f1975092f146bc53a00d20c93556ca2f755d338 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 10 Apr 2020 15:34:04 +0800 Subject: [PATCH 0937/1415] Add TetheringEventCallback CTS test Test APIs below: onOffloadStatusChanged(int) Bug: 153619369 Test: atests CtsTetheringTest Change-Id: Ia7edd0d3d8184e30373ac8b657299107ff9b4c1e --- .../tethering/cts/TetheringManagerTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index b132982e1a..718b4f8892 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,6 +15,9 @@ */ package android.tethering.test; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; @@ -273,6 +276,7 @@ public class TetheringManagerTest { ON_TETHERED_IFACES, ON_ERROR, ON_CLIENTS, + ON_OFFLOAD_STATUS, }; public static class CallbackValue { @@ -330,6 +334,11 @@ public class TetheringManagerTest { mCallbacks.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); } + @Override + public void onOffloadStatusChanged(int status) { + mCallbacks.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); + } + public CallbackValue pollCallback() { try { return mCallbacks.poll(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); @@ -382,6 +391,17 @@ public class TetheringManagerTest { } } + public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { + while (true) { + final CallbackValue cv = pollCallback(); + if (cv == null) fail("No expected offload status change callback"); + if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) continue; + + final int status = (int) cv.callbackParam; + for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return; + } + } + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { return mTetherableRegex; } @@ -403,6 +423,7 @@ public class TetheringManagerTest { mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); tetherEventCallback.expectCallbackStarted(); + tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); final TetheringInterfaceRegexps tetherableRegexs = tetherEventCallback.getTetheringInterfaceRegexps(); @@ -422,10 +443,14 @@ public class TetheringManagerTest { } tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); + tetherEventCallback.expectOneOfOffloadStatusChanged( + TETHER_HARDWARE_OFFLOAD_STARTED, + TETHER_HARDWARE_OFFLOAD_FAILED); mTM.stopTethering(TETHERING_WIFI); tetherEventCallback.expectTetheredInterfacesChanged(null); + tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); mTM.unregisterTetheringEventCallback(tetherEventCallback); } } From 9849d899e82ca196032c5c212e09c3db25f6e005 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Tue, 14 Apr 2020 10:04:07 +0000 Subject: [PATCH 0938/1415] Add TetherableInterfaceRegexps CTS tests Test APIs below: getTetherableWifiRegexs() getTetherableUsbRegexs() getTetherableBluetoothRegexs() TetheringInterfaceRegexps.getTetherableWifiRegexs() TetheringInterfaceRegexps.getTetherableUsbRegexs() TetheringInterfaceRegexps.getTetherableBluetoothRegexs() Bug: 152737526 Test: atest CtsTetheringTest Change-Id: Icb7d8718d0aa6574b4c9dd1e17d7feb300fad2aa Merged-In: Icb7d8718d0aa6574b4c9dd1e17d7feb300fad2aa (cherry picked from commit 9f11d903a1d8cc6705481360bae4fb97cfbb966d, aosp/1271822) --- .../tethering/cts/TetheringManagerTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index b132982e1a..193a5dc3a4 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -428,4 +428,30 @@ public class TetheringManagerTest { tetherEventCallback.expectTetheredInterfacesChanged(null); mTM.unregisterTetheringEventCallback(tetherEventCallback); } + + @Test + public void testGetTetherableInterfaceRegexps() { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); + mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); + tetherEventCallback.expectCallbackStarted(); + + final TetheringInterfaceRegexps tetherableRegexs = + tetherEventCallback.getTetheringInterfaceRegexps(); + final List wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); + final List usbRegexs = tetherableRegexs.getTetherableUsbRegexs(); + final List btRegexs = tetherableRegexs.getTetherableBluetoothRegexs(); + + assertEquals(wifiRegexs, Arrays.asList(mTM.getTetherableWifiRegexs())); + assertEquals(usbRegexs, Arrays.asList(mTM.getTetherableUsbRegexs())); + assertEquals(btRegexs, Arrays.asList(mTM.getTetherableBluetoothRegexs())); + + //Verify that any of interface name should only contain in one array. + wifiRegexs.forEach(s -> assertFalse(usbRegexs.contains(s))); + wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); + usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); + + mTM.unregisterTetheringEventCallback(tetherEventCallback); + } } From 1acfb0125c563f4e164a6aa46cdc8e0fef6d4b91 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 14 Apr 2020 20:19:38 +0800 Subject: [PATCH 0939/1415] Change tethering file structure to respect its package name Bug: 145099347 Test: atest TetheringTests atest CtsTetheringTest Change-Id: I544ab9480bbaa5e18e030d21a28ab4c4a7265795 --- Tethering/AndroidManifest.xml | 2 +- Tethering/AndroidManifest_InProcess.xml | 2 +- Tethering/proguard.flags | 2 +- Tethering/res/values/config.xml | 2 +- .../tethering/ConnectedClientsTracker.java | 2 +- .../tethering/EntitlementManager.java | 5 ++--- .../tethering/IPv6TetheringCoordinator.java | 2 +- .../tethering/OffloadController.java | 4 ++-- .../tethering/OffloadHardwareInterface.java | 2 +- .../tethering/Tethering.java | 4 ++-- .../tethering/TetheringConfiguration.java | 3 +-- .../tethering/TetheringDependencies.java | 2 +- .../tethering/TetheringInterfaceUtils.java | 2 +- .../tethering/TetheringNotificationUpdater.java | 3 +-- .../tethering/TetheringService.java | 2 +- .../tethering/UpstreamNetworkMonitor.java | 2 +- .../tethering/UpstreamNetworkState.java | 2 +- Tethering/tests/unit/AndroidManifest.xml | 4 ++-- .../tethering/ConnectedClientsTrackerTest.kt | 4 ++-- .../tethering/EntitlementManagerTest.java | 3 +-- .../tethering/IPv6TetheringCoordinatorTest.java | 2 +- .../tethering/MockTetheringService.java | 2 +- .../tethering/OffloadControllerTest.java | 8 ++++---- .../tethering/TetheringConfigurationTest.java | 3 +-- .../tethering/TetheringNotificationUpdaterTest.kt | 7 +++---- .../tethering/TetheringServiceTest.java | 4 ++-- .../tethering/TetheringTest.java | 5 ++--- .../tethering/UpstreamNetworkMonitorTest.java | 4 ++-- 28 files changed, 41 insertions(+), 48 deletions(-) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/ConnectedClientsTracker.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/EntitlementManager.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/IPv6TetheringCoordinator.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/OffloadController.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/OffloadHardwareInterface.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/Tethering.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringConfiguration.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringDependencies.java (98%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringInterfaceUtils.java (98%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringNotificationUpdater.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/TetheringService.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/UpstreamNetworkMonitor.java (99%) rename Tethering/src/com/android/{server/connectivity => networkstack}/tethering/UpstreamNetworkState.java (97%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/ConnectedClientsTrackerTest.kt (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/EntitlementManagerTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/IPv6TetheringCoordinatorTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/MockTetheringService.java (96%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/OffloadControllerTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/TetheringConfigurationTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/TetheringNotificationUpdaterTest.kt (98%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/TetheringServiceTest.java (98%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/TetheringTest.java (99%) rename Tethering/tests/unit/src/com/android/{server/connectivity => networkstack}/tethering/UpstreamNetworkMonitorTest.java (99%) diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index ab257475ca..1dc8227e81 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml @@ -43,7 +43,7 @@ android:process="com.android.networkstack.process" android:extractNativeLibs="false" android:persistent="true"> - diff --git a/Tethering/AndroidManifest_InProcess.xml b/Tethering/AndroidManifest_InProcess.xml index bf1f001e03..b1f124097c 100644 --- a/Tethering/AndroidManifest_InProcess.xml +++ b/Tethering/AndroidManifest_InProcess.xml @@ -22,7 +22,7 @@ android:process="system"> - diff --git a/Tethering/proguard.flags b/Tethering/proguard.flags index 1f83a66382..051fbd19fc 100644 --- a/Tethering/proguard.flags +++ b/Tethering/proguard.flags @@ -1,5 +1,5 @@ # Keep class's integer static field for MessageUtils to parsing their name. --keep class com.android.server.connectivity.tethering.Tethering$TetherMasterSM { +-keep class com.android.networkstack.tethering.Tethering$TetherMasterSM { static final int CMD_*; static final int EVENT_*; } diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index 04d6215dce..430fdc4228 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -89,7 +89,7 @@ TYPE_MOBILE_HIPRI is appended. For other changes applied to this list, now and in the future, see - com.android.server.connectivity.tethering.TetheringConfiguration. + com.android.networkstack.tethering.TetheringConfiguration. Note also: the order of this is important. The first upstream type for which a satisfying network exists is used. diff --git a/Tethering/src/com/android/server/connectivity/tethering/ConnectedClientsTracker.java b/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/ConnectedClientsTracker.java rename to Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java index cdd1a5d978..8a96988ae1 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/ConnectedClientsTracker.java +++ b/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_WIFI; diff --git a/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java rename to Tethering/src/com/android/networkstack/tethering/EntitlementManager.java index 639cf65d79..4c7b2d49ee 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; @@ -52,7 +52,6 @@ import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; -import com.android.networkstack.tethering.R; import java.io.PrintWriter; @@ -71,7 +70,7 @@ public class EntitlementManager { @VisibleForTesting protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning"; private static final String ACTION_PROVISIONING_ALARM = - "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"; + "com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM"; private static final String EXTRA_SUBID = "subId"; private final ComponentName mSilentProvisioningService; diff --git a/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java rename to Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java index 66b9ade810..d450c46de7 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.net.IpPrefix; import android.net.LinkAddress; diff --git a/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/OffloadController.java rename to Tethering/src/com/android/networkstack/tethering/OffloadController.java index 15cdb6ad7a..c007c174fe 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; @@ -50,7 +50,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; +import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import java.net.Inet4Address; import java.net.Inet6Address; diff --git a/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java rename to Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index b545717208..85a23fb83f 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.util.TetheringUtils.uint16; diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/Tethering.java rename to Tethering/src/com/android/networkstack/tethering/Tethering.java index 4b2c9215f7..f3cead92be 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STACK; @@ -60,7 +60,7 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; +import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothAdapter; diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java rename to Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 7e9e26f5af..aeac437e24 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.content.Context.TELEPHONY_SERVICE; import static android.net.ConnectivityManager.TYPE_ETHERNET; @@ -33,7 +33,6 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; -import com.android.networkstack.tethering.R; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java similarity index 98% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java rename to Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 0330dad6a1..893c5823dc 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.bluetooth.BluetoothAdapter; import android.content.Context; diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java similarity index 98% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java rename to Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java index 4dd68301f9..ff38f717a1 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.annotation.Nullable; import android.net.LinkProperties; diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java rename to Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index 992cdd8de6..42870560cb 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_USB; @@ -41,7 +41,6 @@ import androidx.annotation.IntRange; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; -import com.android.networkstack.tethering.R; /** * A class to display tethering-related notifications. diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/TetheringService.java rename to Tethering/src/com/android/networkstack/tethering/TetheringService.java index c30be25dbd..3ed211520d 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; diff --git a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java similarity index 99% rename from Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java rename to Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java index 45bb4ab6e5..25ddce4404 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; diff --git a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkState.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java similarity index 97% rename from Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkState.java rename to Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java index 68bb837593..bab9f84cf7 100644 --- a/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkState.java +++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.net.LinkProperties; import android.net.Network; diff --git a/Tethering/tests/unit/AndroidManifest.xml b/Tethering/tests/unit/AndroidManifest.xml index 4ff1d3777f..55640db693 100644 --- a/Tethering/tests/unit/AndroidManifest.xml +++ b/Tethering/tests/unit/AndroidManifest.xml @@ -21,11 +21,11 @@ - + diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt rename to Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt index 1cdc3bbb99..d915354b0c 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering +package com.android.networkstack.tethering import android.net.LinkAddress import android.net.MacAddress @@ -159,4 +159,4 @@ class ConnectedClientsTrackerTest { return time } } -} \ No newline at end of file +} diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java index 6695eed0ff..8bd0edc249 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_ETHERNET; @@ -59,7 +59,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java index 912124357c..820f255145 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.RouteInfo.RTN_UNICAST; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java similarity index 96% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java index 355ece9a44..1c81c1247d 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/MockTetheringService.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static org.mockito.Mockito.mock; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index fe840864fb..65797200fa 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; @@ -26,9 +26,9 @@ import static android.net.NetworkStats.UID_TETHERING; import static android.net.RouteInfo.RTN_UNICAST; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; -import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_IFACE; -import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_UID; -import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; +import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE; +import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; +import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index 3635964dd6..07ddea43f4 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; @@ -44,7 +44,6 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt similarity index 98% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt rename to Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index b86949185c..7bff74b25d 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering +package com.android.networkstack.tethering import android.app.Notification import android.app.NotificationManager @@ -29,8 +29,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.test.BroadcastInterceptingContext -import com.android.networkstack.tethering.R -import com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE +import com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -259,4 +258,4 @@ class TetheringNotificationUpdaterTest { notificationUpdater.notifyTetheringDisabledByRestriction() verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage) } -} \ No newline at end of file +} diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java similarity index 98% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index d9d3e73eb4..51bad9af23 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringServiceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; @@ -37,7 +37,7 @@ import androidx.test.filters.SmallTest; import androidx.test.rule.ServiceTestRule; import androidx.test.runner.AndroidJUnit4; -import com.android.server.connectivity.tethering.MockTetheringService.MockTetheringConnector; +import com.android.networkstack.tethering.MockTetheringService.MockTetheringConnector; import org.junit.After; import org.junit.Before; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 2955903c84..d4be3a26d9 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; @@ -47,7 +47,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; +import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -137,7 +137,6 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.networkstack.tethering.R; import com.android.testutils.MiscAssertsKt; import org.junit.After; diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java similarity index 99% rename from Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java rename to Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java index 7c98f626a4..232588c7ee 100644 --- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; @@ -24,7 +24,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static com.android.server.connectivity.tethering.UpstreamNetworkMonitor.TYPE_NONE; +import static com.android.networkstack.tethering.UpstreamNetworkMonitor.TYPE_NONE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; From 648fc2c8eaca070aafa229f0bc0b9839e4978d1f Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 24 Mar 2020 21:09:51 +0800 Subject: [PATCH 0940/1415] [TNU05] Add no upstream notification Reminder user of unavailable tethering status if there is no internet access. Bug: 147818698 Test: atest TetheringTests Change-Id: Ic6557f9f7703337596100cd6a477fd7239217166 --- Tethering/AndroidManifest.xml | 3 + Tethering/res/values-mcc204-mnc04/strings.xml | 30 --- Tethering/res/values-mcc310-mnc004/config.xml | 20 ++ Tethering/res/values-mcc311-mnc480/config.xml | 20 ++ Tethering/res/values/config.xml | 6 + .../networkstack/tethering/Tethering.java | 10 +- .../tethering/TetheringDependencies.java | 5 +- .../TetheringNotificationUpdater.java | 185 ++++++++++++-- Tethering/tests/unit/AndroidManifest.xml | 1 + .../TetheringNotificationUpdaterTest.kt | 239 +++++++++++++++--- .../networkstack/tethering/TetheringTest.java | 14 +- 11 files changed, 446 insertions(+), 87 deletions(-) delete mode 100644 Tethering/res/values-mcc204-mnc04/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004/config.xml create mode 100644 Tethering/res/values-mcc311-mnc480/config.xml diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index 1dc8227e81..2b2fe4534c 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml @@ -34,11 +34,14 @@ + + + - - - - Tethering has no internet - - Devices can\u2019t connect - - Turn off tethering - - - Hotspot or tethering is on - - Additional charges may apply while roaming - - Continue - diff --git a/Tethering/res/values-mcc310-mnc004/config.xml b/Tethering/res/values-mcc310-mnc004/config.xml new file mode 100644 index 0000000000..8c627d5df0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004/config.xml @@ -0,0 +1,20 @@ + + + + + 5000 + \ No newline at end of file diff --git a/Tethering/res/values-mcc311-mnc480/config.xml b/Tethering/res/values-mcc311-mnc480/config.xml new file mode 100644 index 0000000000..8c627d5df0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480/config.xml @@ -0,0 +1,20 @@ + + + + + 5000 + \ No newline at end of file diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index 3a2084ac92..780a015961 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -200,4 +200,10 @@ @string/tethered_notification_title @string/tethered_notification_message + + + + -1 diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 601a9dbe9e..848f204d4b 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -257,7 +257,7 @@ public class Tethering { mContext = mDeps.getContext(); mNetd = mDeps.getINetd(mContext); mLooper = mDeps.getTetheringLooper(); - mNotificationUpdater = mDeps.getNotificationUpdater(mContext); + mNotificationUpdater = mDeps.getNotificationUpdater(mContext, mLooper); mPublicSync = new Object(); @@ -337,6 +337,11 @@ public class Tethering { filter.addAction(ACTION_RESTRICT_BACKGROUND_CHANGED); mContext.registerReceiver(mStateReceiver, filter, null, mHandler); + final IntentFilter noUpstreamFilter = new IntentFilter(); + noUpstreamFilter.addAction(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING); + mContext.registerReceiver( + mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler); + final WifiManager wifiManager = getWifiManager(); if (wifiManager != null) { wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback()); @@ -855,6 +860,8 @@ public class Tethering { } else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED)) { mLog.log("OBSERVED data saver changed"); handleDataSaverChanged(); + } else if (action.equals(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING)) { + untetherAll(); } } @@ -2011,6 +2018,7 @@ public class Tethering { } finally { mTetheringEventCallbacks.finishBroadcast(); } + mNotificationUpdater.onUpstreamNetworkChanged(network); } private void reportConfigurationChanged(TetheringConfigurationParcel config) { diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 893c5823dc..9b54b5ff24 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -106,8 +106,9 @@ public abstract class TetheringDependencies { /** * Get a reference to the TetheringNotificationUpdater to be used by tethering. */ - public TetheringNotificationUpdater getNotificationUpdater(@NonNull final Context ctx) { - return new TetheringNotificationUpdater(ctx); + public TetheringNotificationUpdater getNotificationUpdater(@NonNull final Context ctx, + @NonNull final Looper looper) { + return new TetheringNotificationUpdater(ctx, looper); } /** diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index 42870560cb..ff83fd1e4f 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -19,18 +19,25 @@ package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static android.text.TextUtils.isEmpty; import android.app.Notification; +import android.app.Notification.Action; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.content.res.Resources; +import android.net.Network; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.UserHandle; import android.provider.Settings; import android.telephony.SubscriptionManager; -import android.text.TextUtils; +import android.telephony.TelephonyManager; import android.util.Log; import android.util.SparseArray; @@ -39,9 +46,13 @@ import androidx.annotation.DrawableRes; import androidx.annotation.IntDef; import androidx.annotation.IntRange; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import java.util.Arrays; +import java.util.List; + /** * A class to display tethering-related notifications. * @@ -58,12 +69,22 @@ public class TetheringNotificationUpdater { private static final String WIFI_DOWNSTREAM = "WIFI"; private static final String USB_DOWNSTREAM = "USB"; private static final String BLUETOOTH_DOWNSTREAM = "BT"; + @VisibleForTesting + static final String ACTION_DISABLE_TETHERING = + "com.android.server.connectivity.tethering.DISABLE_TETHERING"; private static final boolean NOTIFY_DONE = true; private static final boolean NO_NOTIFY = false; - // Id to update and cancel tethering notification. Must be unique within the tethering app. - private static final int ENABLE_NOTIFICATION_ID = 1000; + @VisibleForTesting + static final int EVENT_SHOW_NO_UPSTREAM = 1; + // Id to update and cancel enable notification. Must be unique within the tethering app. + @VisibleForTesting + static final int ENABLE_NOTIFICATION_ID = 1000; // Id to update and cancel restricted notification. Must be unique within the tethering app. - private static final int RESTRICTED_NOTIFICATION_ID = 1001; + @VisibleForTesting + static final int RESTRICTED_NOTIFICATION_ID = 1001; + // Id to update and cancel no upstream notification. Must be unique within the tethering app. + @VisibleForTesting + static final int NO_UPSTREAM_NOTIFICATION_ID = 1002; @VisibleForTesting static final int NO_ICON_ID = 0; @VisibleForTesting @@ -71,14 +92,16 @@ public class TetheringNotificationUpdater { private final Context mContext; private final NotificationManager mNotificationManager; private final NotificationChannel mChannel; + private final Handler mHandler; // WARNING : the constructor is called on a different thread. Thread safety therefore - // relies on this value being initialized to 0, and not any other value. If you need + // relies on these values being initialized to 0 or false, and not any other value. If you need // to change this, you will need to change the thread where the constructor is invoked, // or to introduce synchronization. // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2. // This value has to be made 1 2 and 4, and OR'd with the others. private int mDownstreamTypesMask = DOWNSTREAM_NONE; + private boolean mNoUpstream = false; // WARNING : this value is not able to being initialized to 0 and must have volatile because // telephony service is not guaranteed that is up before tethering service starts. If telephony @@ -87,10 +110,30 @@ public class TetheringNotificationUpdater { // INVALID_SUBSCRIPTION_ID. private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - @IntDef({ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID}) + @IntDef({ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID}) @interface NotificationId {} - public TetheringNotificationUpdater(@NonNull final Context context) { + private static final class MccMncOverrideInfo { + public final List visitedMccMncs; + public final int homeMcc; + public final int homeMnc; + MccMncOverrideInfo(List visitedMccMncs, int mcc, int mnc) { + this.visitedMccMncs = visitedMccMncs; + this.homeMcc = mcc; + this.homeMnc = mnc; + } + } + + private static final SparseArray sCarrierIdToMccMnc = new SparseArray<>(); + + static { + // VZW + sCarrierIdToMccMnc.put( + 1839, new MccMncOverrideInfo(Arrays.asList(new String[] {"20404"}), 311, 480)); + } + + public TetheringNotificationUpdater(@NonNull final Context context, + @NonNull final Looper looper) { mContext = context; mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0) .getSystemService(Context.NOTIFICATION_SERVICE); @@ -99,6 +142,22 @@ public class TetheringNotificationUpdater { context.getResources().getString(R.string.notification_channel_tethering_status), NotificationManager.IMPORTANCE_LOW); mNotificationManager.createNotificationChannel(mChannel); + mHandler = new NotificationHandler(looper); + } + + private class NotificationHandler extends Handler { + NotificationHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case EVENT_SHOW_NO_UPSTREAM: + notifyTetheringNoUpstream(); + break; + } + } } /** Called when downstream has changed */ @@ -106,6 +165,7 @@ public class TetheringNotificationUpdater { if (mDownstreamTypesMask == downstreamTypesMask) return; mDownstreamTypesMask = downstreamTypesMask; updateEnableNotification(); + updateNoUpstreamNotification(); } /** Called when active data subscription id changed */ @@ -113,21 +173,62 @@ public class TetheringNotificationUpdater { if (mActiveDataSubId == subId) return; mActiveDataSubId = subId; updateEnableNotification(); + updateNoUpstreamNotification(); } + /** Called when upstream network changed */ + public void onUpstreamNetworkChanged(@Nullable final Network network) { + final boolean isNoUpstream = (network == null); + if (mNoUpstream == isNoUpstream) return; + mNoUpstream = isNoUpstream; + updateNoUpstreamNotification(); + } + + @NonNull @VisibleForTesting - Resources getResourcesForSubId(@NonNull final Context c, final int subId) { - return SubscriptionManager.getResourcesForSubId(c, subId); + final Handler getHandler() { + return mHandler; + } + + @NonNull + @VisibleForTesting + Resources getResourcesForSubId(@NonNull final Context context, final int subId) { + final Resources res = SubscriptionManager.getResourcesForSubId(context, subId); + final TelephonyManager tm = + ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)) + .createForSubscriptionId(mActiveDataSubId); + final int carrierId = tm.getSimCarrierId(); + final String mccmnc = tm.getSimOperator(); + final MccMncOverrideInfo overrideInfo = sCarrierIdToMccMnc.get(carrierId); + if (overrideInfo != null && overrideInfo.visitedMccMncs.contains(mccmnc)) { + // Re-configure MCC/MNC value to specific carrier to get right resources. + final Configuration config = res.getConfiguration(); + config.mcc = overrideInfo.homeMcc; + config.mnc = overrideInfo.homeMnc; + return context.createConfigurationContext(config).getResources(); + } + return res; } private void updateEnableNotification() { - final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE; + final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE; if (tetheringInactive || setupNotification() == NO_NOTIFY) { clearNotification(ENABLE_NOTIFICATION_ID); } } + private void updateNoUpstreamNotification() { + final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE; + + if (tetheringInactive + || !mNoUpstream + || setupNoUpstreamNotification() == NO_NOTIFY) { + clearNotification(NO_UPSTREAM_NOTIFICATION_ID); + mHandler.removeMessages(EVENT_SHOW_NO_UPSTREAM); + } + } + @VisibleForTesting void tetheringRestrictionLifted() { clearNotification(RESTRICTED_NOTIFICATION_ID); @@ -142,9 +243,38 @@ public class TetheringNotificationUpdater { final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); final String title = res.getString(R.string.disable_tether_notification_title); final String message = res.getString(R.string.disable_tether_notification_message); + if (isEmpty(title) || isEmpty(message)) return; + + final PendingIntent pi = PendingIntent.getActivity( + mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), + 0 /* requestCode */, + new Intent(Settings.ACTION_TETHER_SETTINGS), + Intent.FLAG_ACTIVITY_NEW_TASK, + null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, - RESTRICTED_NOTIFICATION_ID); + RESTRICTED_NOTIFICATION_ID, pi, new Action[0]); + } + + private void notifyTetheringNoUpstream() { + final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); + final String title = res.getString(R.string.no_upstream_notification_title); + final String message = res.getString(R.string.no_upstream_notification_message); + final String disableButton = + res.getString(R.string.no_upstream_notification_disable_button); + if (isEmpty(title) || isEmpty(message) || isEmpty(disableButton)) return; + + final Intent intent = new Intent(ACTION_DISABLE_TETHERING); + intent.setPackage(mContext.getPackageName()); + final PendingIntent pi = PendingIntent.getBroadcast( + mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), + 0 /* requestCode */, + intent, + 0 /* flags */); + final Action action = new Action.Builder(NO_ICON_ID, disableButton, pi).build(); + + showNotification(R.drawable.stat_sys_tether_general, title, message, + NO_UPSTREAM_NOTIFICATION_ID, null /* pendingIntent */, action); } /** @@ -179,12 +309,13 @@ public class TetheringNotificationUpdater { * * @return {@link android.util.SparseArray} with downstream types and icon id info. */ + @NonNull @VisibleForTesting SparseArray getIcons(@ArrayRes int id, @NonNull Resources res) { final String[] array = res.getStringArray(id); final SparseArray icons = new SparseArray<>(); for (String config : array) { - if (TextUtils.isEmpty(config)) continue; + if (isEmpty(config)) continue; final String[] elements = config.split(";"); if (elements.length != 2) { @@ -204,6 +335,18 @@ public class TetheringNotificationUpdater { return icons; } + private boolean setupNoUpstreamNotification() { + final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); + final int delayToShowUpstreamNotification = + res.getInteger(R.integer.delay_to_show_no_upstream_after_no_backhaul); + + if (delayToShowUpstreamNotification < 0) return NO_NOTIFY; + + mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_SHOW_NO_UPSTREAM), + delayToShowUpstreamNotification); + return NOTIFY_DONE; + } + private boolean setupNotification() { final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); final SparseArray downstreamIcons = @@ -214,17 +357,22 @@ public class TetheringNotificationUpdater { final String title = res.getString(R.string.tethering_notification_title); final String message = res.getString(R.string.tethering_notification_message); + if (isEmpty(title) || isEmpty(message)) return NO_NOTIFY; - showNotification(iconId, title, message, ENABLE_NOTIFICATION_ID); + final PendingIntent pi = PendingIntent.getActivity( + mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), + 0 /* requestCode */, + new Intent(Settings.ACTION_TETHER_SETTINGS), + Intent.FLAG_ACTIVITY_NEW_TASK, + null /* options */); + + showNotification(iconId, title, message, ENABLE_NOTIFICATION_ID, pi, new Action[0]); return NOTIFY_DONE; } private void showNotification(@DrawableRes final int iconId, @NonNull final String title, - @NonNull final String message, @NotificationId final int id) { - final Intent intent = new Intent(Settings.ACTION_TETHER_SETTINGS); - final PendingIntent pi = PendingIntent.getActivity( - mContext.createContextAsUser(UserHandle.CURRENT, 0), - 0 /* requestCode */, intent, 0 /* flags */, null /* options */); + @NonNull final String message, @NotificationId final int id, @Nullable PendingIntent pi, + @NonNull final Action... actions) { final Notification notification = new Notification.Builder(mContext, mChannel.getId()) .setSmallIcon(iconId) @@ -236,6 +384,7 @@ public class TetheringNotificationUpdater { .setVisibility(Notification.VISIBILITY_PUBLIC) .setCategory(Notification.CATEGORY_STATUS) .setContentIntent(pi) + .setActions(actions) .build(); mNotificationManager.notify(null /* tag */, id, notification); diff --git a/Tethering/tests/unit/AndroidManifest.xml b/Tethering/tests/unit/AndroidManifest.xml index 55640db693..31eaabff52 100644 --- a/Tethering/tests/unit/AndroidManifest.xml +++ b/Tethering/tests/unit/AndroidManifest.xml @@ -16,6 +16,7 @@ + diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 7bff74b25d..5f8858857c 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -23,14 +23,26 @@ import android.content.res.Resources import android.net.ConnectivityManager.TETHERING_BLUETOOTH import android.net.ConnectivityManager.TETHERING_USB import android.net.ConnectivityManager.TETHERING_WIFI +import android.net.Network +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper import android.os.UserHandle import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID -import androidx.test.platform.app.InstrumentationRegistry +import android.telephony.TelephonyManager import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.test.BroadcastInterceptingContext import com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE +import com.android.networkstack.tethering.TetheringNotificationUpdater.ENABLE_NOTIFICATION_ID +import com.android.networkstack.tethering.TetheringNotificationUpdater.EVENT_SHOW_NO_UPSTREAM +import com.android.networkstack.tethering.TetheringNotificationUpdater.NO_UPSTREAM_NOTIFICATION_ID +import com.android.networkstack.tethering.TetheringNotificationUpdater.RESTRICTED_NOTIFICATION_ID +import com.android.testutils.waitForIdle +import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.fail import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -43,8 +55,8 @@ import org.mockito.Mockito.doReturn import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.times -import org.mockito.Mockito.verifyZeroInteractions import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyZeroInteractions import org.mockito.MockitoAnnotations const val TEST_SUBID = 1 @@ -55,10 +67,13 @@ const val GENERAL_ICON_ID = 4 const val WIFI_MASK = 1 shl TETHERING_WIFI const val USB_MASK = 1 shl TETHERING_USB const val BT_MASK = 1 shl TETHERING_BLUETOOTH -const val TITTLE = "Tethering active" +const val TITLE = "Tethering active" const val MESSAGE = "Tap here to set up." -const val TEST_TITTLE = "Hotspot active" +const val TEST_TITLE = "Hotspot active" const val TEST_MESSAGE = "Tap to set up hotspot." +const val TEST_NO_UPSTREAM_TITLE = "Hotspot has no internet access" +const val TEST_NO_UPSTREAM_MESSAGE = "Device cannot connect to internet." +const val TEST_NO_UPSTREAM_BUTTON = "Turn off hotspot" @RunWith(AndroidJUnit4::class) @SmallTest @@ -67,12 +82,15 @@ class TetheringNotificationUpdaterTest { // should crash if they are used before being initialized. @Mock private lateinit var mockContext: Context @Mock private lateinit var notificationManager: NotificationManager + @Mock private lateinit var telephonyManager: TelephonyManager @Mock private lateinit var defaultResources: Resources @Mock private lateinit var testResources: Resources - // lateinit for this class under test, as it should be reset to a different instance for every - // tests but should always be initialized before use (or the test should crash). + // lateinit for these classes under test, as they should be reset to a different instance for + // every test but should always be initialized before use (or the test should crash). + private lateinit var context: TestContext private lateinit var notificationUpdater: TetheringNotificationUpdater + private lateinit var fakeTetheringThread: HandlerThread private val ENABLE_ICON_CONFIGS = arrayOf( "USB;android.test:drawable/usb", "BT;android.test:drawable/bluetooth", @@ -82,11 +100,19 @@ class TetheringNotificationUpdaterTest { private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) { override fun createContextAsUser(user: UserHandle, flags: Int) = if (user == UserHandle.ALL) mockContext else this + override fun getSystemService(name: String) = + if (name == Context.TELEPHONY_SERVICE) telephonyManager + else super.getSystemService(name) } - private inner class WrappedNotificationUpdater(c: Context) : TetheringNotificationUpdater(c) { + private inner class WrappedNotificationUpdater(c: Context, looper: Looper) + : TetheringNotificationUpdater(c, looper) { override fun getResourcesForSubId(context: Context, subId: Int) = - if (subId == TEST_SUBID) testResources else defaultResources + when (subId) { + TEST_SUBID -> testResources + INVALID_SUBSCRIPTION_ID -> defaultResources + else -> super.getResourcesForSubId(context, subId) + } } private fun setupResources() { @@ -94,12 +120,20 @@ class TetheringNotificationUpdaterTest { .getStringArray(R.array.tethering_notification_icons) doReturn(arrayOf("WIFI;android.test:drawable/wifi")).`when`(testResources) .getStringArray(R.array.tethering_notification_icons) - doReturn(TITTLE).`when`(defaultResources).getString(R.string.tethering_notification_title) + doReturn(5).`when`(testResources) + .getInteger(R.integer.delay_to_show_no_upstream_after_no_backhaul) + doReturn(TITLE).`when`(defaultResources).getString(R.string.tethering_notification_title) doReturn(MESSAGE).`when`(defaultResources) .getString(R.string.tethering_notification_message) - doReturn(TEST_TITTLE).`when`(testResources).getString(R.string.tethering_notification_title) + doReturn(TEST_TITLE).`when`(testResources).getString(R.string.tethering_notification_title) doReturn(TEST_MESSAGE).`when`(testResources) .getString(R.string.tethering_notification_message) + doReturn(TEST_NO_UPSTREAM_TITLE).`when`(testResources) + .getString(R.string.no_upstream_notification_title) + doReturn(TEST_NO_UPSTREAM_MESSAGE).`when`(testResources) + .getString(R.string.no_upstream_notification_message) + doReturn(TEST_NO_UPSTREAM_BUTTON).`when`(testResources) + .getString(R.string.no_upstream_notification_disable_button) doReturn(USB_ICON_ID).`when`(defaultResources) .getIdentifier(eq("android.test:drawable/usb"), any(), any()) doReturn(BT_ICON_ID).`when`(defaultResources) @@ -113,35 +147,61 @@ class TetheringNotificationUpdaterTest { @Before fun setUp() { MockitoAnnotations.initMocks(this) - val context = TestContext(InstrumentationRegistry.getInstrumentation().context) + context = TestContext(InstrumentationRegistry.getInstrumentation().context) doReturn(notificationManager).`when`(mockContext) .getSystemService(Context.NOTIFICATION_SERVICE) - notificationUpdater = WrappedNotificationUpdater(context) + fakeTetheringThread = HandlerThread(this::class.simpleName) + fakeTetheringThread.start() + notificationUpdater = WrappedNotificationUpdater(context, fakeTetheringThread.looper) setupResources() } + @After + fun tearDown() { + fakeTetheringThread.quitSafely() + } + private fun Notification.title() = this.extras.getString(Notification.EXTRA_TITLE) private fun Notification.text() = this.extras.getString(Notification.EXTRA_TEXT) - private fun verifyNotification(iconId: Int = 0, title: String = "", text: String = "") { - verify(notificationManager, never()).cancel(any(), anyInt()) + private fun verifyNotification(iconId: Int, title: String, text: String, id: Int) { + verify(notificationManager, never()).cancel(any(), eq(id)) val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java) verify(notificationManager, times(1)) - .notify(any(), anyInt(), notificationCaptor.capture()) + .notify(any(), eq(id), notificationCaptor.capture()) val notification = notificationCaptor.getValue() assertEquals(iconId, notification.smallIcon.resId) assertEquals(title, notification.title()) assertEquals(text, notification.text()) + } + private fun verifyNotificationCancelled(id: Int) = + verify(notificationManager, times(1)).cancel(any(), eq(id)) + + private val tetheringActiveNotifications = + listOf(NO_UPSTREAM_NOTIFICATION_ID, ENABLE_NOTIFICATION_ID) + + private fun verifyCancelAllTetheringActiveNotifications() { + tetheringActiveNotifications.forEach { + verifyNotificationCancelled(it) + } reset(notificationManager) } - private fun verifyNoNotification() { - verify(notificationManager, times(1)).cancel(any(), anyInt()) - verify(notificationManager, never()).notify(any(), anyInt(), any()) - + private fun verifyOnlyTetheringActiveNotification( + notifyId: Int, + iconId: Int, + title: String, + text: String + ) { + tetheringActiveNotifications.forEach { + when (it) { + notifyId -> verifyNotification(iconId, title, text, notifyId) + else -> verifyNotificationCancelled(it) + } + } reset(notificationManager) } @@ -149,7 +209,7 @@ class TetheringNotificationUpdaterTest { fun testNotificationWithDownstreamChanged() { // Wifi downstream. No notification. notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyNoNotification() + verifyCancelAllTetheringActiveNotifications() // Same downstream changed. Nothing happened. notificationUpdater.onDownstreamChanged(WIFI_MASK) @@ -157,22 +217,23 @@ class TetheringNotificationUpdaterTest { // Wifi and usb downstreams. Show enable notification notificationUpdater.onDownstreamChanged(WIFI_MASK or USB_MASK) - verifyNotification(GENERAL_ICON_ID, TITTLE, MESSAGE) + verifyOnlyTetheringActiveNotification( + ENABLE_NOTIFICATION_ID, GENERAL_ICON_ID, TITLE, MESSAGE) // Usb downstream. Still show enable notification. notificationUpdater.onDownstreamChanged(USB_MASK) - verifyNotification(USB_ICON_ID, TITTLE, MESSAGE) + verifyOnlyTetheringActiveNotification(ENABLE_NOTIFICATION_ID, USB_ICON_ID, TITLE, MESSAGE) // No downstream. No notification. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyNoNotification() + verifyCancelAllTetheringActiveNotifications() } @Test fun testNotificationWithActiveDataSubscriptionIdChanged() { // Usb downstream. Showed enable notification with default resource. notificationUpdater.onDownstreamChanged(USB_MASK) - verifyNotification(USB_ICON_ID, TITTLE, MESSAGE) + verifyOnlyTetheringActiveNotification(ENABLE_NOTIFICATION_ID, USB_ICON_ID, TITLE, MESSAGE) // Same subId changed. Nothing happened. notificationUpdater.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID) @@ -180,15 +241,16 @@ class TetheringNotificationUpdaterTest { // Set test sub id. Clear notification with test resource. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyNoNotification() + verifyCancelAllTetheringActiveNotifications() // Wifi downstream. Show enable notification with test resource. notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyNotification(WIFI_ICON_ID, TEST_TITTLE, TEST_MESSAGE) + verifyOnlyTetheringActiveNotification( + ENABLE_NOTIFICATION_ID, WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE) // No downstream. No notification. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyNoNotification() + verifyCancelAllTetheringActiveNotifications() } private fun assertIconNumbers(number: Int, configs: Array) { @@ -227,10 +289,8 @@ class TetheringNotificationUpdaterTest { @Test fun testSetupRestrictedNotification() { - val title = InstrumentationRegistry.getInstrumentation().context.resources - .getString(R.string.disable_tether_notification_title) - val message = InstrumentationRegistry.getInstrumentation().context.resources - .getString(R.string.disable_tether_notification_message) + val title = context.resources.getString(R.string.disable_tether_notification_title) + val message = context.resources.getString(R.string.disable_tether_notification_message) val disallowTitle = "Tether function is disallowed" val disallowMessage = "Please contact your admin" doReturn(title).`when`(defaultResources) @@ -244,18 +304,127 @@ class TetheringNotificationUpdaterTest { // User restrictions on. Show restricted notification. notificationUpdater.notifyTetheringDisabledByRestriction() - verifyNotification(R.drawable.stat_sys_tether_general, title, message) + verifyNotification(R.drawable.stat_sys_tether_general, title, message, + RESTRICTED_NOTIFICATION_ID) + reset(notificationManager) // User restrictions off. Clear notification. notificationUpdater.tetheringRestrictionLifted() - verifyNoNotification() + verifyNotificationCancelled(RESTRICTED_NOTIFICATION_ID) + reset(notificationManager) // Set test sub id. No notification. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyNoNotification() + verifyCancelAllTetheringActiveNotifications() // User restrictions on again. Show restricted notification with test resource. notificationUpdater.notifyTetheringDisabledByRestriction() - verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage) + verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage, + RESTRICTED_NOTIFICATION_ID) + reset(notificationManager) + } + + val MAX_BACKOFF_MS = 200L + /** + * Waits for all messages, including delayed ones, to be processed. + * + * This will wait until the handler has no more messages to be processed including + * delayed ones, or the timeout has expired. It uses an exponential backoff strategy + * to wait longer and longer to consume less CPU, with the max granularity being + * MAX_BACKOFF_MS. + * + * @return true if all messages have been processed including delayed ones, false if timeout + * + * TODO: Move this method to com.android.testutils.HandlerUtils.kt. + */ + private fun Handler.waitForDelayedMessage(what: Int?, timeoutMs: Long) { + fun hasMatchingMessages() = + if (what == null) hasMessagesOrCallbacks() else hasMessages(what) + val expiry = System.currentTimeMillis() + timeoutMs + var delay = 5L + while (System.currentTimeMillis() < expiry && hasMatchingMessages()) { + // None of Handler, Looper, Message and MessageQueue expose any way to retrieve + // the time when the next (let alone the last) message will be processed, so + // short of examining the internals with reflection sleep() is the only solution. + Thread.sleep(delay) + delay = (delay * 2) + .coerceAtMost(expiry - System.currentTimeMillis()) + .coerceAtMost(MAX_BACKOFF_MS) + } + + val timeout = expiry - System.currentTimeMillis() + if (timeout <= 0) fail("Delayed message did not process yet after ${timeoutMs}ms") + waitForIdle(timeout) + } + + @Test + fun testNotificationWithUpstreamNetworkChanged() { + // Set test sub id. No notification. + notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) + verifyCancelAllTetheringActiveNotifications() + + // Wifi downstream. Show enable notification with test resource. + notificationUpdater.onDownstreamChanged(WIFI_MASK) + verifyOnlyTetheringActiveNotification( + ENABLE_NOTIFICATION_ID, WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE) + + // There is no upstream. Show no upstream notification. + notificationUpdater.onUpstreamNetworkChanged(null) + notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, 500L) + verifyNotification(R.drawable.stat_sys_tether_general, TEST_NO_UPSTREAM_TITLE, + TEST_NO_UPSTREAM_MESSAGE, NO_UPSTREAM_NOTIFICATION_ID) + reset(notificationManager) + + // Same upstream network changed. Nothing happened. + notificationUpdater.onUpstreamNetworkChanged(null) + verifyZeroInteractions(notificationManager) + + // Upstream come back. Clear no upstream notification. + notificationUpdater.onUpstreamNetworkChanged(Network(1000)) + verifyNotificationCancelled(NO_UPSTREAM_NOTIFICATION_ID) + reset(notificationManager) + + // No upstream again. Show no upstream notification. + notificationUpdater.onUpstreamNetworkChanged(null) + notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, 500L) + verifyNotification(R.drawable.stat_sys_tether_general, TEST_NO_UPSTREAM_TITLE, + TEST_NO_UPSTREAM_MESSAGE, NO_UPSTREAM_NOTIFICATION_ID) + reset(notificationManager) + + // No downstream. No notification. + notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) + verifyCancelAllTetheringActiveNotifications() + + // Set R.integer.delay_to_show_no_upstream_after_no_backhaul to 0 and have wifi downstream + // again. Show enable notification only. + doReturn(-1).`when`(testResources) + .getInteger(R.integer.delay_to_show_no_upstream_after_no_backhaul) + notificationUpdater.onDownstreamChanged(WIFI_MASK) + notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, 500L) + verifyOnlyTetheringActiveNotification( + ENABLE_NOTIFICATION_ID, WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE) + } + + @Test + fun testGetResourcesForSubId() { + doReturn(telephonyManager).`when`(telephonyManager).createForSubscriptionId(anyInt()) + doReturn(1234).`when`(telephonyManager).getSimCarrierId() + doReturn("000000").`when`(telephonyManager).getSimOperator() + + val subId = -2 // Use invalid subId to avoid getting resource from cache or real subId. + val config = context.resources.configuration + var res = notificationUpdater.getResourcesForSubId(context, subId) + assertEquals(config.mcc, res.configuration.mcc) + assertEquals(config.mnc, res.configuration.mnc) + + doReturn(1839).`when`(telephonyManager).getSimCarrierId() + res = notificationUpdater.getResourcesForSubId(context, subId) + assertEquals(config.mcc, res.configuration.mcc) + assertEquals(config.mnc, res.configuration.mnc) + + doReturn("20404").`when`(telephonyManager).getSimOperator() + res = notificationUpdater.getResourcesForSubId(context, subId) + assertEquals(311, res.configuration.mcc) + assertEquals(480, res.configuration.mnc) } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 5bec513322..15e253af12 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -383,7 +383,7 @@ public class TetheringTest { } @Override - public TetheringNotificationUpdater getNotificationUpdater(Context ctx) { + public TetheringNotificationUpdater getNotificationUpdater(Context ctx, Looper looper) { return mNotificationUpdater; } } @@ -1691,6 +1691,18 @@ public class TetheringTest { assertEquals(clientAddrParceled, params.clientAddr); } + @Test + public void testUpstreamNetworkChanged() { + final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM) + mTetheringDependencies.mUpstreamNetworkMonitorMasterSM; + final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); + when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState); + stateMachine.chooseUpstreamType(true); + + verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network)); + verify(mNotificationUpdater, times(1)).onUpstreamNetworkChanged(eq(upstreamState.network)); + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } From cb778b120003ae76aaff9b0d2574a570089a3d16 Mon Sep 17 00:00:00 2001 From: evitayan Date: Tue, 7 Apr 2020 13:07:14 -0700 Subject: [PATCH 0941/1415] Test setting config requests for TunnelModeChildSessionParams Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ib3e803159cdf42a8655c0e4d0f22faeabe161c4c --- .../ipsec/ike/cts/ChildSessionParamsTest.java | 90 +++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 37 ++++++++ 2 files changed, 127 insertions(+) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java index 316355252a..7fb1b6dc43 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java @@ -16,20 +16,36 @@ package android.net.ipsec.ike.cts; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.net.LinkAddress; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.TransportModeChildSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet4Address; import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -137,4 +153,78 @@ public class ChildSessionParamsTest extends IkeTestBase { verifyTunnelModeChildParamsWithCustomizedValues(childParams); } + + @Test + public void testBuildChildSessionParamsWithConfigReq() { + TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder() + .addSaProposal(mSaProposal) + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .addInternalAddressRequest(AF_INET6) + .addInternalAddressRequest(IPV4_ADDRESS_REMOTE) + .addInternalAddressRequest(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN) + .addInternalDnsServerRequest(AF_INET) + .addInternalDnsServerRequest(AF_INET6) + .addInternalDhcpServerRequest(AF_INET) + .addInternalDhcpServerRequest(AF_INET) + .build(); + + verifyTunnelModeChildParamsWithDefaultValues(childParams); + + // Verify config request types and number of requests for each type + Map, Integer> expectedAttributeCounts = + new HashMap<>(); + expectedAttributeCounts.put(ConfigRequestIpv4Address.class, 2); + expectedAttributeCounts.put(ConfigRequestIpv6Address.class, 3); + expectedAttributeCounts.put(ConfigRequestIpv4Netmask.class, 1); + expectedAttributeCounts.put(ConfigRequestIpv4DnsServer.class, 1); + expectedAttributeCounts.put(ConfigRequestIpv6DnsServer.class, 1); + expectedAttributeCounts.put(ConfigRequestIpv4DhcpServer.class, 2); + verifyConfigRequestTypes(expectedAttributeCounts, childParams.getConfigurationRequests()); + + // Verify specific IPv4 address request + Set expectedV4Addresses = new HashSet<>(); + expectedV4Addresses.add(IPV4_ADDRESS_REMOTE); + verifySpecificV4AddrConfigReq(expectedV4Addresses, childParams); + + // Verify specific IPv6 address request + Set expectedV6Addresses = new HashSet<>(); + expectedV6Addresses.add(new LinkAddress(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN)); + verifySpecificV6AddrConfigReq(expectedV6Addresses, childParams); + } + + protected void verifySpecificV4AddrConfigReq( + Set expectedAddresses, TunnelModeChildSessionParams childParams) { + for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) { + if (req instanceof ConfigRequestIpv4Address + && ((ConfigRequestIpv4Address) req).getAddress() != null) { + Inet4Address address = ((ConfigRequestIpv4Address) req).getAddress(); + + // Fail if expectedAddresses does not contain this address + assertTrue(expectedAddresses.remove(address)); + } + } + + // Fail if any expected address is not found in result + assertTrue(expectedAddresses.isEmpty()); + } + + protected void verifySpecificV6AddrConfigReq( + Set expectedAddresses, TunnelModeChildSessionParams childParams) { + for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) { + if (req instanceof ConfigRequestIpv6Address + && ((ConfigRequestIpv6Address) req).getAddress() != null) { + ConfigRequestIpv6Address ipv6AddrReq = (ConfigRequestIpv6Address) req; + + // Fail if expectedAddresses does not contain this address + LinkAddress address = + new LinkAddress(ipv6AddrReq.getAddress(), ipv6AddrReq.getPrefixLength()); + assertTrue(expectedAddresses.remove(address)); + } + } + + // Fail if any expected address is not found in result + assertTrue(expectedAddresses.isEmpty()); + } } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index d4b431e837..d3aa8d03d5 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -16,11 +16,17 @@ package android.net.ipsec.ike.cts; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import android.net.InetAddresses; import android.net.ipsec.ike.IkeTrafficSelector; import java.net.Inet4Address; import java.net.Inet6Address; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** Shared parameters and util methods for testing different components of IKE */ abstract class IkeTestBase { @@ -80,4 +86,35 @@ abstract class IkeTestBase { OUTBOUND_TS_END_PORT, InetAddresses.parseNumericAddress("2001:db8:255::64"), InetAddresses.parseNumericAddress("2001:db8:255::255")); + + // Verify Config requests in TunnelModeChildSessionParams and IkeSessionParams + void verifyConfigRequestTypes( + Map, Integer> expectedReqCntMap, List resultReqList) { + Map, Integer> resultReqCntMap = new HashMap<>(); + + // Verify that every config request type in resultReqList is expected, and build + // resultReqCntMap at the same time + for (T resultReq : resultReqList) { + boolean isResultReqExpected = false; + + for (Class expectedReqInterface : expectedReqCntMap.keySet()) { + if (expectedReqInterface.isInstance(resultReq)) { + isResultReqExpected = true; + + resultReqCntMap.put( + expectedReqInterface, + resultReqCntMap.getOrDefault(expectedReqInterface, 0) + 1); + } + } + + if (!isResultReqExpected) { + fail("Failed due to unexpected config request " + resultReq); + } + } + + assertEquals(expectedReqCntMap, resultReqCntMap); + + // TODO: Think of a neat way to validate both counts and values in this method. Probably can + // build Runnables as validators for count and values. + } } From 643abc73d93c0fcc3b316b0b56bc371ebdf47932 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Mon, 13 Apr 2020 22:39:21 -0700 Subject: [PATCH 0942/1415] Ensure location is enabled before getting SSID. When location is disabled, Wi-Fi scan results and SSID are not available to apps. Fixes: 153850762 Fixes: 153396893 Test: atest hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Change-Id: I05285811d7131e116d5e1d072137ed2cf9576d05 --- tests/cts/hostside/AndroidTest.xml | 1 + ...ractRestrictBackgroundNetworkTestCase.java | 31 ---------------- .../net/hostside/NetworkPolicyTestUtils.java | 35 +++++++++++++++++-- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 7cc0dd19cc..b7fefaf3b5 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -20,6 +20,7 @@

    Caller MUST have MANAGE_TEST_NETWORKS permission to use this method. + * + * @param connMgr ConnectivityManager to request network. + * @param testNetworkMgr TestNetworkManager to set up test network. + * @param ifname the name of the interface to be used for the Network LinkProperties. + * @param binder a binder object guarding the lifecycle of this test network. + * @return TestNetworkCallback to retrieve the test network. + * @throws RemoteException if test network setup failed. + * @see android.net.TestNetworkManager + */ + public static TestNetworkCallback setupAndGetTestNetwork( + ConnectivityManager connMgr, + TestNetworkManager testNetworkMgr, + String ifname, + IBinder binder) + throws RemoteException { + NetworkRequest nr = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_TEST) + .removeCapability(NET_CAPABILITY_TRUSTED) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .setNetworkSpecifier(ifname) + .build(); + + TestNetworkCallback cb = new TestNetworkCallback(); + connMgr.requestNetwork(nr, cb); + + // Setup the test network after network request is filed to prevent Network from being + // reaped due to no requests matching it. + testNetworkMgr.setupTestNetwork(ifname, binder); + + return cb; + } +} From a1a0be93f05600017ac21ca8e13b0323081a4c7c Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 15 Apr 2020 01:05:44 +0800 Subject: [PATCH 0945/1415] Remove sendMessage inside EntitlementManager EntitlementManager and its callers(Tethering and UpstreamNetworkMonitor) run in the same threads. Bug: 141256482 Test: atest TetheringTests Change-Id: I0a376d28b123eaab2e8d00a98a4719ce983d3bb2 --- .../tethering/EntitlementManager.java | 92 +++---------------- .../networkstack/tethering/Tethering.java | 6 +- 2 files changed, 15 insertions(+), 83 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java index 4c7b2d49ee..049a9f68bb 100644 --- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java +++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java @@ -38,8 +38,6 @@ import android.content.IntentFilter; import android.net.util.SharedLog; import android.os.Bundle; import android.os.Handler; -import android.os.Looper; -import android.os.Message; import android.os.Parcel; import android.os.PersistableBundle; import android.os.ResultReceiver; @@ -75,11 +73,6 @@ public class EntitlementManager { private final ComponentName mSilentProvisioningService; private static final int MS_PER_HOUR = 60 * 60 * 1000; - private static final int EVENT_START_PROVISIONING = 0; - private static final int EVENT_STOP_PROVISIONING = 1; - private static final int EVENT_UPSTREAM_CHANGED = 2; - private static final int EVENT_MAYBE_RUN_PROVISIONING = 3; - private static final int EVENT_GET_ENTITLEMENT_VALUE = 4; // The ArraySet contains enabled downstream types, ex: // {@link TetheringManager.TETHERING_WIFI} @@ -90,7 +83,7 @@ public class EntitlementManager { private final int mPermissionChangeMessageCode; private final SharedLog mLog; private final SparseIntArray mEntitlementCacheValue; - private final EntitlementHandler mHandler; + private final Handler mHandler; private final StateMachine mTetherMasterSM; // Key: TetheringManager.TETHERING_*(downstream). // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). @@ -112,10 +105,7 @@ public class EntitlementManager { mEntitlementCacheValue = new SparseIntArray(); mTetherMasterSM = tetherMasterSM; mPermissionChangeMessageCode = permissionChangeMessageCode; - final Handler masterHandler = tetherMasterSM.getHandler(); - // Create entitlement's own handler which is associated with TetherMaster thread - // let all entitlement processes run in the same thread. - mHandler = new EntitlementHandler(masterHandler.getLooper()); + mHandler = tetherMasterSM.getHandler(); mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), null, mHandler); mSilentProvisioningService = ComponentName.unflattenFromString( @@ -172,14 +162,9 @@ public class EntitlementManager { * provisioning app UI if there is one. */ public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_START_PROVISIONING, - downstreamType, encodeBool(showProvisioningUi))); - } + if (!isValidDownstreamType(downstreamType)) return; - private void handleStartProvisioningIfNeeded(int type, boolean showProvisioningUi) { - if (!isValidDownstreamType(type)) return; - - if (!mCurrentTethers.contains(type)) mCurrentTethers.add(type); + if (!mCurrentTethers.contains(downstreamType)) mCurrentTethers.add(downstreamType); final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); if (isTetherProvisioningRequired(config)) { @@ -192,9 +177,9 @@ public class EntitlementManager { // till upstream change to cellular. if (mUsingCellularAsUpstream) { if (showProvisioningUi) { - runUiTetherProvisioning(type, config.activeDataSubId); + runUiTetherProvisioning(downstreamType, config.activeDataSubId); } else { - runSilentTetherProvisioning(type, config.activeDataSubId); + runSilentTetherProvisioning(downstreamType, config.activeDataSubId); } mNeedReRunProvisioningUi = false; } else { @@ -211,10 +196,6 @@ public class EntitlementManager { * @param type tethering type from TetheringManager.TETHERING_{@code *} */ public void stopProvisioningIfNeeded(int type) { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_STOP_PROVISIONING, type, 0)); - } - - private void handleStopProvisioningIfNeeded(int type) { if (!isValidDownstreamType(type)) return; mCurrentTethers.remove(type); @@ -230,11 +211,6 @@ public class EntitlementManager { * @param isCellular whether tethering upstream is cellular. */ public void notifyUpstream(boolean isCellular) { - mHandler.sendMessage(mHandler.obtainMessage( - EVENT_UPSTREAM_CHANGED, encodeBool(isCellular), 0)); - } - - private void handleNotifyUpstream(boolean isCellular) { if (DBG) { mLog.i("notifyUpstream: " + isCellular + ", mCellularUpstreamPermitted: " + mCellularUpstreamPermitted @@ -244,16 +220,17 @@ public class EntitlementManager { if (mUsingCellularAsUpstream) { final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); - handleMaybeRunProvisioning(config); + maybeRunProvisioning(config); } } /** Run provisioning if needed */ public void maybeRunProvisioning() { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_MAYBE_RUN_PROVISIONING)); + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + maybeRunProvisioning(config); } - private void handleMaybeRunProvisioning(final TetheringConfiguration config) { + private void maybeRunProvisioning(final TetheringConfiguration config) { if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired(config)) { return; } @@ -319,7 +296,7 @@ public class EntitlementManager { } if (mUsingCellularAsUpstream) { - handleMaybeRunProvisioning(config); + maybeRunProvisioning(config); } } @@ -494,46 +471,6 @@ public class EntitlementManager { } }; - private class EntitlementHandler extends Handler { - EntitlementHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_START_PROVISIONING: - handleStartProvisioningIfNeeded(msg.arg1, toBool(msg.arg2)); - break; - case EVENT_STOP_PROVISIONING: - handleStopProvisioningIfNeeded(msg.arg1); - break; - case EVENT_UPSTREAM_CHANGED: - handleNotifyUpstream(toBool(msg.arg1)); - break; - case EVENT_MAYBE_RUN_PROVISIONING: - final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); - handleMaybeRunProvisioning(config); - break; - case EVENT_GET_ENTITLEMENT_VALUE: - handleRequestLatestTetheringEntitlementValue(msg.arg1, - (ResultReceiver) msg.obj, toBool(msg.arg2)); - break; - default: - mLog.log("Unknown event: " + msg.what); - break; - } - } - } - - private static boolean toBool(int encodedBoolean) { - return encodedBoolean != 0; - } - - private static int encodeBool(boolean b) { - return b ? 1 : 0; - } - private static boolean isValidDownstreamType(int type) { switch (type) { case TETHERING_BLUETOOTH: @@ -644,13 +581,6 @@ public class EntitlementManager { /** Get the last value of the tethering entitlement check. */ public void requestLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver, boolean showEntitlementUi) { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ENTITLEMENT_VALUE, - downstream, encodeBool(showEntitlementUi), receiver)); - - } - - private void handleRequestLatestTetheringEntitlementValue(int downstream, - ResultReceiver receiver, boolean showEntitlementUi) { if (!isValidDownstreamType(downstream)) { receiver.send(TETHER_ERROR_ENTITLEMENT_UNKNOWN, null); return; diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 14abfdc0cc..367ce9bd5c 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -1946,10 +1946,12 @@ public class Tethering { /** Get the latest value of the tethering entitlement check. */ void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, boolean showEntitlementUi) { - if (receiver != null) { + if (receiver == null) return; + + mHandler.post(() -> { mEntitlementMgr.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); - } + }); } /** Register tethering event callback */ From 6fe3606924a9b482db264bd412dedee435592f2b Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Sun, 12 Apr 2020 21:34:11 +0900 Subject: [PATCH 0946/1415] Increase test independence If a test fails without unregistering an agent, other tests will see their requests match the old agent. That means any test failing will fail all subsequent tests, which is not very helpful. Solve this by making sure the agents are unregistered before the test ends. Also ensure the requests are unregistered. Test: NetworkAgentTest Bug: 139268426 Change-Id: If183d78298aa2a0bcae9e2487199dee14014cdfb Merged-In: I2c167803d478d31fd85dc6e6e621f35d36c68fb4 (cherry-picked from aosp/1284556) --- .../src/android/net/cts/NetworkAgentTest.kt | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 2fdd5fb201..d0e3023db6 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -67,6 +67,9 @@ class NetworkAgentTest { private class Provider(context: Context, looper: Looper) : NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") + private val agentsToCleanUp = mutableListOf() + private val callbacksToCleanUp = mutableListOf() + @Before fun setUp() { instrumentation.getUiAutomation().adoptShellPermissionIdentity() @@ -75,11 +78,13 @@ class NetworkAgentTest { @After fun tearDown() { + agentsToCleanUp.forEach { it.unregister() } + callbacksToCleanUp.forEach { mCM.unregisterNetworkCallback(it) } mHandlerThread.quitSafely() instrumentation.getUiAutomation().dropShellPermissionIdentity() } - internal class TestableNetworkAgent( + private class TestableNetworkAgent( looper: Looper, nc: NetworkCapabilities, lp: LinkProperties, @@ -94,12 +99,10 @@ class NetworkAgentTest { } override fun onBandwidthUpdateRequested() { - super.onBandwidthUpdateRequested() history.add(OnBandwidthUpdateRequested) } override fun onNetworkUnwanted() { - super.onNetworkUnwanted() history.add(OnNetworkUnwanted) } @@ -109,6 +112,11 @@ class NetworkAgentTest { } } + private fun requestNetwork(request: NetworkRequest, callback: TestableNetworkCallback) { + mCM.requestNetwork(request, callback) + callbacksToCleanUp.add(callback) + } + private fun createNetworkAgent(): TestableNetworkAgent { val nc = NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) @@ -120,7 +128,9 @@ class NetworkAgentTest { } val lp = LinkProperties() val config = NetworkAgentConfig.Builder().build() - return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config) + return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config).also { + agentsToCleanUp.add(it) + } } private fun createConnectedNetworkAgent(): Pair { @@ -129,8 +139,9 @@ class NetworkAgentTest { .addTransportType(NetworkCapabilities.TRANSPORT_TEST) .build() val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) - mCM.requestNetwork(request, callback) - val agent = createNetworkAgent().also { it.register() } + requestNetwork(request, callback) + val agent = createNetworkAgent() + agent.register() agent.markConnected() return agent to callback } From dce3e15cd347ca563f705b1d5f01c8a7cc70d509 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Mar 2020 21:10:56 +0900 Subject: [PATCH 0947/1415] Test onStartSocketKeepalive Test: this Bug: 139268426 Change-Id: I26f68fdf9b687a2d87c971525b1cd2c48d4579bb Merged-In: I4e251fa0203a1888badef9ed90495fe8b3340a1c (cherry-picked aosp/1258137) --- .../src/android/net/cts/NetworkAgentTest.kt | 161 +++++++++++++++++- 1 file changed, 155 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index d0e3023db6..32f2bfafe2 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -18,29 +18,51 @@ package android.net.cts import android.app.Instrumentation import android.content.Context import android.net.ConnectivityManager +import android.net.KeepalivePacketData +import android.net.LinkAddress import android.net.LinkProperties +import android.net.Network import android.net.NetworkAgent +import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE +import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkProvider import android.net.NetworkRequest -import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested -import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted +import android.net.SocketKeepalive import android.os.Build +import android.os.Handler import android.os.HandlerThread import android.os.Looper +import android.os.Message +import android.os.Messenger +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import androidx.test.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.AsyncChannel import com.android.testutils.ArrayTrackRecord import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback import org.junit.After +import org.junit.Assert.fail import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import java.net.InetAddress +import java.time.Duration +import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertNotNull +import kotlin.test.assertNull import kotlin.test.assertTrue // This test doesn't really have a constraint on how fast the methods should return. If it's @@ -51,18 +73,29 @@ private const val DEFAULT_TIMEOUT_MS = 5000L // requests filed by the test and should never match normal internet requests. 70 is the default // score of Ethernet networks, it's as good a value as any other. private const val TEST_NETWORK_SCORE = 70 +private const val FAKE_NET_ID = 1098 private val instrumentation: Instrumentation get() = InstrumentationRegistry.getInstrumentation() private val context: Context get() = InstrumentationRegistry.getContext() +private fun Message(what: Int, arg1: Int, arg2: Int, obj: Any?) = Message.obtain().also { + it.what = what + it.arg1 = arg1 + it.arg2 = arg2 + it.obj = obj +} @RunWith(AndroidJUnit4::class) class NetworkAgentTest { @Rule @JvmField val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) + private val LOCAL_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.1") + private val REMOTE_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.2") + private val mCM = context.getSystemService(ConnectivityManager::class.java) private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") + private val mFakeConnectivityService by lazy { FakeConnectivityService(mHandlerThread.looper) } private class Provider(context: Context, looper: Looper) : NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") @@ -84,8 +117,37 @@ class NetworkAgentTest { instrumentation.getUiAutomation().dropShellPermissionIdentity() } - private class TestableNetworkAgent( - looper: Looper, + /** + * A fake that helps simulating ConnectivityService talking to a harnessed agent. + * This fake only supports speaking to one harnessed agent at a time because it + * only keeps track of one async channel. + */ + private class FakeConnectivityService(looper: Looper) { + private val msgHistory = ArrayTrackRecord().newReadHead() + private val asyncChannel = AsyncChannel() + private val handler = object : Handler(looper) { + override fun handleMessage(msg: Message) { + msgHistory.add(Message.obtain(msg)) // make a copy as the original will be recycled + when (msg.what) { + AsyncChannel.CMD_CHANNEL_HALF_CONNECTED -> + asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) + AsyncChannel.CMD_CHANNEL_DISCONNECT, AsyncChannel.CMD_CHANNEL_DISCONNECTED -> + fail("Agent unexpectedly disconnected") + } + } + } + + fun connect(agentMsngr: Messenger) = asyncChannel.connect(context, handler, agentMsngr) + + fun sendMessage(what: Int, arg1: Int = 0, arg2: Int = 0, obj: Any? = null) = + asyncChannel.sendMessage(Message(what, arg1, arg2, obj)) + + fun expectMessage(what: Int) = + assertNotNull(msgHistory.poll(DEFAULT_TIMEOUT_MS) { it.what == what }) + } + + private open class TestableNetworkAgent( + val looper: Looper, nc: NetworkCapabilities, lp: LinkProperties, conf: NetworkAgentConfig @@ -96,6 +158,17 @@ class NetworkAgentTest { sealed class CallbackEntry { object OnBandwidthUpdateRequested : CallbackEntry() object OnNetworkUnwanted : CallbackEntry() + data class OnAddKeepalivePacketFilter( + val slot: Int, + val packet: KeepalivePacketData + ) : CallbackEntry() + data class OnRemoveKeepalivePacketFilter(val slot: Int) : CallbackEntry() + data class OnStartSocketKeepalive( + val slot: Int, + val interval: Int, + val packet: KeepalivePacketData + ) : CallbackEntry() + data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry() } override fun onBandwidthUpdateRequested() { @@ -106,9 +179,35 @@ class NetworkAgentTest { history.add(OnNetworkUnwanted) } - inline fun expectCallback() { + override fun onAddKeepalivePacketFilter(slot: Int, packet: KeepalivePacketData) { + history.add(OnAddKeepalivePacketFilter(slot, packet)) + } + + override fun onRemoveKeepalivePacketFilter(slot: Int) { + history.add(OnRemoveKeepalivePacketFilter(slot)) + } + + override fun onStartSocketKeepalive( + slot: Int, + interval: Duration, + packet: KeepalivePacketData + ) { + history.add(OnStartSocketKeepalive(slot, interval.seconds.toInt(), packet)) + } + + override fun onStopSocketKeepalive(slot: Int) { + history.add(OnStopSocketKeepalive(slot)) + } + + inline fun expectCallback(): T { val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") + return foundCallback + } + + fun assertNoCallback() { + assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS), "Handler never became idle") + assertNull(history.peek()) } } @@ -126,7 +225,9 @@ class NetworkAgentTest { addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) } - val lp = LinkProperties() + val lp = LinkProperties().apply { + addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) + } val config = NetworkAgentConfig.Builder().build() return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config).also { agentsToCleanUp.add(it) @@ -146,6 +247,10 @@ class NetworkAgentTest { return agent to callback } + private fun createNetworkAgentWithFakeCS() = createNetworkAgent().also { + mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID))) + } + @Test fun testConnectAndUnregister() { val (agent, callback) = createConnectedNetworkAgent() @@ -166,4 +271,48 @@ class NetworkAgentTest { agent.expectCallback() agent.unregister() } + + @Test + fun testSocketKeepalive(): Unit = createNetworkAgentWithFakeCS().let { agent -> + val packet = object : KeepalivePacketData( + LOCAL_IPV4_ADDRESS /* srcAddress */, 1234 /* srcPort */, + REMOTE_IPV4_ADDRESS /* dstAddress */, 4567 /* dstPort */, + ByteArray(100 /* size */) { it.toByte() /* init */ }) {} + val slot = 4 + val interval = 37 + + mFakeConnectivityService.sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + arg1 = slot, obj = packet) + mFakeConnectivityService.sendMessage(CMD_START_SOCKET_KEEPALIVE, + arg1 = slot, arg2 = interval, obj = packet) + + agent.expectCallback().let { + assertEquals(it.slot, slot) + assertEquals(it.packet, packet) + } + agent.expectCallback().let { + assertEquals(it.slot, slot) + assertEquals(it.interval, interval) + assertEquals(it.packet, packet) + } + + agent.assertNoCallback() + + // Check that when the agent sends a keepalive event, ConnectivityService receives the + // expected message. + agent.sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED) + mFakeConnectivityService.expectMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE).let() { + assertEquals(slot, it.arg1) + assertEquals(SocketKeepalive.ERROR_UNSUPPORTED, it.arg2) + } + + mFakeConnectivityService.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, arg1 = slot) + mFakeConnectivityService.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, arg1 = slot) + agent.expectCallback().let { + assertEquals(it.slot, slot) + } + agent.expectCallback().let { + assertEquals(it.slot, slot) + } + } } From d5273557349f3afe6249404876f75df2a628ddaf Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 13 Apr 2020 14:27:45 +0900 Subject: [PATCH 0948/1415] Test accept unvalidated Test: this Bug: 139268426 Change-Id: I9343f72e1b1f4752e9781ff9b44e2a561d166cfb Merged-In: I3326a2119d66e67566fce0268ea4861729b1c64c (cherry-picked from aosp/1284557) --- .../src/android/net/cts/NetworkAgentTest.kt | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 32f2bfafe2..14f52e1e7c 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -24,7 +24,9 @@ import android.net.LinkProperties import android.net.Network import android.net.NetworkAgent import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE import android.net.NetworkAgentConfig @@ -39,9 +41,11 @@ import android.os.Looper import android.os.Message import android.os.Messenger import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import androidx.test.InstrumentationRegistry @@ -60,6 +64,7 @@ import org.junit.runner.RunWith import java.net.InetAddress import java.time.Duration import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertFailsWith import kotlin.test.assertNotNull import kotlin.test.assertNull @@ -123,27 +128,38 @@ class NetworkAgentTest { * only keeps track of one async channel. */ private class FakeConnectivityService(looper: Looper) { + private val CMD_EXPECT_DISCONNECT = 1 + private var disconnectExpected = false private val msgHistory = ArrayTrackRecord().newReadHead() private val asyncChannel = AsyncChannel() private val handler = object : Handler(looper) { override fun handleMessage(msg: Message) { msgHistory.add(Message.obtain(msg)) // make a copy as the original will be recycled when (msg.what) { + CMD_EXPECT_DISCONNECT -> disconnectExpected = true AsyncChannel.CMD_CHANNEL_HALF_CONNECTED -> asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) - AsyncChannel.CMD_CHANNEL_DISCONNECT, AsyncChannel.CMD_CHANNEL_DISCONNECTED -> - fail("Agent unexpectedly disconnected") + AsyncChannel.CMD_CHANNEL_DISCONNECTED -> + if (!disconnectExpected) { + fail("Agent unexpectedly disconnected") + } else { + disconnectExpected = false + } } } } fun connect(agentMsngr: Messenger) = asyncChannel.connect(context, handler, agentMsngr) + fun disconnect() = asyncChannel.disconnect() + fun sendMessage(what: Int, arg1: Int = 0, arg2: Int = 0, obj: Any? = null) = asyncChannel.sendMessage(Message(what, arg1, arg2, obj)) fun expectMessage(what: Int) = assertNotNull(msgHistory.poll(DEFAULT_TIMEOUT_MS) { it.what == what }) + + fun willExpectDisconnectOnce() = handler.sendEmptyMessage(CMD_EXPECT_DISCONNECT) } private open class TestableNetworkAgent( @@ -169,6 +185,8 @@ class NetworkAgentTest { val packet: KeepalivePacketData ) : CallbackEntry() data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry() + data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry() + object OnAutomaticReconnectDisabled : CallbackEntry() } override fun onBandwidthUpdateRequested() { @@ -199,6 +217,14 @@ class NetworkAgentTest { history.add(OnStopSocketKeepalive(slot)) } + override fun onSaveAcceptUnvalidated(accept: Boolean) { + history.add(OnSaveAcceptUnvalidated(accept)) + } + + override fun onAutomaticReconnectDisabled() { + history.add(OnAutomaticReconnectDisabled) + } + inline fun expectCallback(): T { val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") @@ -315,4 +341,40 @@ class NetworkAgentTest { assertEquals(it.slot, slot) } } + + @Test + fun testSetAcceptUnvalidated() { + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 1) + agent.expectCallback().let { + assertTrue(it.accept) + } + agent.assertNoCallback() + } + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 0) + mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + agent.expectCallback().let { + assertFalse(it.accept) + } + agent.expectCallback() + agent.assertNoCallback() + // When automatic reconnect is turned off, the network is torn down and + // ConnectivityService sends a disconnect. This in turn causes the agent + // to send a DISCONNECTED message to CS. + mFakeConnectivityService.willExpectDisconnectOnce() + mFakeConnectivityService.disconnect() + mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) + agent.expectCallback() + } + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + agent.expectCallback() + agent.assertNoCallback() + mFakeConnectivityService.willExpectDisconnectOnce() + mFakeConnectivityService.disconnect() + mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) + agent.expectCallback() + } + } } From 4f9483a9b8f8c1a8d45b879e6f109e31b137070c Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 14 Apr 2020 03:05:24 +0000 Subject: [PATCH 0949/1415] Test validation status Test: this Bug: 139268426 Change-Id: I04be5cda321af109cb6fd7510362d817ab23b505 Merged-In: I8499d9da8643cf60c912570e7a2ac2207d662e16 (cherry picked from commit 03af30598907add0f64d815f5487ea97e8d61f04, aosp/1284558) --- .../src/android/net/cts/NetworkAgentTest.kt | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 14f52e1e7c..97a15ef634 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -26,15 +26,20 @@ import android.net.NetworkAgent import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER import android.net.NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS import android.net.NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE +import android.net.NetworkAgent.INVALID_NETWORK +import android.net.NetworkAgent.VALID_NETWORK import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkProvider import android.net.NetworkRequest import android.net.SocketKeepalive +import android.net.Uri import android.os.Build +import android.os.Bundle import android.os.Handler import android.os.HandlerThread import android.os.Looper @@ -48,6 +53,7 @@ import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRem import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus import androidx.test.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.AsyncChannel @@ -187,6 +193,7 @@ class NetworkAgentTest { data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry() data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry() object OnAutomaticReconnectDisabled : CallbackEntry() + data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry() } override fun onBandwidthUpdateRequested() { @@ -225,6 +232,23 @@ class NetworkAgentTest { history.add(OnAutomaticReconnectDisabled) } + override fun onValidationStatus(status: Int, uri: Uri?) { + history.add(OnValidationStatus(status, uri)) + } + + // Expects the initial validation event that always occurs immediately after registering + // a NetworkAgent whose network does not require validation (which test networks do + // not, since they lack the INTERNET capability). It always contains the default argument + // for the URI. + fun expectNoInternetValidationStatus() = expectCallback().let { + assertEquals(it.status, VALID_NETWORK) + // The returned Uri is parsed from the empty string, which means it's an + // instance of the (private) Uri.StringUri. There are no real good ways + // to check this, the least bad is to just convert it to a string and + // make sure it's empty. + assertEquals("", it.uri.toString()) + } + inline fun expectCallback(): T { val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") @@ -281,6 +305,7 @@ class NetworkAgentTest { fun testConnectAndUnregister() { val (agent, callback) = createConnectedNetworkAgent() callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectNoInternetValidationStatus() agent.unregister() callback.expectCallback(agent.network) agent.expectCallback() @@ -293,6 +318,7 @@ class NetworkAgentTest { fun testOnBandwidthUpdateRequested() { val (agent, callback) = createConnectedNetworkAgent() callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectNoInternetValidationStatus() mCM.requestBandwidthUpdate(agent.network) agent.expectCallback() agent.unregister() @@ -377,4 +403,25 @@ class NetworkAgentTest { agent.expectCallback() } } + + @Test + fun testValidationStatus() = createNetworkAgentWithFakeCS().let { agent -> + val uri = Uri.parse("http://www.google.com") + val bundle = Bundle().apply { + putString(NetworkAgent.REDIRECT_URL_KEY, uri.toString()) + } + mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, + arg1 = VALID_NETWORK, obj = bundle) + agent.expectCallback().let { + assertEquals(it.status, VALID_NETWORK) + assertEquals(it.uri, uri) + } + + mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, + arg1 = INVALID_NETWORK, obj = Bundle()) + agent.expectCallback().let { + assertEquals(it.status, INVALID_NETWORK) + assertNull(it.uri) + } + } } From e582c5d4be0bf80985abb62f6524872001f2c367 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 14 Apr 2020 03:05:40 +0000 Subject: [PATCH 0950/1415] Test sendCaps and sendProps Test: this Bug: 139268426 Change-Id: I6d30ac0193225826a97ff3853a98b939e571d074 Merged-In: Idefce1174b82668d23c53dd1bf95bc660cb21c28 (cherry picked from commit 7922d354307e4a41a336c29291285550a94da434, aosp/1284560) --- .../src/android/net/cts/NetworkAgentTest.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 97a15ef634..4de3a086ce 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -84,6 +84,7 @@ private const val DEFAULT_TIMEOUT_MS = 5000L // requests filed by the test and should never match normal internet requests. 70 is the default // score of Ethernet networks, it's as good a value as any other. private const val TEST_NETWORK_SCORE = 70 +private const val BETTER_NETWORK_SCORE = 75 private const val FAKE_NET_ID = 1098 private val instrumentation: Instrumentation get() = InstrumentationRegistry.getInstrumentation() @@ -170,8 +171,8 @@ class NetworkAgentTest { private open class TestableNetworkAgent( val looper: Looper, - nc: NetworkCapabilities, - lp: LinkProperties, + val nc: NetworkCapabilities, + val lp: LinkProperties, conf: NetworkAgentConfig ) : NetworkAgent(context, looper, TestableNetworkAgent::class.java.simpleName /* tag */, nc, lp, TEST_NETWORK_SCORE, conf, Provider(context, looper)) { @@ -368,6 +369,25 @@ class NetworkAgentTest { } } + @Test + fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectNoInternetValidationStatus() + val ifaceName = "adhocIface" + val lp = LinkProperties(agent.lp) + lp.setInterfaceName(ifaceName) + agent.sendLinkProperties(lp) + callback.expectLinkPropertiesThat(agent.network) { + it.getInterfaceName() == ifaceName + } + val nc = NetworkCapabilities(agent.nc) + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + agent.sendNetworkCapabilities(nc) + callback.expectCapabilitiesThat(agent.network) { + it.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + } + } + @Test fun testSetAcceptUnvalidated() { createNetworkAgentWithFakeCS().let { agent -> From 2e3c3b8d89d83b138bd06cc31be3fbd5348398a9 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 14 Apr 2020 03:05:52 +0000 Subject: [PATCH 0951/1415] Test sendNetworkScore Test: this Bug: 139268426 Change-Id: Ie46ff2676944e6d6603bbff271fc6dca9935e548 Merged-In: I66cea443f0c6aa9235da577817787d764fbd030b (cherry picked from commit c7091c91558d56632da237cf0a01567fcde3cba2, aosp/1284561) --- .../src/android/net/cts/NetworkAgentTest.kt | 66 ++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 4de3a086ce..659950a0db 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -37,6 +37,7 @@ import android.net.NetworkCapabilities import android.net.NetworkProvider import android.net.NetworkRequest import android.net.SocketKeepalive +import android.net.StringNetworkSpecifier import android.net.Uri import android.os.Build import android.os.Bundle @@ -59,8 +60,10 @@ import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.AsyncChannel import com.android.testutils.ArrayTrackRecord import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback +import java.util.UUID import org.junit.After import org.junit.Assert.fail import org.junit.Before @@ -197,6 +200,8 @@ class NetworkAgentTest { data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry() } + fun getName(): String? = (nc.getNetworkSpecifier() as? StringNetworkSpecifier)?.specifier + override fun onBandwidthUpdateRequested() { history.add(OnBandwidthUpdateRequested) } @@ -267,7 +272,7 @@ class NetworkAgentTest { callbacksToCleanUp.add(callback) } - private fun createNetworkAgent(): TestableNetworkAgent { + private fun createNetworkAgent(name: String? = null): TestableNetworkAgent { val nc = NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) @@ -275,6 +280,9 @@ class NetworkAgentTest { addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + if (null != name) { + setNetworkSpecifier(StringNetworkSpecifier(name)) + } } val lp = LinkProperties().apply { addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) @@ -285,14 +293,15 @@ class NetworkAgentTest { } } - private fun createConnectedNetworkAgent(): Pair { + private fun createConnectedNetworkAgent(name: String? = null): + Pair { val request: NetworkRequest = NetworkRequest.Builder() .clearCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_TEST) .build() val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) requestNetwork(request, callback) - val agent = createNetworkAgent() + val agent = createNetworkAgent(name) agent.register() agent.markConnected() return agent to callback @@ -388,6 +397,57 @@ class NetworkAgentTest { } } + @Test + fun testSendScore() { + // This test will create two networks and check that the one with the stronger + // score wins out for a request that matches them both. + // First create requests to make sure both networks are kept up, using the + // specifier so they are specific to each network + val name1 = UUID.randomUUID().toString() + val name2 = UUID.randomUUID().toString() + val request1 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setNetworkSpecifier(StringNetworkSpecifier(name1)) + .build() + val request2 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setNetworkSpecifier(StringNetworkSpecifier(name2)) + .build() + val callback1 = TestableNetworkCallback() + val callback2 = TestableNetworkCallback() + requestNetwork(request1, callback1) + requestNetwork(request2, callback2) + + // Then file the interesting request + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback() + requestNetwork(request, callback) + + // Connect the first Network + createConnectedNetworkAgent(name1).let { (agent1, _) -> + callback.expectAvailableThenValidatedCallbacks(agent1.network) + // Upgrade agent1 to a better score so that there is no ambiguity when + // agent2 connects that agent1 is still better + agent1.sendNetworkScore(BETTER_NETWORK_SCORE - 1) + // Connect the second agent + createConnectedNetworkAgent(name2).let { (agent2, _) -> + agent2.markConnected() + // The callback should not see anything yet + callback.assertNoCallback(200) + // Now update the score and expect the callback now prefers agent2 + agent2.sendNetworkScore(BETTER_NETWORK_SCORE) + callback.expectCallback(agent2.network) + } + } + + // tearDown() will unregister the requests and agents + } + @Test fun testSetAcceptUnvalidated() { createNetworkAgentWithFakeCS().let { agent -> From 6a9699652523662ef197c85d5b24fde401da9e3c Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 14 Apr 2020 03:06:04 +0000 Subject: [PATCH 0952/1415] Test Signal thresholds Test: this Bug: 139268426 Change-Id: I48ea9afa2a31c3edd4b00a566ed47796912c453a Merged-In: I136f246d0e3ad6744989e7d6f4f8034cc6674def (cherry picked from commit 159bce95cb8ca0aba6cf74a0b57a24dae3aadc05, aosp/1284559) --- .../src/android/net/cts/NetworkAgentTest.kt | 81 ++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 659950a0db..9d1eee9da9 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -52,6 +52,7 @@ import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBan import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSignalStrengthThresholdsUpdated import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus @@ -65,6 +66,7 @@ import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback import java.util.UUID import org.junit.After +import org.junit.Assert.assertArrayEquals import org.junit.Assert.fail import org.junit.Before import org.junit.Rule @@ -83,6 +85,11 @@ import kotlin.test.assertTrue // going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio // without affecting the run time of successful runs. Thus, set a very high timeout. private const val DEFAULT_TIMEOUT_MS = 5000L +// When waiting for a NetworkCallback to determine there was no timeout, waiting is the +// only possible thing (the relevant handler is the one in the real ConnectivityService, +// and then there is the Binder call), so have a short timeout for this as it will be +// exhausted every time. +private const val NO_CALLBACK_TIMEOUT = 200L // Any legal score (0~99) for the test network would do, as it is going to be kept up by the // requests filed by the test and should never match normal internet requests. 70 is the default // score of Ethernet networks, it's as good a value as any other. @@ -198,6 +205,7 @@ class NetworkAgentTest { data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry() object OnAutomaticReconnectDisabled : CallbackEntry() data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry() + data class OnSignalStrengthThresholdsUpdated(val thresholds: IntArray) : CallbackEntry() } fun getName(): String? = (nc.getNetworkSpecifier() as? StringNetworkSpecifier)?.specifier @@ -238,6 +246,17 @@ class NetworkAgentTest { history.add(OnAutomaticReconnectDisabled) } + override fun onSignalStrengthThresholdsUpdated(thresholds: IntArray) { + history.add(OnSignalStrengthThresholdsUpdated(thresholds)) + } + + fun expectEmptySignalStrengths() { + expectCallback().let { + // intArrayOf() without arguments makes an empty array + assertArrayEquals(intArrayOf(), it.thresholds) + } + } + override fun onValidationStatus(status: Int, uri: Uri?) { history.add(OnValidationStatus(status, uri)) } @@ -272,6 +291,14 @@ class NetworkAgentTest { callbacksToCleanUp.add(callback) } + private fun registerNetworkCallback( + request: NetworkRequest, + callback: TestableNetworkCallback + ) { + mCM.registerNetworkCallback(request, callback) + callbacksToCleanUp.add(callback) + } + private fun createNetworkAgent(name: String? = null): TestableNetworkAgent { val nc = NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) @@ -315,6 +342,7 @@ class NetworkAgentTest { fun testConnectAndUnregister() { val (agent, callback) = createConnectedNetworkAgent() callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() agent.expectNoInternetValidationStatus() agent.unregister() callback.expectCallback(agent.network) @@ -328,12 +356,62 @@ class NetworkAgentTest { fun testOnBandwidthUpdateRequested() { val (agent, callback) = createConnectedNetworkAgent() callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() agent.expectNoInternetValidationStatus() mCM.requestBandwidthUpdate(agent.network) agent.expectCallback() agent.unregister() } + @Test + fun testSignalStrengthThresholds() { + val thresholds = intArrayOf(30, 50, 65) + val callbacks = thresholds.map { strength -> + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setSignalStrength(strength) + .build() + TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also { + registerNetworkCallback(request, it) + } + } + createConnectedNetworkAgent().let { (agent, callback) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectCallback().let { + assertArrayEquals(it.thresholds, thresholds) + } + agent.expectNoInternetValidationStatus() + + // Send signal strength and check that the callbacks are called appropriately. + val nc = NetworkCapabilities(agent.nc) + nc.setSignalStrength(20) + agent.sendNetworkCapabilities(nc) + callbacks.forEach { it.assertNoCallback(NO_CALLBACK_TIMEOUT) } + + nc.setSignalStrength(40) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectAvailableCallbacks(agent.network) + callbacks[1].assertNoCallback(NO_CALLBACK_TIMEOUT) + callbacks[2].assertNoCallback(NO_CALLBACK_TIMEOUT) + + nc.setSignalStrength(80) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 80 } + callbacks[1].expectAvailableCallbacks(agent.network) + callbacks[2].expectAvailableCallbacks(agent.network) + + nc.setSignalStrength(55) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 } + callbacks[1].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 } + callbacks[2].expectCallback(agent.network) + } + callbacks.forEach { + mCM.unregisterNetworkCallback(it) + } + } + @Test fun testSocketKeepalive(): Unit = createNetworkAgentWithFakeCS().let { agent -> val packet = object : KeepalivePacketData( @@ -381,6 +459,7 @@ class NetworkAgentTest { @Test fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) -> callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() agent.expectNoInternetValidationStatus() val ifaceName = "adhocIface" val lp = LinkProperties(agent.lp) @@ -438,7 +517,7 @@ class NetworkAgentTest { createConnectedNetworkAgent(name2).let { (agent2, _) -> agent2.markConnected() // The callback should not see anything yet - callback.assertNoCallback(200) + callback.assertNoCallback(NO_CALLBACK_TIMEOUT) // Now update the score and expect the callback now prefers agent2 agent2.sendNetworkScore(BETTER_NETWORK_SCORE) callback.expectCallback(agent2.network) From 5217786c6c1fe9b2276915dfbafc4bd104500021 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 14 Apr 2020 03:06:14 +0000 Subject: [PATCH 0953/1415] Address comments from aosp/1284557 Test: this Bug: 139268426 Change-Id: I5d90fe2716032b7ebd2b425225fe8e96900fe63b Merged-In: I5edbff1d7eed2f939ba26f1ebd7ead49ac67b978 (cherry picked from commit 55d7923c1d75e3d91b79461e2bd3846abdd9eed2, aosp/1284569) --- tests/cts/net/src/android/net/cts/NetworkAgentTest.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 9d1eee9da9..89d3dff66c 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -281,7 +281,8 @@ class NetworkAgentTest { } fun assertNoCallback() { - assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS), "Handler never became idle") + assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS), + "Handler didn't became idle after ${DEFAULT_TIMEOUT_MS}ms") assertNull(history.peek()) } } @@ -536,6 +537,10 @@ class NetworkAgentTest { } agent.assertNoCallback() } + } + + @Test + fun testSetAcceptUnvalidatedPreventAutomaticReconnect() { createNetworkAgentWithFakeCS().let { agent -> mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 0) mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) @@ -552,6 +557,10 @@ class NetworkAgentTest { mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) agent.expectCallback() } + } + + @Test + fun testPreventAutomaticReconnect() { createNetworkAgentWithFakeCS().let { agent -> mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) agent.expectCallback() From da03c6a3f5e5291abeacbbdd931e007765dfaf0a Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 14 Apr 2020 21:49:50 +0800 Subject: [PATCH 0954/1415] Add test for NetworkRequest#canBeSatisfiedBy Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkRequestTest on both Q and R device Bug: 153972141 Change-Id: I614963cdd5f26bf3d47246fdc9eb11e74d05a460 --- .../android/net/cts/NetworkRequestTest.java | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index 8b97c8cb92..751418657f 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -16,8 +16,11 @@ package android.net.cts; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static org.junit.Assert.assertEquals; @@ -26,13 +29,12 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.net.MacAddress; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.NetworkSpecifier; -import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiNetworkSpecifier; import android.os.Build; import android.os.PatternMatcher; -import android.util.Pair; import androidx.test.runner.AndroidJUnit4; @@ -49,6 +51,7 @@ public class NetworkRequestTest { public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); private static final String TEST_SSID = "TestSSID"; + private static final String OTHER_SSID = "OtherSSID"; private static final int TEST_UID = 2097; private static final String TEST_PACKAGE_NAME = "test.package.name"; private static final MacAddress ARBITRARY_ADDRESS = MacAddress.fromString("3:5:8:12:9:2"); @@ -84,4 +87,42 @@ public class NetworkRequestTest { .getNetworkSpecifier(); assertEquals(obtainedSpecifier, specifier); } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testCanBeSatisfiedBy() { + final WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL)) + .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + .build(); + final WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() + .setSsidPattern(new PatternMatcher(OTHER_SSID, PatternMatcher.PATTERN_LITERAL)) + .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + .build(); + final NetworkCapabilities cap = new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET); + final NetworkCapabilities capWithSp = + new NetworkCapabilities(cap).setNetworkSpecifier(specifier1); + final NetworkCapabilities cellCap = new NetworkCapabilities() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_MMS) + .addCapability(NET_CAPABILITY_INTERNET); + final NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .setNetworkSpecifier(specifier1) + .build(); + assertFalse(request.canBeSatisfiedBy(null)); + assertFalse(request.canBeSatisfiedBy(new NetworkCapabilities())); + assertTrue(request.canBeSatisfiedBy(cap)); + assertTrue(request.canBeSatisfiedBy( + new NetworkCapabilities(cap).addTransportType(TRANSPORT_VPN))); + assertTrue(request.canBeSatisfiedBy(capWithSp)); + assertFalse(request.canBeSatisfiedBy( + new NetworkCapabilities(cap).setNetworkSpecifier(specifier2))); + assertFalse(request.canBeSatisfiedBy(cellCap)); + assertEquals(request.canBeSatisfiedBy(capWithSp), + new NetworkCapabilities(capWithSp).satisfiedByNetworkCapabilities(capWithSp)); + } } From ff7fe1e5fe7cbfc5e3f89062baa6a8f52155336b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 15 Apr 2020 00:49:54 +0000 Subject: [PATCH 0955/1415] Add CTS for building IKE and Child SaProposal Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ic50d70f35216a065ff398c38262f2de0b370c5ef Merged-In: Ic50d70f35216a065ff398c38262f2de0b370c5ef (cherry picked from commit 7f95e39c2534b370a28e4d6cf08ebb8b74950fcb) --- .../net/ipsec/ike/cts/SaProposalTest.java | 232 +++++++++++++++++- 1 file changed, 229 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java index 47e8f0174d..e0d3be0540 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java @@ -16,15 +16,241 @@ package android.net.ipsec.ike.cts; +import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP; +import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; +import static android.net.ipsec.ike.SaProposal.DH_GROUP_NONE; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeSaProposal; +import android.util.Pair; + import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + @RunWith(AndroidJUnit4.class) public class SaProposalTest { - @Test - public void testBuildIkeSaProposal() { - // TODO(b/148689509): Add real tests here + private static final List> NORMAL_MODE_CIPHERS = new ArrayList<>(); + private static final List> COMBINED_MODE_CIPHERS = new ArrayList<>(); + private static final List INTEGRITY_ALGOS = new ArrayList<>(); + private static final List DH_GROUPS = new ArrayList<>(); + private static final List DH_GROUPS_WITH_NONE = new ArrayList<>(); + private static final List PRFS = new ArrayList<>(); + + static { + NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)); + NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128)); + NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192)); + NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)); + + COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128)); + COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192)); + COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256)); + + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96); + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_AES_XCBC_96); + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128); + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192); + INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256); + + DH_GROUPS.add(DH_GROUP_1024_BIT_MODP); + DH_GROUPS.add(DH_GROUP_2048_BIT_MODP); + + DH_GROUPS_WITH_NONE.add(DH_GROUP_NONE); + DH_GROUPS_WITH_NONE.addAll(DH_GROUPS); + + PRFS.add(PSEUDORANDOM_FUNCTION_HMAC_SHA1); + PRFS.add(PSEUDORANDOM_FUNCTION_AES128_XCBC); + PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_256); + PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_384); + PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_512); } + + // Package private + static IkeSaProposal buildIkeSaProposalWithNormalModeCipher() { + return buildIkeSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, PRFS, DH_GROUPS); + } + + // Package private + static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher() { + return buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); + } + + private static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher( + boolean hasIntegrityNone) { + List integerAlgos = new ArrayList<>(); + if (hasIntegrityNone) { + integerAlgos.add(INTEGRITY_ALGORITHM_NONE); + } + return buildIkeSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, PRFS, DH_GROUPS); + } + + private static IkeSaProposal buildIkeSaProposal( + List> ciphers, + List integrityAlgos, + List prfs, + List dhGroups) { + IkeSaProposal.Builder builder = new IkeSaProposal.Builder(); + + for (Pair pair : ciphers) { + builder.addEncryptionAlgorithm(pair.first, pair.second); + } + for (int algo : integrityAlgos) { + builder.addIntegrityAlgorithm(algo); + } + for (int algo : prfs) { + builder.addPseudorandomFunction(algo); + } + for (int algo : dhGroups) { + builder.addDhGroup(algo); + } + + return builder.build(); + } + + // Package private + static ChildSaProposal buildChildSaProposalWithNormalModeCipher() { + return buildChildSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, DH_GROUPS_WITH_NONE); + } + + // Package private + static ChildSaProposal buildChildSaProposalWithCombinedModeCipher() { + return buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); + } + + private static ChildSaProposal buildChildSaProposalWithCombinedModeCipher( + boolean hasIntegrityNone) { + List integerAlgos = new ArrayList<>(); + if (hasIntegrityNone) { + integerAlgos.add(INTEGRITY_ALGORITHM_NONE); + } + + return buildChildSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, DH_GROUPS_WITH_NONE); + } + + private static ChildSaProposal buildChildSaProposal( + List> ciphers, + List integrityAlgos, + List dhGroups) { + ChildSaProposal.Builder builder = new ChildSaProposal.Builder(); + + for (Pair pair : ciphers) { + builder.addEncryptionAlgorithm(pair.first, pair.second); + } + for (int algo : integrityAlgos) { + builder.addIntegrityAlgorithm(algo); + } + for (int algo : dhGroups) { + builder.addDhGroup(algo); + } + + return builder.build(); + } + + // Package private + static ChildSaProposal buildChildSaProposalWithOnlyCiphers() { + return buildChildSaProposal( + COMBINED_MODE_CIPHERS, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + } + + @Test + public void testBuildIkeSaProposalWithNormalModeCipher() { + IkeSaProposal saProposal = buildIkeSaProposalWithNormalModeCipher(); + + assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms()); + assertEquals(PRFS, saProposal.getPseudorandomFunctions()); + assertEquals(DH_GROUPS, saProposal.getDhGroups()); + } + + @Test + public void testBuildIkeSaProposalWithCombinedModeCipher() { + IkeSaProposal saProposal = + buildIkeSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(PRFS, saProposal.getPseudorandomFunctions()); + assertEquals(DH_GROUPS, saProposal.getDhGroups()); + assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); + } + + @Test + public void testBuildIkeSaProposalWithCombinedModeCipherAndIntegrityNone() { + IkeSaProposal saProposal = + buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(PRFS, saProposal.getPseudorandomFunctions()); + assertEquals(DH_GROUPS, saProposal.getDhGroups()); + assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms()); + } + + @Test + public void testBuildChildSaProposalWithNormalModeCipher() { + ChildSaProposal saProposal = buildChildSaProposalWithNormalModeCipher(); + + assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms()); + assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); + } + + @Test + public void testBuildChildProposalWithCombinedModeCipher() { + ChildSaProposal saProposal = + buildChildSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); + assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); + } + + @Test + public void testBuildChildProposalWithCombinedModeCipherAndIntegrityNone() { + ChildSaProposal saProposal = + buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms()); + assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); + } + + @Test + public void testBuildChildSaProposalWithOnlyCiphers() { + ChildSaProposal saProposal = buildChildSaProposalWithOnlyCiphers(); + + assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); + assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); + assertTrue(saProposal.getDhGroups().isEmpty()); + } + + // TODO(b/148689509): Test throwing exception when algorithm combination is invalid } From 2b98dce4e9dcb18d18a1567822afc3edcf3c26de Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 15 Apr 2020 00:50:24 +0000 Subject: [PATCH 0956/1415] Test setting proposal, TS and lifetime for ChildSessionParams Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: If19fb12c92f65d487478fda172acb21f6cfb1717 Merged-In: If19fb12c92f65d487478fda172acb21f6cfb1717 (cherry picked from commit ee06cc4c06e54c7cf9cb46acd38066106bdc1cba) --- .../ipsec/ike/cts/ChildSessionParamsTest.java | 140 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 83 +++++++++++ 2 files changed, 223 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java new file mode 100644 index 0000000000..316355252a --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java @@ -0,0 +1,140 @@ +/* + * 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.ipsec.ike.cts; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.ChildSessionParams; +import android.net.ipsec.ike.TransportModeChildSessionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class ChildSessionParamsTest extends IkeTestBase { + private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(3L); + private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(1L); + + // Random proposal. Content doesn't matter + private final ChildSaProposal mSaProposal = + SaProposalTest.buildChildSaProposalWithCombinedModeCipher(); + + private void verifyTunnelModeChildParamsWithDefaultValues(ChildSessionParams childParams) { + assertTrue(childParams instanceof TunnelModeChildSessionParams); + verifyChildParamsWithDefaultValues(childParams); + } + + private void verifyTunnelModeChildParamsWithCustomizedValues(ChildSessionParams childParams) { + assertTrue(childParams instanceof TunnelModeChildSessionParams); + verifyChildParamsWithCustomizedValues(childParams); + } + + private void verifyTransportModeChildParamsWithDefaultValues(ChildSessionParams childParams) { + assertTrue(childParams instanceof TransportModeChildSessionParams); + verifyChildParamsWithDefaultValues(childParams); + } + + private void verifyTransportModeChildParamsWithCustomizedValues( + ChildSessionParams childParams) { + assertTrue(childParams instanceof TransportModeChildSessionParams); + verifyChildParamsWithCustomizedValues(childParams); + } + + private void verifyChildParamsWithDefaultValues(ChildSessionParams childParams) { + assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals()); + + // Do not do assertEquals to the default values to be avoid being a change-detector test + assertTrue(childParams.getHardLifetimeSeconds() > childParams.getSoftLifetimeSeconds()); + assertTrue(childParams.getSoftLifetimeSeconds() > 0); + + assertEquals( + Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS), + childParams.getInboundTrafficSelectors()); + assertEquals( + Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS), + childParams.getOutboundTrafficSelectors()); + } + + private void verifyChildParamsWithCustomizedValues(ChildSessionParams childParams) { + assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals()); + + assertEquals(HARD_LIFETIME_SECONDS, childParams.getHardLifetimeSeconds()); + assertEquals(SOFT_LIFETIME_SECONDS, childParams.getSoftLifetimeSeconds()); + + assertEquals( + Arrays.asList(INBOUND_V4_TS, INBOUND_V6_TS), + childParams.getInboundTrafficSelectors()); + assertEquals( + Arrays.asList(OUTBOUND_V4_TS, OUTBOUND_V6_TS), + childParams.getOutboundTrafficSelectors()); + } + + @Test + public void testBuildTransportModeParamsWithDefaultValues() { + TransportModeChildSessionParams childParams = + new TransportModeChildSessionParams.Builder().addSaProposal(mSaProposal).build(); + + verifyTransportModeChildParamsWithDefaultValues(childParams); + } + + @Test + public void testBuildTunnelModeParamsWithDefaultValues() { + TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder().addSaProposal(mSaProposal).build(); + + verifyTunnelModeChildParamsWithDefaultValues(childParams); + assertTrue(childParams.getConfigurationRequests().isEmpty()); + } + + @Test + public void testBuildTransportModeParamsWithCustomizedValues() { + TransportModeChildSessionParams childParams = + new TransportModeChildSessionParams.Builder() + .addSaProposal(mSaProposal) + .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) + .addInboundTrafficSelectors(INBOUND_V4_TS) + .addInboundTrafficSelectors(INBOUND_V6_TS) + .addOutboundTrafficSelectors(OUTBOUND_V4_TS) + .addOutboundTrafficSelectors(OUTBOUND_V6_TS) + .build(); + + verifyTransportModeChildParamsWithCustomizedValues(childParams); + } + + @Test + public void testBuildTunnelModeParamsWithCustomizedValues() { + TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder() + .addSaProposal(mSaProposal) + .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) + .addInboundTrafficSelectors(INBOUND_V4_TS) + .addInboundTrafficSelectors(INBOUND_V6_TS) + .addOutboundTrafficSelectors(OUTBOUND_V4_TS) + .addOutboundTrafficSelectors(OUTBOUND_V6_TS) + .build(); + + verifyTunnelModeChildParamsWithCustomizedValues(childParams); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java new file mode 100644 index 0000000000..d4b431e837 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -0,0 +1,83 @@ +/* + * 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.ipsec.ike.cts; + +import android.net.InetAddresses; +import android.net.ipsec.ike.IkeTrafficSelector; + +import java.net.Inet4Address; +import java.net.Inet6Address; + +/** Shared parameters and util methods for testing different components of IKE */ +abstract class IkeTestBase { + private static final int MIN_PORT = 0; + private static final int MAX_PORT = 65535; + private static final int INBOUND_TS_START_PORT = MIN_PORT; + private static final int INBOUND_TS_END_PORT = 65520; + private static final int OUTBOUND_TS_START_PORT = 16; + private static final int OUTBOUND_TS_END_PORT = MAX_PORT; + + static final int IP4_PREFIX_LEN = 32; + static final int IP6_PREFIX_LEN = 64; + + static final Inet4Address IPV4_ADDRESS_LOCAL = + (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); + static final Inet4Address IPV4_ADDRESS_REMOTE = + (Inet4Address) (InetAddresses.parseNumericAddress("198.51.100.100")); + static final Inet6Address IPV6_ADDRESS_LOCAL = + (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8::100")); + static final Inet6Address IPV6_ADDRESS_REMOTE = + (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8:255::100")); + + static final IkeTrafficSelector DEFAULT_V4_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("0.0.0.0"), + InetAddresses.parseNumericAddress("255.255.255.255")); + static final IkeTrafficSelector DEFAULT_V6_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("::"), + InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); + static final IkeTrafficSelector INBOUND_V4_TS = + new IkeTrafficSelector( + INBOUND_TS_START_PORT, + INBOUND_TS_END_PORT, + InetAddresses.parseNumericAddress("192.0.2.10"), + InetAddresses.parseNumericAddress("192.0.2.20")); + static final IkeTrafficSelector OUTBOUND_V4_TS = + new IkeTrafficSelector( + OUTBOUND_TS_START_PORT, + OUTBOUND_TS_END_PORT, + InetAddresses.parseNumericAddress("198.51.100.0"), + InetAddresses.parseNumericAddress("198.51.100.255")); + + static final IkeTrafficSelector INBOUND_V6_TS = + new IkeTrafficSelector( + INBOUND_TS_START_PORT, + INBOUND_TS_END_PORT, + InetAddresses.parseNumericAddress("2001:db8::10"), + InetAddresses.parseNumericAddress("2001:db8::128")); + static final IkeTrafficSelector OUTBOUND_V6_TS = + new IkeTrafficSelector( + OUTBOUND_TS_START_PORT, + OUTBOUND_TS_END_PORT, + InetAddresses.parseNumericAddress("2001:db8:255::64"), + InetAddresses.parseNumericAddress("2001:db8:255::255")); +} From 5e89d115fbb0ac48c55484ace010cd7ceb0c6414 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 15 Apr 2020 17:29:01 +0000 Subject: [PATCH 0957/1415] Test setting config requests for TunnelModeChildSessionParams Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ib3e803159cdf42a8655c0e4d0f22faeabe161c4c Merged-In: Ib3e803159cdf42a8655c0e4d0f22faeabe161c4c (cherry picked from commit 7ec4cf34cc443984889c5728a2b538ea91ec5036) --- .../ipsec/ike/cts/ChildSessionParamsTest.java | 90 +++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 37 ++++++++ 2 files changed, 127 insertions(+) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java index 316355252a..7fb1b6dc43 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java @@ -16,20 +16,36 @@ package android.net.ipsec.ike.cts; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.net.LinkAddress; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.TransportModeChildSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet4Address; import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -137,4 +153,78 @@ public class ChildSessionParamsTest extends IkeTestBase { verifyTunnelModeChildParamsWithCustomizedValues(childParams); } + + @Test + public void testBuildChildSessionParamsWithConfigReq() { + TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder() + .addSaProposal(mSaProposal) + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .addInternalAddressRequest(AF_INET6) + .addInternalAddressRequest(IPV4_ADDRESS_REMOTE) + .addInternalAddressRequest(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN) + .addInternalDnsServerRequest(AF_INET) + .addInternalDnsServerRequest(AF_INET6) + .addInternalDhcpServerRequest(AF_INET) + .addInternalDhcpServerRequest(AF_INET) + .build(); + + verifyTunnelModeChildParamsWithDefaultValues(childParams); + + // Verify config request types and number of requests for each type + Map, Integer> expectedAttributeCounts = + new HashMap<>(); + expectedAttributeCounts.put(ConfigRequestIpv4Address.class, 2); + expectedAttributeCounts.put(ConfigRequestIpv6Address.class, 3); + expectedAttributeCounts.put(ConfigRequestIpv4Netmask.class, 1); + expectedAttributeCounts.put(ConfigRequestIpv4DnsServer.class, 1); + expectedAttributeCounts.put(ConfigRequestIpv6DnsServer.class, 1); + expectedAttributeCounts.put(ConfigRequestIpv4DhcpServer.class, 2); + verifyConfigRequestTypes(expectedAttributeCounts, childParams.getConfigurationRequests()); + + // Verify specific IPv4 address request + Set expectedV4Addresses = new HashSet<>(); + expectedV4Addresses.add(IPV4_ADDRESS_REMOTE); + verifySpecificV4AddrConfigReq(expectedV4Addresses, childParams); + + // Verify specific IPv6 address request + Set expectedV6Addresses = new HashSet<>(); + expectedV6Addresses.add(new LinkAddress(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN)); + verifySpecificV6AddrConfigReq(expectedV6Addresses, childParams); + } + + protected void verifySpecificV4AddrConfigReq( + Set expectedAddresses, TunnelModeChildSessionParams childParams) { + for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) { + if (req instanceof ConfigRequestIpv4Address + && ((ConfigRequestIpv4Address) req).getAddress() != null) { + Inet4Address address = ((ConfigRequestIpv4Address) req).getAddress(); + + // Fail if expectedAddresses does not contain this address + assertTrue(expectedAddresses.remove(address)); + } + } + + // Fail if any expected address is not found in result + assertTrue(expectedAddresses.isEmpty()); + } + + protected void verifySpecificV6AddrConfigReq( + Set expectedAddresses, TunnelModeChildSessionParams childParams) { + for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) { + if (req instanceof ConfigRequestIpv6Address + && ((ConfigRequestIpv6Address) req).getAddress() != null) { + ConfigRequestIpv6Address ipv6AddrReq = (ConfigRequestIpv6Address) req; + + // Fail if expectedAddresses does not contain this address + LinkAddress address = + new LinkAddress(ipv6AddrReq.getAddress(), ipv6AddrReq.getPrefixLength()); + assertTrue(expectedAddresses.remove(address)); + } + } + + // Fail if any expected address is not found in result + assertTrue(expectedAddresses.isEmpty()); + } } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index d4b431e837..d3aa8d03d5 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -16,11 +16,17 @@ package android.net.ipsec.ike.cts; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import android.net.InetAddresses; import android.net.ipsec.ike.IkeTrafficSelector; import java.net.Inet4Address; import java.net.Inet6Address; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** Shared parameters and util methods for testing different components of IKE */ abstract class IkeTestBase { @@ -80,4 +86,35 @@ abstract class IkeTestBase { OUTBOUND_TS_END_PORT, InetAddresses.parseNumericAddress("2001:db8:255::64"), InetAddresses.parseNumericAddress("2001:db8:255::255")); + + // Verify Config requests in TunnelModeChildSessionParams and IkeSessionParams + void verifyConfigRequestTypes( + Map, Integer> expectedReqCntMap, List resultReqList) { + Map, Integer> resultReqCntMap = new HashMap<>(); + + // Verify that every config request type in resultReqList is expected, and build + // resultReqCntMap at the same time + for (T resultReq : resultReqList) { + boolean isResultReqExpected = false; + + for (Class expectedReqInterface : expectedReqCntMap.keySet()) { + if (expectedReqInterface.isInstance(resultReq)) { + isResultReqExpected = true; + + resultReqCntMap.put( + expectedReqInterface, + resultReqCntMap.getOrDefault(expectedReqInterface, 0) + 1); + } + } + + if (!isResultReqExpected) { + fail("Failed due to unexpected config request " + resultReq); + } + } + + assertEquals(expectedReqCntMap, resultReqCntMap); + + // TODO: Think of a neat way to validate both counts and values in this method. Probably can + // build Runnables as validators for count and values. + } } From 69f3fa3729e399670c6ba53150fc56bdd99ac363 Mon Sep 17 00:00:00 2001 From: Amit Mahajan Date: Tue, 7 Apr 2020 07:34:45 -0700 Subject: [PATCH 0958/1415] DO NOT MERGE Remove references of telephony-stubs. Since it's not used for now. Test: TH Bug: 153304048 Change-Id: I1812818c3d49463c3840a98212bbab58a110359a --- Tethering/Android.bp | 1 - Tethering/tests/unit/Android.bp | 1 - 2 files changed, 2 deletions(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 5b052df75e..bfb65241ec 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -34,7 +34,6 @@ java_defaults { ], libs: [ "framework-tethering", - "framework-telephony-stubs", "framework-wifi-stubs-systemapi", "unsupportedappusage", ], diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp index 4849fd5d01..26517ceb72 100644 --- a/Tethering/tests/unit/Android.bp +++ b/Tethering/tests/unit/Android.bp @@ -38,7 +38,6 @@ java_defaults { "ext", "framework-minus-apex", "framework-res", - "framework-telephony-stubs", "framework-tethering", "framework-wifi-stubs-module_libs_api", ], From 1e16d9862c532a9aaab39c99ffb3a5f8bfc5466c Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Thu, 16 Apr 2020 00:17:32 +0000 Subject: [PATCH 0959/1415] Add TetheringEventCallback CTS test Test APIs below: onOffloadStatusChanged(int) Bug: 153619369 Test: atests CtsTetheringTest Change-Id: Ia7edd0d3d8184e30373ac8b657299107ff9b4c1e Merged-In: Ia7edd0d3d8184e30373ac8b657299107ff9b4c1e (cherry picked from commit c1153b7348dac9d4f0b0ad89acf17e52d00e83b9, aosp/1284554) --- .../tethering/cts/TetheringManagerTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 193a5dc3a4..f430f22371 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,6 +15,9 @@ */ package android.tethering.test; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; @@ -273,6 +276,7 @@ public class TetheringManagerTest { ON_TETHERED_IFACES, ON_ERROR, ON_CLIENTS, + ON_OFFLOAD_STATUS, }; public static class CallbackValue { @@ -330,6 +334,11 @@ public class TetheringManagerTest { mCallbacks.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); } + @Override + public void onOffloadStatusChanged(int status) { + mCallbacks.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); + } + public CallbackValue pollCallback() { try { return mCallbacks.poll(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); @@ -382,6 +391,17 @@ public class TetheringManagerTest { } } + public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { + while (true) { + final CallbackValue cv = pollCallback(); + if (cv == null) fail("No expected offload status change callback"); + if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) continue; + + final int status = (int) cv.callbackParam; + for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return; + } + } + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { return mTetherableRegex; } @@ -403,6 +423,7 @@ public class TetheringManagerTest { mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); tetherEventCallback.expectCallbackStarted(); + tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); final TetheringInterfaceRegexps tetherableRegexs = tetherEventCallback.getTetheringInterfaceRegexps(); @@ -422,10 +443,14 @@ public class TetheringManagerTest { } tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); + tetherEventCallback.expectOneOfOffloadStatusChanged( + TETHER_HARDWARE_OFFLOAD_STARTED, + TETHER_HARDWARE_OFFLOAD_FAILED); mTM.stopTethering(TETHERING_WIFI); tetherEventCallback.expectTetheredInterfacesChanged(null); + tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); mTM.unregisterTetheringEventCallback(tetherEventCallback); } From 13301d025a340f69493e3c77880c32dd96b51170 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 16 Apr 2020 00:18:31 +0000 Subject: [PATCH 0960/1415] Add test for NetworkRequest#canBeSatisfiedBy Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkRequestTest on both Q and R device Bug: 153972141 Change-Id: I614963cdd5f26bf3d47246fdc9eb11e74d05a460 Merged-In: I614963cdd5f26bf3d47246fdc9eb11e74d05a460 (cherry picked from commit 8f9325fcf28c4248eb3eb4bf21ec6a103eec614a) --- .../android/net/cts/NetworkRequestTest.java | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index 8b97c8cb92..751418657f 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -16,8 +16,11 @@ package android.net.cts; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static org.junit.Assert.assertEquals; @@ -26,13 +29,12 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.net.MacAddress; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.NetworkSpecifier; -import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiNetworkSpecifier; import android.os.Build; import android.os.PatternMatcher; -import android.util.Pair; import androidx.test.runner.AndroidJUnit4; @@ -49,6 +51,7 @@ public class NetworkRequestTest { public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); private static final String TEST_SSID = "TestSSID"; + private static final String OTHER_SSID = "OtherSSID"; private static final int TEST_UID = 2097; private static final String TEST_PACKAGE_NAME = "test.package.name"; private static final MacAddress ARBITRARY_ADDRESS = MacAddress.fromString("3:5:8:12:9:2"); @@ -84,4 +87,42 @@ public class NetworkRequestTest { .getNetworkSpecifier(); assertEquals(obtainedSpecifier, specifier); } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testCanBeSatisfiedBy() { + final WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL)) + .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + .build(); + final WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() + .setSsidPattern(new PatternMatcher(OTHER_SSID, PatternMatcher.PATTERN_LITERAL)) + .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + .build(); + final NetworkCapabilities cap = new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET); + final NetworkCapabilities capWithSp = + new NetworkCapabilities(cap).setNetworkSpecifier(specifier1); + final NetworkCapabilities cellCap = new NetworkCapabilities() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_MMS) + .addCapability(NET_CAPABILITY_INTERNET); + final NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .setNetworkSpecifier(specifier1) + .build(); + assertFalse(request.canBeSatisfiedBy(null)); + assertFalse(request.canBeSatisfiedBy(new NetworkCapabilities())); + assertTrue(request.canBeSatisfiedBy(cap)); + assertTrue(request.canBeSatisfiedBy( + new NetworkCapabilities(cap).addTransportType(TRANSPORT_VPN))); + assertTrue(request.canBeSatisfiedBy(capWithSp)); + assertFalse(request.canBeSatisfiedBy( + new NetworkCapabilities(cap).setNetworkSpecifier(specifier2))); + assertFalse(request.canBeSatisfiedBy(cellCap)); + assertEquals(request.canBeSatisfiedBy(capWithSp), + new NetworkCapabilities(capWithSp).satisfiedByNetworkCapabilities(capWithSp)); + } } From 3936e08f650fad6d7a3c3a57c5ec2ec562992a51 Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 14 Apr 2020 15:16:46 +0800 Subject: [PATCH 0961/1415] Add EntitlementResult CTS tests Test APIs below: requestLatestTetheringEntitlementResult(int, boolean, java.util.concurrent.Executor, android.net.TetheringManager.OnTetheringEntitlementResultListener) requestLatestTetheringEntitlementResult(int, android.os.ResultReceiver, boolean) OnTetheringEntitlementResultListener.onTetheringEntitlementResult(int) Bug: 152829363 Test: atests CtsTetheringTest Change-Id: Icf0d9cacd97eeaa7ceb78f4924c5a6be6e588b30 --- .../tethering/cts/TetheringManagerTest.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index f430f22371..ccad14cdd2 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -20,6 +20,8 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -35,9 +37,12 @@ import android.net.LinkAddress; import android.net.Network; import android.net.TetheredClient; import android.net.TetheringManager; +import android.net.TetheringManager.OnTetheringEntitlementResultListener; import android.net.TetheringManager.TetheringEventCallback; import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; +import android.os.Bundle; +import android.os.ResultReceiver; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; @@ -52,8 +57,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) public class TetheringManagerTest { @@ -472,11 +481,60 @@ public class TetheringManagerTest { assertEquals(usbRegexs, Arrays.asList(mTM.getTetherableUsbRegexs())); assertEquals(btRegexs, Arrays.asList(mTM.getTetherableBluetoothRegexs())); - //Verify that any of interface name should only contain in one array. + //Verify that any regex name should only contain in one array. wifiRegexs.forEach(s -> assertFalse(usbRegexs.contains(s))); wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); mTM.unregisterTetheringEventCallback(tetherEventCallback); } + + private class EntitlementResultListener implements OnTetheringEntitlementResultListener { + private final CompletableFuture future = new CompletableFuture<>(); + + @Override + public void onTetheringEntitlementResult(int result) { + future.complete(result); + } + + public int get(long timeout, TimeUnit unit) throws Exception { + return future.get(timeout, unit); + } + + } + + private void assertEntitlementResult(final Consumer functor, + final int expect) throws Exception { + final EntitlementResultListener listener = new EntitlementResultListener(); + functor.accept(listener); + + assertEquals(expect, listener.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + + @Test + public void testRequestLatestEntitlementResult() throws Exception { + // Verify that requestLatestTetheringEntitlementResult() can get entitlement + // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener. + assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI_P2P, false, c -> c.run(), listener), + TETHER_ERROR_ENTITLEMENT_UNKNOWN); + + // Verify that requestLatestTetheringEntitlementResult() can get entitlement + // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via receiver. + assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI_P2P, + new ResultReceiver(null /* handler */) { + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + listener.onTetheringEntitlementResult(resultCode); + } + }, false), + TETHER_ERROR_ENTITLEMENT_UNKNOWN); + + // Verify that null listener will cause IllegalArgumentException. + try { + mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI, false, c -> c.run(), null); + } catch (IllegalArgumentException expect) { } + } } From 1317e27e91b9eb08f9769cb5dae0526235d3000d Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 16 Apr 2020 14:35:49 +0800 Subject: [PATCH 0962/1415] [TNU05.1] Address aosp/1237036 leftover comments Bug: 147818698 Test: atest TetheringTests Change-Id: Ife738339aeae00d2063fea6918b50204daef24fc --- .../TetheringNotificationUpdater.java | 18 ++++++++---------- .../TetheringNotificationUpdaterTest.kt | 3 ++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index ff83fd1e4f..de2f90e50e 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -50,9 +50,6 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; -import java.util.Arrays; -import java.util.List; - /** * A class to display tethering-related notifications. * @@ -89,6 +86,9 @@ public class TetheringNotificationUpdater { static final int NO_ICON_ID = 0; @VisibleForTesting static final int DOWNSTREAM_NONE = 0; + // Refer to TelephonyManager#getSimCarrierId for more details about carrier id. + @VisibleForTesting + static final int VERIZON_CARRIER_ID = 1839; private final Context mContext; private final NotificationManager mNotificationManager; private final NotificationChannel mChannel; @@ -114,11 +114,11 @@ public class TetheringNotificationUpdater { @interface NotificationId {} private static final class MccMncOverrideInfo { - public final List visitedMccMncs; + public final String visitedMccMnc; public final int homeMcc; public final int homeMnc; - MccMncOverrideInfo(List visitedMccMncs, int mcc, int mnc) { - this.visitedMccMncs = visitedMccMncs; + MccMncOverrideInfo(String visitedMccMnc, int mcc, int mnc) { + this.visitedMccMnc = visitedMccMnc; this.homeMcc = mcc; this.homeMnc = mnc; } @@ -127,9 +127,7 @@ public class TetheringNotificationUpdater { private static final SparseArray sCarrierIdToMccMnc = new SparseArray<>(); static { - // VZW - sCarrierIdToMccMnc.put( - 1839, new MccMncOverrideInfo(Arrays.asList(new String[] {"20404"}), 311, 480)); + sCarrierIdToMccMnc.put(VERIZON_CARRIER_ID, new MccMncOverrideInfo("20404", 311, 480)); } public TetheringNotificationUpdater(@NonNull final Context context, @@ -200,7 +198,7 @@ public class TetheringNotificationUpdater { final int carrierId = tm.getSimCarrierId(); final String mccmnc = tm.getSimOperator(); final MccMncOverrideInfo overrideInfo = sCarrierIdToMccMnc.get(carrierId); - if (overrideInfo != null && overrideInfo.visitedMccMncs.contains(mccmnc)) { + if (overrideInfo != null && overrideInfo.visitedMccMnc.equals(mccmnc)) { // Re-configure MCC/MNC value to specific carrier to get right resources. final Configuration config = res.getConfiguration(); config.mcc = overrideInfo.homeMcc; diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 5f8858857c..294bf1b7e1 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -39,6 +39,7 @@ import com.android.networkstack.tethering.TetheringNotificationUpdater.ENABLE_NO import com.android.networkstack.tethering.TetheringNotificationUpdater.EVENT_SHOW_NO_UPSTREAM import com.android.networkstack.tethering.TetheringNotificationUpdater.NO_UPSTREAM_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.RESTRICTED_NOTIFICATION_ID +import com.android.networkstack.tethering.TetheringNotificationUpdater.VERIZON_CARRIER_ID import com.android.testutils.waitForIdle import org.junit.After import org.junit.Assert.assertEquals @@ -417,7 +418,7 @@ class TetheringNotificationUpdaterTest { assertEquals(config.mcc, res.configuration.mcc) assertEquals(config.mnc, res.configuration.mnc) - doReturn(1839).`when`(telephonyManager).getSimCarrierId() + doReturn(VERIZON_CARRIER_ID).`when`(telephonyManager).getSimCarrierId() res = notificationUpdater.getResourcesForSubId(context, subId) assertEquals(config.mcc, res.configuration.mcc) assertEquals(config.mnc, res.configuration.mnc) From 5585672f92d679911a461fa37a994b83e5c0bad1 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 30 Mar 2020 17:30:46 +0800 Subject: [PATCH 0963/1415] Add tests for NetworkRequest API This change inculdes coverage of NetworkRequest#Builder().clearCapabilities() and NetworkRequest#getRequestorPackageName() Bug: 153614623 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkRequestTest Change-Id: Id4e31013cfae78c25abd27b557da4e3e9487870c --- .../android/net/cts/NetworkRequestTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index 751418657f..08bf1e424b 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -62,6 +62,18 @@ public class NetworkRequestTest { .hasCapability(NET_CAPABILITY_MMS)); assertFalse(new NetworkRequest.Builder().removeCapability(NET_CAPABILITY_MMS).build() .hasCapability(NET_CAPABILITY_MMS)); + + final NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build(); + // Verify request has no capabilities + verifyNoCapabilities(nr); + } + + private void verifyNoCapabilities(NetworkRequest nr) { + // NetworkCapabilities.mNetworkCapabilities is defined as type long + final int MAX_POSSIBLE_CAPABILITY = Long.SIZE; + for(int bit = 0; bit < MAX_POSSIBLE_CAPABILITY; bit++) { + assertFalse(nr.hasCapability(bit)); + } } @Test @@ -86,6 +98,29 @@ public class NetworkRequestTest { .build() .getNetworkSpecifier(); assertEquals(obtainedSpecifier, specifier); + + assertNull(new NetworkRequest.Builder() + .clearCapabilities() + .build() + .getNetworkSpecifier()); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testRequestorPackageName() { + assertNull(new NetworkRequest.Builder().build().getRequestorPackageName()); + final String pkgName = "android.net.test"; + final NetworkCapabilities nc = new NetworkCapabilities.Builder() + .setRequestorPackageName(pkgName) + .build(); + final NetworkRequest nr = new NetworkRequest.Builder() + .setCapabilities(nc) + .build(); + assertEquals(pkgName, nr.getRequestorPackageName()); + assertNull(new NetworkRequest.Builder() + .clearCapabilities() + .build() + .getRequestorPackageName()); } @Test From 85f0fca1f071250fcb8f286e6bca30d0fcd8a965 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 10 Apr 2020 11:09:14 +0800 Subject: [PATCH 0964/1415] Add more tests to CtsTetheringTest Add TetheringIntegrationTests into CtsTetheringTest Bug: 148636687 Test: atest CtsTetheringTest atest TetheringIntegrationTests Change-Id: I606097a8db9ed3d2b3eaf933bb1d904e437ab27d --- tests/cts/tethering/Android.bp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 0f98125d6f..63de301d69 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -25,12 +25,19 @@ android_test { ], static_libs: [ + "TetheringIntegrationTestsLib", "compatibility-device-util-axt", "ctstestrunner-axt", "junit", "junit-params", ], + jni_libs: [ + // For mockito extended + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], + // Change to system current when TetheringManager move to bootclass path. platform_apis: true, @@ -41,4 +48,6 @@ android_test { "mts", ], + // Include both the 32 and 64 bit versions + compile_multilib: "both", } From bbc5554392548ebebc09c9469b03353b35c4f9f4 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 20 Mar 2020 16:36:24 +0800 Subject: [PATCH 0965/1415] Add test for NetworkRequest#getRequestorUid() Add test for new API. Bug: 151110379 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkRequestTest Change-Id: I9602cac142b3e45d12e66a6f3f35ab594e6590c1 --- .../src/android/net/cts/NetworkRequestTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index 08bf1e424b..6a1d9de6f6 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -34,6 +34,7 @@ import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.wifi.WifiNetworkSpecifier; import android.os.Build; +import android.os.Process; import android.os.PatternMatcher; import androidx.test.runner.AndroidJUnit4; @@ -160,4 +161,19 @@ public class NetworkRequestTest { assertEquals(request.canBeSatisfiedBy(capWithSp), new NetworkCapabilities(capWithSp).satisfiedByNetworkCapabilities(capWithSp)); } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testRequestorUid() { + final NetworkCapabilities nc = new NetworkCapabilities(); + // Verify default value is INVALID_UID + assertEquals(Process.INVALID_UID, new NetworkRequest.Builder() + .setCapabilities(nc).build().getRequestorUid()); + + nc.setRequestorUid(1314); + final NetworkRequest nr = new NetworkRequest.Builder().setCapabilities(nc).build(); + assertEquals(1314, nr.getRequestorUid()); + + assertEquals(Process.INVALID_UID, new NetworkRequest.Builder() + .clearCapabilities().build().getRequestorUid()); + } } From 23e025e47ccb0b2f19d2dc428809880331d760e0 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 16 Apr 2020 00:19:16 +0000 Subject: [PATCH 0966/1415] Create TestNetworkUtils for IKE and IPsec CTS Create TestNetworkUtils that provides interfaces to set up test network. It will be used by both IKE and IPsec CTS Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I1c49711d3c6ce03ceafdbf3004e25d9d59a6201c Merged-In: I1c49711d3c6ce03ceafdbf3004e25d9d59a6201c (cherry picked from commit 91b034d5c649d8b7de1ff6d936f4859f927eb202) --- .../net/ipsec/ike/cts/TestNetworkUtils.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java new file mode 100644 index 0000000000..5b08cdc8f2 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java @@ -0,0 +1,87 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; + +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkRequest; +import android.net.TestNetworkManager; +import android.os.IBinder; +import android.os.RemoteException; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +// TODO(b/148689509): Share this class with net CTS test (e.g. IpSecManagerTunnelTest) +public class TestNetworkUtils { + private static final int TIMEOUT_MS = 500; + + /** Callback to receive requested test network. */ + public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CompletableFuture futureNetwork = new CompletableFuture<>(); + + @Override + public void onAvailable(Network network) { + futureNetwork.complete(network); + } + + public Network getNetworkBlocking() throws Exception { + return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + /** + * Set up test network. + * + *

    Caller MUST have MANAGE_TEST_NETWORKS permission to use this method. + * + * @param connMgr ConnectivityManager to request network. + * @param testNetworkMgr TestNetworkManager to set up test network. + * @param ifname the name of the interface to be used for the Network LinkProperties. + * @param binder a binder object guarding the lifecycle of this test network. + * @return TestNetworkCallback to retrieve the test network. + * @throws RemoteException if test network setup failed. + * @see android.net.TestNetworkManager + */ + public static TestNetworkCallback setupAndGetTestNetwork( + ConnectivityManager connMgr, + TestNetworkManager testNetworkMgr, + String ifname, + IBinder binder) + throws RemoteException { + NetworkRequest nr = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_TEST) + .removeCapability(NET_CAPABILITY_TRUSTED) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .setNetworkSpecifier(ifname) + .build(); + + TestNetworkCallback cb = new TestNetworkCallback(); + connMgr.requestNetwork(nr, cb); + + // Setup the test network after network request is filed to prevent Network from being + // reaped due to no requests matching it. + testNetworkMgr.setupTestNetwork(ifname, binder); + + return cb; + } +} From 8d10ebe3d70964c3dd5fc0fe3adfe20d045290fe Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Fri, 17 Apr 2020 06:10:14 +0000 Subject: [PATCH 0967/1415] Add EntitlementResult CTS tests Test APIs below: requestLatestTetheringEntitlementResult(int, boolean, java.util.concurrent.Executor, android.net.TetheringManager.OnTetheringEntitlementResultListener) requestLatestTetheringEntitlementResult(int, android.os.ResultReceiver, boolean) OnTetheringEntitlementResultListener.onTetheringEntitlementResult(int) Bug: 152829363 Test: atests CtsTetheringTest Change-Id: Icf0d9cacd97eeaa7ceb78f4924c5a6be6e588b30 Merged-In: Icf0d9cacd97eeaa7ceb78f4924c5a6be6e588b30 (cherry picked from commit 4bed8dff67d4a6824098188cd9602668d8705a7e, aosp/1272946) --- .../tethering/cts/TetheringManagerTest.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index f430f22371..ccad14cdd2 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -20,6 +20,8 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -35,9 +37,12 @@ import android.net.LinkAddress; import android.net.Network; import android.net.TetheredClient; import android.net.TetheringManager; +import android.net.TetheringManager.OnTetheringEntitlementResultListener; import android.net.TetheringManager.TetheringEventCallback; import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; +import android.os.Bundle; +import android.os.ResultReceiver; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; @@ -52,8 +57,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) public class TetheringManagerTest { @@ -472,11 +481,60 @@ public class TetheringManagerTest { assertEquals(usbRegexs, Arrays.asList(mTM.getTetherableUsbRegexs())); assertEquals(btRegexs, Arrays.asList(mTM.getTetherableBluetoothRegexs())); - //Verify that any of interface name should only contain in one array. + //Verify that any regex name should only contain in one array. wifiRegexs.forEach(s -> assertFalse(usbRegexs.contains(s))); wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); mTM.unregisterTetheringEventCallback(tetherEventCallback); } + + private class EntitlementResultListener implements OnTetheringEntitlementResultListener { + private final CompletableFuture future = new CompletableFuture<>(); + + @Override + public void onTetheringEntitlementResult(int result) { + future.complete(result); + } + + public int get(long timeout, TimeUnit unit) throws Exception { + return future.get(timeout, unit); + } + + } + + private void assertEntitlementResult(final Consumer functor, + final int expect) throws Exception { + final EntitlementResultListener listener = new EntitlementResultListener(); + functor.accept(listener); + + assertEquals(expect, listener.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + + @Test + public void testRequestLatestEntitlementResult() throws Exception { + // Verify that requestLatestTetheringEntitlementResult() can get entitlement + // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener. + assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI_P2P, false, c -> c.run(), listener), + TETHER_ERROR_ENTITLEMENT_UNKNOWN); + + // Verify that requestLatestTetheringEntitlementResult() can get entitlement + // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via receiver. + assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI_P2P, + new ResultReceiver(null /* handler */) { + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + listener.onTetheringEntitlementResult(resultCode); + } + }, false), + TETHER_ERROR_ENTITLEMENT_UNKNOWN); + + // Verify that null listener will cause IllegalArgumentException. + try { + mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI, false, c -> c.run(), null); + } catch (IllegalArgumentException expect) { } + } } From 685f072bfde95cf5e38e5406bfa8365ad2c141b5 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Fri, 17 Apr 2020 06:10:36 +0000 Subject: [PATCH 0968/1415] Add more tests to CtsTetheringTest Add TetheringIntegrationTests into CtsTetheringTest Bug: 148636687 Test: atest CtsTetheringTest atest TetheringIntegrationTests Change-Id: I606097a8db9ed3d2b3eaf933bb1d904e437ab27d Merged-In: I606097a8db9ed3d2b3eaf933bb1d904e437ab27d (cherry picked from commit 1f7305c9740a7a1a724c4023f8c55ce827391f73, aosp/1280233) --- tests/cts/tethering/Android.bp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 0f98125d6f..63de301d69 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -25,12 +25,19 @@ android_test { ], static_libs: [ + "TetheringIntegrationTestsLib", "compatibility-device-util-axt", "ctstestrunner-axt", "junit", "junit-params", ], + jni_libs: [ + // For mockito extended + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], + // Change to system current when TetheringManager move to bootclass path. platform_apis: true, @@ -41,4 +48,6 @@ android_test { "mts", ], + // Include both the 32 and 64 bit versions + compile_multilib: "both", } From 48e081279645d56fbe0ad57aaedd1b8c298a6f8d Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 17 Apr 2020 17:48:53 +0800 Subject: [PATCH 0969/1415] Move DhcpInfoTest to FrameworksNetCommonTests Move to frameworks/base/tests/net/common so that it can be run in cts test and presubmit test. Bug: 154299158 Test: atest CtsNetTestCasesLatestSdk:android.net.DhcpInfoTest Change-Id: I8d70565fe3388fd8351002f2ed87c43343879e57 --- .../net/src/android/net/cts/DhcpInfoTest.java | 114 ------------------ 1 file changed, 114 deletions(-) delete mode 100644 tests/cts/net/src/android/net/cts/DhcpInfoTest.java diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java deleted file mode 100644 index b8d239272a..0000000000 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2009 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.net.shared.Inet4AddressUtils.inet4AddressToIntHTL; - -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; -import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.annotation.Nullable; -import android.net.DhcpInfo; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.net.InetAddress; - -@RunWith(AndroidJUnit4.class) -public class DhcpInfoTest { - private static final String STR_ADDR1 = "255.255.255.255"; - private static final String STR_ADDR2 = "127.0.0.1"; - private static final String STR_ADDR3 = "192.168.1.1"; - private static final String STR_ADDR4 = "192.168.1.0"; - private static final int LEASE_TIME = 9999; - - private int ipToInteger(String ipString) throws Exception { - return inet4AddressToIntHTL((Inet4Address) InetAddress.getByName(ipString)); - } - - private DhcpInfo createDhcpInfoObject() throws Exception { - final DhcpInfo dhcpInfo = new DhcpInfo(); - dhcpInfo.ipAddress = ipToInteger(STR_ADDR1); - dhcpInfo.gateway = ipToInteger(STR_ADDR2); - dhcpInfo.netmask = ipToInteger(STR_ADDR3); - dhcpInfo.dns1 = ipToInteger(STR_ADDR4); - dhcpInfo.dns2 = ipToInteger(STR_ADDR4); - dhcpInfo.serverAddress = ipToInteger(STR_ADDR2); - dhcpInfo.leaseDuration = LEASE_TIME; - return dhcpInfo; - } - - @Test - public void testConstructor() { - new DhcpInfo(); - } - - @Test - public void testToString() throws Exception { - final String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 " - + "dns1 0.0.0.0 dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; - - DhcpInfo dhcpInfo = new DhcpInfo(); - - // Test default string. - assertEquals(expectedDefault, dhcpInfo.toString()); - - dhcpInfo = createDhcpInfoObject(); - - final String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask " - + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server " - + STR_ADDR2 + " lease " + LEASE_TIME + " seconds"; - // Test with new values - assertEquals(expected, dhcpInfo.toString()); - } - - private boolean dhcpInfoEquals(@Nullable DhcpInfo left, @Nullable DhcpInfo right) { - if (left == null && right == null) return true; - - if (left == null || right == null) return false; - - return left.ipAddress == right.ipAddress - && left.gateway == right.gateway - && left.netmask == right.netmask - && left.dns1 == right.dns1 - && left.dns2 == right.dns2 - && left.serverAddress == right.serverAddress - && left.leaseDuration == right.leaseDuration; - } - - @Test - public void testParcelDhcpInfo() throws Exception { - // Cannot use assertParcelSane() here because this requires .equals() to work as - // defined, but DhcpInfo has a different legacy behavior that we cannot change. - final DhcpInfo dhcpInfo = createDhcpInfoObject(); - assertFieldCountEquals(7, DhcpInfo.class); - - final DhcpInfo dhcpInfoRoundTrip = parcelingRoundTrip(dhcpInfo); - assertTrue(dhcpInfoEquals(null, null)); - assertFalse(dhcpInfoEquals(null, dhcpInfoRoundTrip)); - assertFalse(dhcpInfoEquals(dhcpInfo, null)); - assertTrue(dhcpInfoEquals(dhcpInfo, dhcpInfoRoundTrip)); - } -} From 1f66261a3c973dd0748d365ea71b0a0993b1c4e2 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 26 Mar 2020 15:29:53 +0800 Subject: [PATCH 0970/1415] [TNU06] Add roaming notification Warn user of potential data charges if the backhaul is cellular and user is roaming. Bug: 145629001 Test: atest TetheringTests Change-Id: I74b4f87c2f6aad09e05d3f2a779f880396885953 --- Tethering/res/values-mcc310-mnc004/config.xml | 3 + Tethering/res/values-mcc311-mnc480/config.xml | 3 + Tethering/res/values/config.xml | 5 + .../networkstack/tethering/Tethering.java | 17 +- .../TetheringNotificationUpdater.java | 102 +++++++--- .../TetheringNotificationUpdaterTest.kt | 186 +++++++++++------- .../networkstack/tethering/TetheringTest.java | 25 ++- 7 files changed, 247 insertions(+), 94 deletions(-) diff --git a/Tethering/res/values-mcc310-mnc004/config.xml b/Tethering/res/values-mcc310-mnc004/config.xml index 8c627d5df0..5c5be0466a 100644 --- a/Tethering/res/values-mcc310-mnc004/config.xml +++ b/Tethering/res/values-mcc310-mnc004/config.xml @@ -17,4 +17,7 @@ 5000 + + + true \ No newline at end of file diff --git a/Tethering/res/values-mcc311-mnc480/config.xml b/Tethering/res/values-mcc311-mnc480/config.xml index 8c627d5df0..5c5be0466a 100644 --- a/Tethering/res/values-mcc311-mnc480/config.xml +++ b/Tethering/res/values-mcc311-mnc480/config.xml @@ -17,4 +17,7 @@ 5000 + + + true \ No newline at end of file diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index 780a015961..aed5ab8df6 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -206,4 +206,9 @@ -1 + + + + false diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 14d288699e..97b19466b3 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -81,6 +81,7 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.TetherStatesParcel; import android.net.TetheredClient; @@ -1476,7 +1477,7 @@ public class Tethering { if (mTetherUpstream != newUpstream) { mTetherUpstream = newUpstream; mUpstreamNetworkMonitor.setCurrentUpstream(mTetherUpstream); - reportUpstreamChanged(mTetherUpstream); + reportUpstreamChanged(ns); } } @@ -1598,7 +1599,8 @@ public class Tethering { } } - private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { + @VisibleForTesting + void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) { mOffload.sendOffloadExemptPrefixes((Set) o); return; @@ -1624,6 +1626,9 @@ public class Tethering { switch (arg1) { case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES: + if (ns.network.equals(mTetherUpstream)) { + mNotificationUpdater.onUpstreamCapabilitiesChanged(ns.networkCapabilities); + } handleNewUpstreamNetworkState(ns); break; case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES: @@ -2009,8 +2014,10 @@ public class Tethering { }); } - private void reportUpstreamChanged(Network network) { + private void reportUpstreamChanged(UpstreamNetworkState ns) { final int length = mTetheringEventCallbacks.beginBroadcast(); + final Network network = (ns != null) ? ns.network : null; + final NetworkCapabilities capabilities = (ns != null) ? ns.networkCapabilities : null; try { for (int i = 0; i < length; i++) { try { @@ -2022,7 +2029,9 @@ public class Tethering { } finally { mTetheringEventCallbacks.finishBroadcast(); } - mNotificationUpdater.onUpstreamNetworkChanged(network); + // Need to notify capabilities change after upstream network changed because new network's + // capabilities should be checked every time. + mNotificationUpdater.onUpstreamCapabilitiesChanged(capabilities); } private void reportConfigurationChanged(TetheringConfigurationParcel config) { diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index de2f90e50e..f490cc4719 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -16,6 +16,7 @@ package com.android.networkstack.tethering; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; @@ -30,7 +31,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; -import android.net.Network; +import android.net.NetworkCapabilities; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -50,6 +51,9 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * A class to display tethering-related notifications. * @@ -82,6 +86,9 @@ public class TetheringNotificationUpdater { // Id to update and cancel no upstream notification. Must be unique within the tethering app. @VisibleForTesting static final int NO_UPSTREAM_NOTIFICATION_ID = 1002; + // Id to update and cancel roaming notification. Must be unique within the tethering app. + @VisibleForTesting + static final int ROAMING_NOTIFICATION_ID = 1003; @VisibleForTesting static final int NO_ICON_ID = 0; @VisibleForTesting @@ -95,13 +102,14 @@ public class TetheringNotificationUpdater { private final Handler mHandler; // WARNING : the constructor is called on a different thread. Thread safety therefore - // relies on these values being initialized to 0 or false, and not any other value. If you need - // to change this, you will need to change the thread where the constructor is invoked, - // or to introduce synchronization. + // relies on these values being initialized to 0, false or null, and not any other value. If you + // need to change this, you will need to change the thread where the constructor is invoked, or + // to introduce synchronization. // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2. // This value has to be made 1 2 and 4, and OR'd with the others. private int mDownstreamTypesMask = DOWNSTREAM_NONE; private boolean mNoUpstream = false; + private boolean mRoaming = false; // WARNING : this value is not able to being initialized to 0 and must have volatile because // telephony service is not guaranteed that is up before tethering service starts. If telephony @@ -110,7 +118,13 @@ public class TetheringNotificationUpdater { // INVALID_SUBSCRIPTION_ID. private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - @IntDef({ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID}) + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + ENABLE_NOTIFICATION_ID, + RESTRICTED_NOTIFICATION_ID, + NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID + }) @interface NotificationId {} private static final class MccMncOverrideInfo { @@ -160,26 +174,22 @@ public class TetheringNotificationUpdater { /** Called when downstream has changed */ public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) { - if (mDownstreamTypesMask == downstreamTypesMask) return; - mDownstreamTypesMask = downstreamTypesMask; - updateEnableNotification(); - updateNoUpstreamNotification(); + updateActiveNotifications( + mActiveDataSubId, downstreamTypesMask, mNoUpstream, mRoaming); } /** Called when active data subscription id changed */ public void onActiveDataSubscriptionIdChanged(final int subId) { - if (mActiveDataSubId == subId) return; - mActiveDataSubId = subId; - updateEnableNotification(); - updateNoUpstreamNotification(); + updateActiveNotifications(subId, mDownstreamTypesMask, mNoUpstream, mRoaming); } - /** Called when upstream network changed */ - public void onUpstreamNetworkChanged(@Nullable final Network network) { - final boolean isNoUpstream = (network == null); - if (mNoUpstream == isNoUpstream) return; - mNoUpstream = isNoUpstream; - updateNoUpstreamNotification(); + /** Called when upstream network capabilities changed */ + public void onUpstreamCapabilitiesChanged(@Nullable final NetworkCapabilities capabilities) { + final boolean isNoUpstream = (capabilities == null); + final boolean isRoaming = capabilities != null + && !capabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING); + updateActiveNotifications( + mActiveDataSubId, mDownstreamTypesMask, isNoUpstream, isRoaming); } @NonNull @@ -208,6 +218,25 @@ public class TetheringNotificationUpdater { return res; } + private void updateActiveNotifications(final int subId, final int downstreamTypes, + final boolean noUpstream, final boolean isRoaming) { + final boolean tetheringActiveChanged = + (downstreamTypes == DOWNSTREAM_NONE) != (mDownstreamTypesMask == DOWNSTREAM_NONE); + final boolean subIdChanged = subId != mActiveDataSubId; + final boolean downstreamChanged = downstreamTypes != mDownstreamTypesMask; + final boolean upstreamChanged = noUpstream != mNoUpstream; + final boolean roamingChanged = isRoaming != mRoaming; + final boolean updateAll = tetheringActiveChanged || subIdChanged; + mActiveDataSubId = subId; + mDownstreamTypesMask = downstreamTypes; + mNoUpstream = noUpstream; + mRoaming = isRoaming; + + if (updateAll || downstreamChanged) updateEnableNotification(); + if (updateAll || upstreamChanged) updateNoUpstreamNotification(); + if (updateAll || roamingChanged) updateRoamingNotification(); + } + private void updateEnableNotification() { final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE; @@ -219,14 +248,20 @@ public class TetheringNotificationUpdater { private void updateNoUpstreamNotification() { final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE; - if (tetheringInactive - || !mNoUpstream - || setupNoUpstreamNotification() == NO_NOTIFY) { + if (tetheringInactive || !mNoUpstream || setupNoUpstreamNotification() == NO_NOTIFY) { clearNotification(NO_UPSTREAM_NOTIFICATION_ID); mHandler.removeMessages(EVENT_SHOW_NO_UPSTREAM); } } + private void updateRoamingNotification() { + final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE; + + if (tetheringInactive || !mRoaming || setupRoamingNotification() == NO_NOTIFY) { + clearNotification(ROAMING_NOTIFICATION_ID); + } + } + @VisibleForTesting void tetheringRestrictionLifted() { clearNotification(RESTRICTED_NOTIFICATION_ID); @@ -333,6 +368,29 @@ public class TetheringNotificationUpdater { return icons; } + private boolean setupRoamingNotification() { + final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); + final boolean upstreamRoamingNotification = + res.getBoolean(R.bool.config_upstream_roaming_notification); + + if (!upstreamRoamingNotification) return NO_NOTIFY; + + final String title = res.getString(R.string.upstream_roaming_notification_title); + final String message = res.getString(R.string.upstream_roaming_notification_message); + if (isEmpty(title) || isEmpty(message)) return NO_NOTIFY; + + final PendingIntent pi = PendingIntent.getActivity( + mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), + 0 /* requestCode */, + new Intent(Settings.ACTION_TETHER_SETTINGS), + Intent.FLAG_ACTIVITY_NEW_TASK, + null /* options */); + + showNotification(R.drawable.stat_sys_tether_general, title, message, + ROAMING_NOTIFICATION_ID, pi, new Action[0]); + return NOTIFY_DONE; + } + private boolean setupNoUpstreamNotification() { final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); final int delayToShowUpstreamNotification = diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 294bf1b7e1..04f31a7a28 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -23,10 +23,11 @@ import android.content.res.Resources import android.net.ConnectivityManager.TETHERING_BLUETOOTH import android.net.ConnectivityManager.TETHERING_USB import android.net.ConnectivityManager.TETHERING_WIFI -import android.net.Network import android.os.Handler import android.os.HandlerThread import android.os.Looper +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING import android.os.UserHandle import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.telephony.TelephonyManager @@ -39,6 +40,7 @@ import com.android.networkstack.tethering.TetheringNotificationUpdater.ENABLE_NO import com.android.networkstack.tethering.TetheringNotificationUpdater.EVENT_SHOW_NO_UPSTREAM import com.android.networkstack.tethering.TetheringNotificationUpdater.NO_UPSTREAM_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.RESTRICTED_NOTIFICATION_ID +import com.android.networkstack.tethering.TetheringNotificationUpdater.ROAMING_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.VERIZON_CARRIER_ID import com.android.testutils.waitForIdle import org.junit.After @@ -75,6 +77,8 @@ const val TEST_MESSAGE = "Tap to set up hotspot." const val TEST_NO_UPSTREAM_TITLE = "Hotspot has no internet access" const val TEST_NO_UPSTREAM_MESSAGE = "Device cannot connect to internet." const val TEST_NO_UPSTREAM_BUTTON = "Turn off hotspot" +const val TEST_ROAMING_TITLE = "Hotspot is on" +const val TEST_ROAMING_MESSAGE = "Additional charges may apply while roaming." @RunWith(AndroidJUnit4::class) @SmallTest @@ -98,6 +102,11 @@ class TetheringNotificationUpdaterTest { "WIFI|BT;android.test:drawable/general", "WIFI|USB;android.test:drawable/general", "USB|BT;android.test:drawable/general", "WIFI|USB|BT;android.test:drawable/general") + private val ROAMING_CAPABILITIES = NetworkCapabilities() + private val HOME_CAPABILITIES = NetworkCapabilities().addCapability(NET_CAPABILITY_NOT_ROAMING) + private val NOTIFICATION_ICON_ID = R.drawable.stat_sys_tether_general + private val TIMEOUT_MS = 500L + private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) { override fun createContextAsUser(user: UserHandle, flags: Int) = if (user == UserHandle.ALL) mockContext else this @@ -123,6 +132,8 @@ class TetheringNotificationUpdaterTest { .getStringArray(R.array.tethering_notification_icons) doReturn(5).`when`(testResources) .getInteger(R.integer.delay_to_show_no_upstream_after_no_backhaul) + doReturn(true).`when`(testResources) + .getBoolean(R.bool.config_upstream_roaming_notification) doReturn(TITLE).`when`(defaultResources).getString(R.string.tethering_notification_title) doReturn(MESSAGE).`when`(defaultResources) .getString(R.string.tethering_notification_message) @@ -135,6 +146,10 @@ class TetheringNotificationUpdaterTest { .getString(R.string.no_upstream_notification_message) doReturn(TEST_NO_UPSTREAM_BUTTON).`when`(testResources) .getString(R.string.no_upstream_notification_disable_button) + doReturn(TEST_ROAMING_TITLE).`when`(testResources) + .getString(R.string.upstream_roaming_notification_title) + doReturn(TEST_ROAMING_MESSAGE).`when`(testResources) + .getString(R.string.upstream_roaming_notification_message) doReturn(USB_ICON_ID).`when`(defaultResources) .getIdentifier(eq("android.test:drawable/usb"), any(), any()) doReturn(BT_ICON_ID).`when`(defaultResources) @@ -176,41 +191,25 @@ class TetheringNotificationUpdaterTest { assertEquals(iconId, notification.smallIcon.resId) assertEquals(title, notification.title()) assertEquals(text, notification.text()) - } - private fun verifyNotificationCancelled(id: Int) = - verify(notificationManager, times(1)).cancel(any(), eq(id)) - - private val tetheringActiveNotifications = - listOf(NO_UPSTREAM_NOTIFICATION_ID, ENABLE_NOTIFICATION_ID) - - private fun verifyCancelAllTetheringActiveNotifications() { - tetheringActiveNotifications.forEach { - verifyNotificationCancelled(it) - } reset(notificationManager) } - private fun verifyOnlyTetheringActiveNotification( - notifyId: Int, - iconId: Int, - title: String, - text: String + private fun verifyNotificationCancelled( + notificationIds: List, + resetAfterVerified: Boolean = true ) { - tetheringActiveNotifications.forEach { - when (it) { - notifyId -> verifyNotification(iconId, title, text, notifyId) - else -> verifyNotificationCancelled(it) - } + notificationIds.forEach { + verify(notificationManager, times(1)).cancel(any(), eq(it)) } - reset(notificationManager) + if (resetAfterVerified) reset(notificationManager) } @Test fun testNotificationWithDownstreamChanged() { // Wifi downstream. No notification. notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyCancelAllTetheringActiveNotifications() + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID)) // Same downstream changed. Nothing happened. notificationUpdater.onDownstreamChanged(WIFI_MASK) @@ -218,23 +217,23 @@ class TetheringNotificationUpdaterTest { // Wifi and usb downstreams. Show enable notification notificationUpdater.onDownstreamChanged(WIFI_MASK or USB_MASK) - verifyOnlyTetheringActiveNotification( - ENABLE_NOTIFICATION_ID, GENERAL_ICON_ID, TITLE, MESSAGE) + verifyNotification(GENERAL_ICON_ID, TITLE, MESSAGE, ENABLE_NOTIFICATION_ID) // Usb downstream. Still show enable notification. notificationUpdater.onDownstreamChanged(USB_MASK) - verifyOnlyTetheringActiveNotification(ENABLE_NOTIFICATION_ID, USB_ICON_ID, TITLE, MESSAGE) + verifyNotification(USB_ICON_ID, TITLE, MESSAGE, ENABLE_NOTIFICATION_ID) // No downstream. No notification. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyCancelAllTetheringActiveNotifications() + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID)) } @Test fun testNotificationWithActiveDataSubscriptionIdChanged() { // Usb downstream. Showed enable notification with default resource. notificationUpdater.onDownstreamChanged(USB_MASK) - verifyOnlyTetheringActiveNotification(ENABLE_NOTIFICATION_ID, USB_ICON_ID, TITLE, MESSAGE) + verifyNotification(USB_ICON_ID, TITLE, MESSAGE, ENABLE_NOTIFICATION_ID) // Same subId changed. Nothing happened. notificationUpdater.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID) @@ -242,16 +241,17 @@ class TetheringNotificationUpdaterTest { // Set test sub id. Clear notification with test resource. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyCancelAllTetheringActiveNotifications() + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID)) // Wifi downstream. Show enable notification with test resource. notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyOnlyTetheringActiveNotification( - ENABLE_NOTIFICATION_ID, WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE) + verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) // No downstream. No notification. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyCancelAllTetheringActiveNotifications() + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID)) } private fun assertIconNumbers(number: Int, configs: Array) { @@ -305,24 +305,21 @@ class TetheringNotificationUpdaterTest { // User restrictions on. Show restricted notification. notificationUpdater.notifyTetheringDisabledByRestriction() - verifyNotification(R.drawable.stat_sys_tether_general, title, message, - RESTRICTED_NOTIFICATION_ID) - reset(notificationManager) + verifyNotification(NOTIFICATION_ICON_ID, title, message, RESTRICTED_NOTIFICATION_ID) // User restrictions off. Clear notification. notificationUpdater.tetheringRestrictionLifted() - verifyNotificationCancelled(RESTRICTED_NOTIFICATION_ID) - reset(notificationManager) + verifyNotificationCancelled(listOf(RESTRICTED_NOTIFICATION_ID)) // Set test sub id. No notification. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyCancelAllTetheringActiveNotifications() + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID)) // User restrictions on again. Show restricted notification with test resource. notificationUpdater.notifyTetheringDisabledByRestriction() - verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage, + verifyNotification(NOTIFICATION_ICON_ID, disallowTitle, disallowMessage, RESTRICTED_NOTIFICATION_ID) - reset(notificationManager) } val MAX_BACKOFF_MS = 200L @@ -359,51 +356,53 @@ class TetheringNotificationUpdaterTest { } @Test - fun testNotificationWithUpstreamNetworkChanged() { + fun testNotificationWithUpstreamCapabilitiesChanged_NoUpstream() { // Set test sub id. No notification. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyCancelAllTetheringActiveNotifications() + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID)) // Wifi downstream. Show enable notification with test resource. notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyOnlyTetheringActiveNotification( - ENABLE_NOTIFICATION_ID, WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE) + verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) // There is no upstream. Show no upstream notification. - notificationUpdater.onUpstreamNetworkChanged(null) - notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, 500L) - verifyNotification(R.drawable.stat_sys_tether_general, TEST_NO_UPSTREAM_TITLE, - TEST_NO_UPSTREAM_MESSAGE, NO_UPSTREAM_NOTIFICATION_ID) - reset(notificationManager) + notificationUpdater.onUpstreamCapabilitiesChanged(null) + notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) + verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, + NO_UPSTREAM_NOTIFICATION_ID) - // Same upstream network changed. Nothing happened. - notificationUpdater.onUpstreamNetworkChanged(null) + // Same capabilities changed. Nothing happened. + notificationUpdater.onUpstreamCapabilitiesChanged(null) verifyZeroInteractions(notificationManager) // Upstream come back. Clear no upstream notification. - notificationUpdater.onUpstreamNetworkChanged(Network(1000)) - verifyNotificationCancelled(NO_UPSTREAM_NOTIFICATION_ID) - reset(notificationManager) + notificationUpdater.onUpstreamCapabilitiesChanged(HOME_CAPABILITIES) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID)) // No upstream again. Show no upstream notification. - notificationUpdater.onUpstreamNetworkChanged(null) - notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, 500L) - verifyNotification(R.drawable.stat_sys_tether_general, TEST_NO_UPSTREAM_TITLE, - TEST_NO_UPSTREAM_MESSAGE, NO_UPSTREAM_NOTIFICATION_ID) - reset(notificationManager) + notificationUpdater.onUpstreamCapabilitiesChanged(null) + notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) + verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, + NO_UPSTREAM_NOTIFICATION_ID) // No downstream. No notification. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyCancelAllTetheringActiveNotifications() + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID)) - // Set R.integer.delay_to_show_no_upstream_after_no_backhaul to 0 and have wifi downstream - // again. Show enable notification only. + // Put up enable notification with wifi downstream and home capabilities. + notificationUpdater.onDownstreamChanged(WIFI_MASK) + notificationUpdater.onUpstreamCapabilitiesChanged(HOME_CAPABILITIES) + verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) + + // Set R.integer.delay_to_show_no_upstream_after_no_backhaul to -1 and change to no upstream + // again. Don't put up no upstream notification. doReturn(-1).`when`(testResources) .getInteger(R.integer.delay_to_show_no_upstream_after_no_backhaul) - notificationUpdater.onDownstreamChanged(WIFI_MASK) - notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, 500L) - verifyOnlyTetheringActiveNotification( - ENABLE_NOTIFICATION_ID, WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE) + notificationUpdater.onUpstreamCapabilitiesChanged(null) + notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID)) } @Test @@ -428,4 +427,57 @@ class TetheringNotificationUpdaterTest { assertEquals(311, res.configuration.mcc) assertEquals(480, res.configuration.mnc) } + + @Test + fun testNotificationWithUpstreamCapabilitiesChanged_Roaming() { + // Set test sub id. Clear notification. + notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID)) + + // Wifi downstream. Show enable notification with test resource. + notificationUpdater.onDownstreamChanged(WIFI_MASK) + verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) + + // Upstream capabilities changed to roaming state. Show roaming notification. + notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) + verifyNotification(NOTIFICATION_ICON_ID, TEST_ROAMING_TITLE, TEST_ROAMING_MESSAGE, + ROAMING_NOTIFICATION_ID) + + // Same capabilities change. Nothing happened. + notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) + verifyZeroInteractions(notificationManager) + + // Upstream capabilities changed to home state. Clear roaming notification. + notificationUpdater.onUpstreamCapabilitiesChanged(HOME_CAPABILITIES) + verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID)) + + // Upstream capabilities changed to roaming state again. Show roaming notification. + notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) + verifyNotification(NOTIFICATION_ICON_ID, TEST_ROAMING_TITLE, TEST_ROAMING_MESSAGE, + ROAMING_NOTIFICATION_ID) + + // No upstream. Clear roaming notification and show no upstream notification. + notificationUpdater.onUpstreamCapabilitiesChanged(null) + notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) + verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID), false) + verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, + NO_UPSTREAM_NOTIFICATION_ID) + + // No downstream. No notification. + notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) + verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, + ROAMING_NOTIFICATION_ID)) + + // Wifi downstream again. Show enable notification with test resource. + notificationUpdater.onDownstreamChanged(WIFI_MASK) + verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) + + // Set R.bool.config_upstream_roaming_notification to false and change upstream + // network to roaming state again. No roaming notification. + doReturn(false).`when`(testResources) + .getBoolean(R.bool.config_upstream_roaming_notification) + notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) + } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 15e253af12..28bfae0ced 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -48,6 +48,7 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; +import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -1700,7 +1701,29 @@ public class TetheringTest { stateMachine.chooseUpstreamType(true); verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network)); - verify(mNotificationUpdater, times(1)).onUpstreamNetworkChanged(eq(upstreamState.network)); + verify(mNotificationUpdater, times(1)).onUpstreamCapabilitiesChanged(any()); + } + + @Test + public void testUpstreamCapabilitiesChanged() { + final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM) + mTetheringDependencies.mUpstreamNetworkMonitorMasterSM; + final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); + when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState); + stateMachine.chooseUpstreamType(true); + + stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState); + // Should have two onUpstreamCapabilitiesChanged(). + // One is called by reportUpstreamChanged(). One is called by EVENT_ON_CAPABILITIES. + verify(mNotificationUpdater, times(2)).onUpstreamCapabilitiesChanged(any()); + reset(mNotificationUpdater); + + // Verify that onUpstreamCapabilitiesChanged won't be called if not current upstream network + // capabilities changed. + final UpstreamNetworkState upstreamState2 = new UpstreamNetworkState( + upstreamState.linkProperties, upstreamState.networkCapabilities, new Network(101)); + stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState2); + verify(mNotificationUpdater, never()).onUpstreamCapabilitiesChanged(any()); } // TODO: Test that a request for hotspot mode doesn't interfere with an From dacbdaa3787d5bf67124ca9fdb564765644a8479 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 30 Mar 2020 17:30:46 +0800 Subject: [PATCH 0971/1415] Add tests for NetworkRequest API This change inculdes coverage of NetworkRequest#Builder().clearCapabilities() and NetworkRequest#getRequestorPackageName() Bug: 153614623 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkRequestTest Change-Id: Id4e31013cfae78c25abd27b557da4e3e9487870c Merged-In: Id4e31013cfae78c25abd27b557da4e3e9487870c --- .../android/net/cts/NetworkRequestTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index 751418657f..08bf1e424b 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -62,6 +62,18 @@ public class NetworkRequestTest { .hasCapability(NET_CAPABILITY_MMS)); assertFalse(new NetworkRequest.Builder().removeCapability(NET_CAPABILITY_MMS).build() .hasCapability(NET_CAPABILITY_MMS)); + + final NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build(); + // Verify request has no capabilities + verifyNoCapabilities(nr); + } + + private void verifyNoCapabilities(NetworkRequest nr) { + // NetworkCapabilities.mNetworkCapabilities is defined as type long + final int MAX_POSSIBLE_CAPABILITY = Long.SIZE; + for(int bit = 0; bit < MAX_POSSIBLE_CAPABILITY; bit++) { + assertFalse(nr.hasCapability(bit)); + } } @Test @@ -86,6 +98,29 @@ public class NetworkRequestTest { .build() .getNetworkSpecifier(); assertEquals(obtainedSpecifier, specifier); + + assertNull(new NetworkRequest.Builder() + .clearCapabilities() + .build() + .getNetworkSpecifier()); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testRequestorPackageName() { + assertNull(new NetworkRequest.Builder().build().getRequestorPackageName()); + final String pkgName = "android.net.test"; + final NetworkCapabilities nc = new NetworkCapabilities.Builder() + .setRequestorPackageName(pkgName) + .build(); + final NetworkRequest nr = new NetworkRequest.Builder() + .setCapabilities(nc) + .build(); + assertEquals(pkgName, nr.getRequestorPackageName()); + assertNull(new NetworkRequest.Builder() + .clearCapabilities() + .build() + .getRequestorPackageName()); } @Test From d1e528ae9cb3157d71ee0b200b6f257dddf58f0d Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 20 Mar 2020 16:36:24 +0800 Subject: [PATCH 0972/1415] Add test for NetworkRequest#getRequestorUid() Add test for new API. Bug: 151110379 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkRequestTest Change-Id: I9602cac142b3e45d12e66a6f3f35ab594e6590c1 Merged-In: I9602cac142b3e45d12e66a6f3f35ab594e6590c1 --- .../src/android/net/cts/NetworkRequestTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index 08bf1e424b..6a1d9de6f6 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -34,6 +34,7 @@ import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.wifi.WifiNetworkSpecifier; import android.os.Build; +import android.os.Process; import android.os.PatternMatcher; import androidx.test.runner.AndroidJUnit4; @@ -160,4 +161,19 @@ public class NetworkRequestTest { assertEquals(request.canBeSatisfiedBy(capWithSp), new NetworkCapabilities(capWithSp).satisfiedByNetworkCapabilities(capWithSp)); } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testRequestorUid() { + final NetworkCapabilities nc = new NetworkCapabilities(); + // Verify default value is INVALID_UID + assertEquals(Process.INVALID_UID, new NetworkRequest.Builder() + .setCapabilities(nc).build().getRequestorUid()); + + nc.setRequestorUid(1314); + final NetworkRequest nr = new NetworkRequest.Builder().setCapabilities(nc).build(); + assertEquals(1314, nr.getRequestorUid()); + + assertEquals(Process.INVALID_UID, new NetworkRequest.Builder() + .clearCapabilities().build().getRequestorUid()); + } } From 170e87344294314a892ab477d5ffcf6f66894093 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 17 Apr 2020 16:26:45 +0000 Subject: [PATCH 0973/1415] Move DhcpInfoTest to FrameworksNetCommonTests Move to frameworks/base/tests/net/common so that it can be run in cts test and presubmit test. Bug: 154299158 Test: atest CtsNetTestCasesLatestSdk:android.net.DhcpInfoTest Change-Id: I1052c2b46ce427102429c3c7d8cf25f3e79f2789 Merged-In: I8d70565fe3388fd8351002f2ed87c43343879e57 --- .../net/src/android/net/cts/DhcpInfoTest.java | 114 ------------------ 1 file changed, 114 deletions(-) delete mode 100644 tests/cts/net/src/android/net/cts/DhcpInfoTest.java diff --git a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java b/tests/cts/net/src/android/net/cts/DhcpInfoTest.java deleted file mode 100644 index b8d239272a..0000000000 --- a/tests/cts/net/src/android/net/cts/DhcpInfoTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2009 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.net.shared.Inet4AddressUtils.inet4AddressToIntHTL; - -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; -import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.annotation.Nullable; -import android.net.DhcpInfo; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.net.InetAddress; - -@RunWith(AndroidJUnit4.class) -public class DhcpInfoTest { - private static final String STR_ADDR1 = "255.255.255.255"; - private static final String STR_ADDR2 = "127.0.0.1"; - private static final String STR_ADDR3 = "192.168.1.1"; - private static final String STR_ADDR4 = "192.168.1.0"; - private static final int LEASE_TIME = 9999; - - private int ipToInteger(String ipString) throws Exception { - return inet4AddressToIntHTL((Inet4Address) InetAddress.getByName(ipString)); - } - - private DhcpInfo createDhcpInfoObject() throws Exception { - final DhcpInfo dhcpInfo = new DhcpInfo(); - dhcpInfo.ipAddress = ipToInteger(STR_ADDR1); - dhcpInfo.gateway = ipToInteger(STR_ADDR2); - dhcpInfo.netmask = ipToInteger(STR_ADDR3); - dhcpInfo.dns1 = ipToInteger(STR_ADDR4); - dhcpInfo.dns2 = ipToInteger(STR_ADDR4); - dhcpInfo.serverAddress = ipToInteger(STR_ADDR2); - dhcpInfo.leaseDuration = LEASE_TIME; - return dhcpInfo; - } - - @Test - public void testConstructor() { - new DhcpInfo(); - } - - @Test - public void testToString() throws Exception { - final String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 " - + "dns1 0.0.0.0 dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds"; - - DhcpInfo dhcpInfo = new DhcpInfo(); - - // Test default string. - assertEquals(expectedDefault, dhcpInfo.toString()); - - dhcpInfo = createDhcpInfoObject(); - - final String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask " - + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server " - + STR_ADDR2 + " lease " + LEASE_TIME + " seconds"; - // Test with new values - assertEquals(expected, dhcpInfo.toString()); - } - - private boolean dhcpInfoEquals(@Nullable DhcpInfo left, @Nullable DhcpInfo right) { - if (left == null && right == null) return true; - - if (left == null || right == null) return false; - - return left.ipAddress == right.ipAddress - && left.gateway == right.gateway - && left.netmask == right.netmask - && left.dns1 == right.dns1 - && left.dns2 == right.dns2 - && left.serverAddress == right.serverAddress - && left.leaseDuration == right.leaseDuration; - } - - @Test - public void testParcelDhcpInfo() throws Exception { - // Cannot use assertParcelSane() here because this requires .equals() to work as - // defined, but DhcpInfo has a different legacy behavior that we cannot change. - final DhcpInfo dhcpInfo = createDhcpInfoObject(); - assertFieldCountEquals(7, DhcpInfo.class); - - final DhcpInfo dhcpInfoRoundTrip = parcelingRoundTrip(dhcpInfo); - assertTrue(dhcpInfoEquals(null, null)); - assertFalse(dhcpInfoEquals(null, dhcpInfoRoundTrip)); - assertFalse(dhcpInfoEquals(dhcpInfo, null)); - assertTrue(dhcpInfoEquals(dhcpInfo, dhcpInfoRoundTrip)); - } -} From 21ec1de1ff8bbc96c1ca42463e84c82f22de2c03 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Fri, 17 Apr 2020 17:26:51 +0800 Subject: [PATCH 0974/1415] Update network object when wifi meterness is changed The new wifi disconnect behavior is introduced. When wifi network is changed from unmetered to metered, the wifi network will disconnect and reconnect. Update the test to verify the same SSID wifi is connected and also update the target network to verfiy the metered preference. Bug: 153400606 Test: atest CtsNetTestCases:android.net.cts.ConnectivityManagerTest\ #testGetMultipathPreference Change-Id: Ic298d3d85d8c6b77c8df7614a945f2c22dcdff38 --- .../net/src/android/net/cts/ConnectivityManagerTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index fa7e1381b3..3a52ee60a3 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -709,7 +709,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testGetMultipathPreference() throws Exception { final ContentResolver resolver = mContext.getContentResolver(); - final Network network = ensureWifiConnected(); + ensureWifiConnected(); final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID()); final String oldMeteredSetting = getWifiMeteredStatus(ssid); final String oldMeteredMultipathPreference = Settings.Global.getString( @@ -721,6 +721,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { Integer.toString(newMeteredPreference)); setWifiMeteredStatus(ssid, "true"); waitForActiveNetworkMetered(true); + // Wifi meterness changes from unmetered to metered will disconnect and reconnect since + // R. + final Network network = mCm.getActiveNetwork(); + assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID())); assertEquals(mCm.getNetworkCapabilities(network).hasCapability( NET_CAPABILITY_NOT_METERED), false); assertMultipathPreferenceIsEventually(network, initialMeteredPreference, @@ -736,6 +740,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { oldMeteredPreference, newMeteredPreference); setWifiMeteredStatus(ssid, "false"); + // No disconnect from unmetered to metered. waitForActiveNetworkMetered(false); assertEquals(mCm.getNetworkCapabilities(network).hasCapability( NET_CAPABILITY_NOT_METERED), true); From 5cfd8d6bb1c08711af322f9e2f7d5e114b2af16e Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 20 Apr 2020 15:34:19 +0800 Subject: [PATCH 0975/1415] Remove upper bound check of getTotal* APIs in TrafficStatsTest Currently, this cause flakiness since some background traffic was counted when performing tests, or the traffic generated by adb over network. While there is no good way to filter out all reasonable cases, disable the upper bound checks. Test: atest TrafficStatsTest Bug: 142978584 Change-Id: I8140310c9caeff6069d1f55590bf40f83bf211e4 --- .../src/android/net/cts/TrafficStatsTest.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 577e24ac29..37bdd44fbf 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -16,11 +16,9 @@ package android.net.cts; -import android.content.pm.PackageManager; import android.net.NetworkStats; import android.net.TrafficStats; import android.os.Process; -import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; import android.util.Log; @@ -267,28 +265,6 @@ public class TrafficStatsTest extends AndroidTestCase { assertTrue("ifrxp: " + ifaceRxPacketsBefore + " -> " + ifaceRxPacketsAfter, totalRxPacketsAfter >= totalRxPacketsBefore + ifaceRxDeltaPackets); - // If the adb TCP port is opened, this test may be run by adb over network. - // Huge amount of data traffic might go through the network and accounted into total packets - // stats. The upper bound check would be meaningless. - // TODO: Consider precisely calculate the traffic accounted due to adb over network and - // subtract it when checking upper bound instead of skip checking. - final PackageManager pm = mContext.getPackageManager(); - if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 - || SystemProperties.getInt("service.adb.tcp.port", -1) > -1 - || !pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) { - Log.i(LOG_TAG, "adb is running over the network, skip the upper bound check"); - } else { - // Fudge by 132 packets of 1500 bytes not related to the test. - assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, - totalTxPacketsAfter <= totalTxPacketsBefore + uidTxDeltaPackets + 132); - assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, - totalRxPacketsAfter <= totalRxPacketsBefore + uidRxDeltaPackets + 132); - assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, - totalTxBytesAfter <= totalTxBytesBefore + uidTxDeltaBytes + 132 * 1500); - assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, - totalRxBytesAfter <= totalRxBytesBefore + uidRxDeltaBytes + 132 * 1500); - } - // Localhost traffic should *not* count against mobile stats, // There might be some other traffic, but nowhere near 1MB. assertInRange("mtxp", mobileTxPacketsAfter, mobileTxPacketsBefore, From de93db8570ab73f1d065186a225734a43eea87c4 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 13 Apr 2020 12:55:24 +0900 Subject: [PATCH 0976/1415] Mark some aidl_interface modules as unstable With b/152655547, all aidl_interface modules are considered as stable unless it is explicitly with "unstable: true". This change marks the aidl_interface that are not used across updatable module bounraries as unstable, so that the build system does not run the API dumping/checking on them. Exempt-From-Owner-Approval: cherry-pick from internal Bug: 152655547 Test: m Merged-In: I1257c66de6dd42b2d32d47ed74cb2878f79d14fb (cherry picked from commit 6c9c10c91efa5efacd0b3af61be3e623c3682df0) Change-Id: I1257c66de6dd42b2d32d47ed74cb2878f79d14fb --- Tethering/common/TetheringLib/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 31c40d2a33..ee6b9f12f9 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -16,6 +16,7 @@ // AIDL interfaces between the core system and the tethering mainline module. aidl_interface { name: "tethering-aidl-interfaces", + unstable: true, local_include_dir: "src", include_dirs: ["frameworks/base/core/java"], // For framework parcelables. srcs: [ From 01a9451cb49d7827ebe3daa5312c59825c3b4163 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 20 Apr 2020 14:13:32 +0800 Subject: [PATCH 0977/1415] [TNU07] Remove unused resources Some strings are not used, so just remove them. Bug: 154445061 Test: atest TetheringTests Change-Id: Ie67f7f4d0863d58c4c5206e445c1dbdfe3f65f60 --- .../res/values-mcc310-mnc004/strings.xml | 2 -- .../res/values-mcc310-mnc120/strings.xml | 22 ------------------- .../res/values-mcc311-mnc480/strings.xml | 2 -- .../res/values-mcc311-mnc490/strings.xml | 22 ------------------- .../res/values-mcc312-mnc530/strings.xml | 22 ------------------- Tethering/res/values/strings.xml | 5 ----- 6 files changed, 75 deletions(-) delete mode 100644 Tethering/res/values-mcc310-mnc120/strings.xml delete mode 100644 Tethering/res/values-mcc311-mnc490/strings.xml delete mode 100644 Tethering/res/values-mcc312-mnc530/strings.xml diff --git a/Tethering/res/values-mcc310-mnc004/strings.xml b/Tethering/res/values-mcc310-mnc004/strings.xml index 9dadd49cf8..ce9ff60807 100644 --- a/Tethering/res/values-mcc310-mnc004/strings.xml +++ b/Tethering/res/values-mcc310-mnc004/strings.xml @@ -25,6 +25,4 @@ Hotspot or tethering is on Additional charges may apply while roaming - - Continue diff --git a/Tethering/res/values-mcc310-mnc120/strings.xml b/Tethering/res/values-mcc310-mnc120/strings.xml deleted file mode 100644 index 618df90c71..0000000000 --- a/Tethering/res/values-mcc310-mnc120/strings.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - %1$d device connected. - %1$d devices connected. - - \ No newline at end of file diff --git a/Tethering/res/values-mcc311-mnc480/strings.xml b/Tethering/res/values-mcc311-mnc480/strings.xml index 9dadd49cf8..ce9ff60807 100644 --- a/Tethering/res/values-mcc311-mnc480/strings.xml +++ b/Tethering/res/values-mcc311-mnc480/strings.xml @@ -25,6 +25,4 @@ Hotspot or tethering is on Additional charges may apply while roaming - - Continue diff --git a/Tethering/res/values-mcc311-mnc490/strings.xml b/Tethering/res/values-mcc311-mnc490/strings.xml deleted file mode 100644 index 618df90c71..0000000000 --- a/Tethering/res/values-mcc311-mnc490/strings.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - %1$d device connected. - %1$d devices connected. - - \ No newline at end of file diff --git a/Tethering/res/values-mcc312-mnc530/strings.xml b/Tethering/res/values-mcc312-mnc530/strings.xml deleted file mode 100644 index 618df90c71..0000000000 --- a/Tethering/res/values-mcc312-mnc530/strings.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - %1$d device connected. - %1$d devices connected. - - \ No newline at end of file diff --git a/Tethering/res/values/strings.xml b/Tethering/res/values/strings.xml index 4fa60d4125..d63c7c5063 100644 --- a/Tethering/res/values/strings.xml +++ b/Tethering/res/values/strings.xml @@ -19,9 +19,6 @@ Tethering or hotspot active Tap to set up. - - - - - From 57f26333a816988019a8418db33bedc14bc97910 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 20 Apr 2020 15:38:00 +0800 Subject: [PATCH 0978/1415] [TNU08] Remove the "tethering is on" notification All carriers discarded the requirement to put up a standing notification when tethering is on. Thus, remove the "tethering is on" notification. Bug: 154438388 Test: atest TetheringTests Change-Id: Ife3915837b6b7b83d3eaaa84b71b6409ff37b71c --- Tethering/res/values/config.xml | 45 ---- Tethering/res/values/overlayable.xml | 38 ---- .../TetheringNotificationUpdater.java | 100 --------- .../TetheringNotificationUpdaterTest.kt | 207 ++++-------------- 4 files changed, 39 insertions(+), 351 deletions(-) diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index aed5ab8df6..effc24ac4d 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -156,51 +156,6 @@ com.android.settings/.wifi.tether.TetherService - - - - - USB;com.android.networkstack.tethering:drawable/stat_sys_tether_usb - BT;com.android.networkstack.tethering:drawable/stat_sys_tether_bluetooth - WIFI|USB,WIFI|BT,USB|BT,WIFI|USB|BT;com.android.networkstack.tethering:drawable/stat_sys_tether_general - - - @string/tethered_notification_title - - @string/tethered_notification_message - - - - - - - diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index f490cc4719..7fd6b61ccd 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -17,9 +17,6 @@ package com.android.networkstack.tethering; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; -import static android.net.TetheringManager.TETHERING_BLUETOOTH; -import static android.net.TetheringManager.TETHERING_USB; -import static android.net.TetheringManager.TETHERING_WIFI; import static android.text.TextUtils.isEmpty; import android.app.Notification; @@ -39,10 +36,8 @@ import android.os.UserHandle; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.util.Log; import android.util.SparseArray; -import androidx.annotation.ArrayRes; import androidx.annotation.DrawableRes; import androidx.annotation.IntDef; import androidx.annotation.IntRange; @@ -77,9 +72,6 @@ public class TetheringNotificationUpdater { private static final boolean NO_NOTIFY = false; @VisibleForTesting static final int EVENT_SHOW_NO_UPSTREAM = 1; - // Id to update and cancel enable notification. Must be unique within the tethering app. - @VisibleForTesting - static final int ENABLE_NOTIFICATION_ID = 1000; // Id to update and cancel restricted notification. Must be unique within the tethering app. @VisibleForTesting static final int RESTRICTED_NOTIFICATION_ID = 1001; @@ -120,7 +112,6 @@ public class TetheringNotificationUpdater { @Retention(RetentionPolicy.SOURCE) @IntDef(value = { - ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID @@ -223,7 +214,6 @@ public class TetheringNotificationUpdater { final boolean tetheringActiveChanged = (downstreamTypes == DOWNSTREAM_NONE) != (mDownstreamTypesMask == DOWNSTREAM_NONE); final boolean subIdChanged = subId != mActiveDataSubId; - final boolean downstreamChanged = downstreamTypes != mDownstreamTypesMask; final boolean upstreamChanged = noUpstream != mNoUpstream; final boolean roamingChanged = isRoaming != mRoaming; final boolean updateAll = tetheringActiveChanged || subIdChanged; @@ -232,19 +222,10 @@ public class TetheringNotificationUpdater { mNoUpstream = noUpstream; mRoaming = isRoaming; - if (updateAll || downstreamChanged) updateEnableNotification(); if (updateAll || upstreamChanged) updateNoUpstreamNotification(); if (updateAll || roamingChanged) updateRoamingNotification(); } - private void updateEnableNotification() { - final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE; - - if (tetheringInactive || setupNotification() == NO_NOTIFY) { - clearNotification(ENABLE_NOTIFICATION_ID); - } - } - private void updateNoUpstreamNotification() { final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE; @@ -310,64 +291,6 @@ public class TetheringNotificationUpdater { NO_UPSTREAM_NOTIFICATION_ID, null /* pendingIntent */, action); } - /** - * Returns the downstream types mask which convert from given string. - * - * @param types This string has to be made by "WIFI", "USB", "BT", and OR'd with the others. - * - * @return downstream types mask value. - */ - @VisibleForTesting - @IntRange(from = 0, to = 7) - int getDownstreamTypesMask(@NonNull final String types) { - int downstreamTypesMask = DOWNSTREAM_NONE; - final String[] downstreams = types.split("\\|"); - for (String downstream : downstreams) { - if (USB_DOWNSTREAM.equals(downstream.trim())) { - downstreamTypesMask |= (1 << TETHERING_USB); - } else if (WIFI_DOWNSTREAM.equals(downstream.trim())) { - downstreamTypesMask |= (1 << TETHERING_WIFI); - } else if (BLUETOOTH_DOWNSTREAM.equals(downstream.trim())) { - downstreamTypesMask |= (1 << TETHERING_BLUETOOTH); - } - } - return downstreamTypesMask; - } - - /** - * Returns the icons {@link android.util.SparseArray} which get from given string-array resource - * id. - * - * @param id String-array resource id - * - * @return {@link android.util.SparseArray} with downstream types and icon id info. - */ - @NonNull - @VisibleForTesting - SparseArray getIcons(@ArrayRes int id, @NonNull Resources res) { - final String[] array = res.getStringArray(id); - final SparseArray icons = new SparseArray<>(); - for (String config : array) { - if (isEmpty(config)) continue; - - final String[] elements = config.split(";"); - if (elements.length != 2) { - Log.wtf(TAG, - "Unexpected format in Tethering notification configuration : " + config); - continue; - } - - final String[] types = elements[0].split(","); - for (String type : types) { - int mask = getDownstreamTypesMask(type); - if (mask == DOWNSTREAM_NONE) continue; - icons.put(mask, res.getIdentifier( - elements[1].trim(), null /* defType */, null /* defPackage */)); - } - } - return icons; - } - private boolean setupRoamingNotification() { final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); final boolean upstreamRoamingNotification = @@ -403,29 +326,6 @@ public class TetheringNotificationUpdater { return NOTIFY_DONE; } - private boolean setupNotification() { - final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); - final SparseArray downstreamIcons = - getIcons(R.array.tethering_notification_icons, res); - - final int iconId = downstreamIcons.get(mDownstreamTypesMask, NO_ICON_ID); - if (iconId == NO_ICON_ID) return NO_NOTIFY; - - final String title = res.getString(R.string.tethering_notification_title); - final String message = res.getString(R.string.tethering_notification_message); - if (isEmpty(title) || isEmpty(message)) return NO_NOTIFY; - - final PendingIntent pi = PendingIntent.getActivity( - mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), - 0 /* requestCode */, - new Intent(Settings.ACTION_TETHER_SETTINGS), - Intent.FLAG_ACTIVITY_NEW_TASK, - null /* options */); - - showNotification(iconId, title, message, ENABLE_NOTIFICATION_ID, pi, new Action[0]); - return NOTIFY_DONE; - } - private void showNotification(@DrawableRes final int iconId, @NonNull final String title, @NonNull final String message, @NotificationId final int id, @Nullable PendingIntent pi, @NonNull final Action... actions) { diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 04f31a7a28..745468fdf3 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -20,8 +20,6 @@ import android.app.Notification import android.app.NotificationManager import android.content.Context import android.content.res.Resources -import android.net.ConnectivityManager.TETHERING_BLUETOOTH -import android.net.ConnectivityManager.TETHERING_USB import android.net.ConnectivityManager.TETHERING_WIFI import android.os.Handler import android.os.HandlerThread @@ -29,14 +27,12 @@ import android.os.Looper import android.net.NetworkCapabilities import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING import android.os.UserHandle -import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.telephony.TelephonyManager import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.test.BroadcastInterceptingContext import com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE -import com.android.networkstack.tethering.TetheringNotificationUpdater.ENABLE_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.EVENT_SHOW_NO_UPSTREAM import com.android.networkstack.tethering.TetheringNotificationUpdater.NO_UPSTREAM_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.RESTRICTED_NOTIFICATION_ID @@ -63,17 +59,9 @@ import org.mockito.Mockito.verifyZeroInteractions import org.mockito.MockitoAnnotations const val TEST_SUBID = 1 -const val WIFI_ICON_ID = 1 -const val USB_ICON_ID = 2 -const val BT_ICON_ID = 3 -const val GENERAL_ICON_ID = 4 const val WIFI_MASK = 1 shl TETHERING_WIFI -const val USB_MASK = 1 shl TETHERING_USB -const val BT_MASK = 1 shl TETHERING_BLUETOOTH -const val TITLE = "Tethering active" -const val MESSAGE = "Tap here to set up." -const val TEST_TITLE = "Hotspot active" -const val TEST_MESSAGE = "Tap to set up hotspot." +const val TEST_DISALLOW_TITLE = "Tether function is disallowed" +const val TEST_DISALLOW_MESSAGE = "Please contact your admin" const val TEST_NO_UPSTREAM_TITLE = "Hotspot has no internet access" const val TEST_NO_UPSTREAM_MESSAGE = "Device cannot connect to internet." const val TEST_NO_UPSTREAM_BUTTON = "Turn off hotspot" @@ -88,7 +76,6 @@ class TetheringNotificationUpdaterTest { @Mock private lateinit var mockContext: Context @Mock private lateinit var notificationManager: NotificationManager @Mock private lateinit var telephonyManager: TelephonyManager - @Mock private lateinit var defaultResources: Resources @Mock private lateinit var testResources: Resources // lateinit for these classes under test, as they should be reset to a different instance for @@ -97,11 +84,6 @@ class TetheringNotificationUpdaterTest { private lateinit var notificationUpdater: TetheringNotificationUpdater private lateinit var fakeTetheringThread: HandlerThread - private val ENABLE_ICON_CONFIGS = arrayOf( - "USB;android.test:drawable/usb", "BT;android.test:drawable/bluetooth", - "WIFI|BT;android.test:drawable/general", "WIFI|USB;android.test:drawable/general", - "USB|BT;android.test:drawable/general", "WIFI|USB|BT;android.test:drawable/general") - private val ROAMING_CAPABILITIES = NetworkCapabilities() private val HOME_CAPABILITIES = NetworkCapabilities().addCapability(NET_CAPABILITY_NOT_ROAMING) private val NOTIFICATION_ICON_ID = R.drawable.stat_sys_tether_general @@ -117,29 +99,19 @@ class TetheringNotificationUpdaterTest { private inner class WrappedNotificationUpdater(c: Context, looper: Looper) : TetheringNotificationUpdater(c, looper) { - override fun getResourcesForSubId(context: Context, subId: Int) = - when (subId) { - TEST_SUBID -> testResources - INVALID_SUBSCRIPTION_ID -> defaultResources - else -> super.getResourcesForSubId(context, subId) - } + override fun getResourcesForSubId(c: Context, subId: Int) = + if (subId == TEST_SUBID) testResources else super.getResourcesForSubId(c, subId) } private fun setupResources() { - doReturn(ENABLE_ICON_CONFIGS).`when`(defaultResources) - .getStringArray(R.array.tethering_notification_icons) - doReturn(arrayOf("WIFI;android.test:drawable/wifi")).`when`(testResources) - .getStringArray(R.array.tethering_notification_icons) doReturn(5).`when`(testResources) .getInteger(R.integer.delay_to_show_no_upstream_after_no_backhaul) doReturn(true).`when`(testResources) .getBoolean(R.bool.config_upstream_roaming_notification) - doReturn(TITLE).`when`(defaultResources).getString(R.string.tethering_notification_title) - doReturn(MESSAGE).`when`(defaultResources) - .getString(R.string.tethering_notification_message) - doReturn(TEST_TITLE).`when`(testResources).getString(R.string.tethering_notification_title) - doReturn(TEST_MESSAGE).`when`(testResources) - .getString(R.string.tethering_notification_message) + doReturn(TEST_DISALLOW_TITLE).`when`(testResources) + .getString(R.string.disable_tether_notification_title) + doReturn(TEST_DISALLOW_MESSAGE).`when`(testResources) + .getString(R.string.disable_tether_notification_message) doReturn(TEST_NO_UPSTREAM_TITLE).`when`(testResources) .getString(R.string.no_upstream_notification_title) doReturn(TEST_NO_UPSTREAM_MESSAGE).`when`(testResources) @@ -150,14 +122,6 @@ class TetheringNotificationUpdaterTest { .getString(R.string.upstream_roaming_notification_title) doReturn(TEST_ROAMING_MESSAGE).`when`(testResources) .getString(R.string.upstream_roaming_notification_message) - doReturn(USB_ICON_ID).`when`(defaultResources) - .getIdentifier(eq("android.test:drawable/usb"), any(), any()) - doReturn(BT_ICON_ID).`when`(defaultResources) - .getIdentifier(eq("android.test:drawable/bluetooth"), any(), any()) - doReturn(GENERAL_ICON_ID).`when`(defaultResources) - .getIdentifier(eq("android.test:drawable/general"), any(), any()) - doReturn(WIFI_ICON_ID).`when`(testResources) - .getIdentifier(eq("android.test:drawable/wifi"), any(), any()) } @Before @@ -206,119 +170,27 @@ class TetheringNotificationUpdaterTest { } @Test - fun testNotificationWithDownstreamChanged() { - // Wifi downstream. No notification. - notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID)) - - // Same downstream changed. Nothing happened. - notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyZeroInteractions(notificationManager) - - // Wifi and usb downstreams. Show enable notification - notificationUpdater.onDownstreamChanged(WIFI_MASK or USB_MASK) - verifyNotification(GENERAL_ICON_ID, TITLE, MESSAGE, ENABLE_NOTIFICATION_ID) - - // Usb downstream. Still show enable notification. - notificationUpdater.onDownstreamChanged(USB_MASK) - verifyNotification(USB_ICON_ID, TITLE, MESSAGE, ENABLE_NOTIFICATION_ID) - - // No downstream. No notification. - notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, - ROAMING_NOTIFICATION_ID)) - } - - @Test - fun testNotificationWithActiveDataSubscriptionIdChanged() { - // Usb downstream. Showed enable notification with default resource. - notificationUpdater.onDownstreamChanged(USB_MASK) - verifyNotification(USB_ICON_ID, TITLE, MESSAGE, ENABLE_NOTIFICATION_ID) - - // Same subId changed. Nothing happened. - notificationUpdater.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID) - verifyZeroInteractions(notificationManager) - - // Set test sub id. Clear notification with test resource. + fun testRestrictedNotification() { + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, - ROAMING_NOTIFICATION_ID)) - - // Wifi downstream. Show enable notification with test resource. - notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) - - // No downstream. No notification. - notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, - ROAMING_NOTIFICATION_ID)) - } - - private fun assertIconNumbers(number: Int, configs: Array) { - doReturn(configs).`when`(defaultResources) - .getStringArray(R.array.tethering_notification_icons) - assertEquals(number, notificationUpdater.getIcons( - R.array.tethering_notification_icons, defaultResources).size()) - } - - @Test - fun testGetIcons() { - assertIconNumbers(0, arrayOfNulls(0)) - assertIconNumbers(0, arrayOf(null, "")) - assertIconNumbers(3, arrayOf( - // These configurations are invalid with wrong strings or symbols. - ";", ",", "|", "|,;", "WIFI", "1;2", " U SB; ", "bt;", "WIFI;USB;BT", "WIFI|USB|BT", - "WIFI,BT,USB", " WIFI| | | USB, test:drawable/test", - // This configuration is valid with two downstream types (USB, BT). - "USB|,,,,,|BT;drawable/test ", - // This configuration is valid with one downstream types (WIFI). - " WIFI ; android.test:drawable/xxx ")) - } - - @Test - fun testGetDownstreamTypesMask() { - assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("")) - assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("1")) - assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("WIFI_P2P")) - assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("usb")) - assertEquals(WIFI_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI ")) - assertEquals(USB_MASK, notificationUpdater.getDownstreamTypesMask("USB | B T")) - assertEquals(BT_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI: | BT")) - assertEquals(WIFI_MASK or USB_MASK, - notificationUpdater.getDownstreamTypesMask("1|2|USB|WIFI|BLUETOOTH||")) - } - - @Test - fun testSetupRestrictedNotification() { - val title = context.resources.getString(R.string.disable_tether_notification_title) - val message = context.resources.getString(R.string.disable_tether_notification_message) - val disallowTitle = "Tether function is disallowed" - val disallowMessage = "Please contact your admin" - doReturn(title).`when`(defaultResources) - .getString(R.string.disable_tether_notification_title) - doReturn(message).`when`(defaultResources) - .getString(R.string.disable_tether_notification_message) - doReturn(disallowTitle).`when`(testResources) - .getString(R.string.disable_tether_notification_title) - doReturn(disallowMessage).`when`(testResources) - .getString(R.string.disable_tether_notification_message) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) // User restrictions on. Show restricted notification. notificationUpdater.notifyTetheringDisabledByRestriction() - verifyNotification(NOTIFICATION_ICON_ID, title, message, RESTRICTED_NOTIFICATION_ID) + verifyNotification(NOTIFICATION_ICON_ID, TEST_DISALLOW_TITLE, TEST_DISALLOW_MESSAGE, + RESTRICTED_NOTIFICATION_ID) // User restrictions off. Clear notification. notificationUpdater.tetheringRestrictionLifted() verifyNotificationCancelled(listOf(RESTRICTED_NOTIFICATION_ID)) - // Set test sub id. No notification. - notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, - ROAMING_NOTIFICATION_ID)) + // No downstream. + notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) + verifyZeroInteractions(notificationManager) - // User restrictions on again. Show restricted notification with test resource. + // User restrictions on again. Show restricted notification. notificationUpdater.notifyTetheringDisabledByRestriction() - verifyNotification(NOTIFICATION_ICON_ID, disallowTitle, disallowMessage, + verifyNotification(NOTIFICATION_ICON_ID, TEST_DISALLOW_TITLE, TEST_DISALLOW_MESSAGE, RESTRICTED_NOTIFICATION_ID) } @@ -356,15 +228,14 @@ class TetheringNotificationUpdaterTest { } @Test - fun testNotificationWithUpstreamCapabilitiesChanged_NoUpstream() { - // Set test sub id. No notification. + fun testNoUpstreamNotification() { + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, - ROAMING_NOTIFICATION_ID)) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) - // Wifi downstream. Show enable notification with test resource. + // Wifi downstream. notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) // There is no upstream. Show no upstream notification. notificationUpdater.onUpstreamCapabilitiesChanged(null) @@ -386,15 +257,14 @@ class TetheringNotificationUpdaterTest { verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, NO_UPSTREAM_NOTIFICATION_ID) - // No downstream. No notification. + // No downstream. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, - ROAMING_NOTIFICATION_ID)) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) - // Put up enable notification with wifi downstream and home capabilities. + // Wifi downstream and home capabilities. notificationUpdater.onDownstreamChanged(WIFI_MASK) notificationUpdater.onUpstreamCapabilitiesChanged(HOME_CAPABILITIES) - verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) // Set R.integer.delay_to_show_no_upstream_after_no_backhaul to -1 and change to no upstream // again. Don't put up no upstream notification. @@ -429,15 +299,14 @@ class TetheringNotificationUpdaterTest { } @Test - fun testNotificationWithUpstreamCapabilitiesChanged_Roaming() { - // Set test sub id. Clear notification. + fun testRoamingNotification() { + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, - ROAMING_NOTIFICATION_ID)) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) - // Wifi downstream. Show enable notification with test resource. + // Wifi downstream. notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) // Upstream capabilities changed to roaming state. Show roaming notification. notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) @@ -464,14 +333,16 @@ class TetheringNotificationUpdaterTest { verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, NO_UPSTREAM_NOTIFICATION_ID) - // No downstream. No notification. + // No downstream. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) - verifyNotificationCancelled(listOf(ENABLE_NOTIFICATION_ID, NO_UPSTREAM_NOTIFICATION_ID, - ROAMING_NOTIFICATION_ID)) + verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) - // Wifi downstream again. Show enable notification with test resource. + // Wifi downstream again. notificationUpdater.onDownstreamChanged(WIFI_MASK) - verifyNotification(WIFI_ICON_ID, TEST_TITLE, TEST_MESSAGE, ENABLE_NOTIFICATION_ID) + notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) + verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID), false) + verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, + NO_UPSTREAM_NOTIFICATION_ID) // Set R.bool.config_upstream_roaming_notification to false and change upstream // network to roaming state again. No roaming notification. From 958e8d1ceb9753ab760752dbd35be101a3d0346a Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 20 Apr 2020 18:51:17 +0900 Subject: [PATCH 0979/1415] Skip new UrlQuerySanitizer tests on Q The tests verify behavior that was only fixed on R, but UrlQuerySanitizerTest is part of MTS which needs to pass on Q. Test: atest CtsNetTestCasesLatestSdk:UrlQuerySanitizerTest Bug: 150904735 Change-Id: I214b2fd8a45732a41e8604db70c83a8e3f4a45e4 --- .../net/cts/UrlQuerySanitizerTest.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java index 82b3b14d34..5a70928e37 100644 --- a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -16,16 +16,38 @@ package android.net.cts; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import android.net.UrlQuerySanitizer; import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; import android.net.UrlQuerySanitizer.ParameterValuePair; import android.net.UrlQuerySanitizer.ValueSanitizer; -import android.test.AndroidTestCase; +import android.os.Build; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; import java.util.List; import java.util.Set; -public class UrlQuerySanitizerTest extends AndroidTestCase { +@SmallTest +@RunWith(AndroidJUnit4.class) +public class UrlQuerySanitizerTest { + @Rule + public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); + private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; // URL for test. @@ -42,6 +64,7 @@ public class UrlQuerySanitizerTest extends AndroidTestCase { private static final String AGE = "age"; private static final String HEIGHT = "height"; + @Test public void testUrlQuerySanitizer() { MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer(); assertFalse(uqs.getAllowUnregisteredParamaters()); @@ -210,12 +233,14 @@ public class UrlQuerySanitizerTest extends AndroidTestCase { } + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // Only fixed in R public void testScriptUrlOk_73822755() { ValueSanitizer sanitizer = new UrlQuerySanitizer.IllegalCharacterValueSanitizer( UrlQuerySanitizer.IllegalCharacterValueSanitizer.SCRIPT_URL_OK); assertEquals("javascript:alert()", sanitizer.sanitize("javascript:alert()")); } + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // Only fixed in R public void testScriptUrlBlocked_73822755() { ValueSanitizer sanitizer = UrlQuerySanitizer.getUrlAndSpaceLegal(); assertEquals("", sanitizer.sanitize("javascript:alert()")); From 257cad80525882bf7aec05e172a182e9fd9f2ab4 Mon Sep 17 00:00:00 2001 From: markchien Date: Sat, 11 Apr 2020 18:53:35 +0800 Subject: [PATCH 0980/1415] Test enable tethering permission and stopAllTethering 1. Test whether start tethering is gated by suitable permission. 2. Test stopAllTethering Bug: 153613718 Test: atest CtsTetheringTest Change-Id: I38702886ea355e1aec8eb8ac404fdd46a44582e3 --- tests/cts/tethering/Android.bp | 1 + .../tethering/cts/TetheringManagerTest.java | 274 ++++++++++++------ 2 files changed, 189 insertions(+), 86 deletions(-) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 63de301d69..a5930aa98b 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -27,6 +27,7 @@ android_test { static_libs: [ "TetheringIntegrationTestsLib", "compatibility-device-util-axt", + "net-tests-utils", "ctstestrunner-axt", "junit", "junit-params", diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index ccad14cdd2..60f9400363 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,20 +15,24 @@ */ package android.tethering.test; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; +import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.app.UiAutomation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -48,6 +52,8 @@ import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.testutils.ArrayTrackRecord; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -77,11 +83,21 @@ public class TetheringManagerTest { private static final int DEFAULT_TIMEOUT_MS = 60_000; + private void adoptShellPermissionIdentity() { + final UiAutomation uiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uiAutomation.adoptShellPermissionIdentity(); + } + + private void dropShellPermissionIdentity() { + final UiAutomation uiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uiAutomation.dropShellPermissionIdentity(); + } + @Before public void setUp() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(); + adoptShellPermissionIdentity(); mContext = InstrumentationRegistry.getContext(); mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); mTetherChangeReceiver = new TetherChangeReceiver(); @@ -93,10 +109,9 @@ public class TetheringManagerTest { @After public void tearDown() throws Exception { + mTM.stopAllTethering(); mContext.unregisterReceiver(mTetherChangeReceiver); - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .dropShellPermissionIdentity(); + dropShellPermissionIdentity(); } private class TetherChangeReceiver extends BroadcastReceiver { @@ -202,15 +217,54 @@ public class TetheringManagerTest { } } - private class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static int TIMEOUT_MS = 30_000; + public static class CallbackValue { + public final int error; + + private CallbackValue(final int e) { + error = e; + } + + public static class OnTetheringStarted extends CallbackValue { + OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); } + } + + public static class OnTetheringFailed extends CallbackValue { + OnTetheringFailed(final int error) { super(error); } + } + + @Override + public String toString() { + return String.format("%s(%d)", getClass().getSimpleName(), error); + } + } + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + @Override public void onTetheringStarted() { - // Do nothing, TetherChangeReceiver will wait until it receives the broadcast. + mHistory.add(new CallbackValue.OnTetheringStarted()); } @Override public void onTetheringFailed(final int error) { - fail("startTethering fail: " + error); + mHistory.add(new CallbackValue.OnTetheringFailed(error)); + } + + public void verifyTetheringStarted() { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv); + assertTrue("Fail start tethering:" + cv, + cv instanceof CallbackValue.OnTetheringStarted); + } + + public void expectTetheringFailed(final int expected) throws InterruptedException { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv); + assertTrue("Expect fail with error code " + expected + ", but received: " + cv, + (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected)); } } @@ -244,8 +298,10 @@ public class TetheringManagerTest { mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(), - startTetheringCallback); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); + mTetherChangeReceiver.expectActiveTethering(wifiRegexs); mTM.stopTethering(TETHERING_WIFI); @@ -277,6 +333,7 @@ public class TetheringManagerTest { // Must poll the callback before looking at the member. private static class TestTetheringEventCallback implements TetheringEventCallback { + private static final int TIMEOUT_MS = 30_000; public enum CallbackType { ON_SUPPORTED, ON_UPSTREAM, @@ -299,7 +356,10 @@ public class TetheringManagerTest { this.callbackParam2 = param2; } } - private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + private TetheringInterfaceRegexps mTetherableRegex; private List mTetherableIfaces; @@ -307,108 +367,96 @@ public class TetheringManagerTest { @Override public void onTetheringSupported(boolean supported) { - mCallbacks.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); } @Override public void onUpstreamChanged(Network network) { - mCallbacks.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); } @Override public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { mTetherableRegex = reg; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); } @Override public void onTetherableInterfacesChanged(List interfaces) { mTetherableIfaces = interfaces; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); } @Override public void onTetheredInterfacesChanged(List interfaces) { mTetheredIfaces = interfaces; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); } @Override public void onError(String ifName, int error) { - mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); + mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); } @Override public void onClientsChanged(Collection clients) { - mCallbacks.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); } @Override public void onOffloadStatusChanged(int status) { - mCallbacks.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); - } - - public CallbackValue pollCallback() { - try { - return mCallbacks.poll(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - fail("Callback not seen"); - } - return null; + mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); } public void expectTetherableInterfacesChanged(@NonNull List regexs) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected tetherable ifaces callback"); - if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) continue; - - final List interfaces = (List) cv.callbackParam; - if (isIfaceMatch(regexs, interfaces)) break; - } + assertNotNull("No expected tetherable ifaces callback", mHistory.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; + final List interfaces = (List) cv.callbackParam; + return isIfaceMatch(regexs, interfaces); + })); } public void expectTetheredInterfacesChanged(@NonNull List regexs) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected tethered ifaces callback"); - if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) continue; + assertNotNull("No expected tethered ifaces callback", mHistory.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; - final List interfaces = (List) cv.callbackParam; + final List interfaces = (List) cv.callbackParam; - // Null regexs means no active tethering. - if (regexs == null) { - if (interfaces.size() == 0) break; - } else if (isIfaceMatch(regexs, interfaces)) { - break; - } - } + // Null regexs means no active tethering. + if (regexs == null) return interfaces.isEmpty(); + + return isIfaceMatch(regexs, interfaces); + })); } public void expectCallbackStarted() { + int receivedBitMap = 0; // The each bit represent a type from CallbackType.ON_*. // Expect all of callbacks except for ON_ERROR. - final int expectedBitMap = 0x7f ^ (1 << CallbackType.ON_ERROR.ordinal()); - int receivedBitMap = 0; - while (receivedBitMap != expectedBitMap) { - final CallbackValue cv = pollCallback(); + final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal()); + // Receive ON_ERROR on started callback is not matter. It just means tethering is + // failed last time, should able to continue the test this time. + while ((receivedBitMap & expectedBitMap) != expectedBitMap) { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); if (cv == null) { fail("No expected callbacks, " + "expected bitmap: " + expectedBitMap + ", actual: " + receivedBitMap); } - receivedBitMap = receivedBitMap | (1 << cv.callbackType.ordinal()); + receivedBitMap |= (1 << cv.callbackType.ordinal()); } } public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected offload status change callback"); - if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) continue; + assertNotNull("No offload status changed", mHistory.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; final int status = (int) cv.callbackParam; - for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return; - } + for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return true; + + return false; + })); } public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { @@ -424,52 +472,78 @@ public class TetheringManagerTest { } } - @Test - public void testRegisterTetheringEventCallback() throws Exception { - if (!mTM.isTetheringSupported()) return; - + private TestTetheringEventCallback registerTetheringEventCallback() { final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); - mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); + mTM.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); tetherEventCallback.expectCallbackStarted(); - tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - final TetheringInterfaceRegexps tetherableRegexs = - tetherEventCallback.getTetheringInterfaceRegexps(); - final List wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); - if (wifiRegexs.size() == 0) return; + return tetherEventCallback; + } + private void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) { + mTM.unregisterTetheringEventCallback(callback); + } + + private List getWifiTetherableInterfaceRegexps( + final TestTetheringEventCallback callback) { + return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); + } + + private boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) { + return !getWifiTetherableInterfaceRegexps(callback).isEmpty(); + } + + private void startWifiTethering(final TestTetheringEventCallback callback) + throws InterruptedException { + final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); final boolean isIfaceAvailWhenNoTethering = - isIfaceMatch(wifiRegexs, tetherEventCallback.getTetherableInterfaces()); + isIfaceMatch(wifiRegexs, callback.getTetherableInterfaces()); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(), - new StartTetheringCallback()); + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); // If interface is already available before starting tethering, the available callback may // not be sent after tethering enabled. if (!isIfaceAvailWhenNoTethering) { - tetherEventCallback.expectTetherableInterfacesChanged(wifiRegexs); + callback.expectTetherableInterfacesChanged(wifiRegexs); } - tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); - tetherEventCallback.expectOneOfOffloadStatusChanged( + callback.expectTetheredInterfacesChanged(wifiRegexs); + + callback.expectOneOfOffloadStatusChanged( TETHER_HARDWARE_OFFLOAD_STARTED, TETHER_HARDWARE_OFFLOAD_FAILED); + } + private void stopWifiTethering(final TestTetheringEventCallback callback) { mTM.stopTethering(TETHERING_WIFI); + callback.expectTetheredInterfacesChanged(null); + callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + } - tetherEventCallback.expectTetheredInterfacesChanged(null); - tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - mTM.unregisterTetheringEventCallback(tetherEventCallback); + @Test + public void testRegisterTetheringEventCallback() throws Exception { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + + if (!isWifiTetheringSupported(tetherEventCallback)) return; + + startWifiTethering(tetherEventCallback); + + stopWifiTethering(tetherEventCallback); + + unregisterTetheringEventCallback(tetherEventCallback); } @Test public void testGetTetherableInterfaceRegexps() { if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); - mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); - tetherEventCallback.expectCallbackStarted(); + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); final TetheringInterfaceRegexps tetherableRegexs = tetherEventCallback.getTetheringInterfaceRegexps(); @@ -486,7 +560,35 @@ public class TetheringManagerTest { wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); - mTM.unregisterTetheringEventCallback(tetherEventCallback); + unregisterTetheringEventCallback(tetherEventCallback); + } + + @Test + public void testStopAllTethering() throws Exception { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + + if (!isWifiTetheringSupported(tetherEventCallback)) return; + + // TODO: start ethernet tethering here when TetheringManagerTest is moved to + // TetheringIntegrationTest. + + startWifiTethering(tetherEventCallback); + + mTM.stopAllTethering(); + tetherEventCallback.expectTetheredInterfacesChanged(null); + + unregisterTetheringEventCallback(tetherEventCallback); + } + + @Test + public void testEnableTetheringPermission() throws Exception { + dropShellPermissionIdentity(); + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); } private class EntitlementResultListener implements OnTetheringEntitlementResultListener { From 0f0e3a99f1c244d3e74b143b8e8c6e95f13f3014 Mon Sep 17 00:00:00 2001 From: Amit Mahajan Date: Tue, 7 Apr 2020 07:34:45 -0700 Subject: [PATCH 0981/1415] DO NOT MERGE Remove references of telephony-stubs. Since it's not used for now. Test: TH Bug: 153304048 Merged-in: I1812818c3d49463c3840a98212bbab58a110359a Change-Id: I1812818c3d49463c3840a98212bbab58a110359a --- Tethering/Android.bp | 1 - Tethering/tests/unit/Android.bp | 1 - 2 files changed, 2 deletions(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 5b052df75e..bfb65241ec 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -34,7 +34,6 @@ java_defaults { ], libs: [ "framework-tethering", - "framework-telephony-stubs", "framework-wifi-stubs-systemapi", "unsupportedappusage", ], diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp index 4849fd5d01..26517ceb72 100644 --- a/Tethering/tests/unit/Android.bp +++ b/Tethering/tests/unit/Android.bp @@ -38,7 +38,6 @@ java_defaults { "ext", "framework-minus-apex", "framework-res", - "framework-telephony-stubs", "framework-tethering", "framework-wifi-stubs-module_libs_api", ], From 64343b0b8d7c8eca363bd3e4e6d6d70c78da6224 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Thu, 26 Mar 2020 11:50:35 -0700 Subject: [PATCH 0982/1415] Set attributionTag for noteOp(WRITE_SETTINGS) calls Test: atest FrameworksNetTests TetheringTests:TetheringServiceTest Bug: 136595429 Merged-In: I33f787644c44d7b0e5ce17a433820cfcd985cdfb Change-Id: Ic3d937e7bb5141798234ed5b2852c1f768e97495 --- .../src/android/net/ITetheringConnector.aidl | 28 +++++--- .../src/android/net/TetheringManager.java | 43 +++++++----- .../tethering/TetheringService.java | 68 ++++++++++++------- .../tethering/TetheringServiceTest.java | 20 +++--- 4 files changed, 101 insertions(+), 58 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl index 8be79645bd..cf094aac2c 100644 --- a/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl +++ b/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl @@ -22,25 +22,31 @@ import android.os.ResultReceiver; /** @hide */ oneway interface ITetheringConnector { - void tether(String iface, String callerPkg, IIntResultListener receiver); - - void untether(String iface, String callerPkg, IIntResultListener receiver); - - void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver); - - void startTethering(in TetheringRequestParcel request, String callerPkg, + void tether(String iface, String callerPkg, String callingAttributionTag, IIntResultListener receiver); - void stopTethering(int type, String callerPkg, IIntResultListener receiver); + void untether(String iface, String callerPkg, String callingAttributionTag, + IIntResultListener receiver); + + void setUsbTethering(boolean enable, String callerPkg, + String callingAttributionTag, IIntResultListener receiver); + + void startTethering(in TetheringRequestParcel request, String callerPkg, + String callingAttributionTag, IIntResultListener receiver); + + void stopTethering(int type, String callerPkg, String callingAttributionTag, + IIntResultListener receiver); void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver, - boolean showEntitlementUi, String callerPkg); + boolean showEntitlementUi, String callerPkg, String callingAttributionTag); void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); - void isTetheringSupported(String callerPkg, IIntResultListener receiver); + void isTetheringSupported(String callerPkg, String callingAttributionTag, + IIntResultListener receiver); - void stopAllTethering(String callerPkg, IIntResultListener receiver); + void stopAllTethering(String callerPkg, String callingAttributionTag, + IIntResultListener receiver); } diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 0107a7ef5b..04ca033828 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -484,13 +484,20 @@ public class TetheringManager { return dispatcher.waitForResult((connector, listener) -> { try { - connector.tether(iface, callerPkg, listener); + connector.tether(iface, callerPkg, getAttributionTag(), listener); } catch (RemoteException e) { throw new IllegalStateException(e); } }); } + /** + * @return the context's attribution tag + */ + private @Nullable String getAttributionTag() { + return null; + } + /** * Stop tethering the named interface. * @@ -509,7 +516,7 @@ public class TetheringManager { return dispatcher.waitForResult((connector, listener) -> { try { - connector.untether(iface, callerPkg, listener); + connector.untether(iface, callerPkg, getAttributionTag(), listener); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -536,7 +543,8 @@ public class TetheringManager { return dispatcher.waitForResult((connector, listener) -> { try { - connector.setUsbTethering(enable, callerPkg, listener); + connector.setUsbTethering(enable, callerPkg, getAttributionTag(), + listener); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -735,7 +743,8 @@ public class TetheringManager { }); } }; - getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener)); + getConnector(c -> c.startTethering(request.getParcel(), callerPkg, + getAttributionTag(), listener)); } /** @@ -775,7 +784,8 @@ public class TetheringManager { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "stopTethering caller:" + callerPkg); - getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() { + getConnector(c -> c.stopTethering(type, callerPkg, getAttributionTag(), + new IIntResultListener.Stub() { @Override public void onResult(int resultCode) { // TODO: provide an API to obtain result @@ -861,7 +871,7 @@ public class TetheringManager { Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg); getConnector(c -> c.requestLatestTetheringEntitlementResult( - type, receiver, showEntitlementUi, callerPkg)); + type, receiver, showEntitlementUi, callerPkg, getAttributionTag())); } /** @@ -1312,7 +1322,7 @@ public class TetheringManager { final RequestDispatcher dispatcher = new RequestDispatcher(); final int ret = dispatcher.waitForResult((connector, listener) -> { try { - connector.isTetheringSupported(callerPkg, listener); + connector.isTetheringSupported(callerPkg, getAttributionTag(), listener); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -1335,14 +1345,15 @@ public class TetheringManager { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "stopAllTethering caller:" + callerPkg); - getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() { - @Override - public void onResult(int resultCode) { - // TODO: add an API parameter to send result to caller. - // This has never been possible as stopAllTethering has always been void and never - // taken a callback object. The only indication that callers have is if the call - // results in a TETHER_STATE_CHANGE broadcast. - } - })); + getConnector(c -> c.stopAllTethering(callerPkg, getAttributionTag(), + new IIntResultListener.Stub() { + @Override + public void onResult(int resultCode) { + // TODO: add an API parameter to send result to caller. + // This has never been possible as stopAllTethering has always been void + // and never taken a callback object. The only indication that callers have + // is if the call results in a TETHER_STATE_CHANGE broadcast. + } + })); } } diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java index 3ed211520d..c82e2be72a 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -119,8 +119,9 @@ public class TetheringService extends Service { } @Override - public void tether(String iface, String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void tether(String iface, String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { listener.onResult(mTethering.tether(iface)); @@ -128,8 +129,9 @@ public class TetheringService extends Service { } @Override - public void untether(String iface, String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void untether(String iface, String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { listener.onResult(mTethering.untether(iface)); @@ -137,8 +139,9 @@ public class TetheringService extends Service { } @Override - public void setUsbTethering(boolean enable, String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void setUsbTethering(boolean enable, String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { listener.onResult(mTethering.setUsbTethering(enable)); @@ -147,15 +150,16 @@ public class TetheringService extends Service { @Override public void startTethering(TetheringRequestParcel request, String callerPkg, - IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + String callingAttributionTag, IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; mTethering.startTethering(request, listener); } @Override - public void stopTethering(int type, String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void stopTethering(int type, String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { mTethering.stopTethering(type); @@ -165,8 +169,8 @@ public class TetheringService extends Service { @Override public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, - boolean showEntitlementUi, String callerPkg) { - if (checkAndNotifyCommonError(callerPkg, receiver)) return; + boolean showEntitlementUi, String callerPkg, String callingAttributionTag) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, receiver)) return; mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); } @@ -196,8 +200,9 @@ public class TetheringService extends Service { } @Override - public void stopAllTethering(String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void stopAllTethering(String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { mTethering.untetherAll(); @@ -206,8 +211,9 @@ public class TetheringService extends Service { } @Override - public void isTetheringSupported(String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void isTetheringSupported(String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { listener.onResult(TETHER_ERROR_NO_ERROR); @@ -220,9 +226,10 @@ public class TetheringService extends Service { mTethering.dump(fd, writer, args); } - private boolean checkAndNotifyCommonError(String callerPkg, IIntResultListener listener) { + private boolean checkAndNotifyCommonError(String callerPkg, String callingAttributionTag, + IIntResultListener listener) { try { - if (!mService.hasTetherChangePermission(callerPkg)) { + if (!mService.hasTetherChangePermission(callerPkg, callingAttributionTag)) { listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); return true; } @@ -237,8 +244,9 @@ public class TetheringService extends Service { return false; } - private boolean checkAndNotifyCommonError(String callerPkg, ResultReceiver receiver) { - if (!mService.hasTetherChangePermission(callerPkg)) { + private boolean checkAndNotifyCommonError(String callerPkg, String callingAttributionTag, + ResultReceiver receiver) { + if (!mService.hasTetherChangePermission(callerPkg, callingAttributionTag)) { receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null); return true; } @@ -266,7 +274,7 @@ public class TetheringService extends Service { return tetherEnabledInSettings && mTethering.hasTetherableConfiguration(); } - private boolean hasTetherChangePermission(String callerPkg) { + private boolean hasTetherChangePermission(String callerPkg, String callingAttributionTag) { if (checkCallingOrSelfPermission( android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) { return true; @@ -278,14 +286,28 @@ public class TetheringService extends Service { int uid = Binder.getCallingUid(); // If callerPkg's uid is not same as Binder.getCallingUid(), // checkAndNoteWriteSettingsOperation will return false and the operation will be denied. - if (Settings.checkAndNoteWriteSettingsOperation(mContext, uid, callerPkg, - false /* throwException */)) { + if (checkAndNoteWriteSettingsOperation(mContext, uid, callerPkg, + callingAttributionTag, false /* throwException */)) { return true; } return false; } + /** + * Check if the package is a allowed to write settings. This also accounts that such an access + * happened. + * + * @return {@code true} iff the package is allowed to write settings. + */ + // TODO: Remove method and replace with direct call once R code is pushed to AOSP + private static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, + @NonNull String callingPackage, @Nullable String callingAttributionTag, + boolean throwException) { + return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage, + throwException); + } + private boolean hasTetherAccessPermission() { if (checkCallingOrSelfPermission( android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) { diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index 51bad9af23..7df9fc6850 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -52,6 +52,7 @@ import org.mockito.MockitoAnnotations; public final class TetheringServiceTest { private static final String TEST_IFACE_NAME = "test_wlan0"; private static final String TEST_CALLER_PKG = "test_pkg"; + private static final String TEST_ATTRIBUTION_TAG = null; @Mock private ITetheringEventCallback mITetheringEventCallback; @Rule public ServiceTestRule mServiceTestRule; private Tethering mTethering; @@ -95,7 +96,7 @@ public final class TetheringServiceTest { public void testTether() throws Exception { when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).tether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); @@ -106,7 +107,8 @@ public final class TetheringServiceTest { public void testUntether() throws Exception { when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).untether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); @@ -117,7 +119,8 @@ public final class TetheringServiceTest { public void testSetUsbTethering() throws Exception { when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR); final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, + TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).setUsbTethering(true /* enable */); verifyNoMoreInteractions(mTethering); @@ -129,7 +132,7 @@ public final class TetheringServiceTest { final TestTetheringResult result = new TestTetheringResult(); final TetheringRequestParcel request = new TetheringRequestParcel(); request.tetheringType = TETHERING_WIFI; - mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).startTethering(eq(request), eq(result)); verifyNoMoreInteractions(mTethering); @@ -138,7 +141,8 @@ public final class TetheringServiceTest { @Test public void testStopTethering() throws Exception { final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result); + mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).stopTethering(TETHERING_WIFI); verifyNoMoreInteractions(mTethering); @@ -149,7 +153,7 @@ public final class TetheringServiceTest { public void testRequestLatestTetheringEntitlementResult() throws Exception { final ResultReceiver result = new ResultReceiver(null); mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, - true /* showEntitlementUi */, TEST_CALLER_PKG); + true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI), eq(result), eq(true) /* showEntitlementUi */); @@ -176,7 +180,7 @@ public final class TetheringServiceTest { @Test public void testStopAllTethering() throws Exception { final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result); + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).untetherAll(); verifyNoMoreInteractions(mTethering); @@ -186,7 +190,7 @@ public final class TetheringServiceTest { @Test public void testIsTetheringSupported() throws Exception { final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result); + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); From 3ee47d42333849f25a0a5618f217156790ef8c36 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Mon, 20 Apr 2020 15:15:58 +0000 Subject: [PATCH 0983/1415] Update network object when wifi meterness is changed The new wifi disconnect behavior is introduced. When wifi network is changed from unmetered to metered, the wifi network will disconnect and reconnect. Update the test to verify the same SSID wifi is connected and also update the target network to verfiy the metered preference. Bug: 153400606 Test: atest CtsNetTestCases:android.net.cts.ConnectivityManagerTest\ #testGetMultipathPreference Change-Id: Ic298d3d85d8c6b77c8df7614a945f2c22dcdff38 Merged-In: Ic298d3d85d8c6b77c8df7614a945f2c22dcdff38 (cherry picked from commit 37d5d4387cce865d159e80e5101685b4c2a13731) --- .../net/src/android/net/cts/ConnectivityManagerTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index fa7e1381b3..3a52ee60a3 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -709,7 +709,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testGetMultipathPreference() throws Exception { final ContentResolver resolver = mContext.getContentResolver(); - final Network network = ensureWifiConnected(); + ensureWifiConnected(); final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID()); final String oldMeteredSetting = getWifiMeteredStatus(ssid); final String oldMeteredMultipathPreference = Settings.Global.getString( @@ -721,6 +721,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { Integer.toString(newMeteredPreference)); setWifiMeteredStatus(ssid, "true"); waitForActiveNetworkMetered(true); + // Wifi meterness changes from unmetered to metered will disconnect and reconnect since + // R. + final Network network = mCm.getActiveNetwork(); + assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID())); assertEquals(mCm.getNetworkCapabilities(network).hasCapability( NET_CAPABILITY_NOT_METERED), false); assertMultipathPreferenceIsEventually(network, initialMeteredPreference, @@ -736,6 +740,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { oldMeteredPreference, newMeteredPreference); setWifiMeteredStatus(ssid, "false"); + // No disconnect from unmetered to metered. waitForActiveNetworkMetered(false); assertEquals(mCm.getNetworkCapabilities(network).hasCapability( NET_CAPABILITY_NOT_METERED), true); From 6f8e61226444178d653f151f3066946fb60cf30b Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 21 Apr 2020 03:46:08 +0000 Subject: [PATCH 0984/1415] Remove upper bound check of getTotal* APIs in TrafficStatsTest Currently, this cause flakiness since some background traffic was counted when performing tests, or the traffic generated by adb over network. While there is no good way to filter out all reasonable cases, disable the upper bound checks. Test: atest TrafficStatsTest Bug: 142978584 Change-Id: I22edc46039bf35e544d9ce8a9f3a00b713478e05 Merged-In: I22edc46039bf35e544d9ce8a9f3a00b713478e05 Merged-In: I8140310c9caeff6069d1f55590bf40f83bf211e4 (cherry picked from commit 8accc6aa11213a7a8287a2ec0f75f17a02173f99) --- .../src/android/net/cts/TrafficStatsTest.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 577e24ac29..37bdd44fbf 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -16,11 +16,9 @@ package android.net.cts; -import android.content.pm.PackageManager; import android.net.NetworkStats; import android.net.TrafficStats; import android.os.Process; -import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; import android.util.Log; @@ -267,28 +265,6 @@ public class TrafficStatsTest extends AndroidTestCase { assertTrue("ifrxp: " + ifaceRxPacketsBefore + " -> " + ifaceRxPacketsAfter, totalRxPacketsAfter >= totalRxPacketsBefore + ifaceRxDeltaPackets); - // If the adb TCP port is opened, this test may be run by adb over network. - // Huge amount of data traffic might go through the network and accounted into total packets - // stats. The upper bound check would be meaningless. - // TODO: Consider precisely calculate the traffic accounted due to adb over network and - // subtract it when checking upper bound instead of skip checking. - final PackageManager pm = mContext.getPackageManager(); - if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 - || SystemProperties.getInt("service.adb.tcp.port", -1) > -1 - || !pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) { - Log.i(LOG_TAG, "adb is running over the network, skip the upper bound check"); - } else { - // Fudge by 132 packets of 1500 bytes not related to the test. - assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, - totalTxPacketsAfter <= totalTxPacketsBefore + uidTxDeltaPackets + 132); - assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, - totalRxPacketsAfter <= totalRxPacketsBefore + uidRxDeltaPackets + 132); - assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, - totalTxBytesAfter <= totalTxBytesBefore + uidTxDeltaBytes + 132 * 1500); - assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, - totalRxBytesAfter <= totalRxBytesBefore + uidRxDeltaBytes + 132 * 1500); - } - // Localhost traffic should *not* count against mobile stats, // There might be some other traffic, but nowhere near 1MB. assertInRange("mtxp", mobileTxPacketsAfter, mobileTxPacketsBefore, From a7f8f2d01ca33d18381ab906aa051f6264f9920e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 21 Apr 2020 15:09:16 +0900 Subject: [PATCH 0985/1415] Fix test initialization errors on Q ConnectivityDiagnosticsManagerTest, MultinetworkApiTest, NetworkAgentTest crashed before the runner could start them: - Ignore ConnectivityDiagnosticsManagerTest on Q: it tests an API that was introduced in R. - Build JNI libraries used by MultinetworkApiTest against the NDK to avoid errors loading the libraries on older platforms, when transitive dependencies have been added. - Do not attempt to override Handler#getLooper() (which is final) in NetworkAgentTest; it appears to have been overridden by accident by specifying "val looper" in the TestableNetworkAgent definition, which generates a getter. Test: atest CtsNetTestCasesLatestSdk:ConnectivityDiagnosticsManagerTest atest CtsNetTestCasesLatestSdk:MultinetworkApiTest atest CtsNetTestCasesLatestSdk:NetworkAgentTest Bug: 150918852 Change-Id: I262b54c6897ed755adaeb2b118c638320634f7a1 --- tests/cts/net/jni/Android.bp | 2 + tests/cts/net/jni/NativeDnsJni.c | 41 +++++++++++-------- tests/cts/net/jni/NativeMultinetworkJni.cpp | 35 ++++++++-------- .../ConnectivityDiagnosticsManagerTest.java | 9 ++-- .../src/android/net/cts/NetworkAgentTest.kt | 2 +- 5 files changed, 51 insertions(+), 38 deletions(-) diff --git a/tests/cts/net/jni/Android.bp b/tests/cts/net/jni/Android.bp index baed48dfae..3953aeb701 100644 --- a/tests/cts/net/jni/Android.bp +++ b/tests/cts/net/jni/Android.bp @@ -16,6 +16,7 @@ cc_library_shared { name: "libnativedns_jni", srcs: ["NativeDnsJni.c"], + sdk_version: "current", shared_libs: [ "libnativehelper_compat_libc++", @@ -35,6 +36,7 @@ cc_library_shared { name: "libnativemultinetwork_jni", srcs: ["NativeMultinetworkJni.cpp"], + sdk_version: "current", cflags: [ "-Wall", "-Werror", diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 6d3d1c3250..4ec800e555 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -19,7 +19,12 @@ #include #include #include -#include + +#include + +#define LOG_TAG "NativeDns-JNI" +#define LOGD(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) const char *GoogleDNSIpV4Address="8.8.8.8"; const char *GoogleDNSIpV4Address2="8.8.4.4"; @@ -33,7 +38,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas struct addrinfo *answer; int res = getaddrinfo(node, service, NULL, &answer); - ALOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res)); + LOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res)); if (res != 0) return JNI_FALSE; // check for v4 & v6 @@ -47,12 +52,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, buf, sizeof(buf)); foundv4 = 1; - ALOGD(" %s", buf); + LOGD(" %s", buf); } else if (current->ai_addr->sa_family == AF_INET6) { inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, buf, sizeof(buf)); foundv6 = 1; - ALOGD(" %s", buf); + LOGD(" %s", buf); } current = current->ai_next; } @@ -60,14 +65,14 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas freeaddrinfo(answer); answer = NULL; if (foundv4 != 1 && foundv6 != 1) { - ALOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address"); + LOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address"); return JNI_FALSE; } } node = "ipv6.google.com"; res = getaddrinfo(node, service, NULL, &answer); - ALOGD("getaddrinfo(ipv6.google.com) gave res=%d", res); + LOGD("getaddrinfo(ipv6.google.com) gave res=%d", res); if (res != 0) return JNI_FALSE; { @@ -79,12 +84,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas if (current->ai_addr->sa_family == AF_INET) { inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, buf, sizeof(buf)); - ALOGD(" %s", buf); + LOGD(" %s", buf); foundv4 = 1; } else if (current->ai_addr->sa_family == AF_INET6) { inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, buf, sizeof(buf)); - ALOGD(" %s", buf); + LOGD(" %s", buf); foundv6 = 1; } current = current->ai_next; @@ -93,7 +98,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas freeaddrinfo(answer); answer = NULL; if (foundv4 == 1 || foundv6 != 1) { - ALOGD("getaddrinfo(ipv6.google.com) didn't find only v6"); + LOGD("getaddrinfo(ipv6.google.com) didn't find only v6"); return JNI_FALSE; } } @@ -116,12 +121,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas res = getnameinfo((const struct sockaddr*)&sa4, sizeof(sa4), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { - ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res, + LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res, gai_strerror(res)); return JNI_FALSE; } if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { - ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", GoogleDNSIpV4Address, buf); return JNI_FALSE; } @@ -129,12 +134,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas memset(buf, 0, sizeof(buf)); res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { - ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, + LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, res, gai_strerror(res)); return JNI_FALSE; } if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { - ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", GoogleDNSIpV6Address2, buf); return JNI_FALSE; } @@ -142,11 +147,11 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas // gethostbyname struct hostent *my_hostent = gethostbyname("www.youtube.com"); if (my_hostent == NULL) { - ALOGD("gethostbyname(www.youtube.com) gave null response"); + LOGD("gethostbyname(www.youtube.com) gave null response"); return JNI_FALSE; } if ((my_hostent->h_addr_list == NULL) || (*my_hostent->h_addr_list == NULL)) { - ALOGD("gethostbyname(www.youtube.com) gave 0 addresses"); + LOGD("gethostbyname(www.youtube.com) gave 0 addresses"); return JNI_FALSE; } { @@ -154,7 +159,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas while (*current != NULL) { char buf[256]; inet_ntop(my_hostent->h_addrtype, *current, buf, sizeof(buf)); - ALOGD("gethostbyname(www.youtube.com) gave %s", buf); + LOGD("gethostbyname(www.youtube.com) gave %s", buf); current++; } } @@ -164,11 +169,11 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas inet_pton(AF_INET6, GoogleDNSIpV6Address, addr6); my_hostent = gethostbyaddr(addr6, sizeof(addr6), AF_INET6); if (my_hostent == NULL) { - ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address); + LOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address); return JNI_FALSE; } - ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address, + LOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address, my_hostent->h_name ? my_hostent->h_name : "null"); if (my_hostent->h_name == NULL) return JNI_FALSE; diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index 2832c3d142..cd94709fd5 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "MultinetworkApiTest" -#include #include #include @@ -34,9 +33,13 @@ #include +#include #include #include +#define LOGD(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) + #define EXPECT_GE(env, actual, expected, msg) \ do { \ if (actual < expected) { \ @@ -138,7 +141,7 @@ int expectAnswersNotValid(JNIEnv* env, int fd, int expectedErrno) { uint8_t buf[MAXPACKET] = {}; int res = getAsyncResponse(env, fd, TIMEOUT_MS, &rcode, buf, MAXPACKET); if (res != expectedErrno) { - ALOGD("res:%d, expectedErrno = %d", res, expectedErrno); + LOGD("res:%d, expectedErrno = %d", res, expectedErrno); return (res > 0) ? -EREMOTEIO : res; } return 0; @@ -326,7 +329,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runGetaddrinfoCheck( const int saved_errno = errno; freeaddrinfo(res); - ALOGD("android_getaddrinfofornetwork(%" PRIu64 ", %s) returned rval=%d errno=%d", + LOGD("android_getaddrinfofornetwork(%" PRIu64 ", %s) returned rval=%d errno=%d", handle, kHostname, rval, saved_errno); return rval == 0 ? 0 : -saved_errno; } @@ -339,7 +342,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetprocnetwork( errno = 0; int rval = android_setprocnetwork(handle); const int saved_errno = errno; - ALOGD("android_setprocnetwork(%" PRIu64 ") returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%" PRIu64 ") returned rval=%d errno=%d", handle, rval, saved_errno); return rval == 0 ? 0 : -saved_errno; } @@ -352,14 +355,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetsocknetwork( errno = 0; int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { - ALOGD("socket() failed, errno=%d", errno); + LOGD("socket() failed, errno=%d", errno); return -errno; } errno = 0; int rval = android_setsocknetwork(handle, fd); const int saved_errno = errno; - ALOGD("android_setprocnetwork(%" PRIu64 ", %d) returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%" PRIu64 ", %d) returned rval=%d errno=%d", handle, fd, rval, saved_errno); close(fd); return rval == 0 ? 0 : -saved_errno; @@ -404,7 +407,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( static const char kPort[] = "443"; int rval = android_getaddrinfofornetwork(handle, kHostname, kPort, &kHints, &res); if (rval != 0) { - ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", + LOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", handle, kHostname, rval, errno); freeaddrinfo(res); return -errno; @@ -413,14 +416,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( // Rely upon getaddrinfo sorting the best destination to the front. int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd < 0) { - ALOGD("socket(%d, %d, %d) failed, errno=%d", + LOGD("socket(%d, %d, %d) failed, errno=%d", res->ai_family, res->ai_socktype, res->ai_protocol, errno); freeaddrinfo(res); return -errno; } rval = android_setsocknetwork(handle, fd); - ALOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", handle, fd, rval, errno); if (rval != 0) { close(fd); @@ -430,7 +433,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( char addrstr[kSockaddrStrLen+1]; sockaddr_ntop(res->ai_addr, res->ai_addrlen, addrstr, sizeof(addrstr)); - ALOGD("Attempting connect() to %s ...", addrstr); + LOGD("Attempting connect() to %s ...", addrstr); rval = connect(fd, res->ai_addr, res->ai_addrlen); if (rval != 0) { @@ -447,7 +450,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -errno; } sockaddr_ntop((const struct sockaddr *)&src_addr, sizeof(src_addr), addrstr, sizeof(addrstr)); - ALOGD("... from %s", addrstr); + LOGD("... from %s", addrstr); // Don't let reads or writes block indefinitely. const struct timeval timeo = { 2, 0 }; // 2 seconds @@ -479,7 +482,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( sent = send(fd, quic_packet, sizeof(quic_packet), 0); if (sent < (ssize_t)sizeof(quic_packet)) { errnum = errno; - ALOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum); + LOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum); close(fd); return -errnum; } @@ -489,14 +492,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( break; } else { errnum = errno; - ALOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d", + LOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d", i + 1, MAX_RETRIES, rcvd, errnum); } } if (rcvd < 9) { - ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); + LOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { - ALOGD("Does this network block UDP port %s?", kPort); + LOGD("Does this network block UDP port %s?", kPort); } close(fd); return -EPROTO; @@ -504,7 +507,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); if (conn_id_cmp != 0) { - ALOGD("sent and received connection IDs do not match"); + LOGD("sent and received connection IDs do not match"); close(fd); return -EPROTO; } diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 0a80047fdf..9d357055d1 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -18,15 +18,17 @@ package android.net.cts; import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import android.content.Context; import android.net.ConnectivityDiagnosticsManager; import android.net.NetworkRequest; +import android.os.Build; import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; @@ -34,7 +36,8 @@ import org.junit.runner.RunWith; import java.util.concurrent.Executor; -@RunWith(AndroidJUnit4.class) +@RunWith(DevSdkIgnoreRunner.class) +@IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q public class ConnectivityDiagnosticsManagerTest { private static final Executor INLINE_EXECUTOR = x -> x.run(); private static final NetworkRequest DEFAULT_REQUEST = new NetworkRequest.Builder().build(); diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 89d3dff66c..03b961bc4b 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -180,7 +180,7 @@ class NetworkAgentTest { } private open class TestableNetworkAgent( - val looper: Looper, + looper: Looper, val nc: NetworkCapabilities, val lp: LinkProperties, conf: NetworkAgentConfig From 90b45356d6c25f95f7da1252cec4d6beb3ffdb82 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 21 Apr 2020 17:42:47 +0800 Subject: [PATCH 0986/1415] Include NetworkStaticLibTestsLib into tethering coverage test Bug: 148636687 Test: atest NetworkStaticLibTests Test: atest TetheringCoverageTests Change-Id: I8cd9dbc9fe163583ff1d016c9262546949105b80 --- Tethering/tests/integration/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp index 6b751afdf5..3305ed0844 100644 --- a/Tethering/tests/integration/Android.bp +++ b/Tethering/tests/integration/Android.bp @@ -69,6 +69,7 @@ android_test { test_config: "AndroidTest_Coverage.xml", defaults: ["libnetworkstackutilsjni_deps"], static_libs: [ + "NetworkStaticLibTestsLib", "NetworkStackTestsLib", "TetheringTestsLib", "TetheringIntegrationTestsLib", From 06e440101bfd630e7ff6ce7a64314b47dd38249e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 21 Apr 2020 22:22:54 +0900 Subject: [PATCH 0987/1415] Retry the call that fetches the tethering offload HAL. The CL that moved the initialization of the tethering offload config HAL from C++ to Java caused the code not to retry fetching the service if it is not ready when tethering is started. This is because the C++ version of getService() retries, but the Java version only retries if getService(true) is called. Make the new code retry as well. b/152430668#comment4 asserts that the fetch will be retried only if the service is installed on the device, so the retries should be attempted (and thus should not have any startup time impact) on devices that do not support tethering offload. Bug: 152430668 Test: builds, boots, tethering offload works Change-Id: I093f127d90b2aa1b13eb0748378a24726d419472 --- .../networkstack/tethering/OffloadHardwareInterface.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index 85a23fb83f..55344fc75d 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -142,7 +142,7 @@ public class OffloadHardwareInterface { public boolean initOffloadConfig() { IOffloadConfig offloadConfig; try { - offloadConfig = IOffloadConfig.getService(); + offloadConfig = IOffloadConfig.getService(true /*retry*/); } catch (RemoteException e) { mLog.e("getIOffloadConfig error " + e); return false; From e96bd02054d620bb37acea0f7fcd56ee7c2287c5 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 21 Apr 2020 12:42:37 +0000 Subject: [PATCH 0988/1415] Fix test initialization errors on Q ConnectivityDiagnosticsManagerTest, MultinetworkApiTest, NetworkAgentTest crashed before the runner could start them: - Ignore ConnectivityDiagnosticsManagerTest on Q: it tests an API that was introduced in R. - Build JNI libraries used by MultinetworkApiTest against the NDK to avoid errors loading the libraries on older platforms, when transitive dependencies have been added. - Do not attempt to override Handler#getLooper() (which is final) in NetworkAgentTest; it appears to have been overridden by accident by specifying "val looper" in the TestableNetworkAgent definition, which generates a getter. Test: atest CtsNetTestCasesLatestSdk:ConnectivityDiagnosticsManagerTest atest CtsNetTestCasesLatestSdk:MultinetworkApiTest atest CtsNetTestCasesLatestSdk:NetworkAgentTest Bug: 150918852 Merged-In: I262b54c6897ed755adaeb2b118c638320634f7a1 Change-Id: I262b54c6897ed755adaeb2b118c638320634f7a1 --- tests/cts/net/jni/Android.bp | 2 + tests/cts/net/jni/NativeDnsJni.c | 41 +++++++++++-------- tests/cts/net/jni/NativeMultinetworkJni.cpp | 35 ++++++++-------- .../ConnectivityDiagnosticsManagerTest.java | 9 ++-- .../src/android/net/cts/NetworkAgentTest.kt | 2 +- 5 files changed, 51 insertions(+), 38 deletions(-) diff --git a/tests/cts/net/jni/Android.bp b/tests/cts/net/jni/Android.bp index baed48dfae..3953aeb701 100644 --- a/tests/cts/net/jni/Android.bp +++ b/tests/cts/net/jni/Android.bp @@ -16,6 +16,7 @@ cc_library_shared { name: "libnativedns_jni", srcs: ["NativeDnsJni.c"], + sdk_version: "current", shared_libs: [ "libnativehelper_compat_libc++", @@ -35,6 +36,7 @@ cc_library_shared { name: "libnativemultinetwork_jni", srcs: ["NativeMultinetworkJni.cpp"], + sdk_version: "current", cflags: [ "-Wall", "-Werror", diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 6d3d1c3250..4ec800e555 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -19,7 +19,12 @@ #include #include #include -#include + +#include + +#define LOG_TAG "NativeDns-JNI" +#define LOGD(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) const char *GoogleDNSIpV4Address="8.8.8.8"; const char *GoogleDNSIpV4Address2="8.8.4.4"; @@ -33,7 +38,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas struct addrinfo *answer; int res = getaddrinfo(node, service, NULL, &answer); - ALOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res)); + LOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res)); if (res != 0) return JNI_FALSE; // check for v4 & v6 @@ -47,12 +52,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, buf, sizeof(buf)); foundv4 = 1; - ALOGD(" %s", buf); + LOGD(" %s", buf); } else if (current->ai_addr->sa_family == AF_INET6) { inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, buf, sizeof(buf)); foundv6 = 1; - ALOGD(" %s", buf); + LOGD(" %s", buf); } current = current->ai_next; } @@ -60,14 +65,14 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas freeaddrinfo(answer); answer = NULL; if (foundv4 != 1 && foundv6 != 1) { - ALOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address"); + LOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address"); return JNI_FALSE; } } node = "ipv6.google.com"; res = getaddrinfo(node, service, NULL, &answer); - ALOGD("getaddrinfo(ipv6.google.com) gave res=%d", res); + LOGD("getaddrinfo(ipv6.google.com) gave res=%d", res); if (res != 0) return JNI_FALSE; { @@ -79,12 +84,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas if (current->ai_addr->sa_family == AF_INET) { inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, buf, sizeof(buf)); - ALOGD(" %s", buf); + LOGD(" %s", buf); foundv4 = 1; } else if (current->ai_addr->sa_family == AF_INET6) { inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, buf, sizeof(buf)); - ALOGD(" %s", buf); + LOGD(" %s", buf); foundv6 = 1; } current = current->ai_next; @@ -93,7 +98,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas freeaddrinfo(answer); answer = NULL; if (foundv4 == 1 || foundv6 != 1) { - ALOGD("getaddrinfo(ipv6.google.com) didn't find only v6"); + LOGD("getaddrinfo(ipv6.google.com) didn't find only v6"); return JNI_FALSE; } } @@ -116,12 +121,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas res = getnameinfo((const struct sockaddr*)&sa4, sizeof(sa4), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { - ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res, + LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res, gai_strerror(res)); return JNI_FALSE; } if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { - ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", GoogleDNSIpV4Address, buf); return JNI_FALSE; } @@ -129,12 +134,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas memset(buf, 0, sizeof(buf)); res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { - ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, + LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, res, gai_strerror(res)); return JNI_FALSE; } if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { - ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", GoogleDNSIpV6Address2, buf); return JNI_FALSE; } @@ -142,11 +147,11 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas // gethostbyname struct hostent *my_hostent = gethostbyname("www.youtube.com"); if (my_hostent == NULL) { - ALOGD("gethostbyname(www.youtube.com) gave null response"); + LOGD("gethostbyname(www.youtube.com) gave null response"); return JNI_FALSE; } if ((my_hostent->h_addr_list == NULL) || (*my_hostent->h_addr_list == NULL)) { - ALOGD("gethostbyname(www.youtube.com) gave 0 addresses"); + LOGD("gethostbyname(www.youtube.com) gave 0 addresses"); return JNI_FALSE; } { @@ -154,7 +159,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas while (*current != NULL) { char buf[256]; inet_ntop(my_hostent->h_addrtype, *current, buf, sizeof(buf)); - ALOGD("gethostbyname(www.youtube.com) gave %s", buf); + LOGD("gethostbyname(www.youtube.com) gave %s", buf); current++; } } @@ -164,11 +169,11 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas inet_pton(AF_INET6, GoogleDNSIpV6Address, addr6); my_hostent = gethostbyaddr(addr6, sizeof(addr6), AF_INET6); if (my_hostent == NULL) { - ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address); + LOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address); return JNI_FALSE; } - ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address, + LOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address, my_hostent->h_name ? my_hostent->h_name : "null"); if (my_hostent->h_name == NULL) return JNI_FALSE; diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index 2832c3d142..cd94709fd5 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "MultinetworkApiTest" -#include #include #include @@ -34,9 +33,13 @@ #include +#include #include #include +#define LOGD(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) + #define EXPECT_GE(env, actual, expected, msg) \ do { \ if (actual < expected) { \ @@ -138,7 +141,7 @@ int expectAnswersNotValid(JNIEnv* env, int fd, int expectedErrno) { uint8_t buf[MAXPACKET] = {}; int res = getAsyncResponse(env, fd, TIMEOUT_MS, &rcode, buf, MAXPACKET); if (res != expectedErrno) { - ALOGD("res:%d, expectedErrno = %d", res, expectedErrno); + LOGD("res:%d, expectedErrno = %d", res, expectedErrno); return (res > 0) ? -EREMOTEIO : res; } return 0; @@ -326,7 +329,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runGetaddrinfoCheck( const int saved_errno = errno; freeaddrinfo(res); - ALOGD("android_getaddrinfofornetwork(%" PRIu64 ", %s) returned rval=%d errno=%d", + LOGD("android_getaddrinfofornetwork(%" PRIu64 ", %s) returned rval=%d errno=%d", handle, kHostname, rval, saved_errno); return rval == 0 ? 0 : -saved_errno; } @@ -339,7 +342,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetprocnetwork( errno = 0; int rval = android_setprocnetwork(handle); const int saved_errno = errno; - ALOGD("android_setprocnetwork(%" PRIu64 ") returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%" PRIu64 ") returned rval=%d errno=%d", handle, rval, saved_errno); return rval == 0 ? 0 : -saved_errno; } @@ -352,14 +355,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetsocknetwork( errno = 0; int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { - ALOGD("socket() failed, errno=%d", errno); + LOGD("socket() failed, errno=%d", errno); return -errno; } errno = 0; int rval = android_setsocknetwork(handle, fd); const int saved_errno = errno; - ALOGD("android_setprocnetwork(%" PRIu64 ", %d) returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%" PRIu64 ", %d) returned rval=%d errno=%d", handle, fd, rval, saved_errno); close(fd); return rval == 0 ? 0 : -saved_errno; @@ -404,7 +407,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( static const char kPort[] = "443"; int rval = android_getaddrinfofornetwork(handle, kHostname, kPort, &kHints, &res); if (rval != 0) { - ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", + LOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", handle, kHostname, rval, errno); freeaddrinfo(res); return -errno; @@ -413,14 +416,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( // Rely upon getaddrinfo sorting the best destination to the front. int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd < 0) { - ALOGD("socket(%d, %d, %d) failed, errno=%d", + LOGD("socket(%d, %d, %d) failed, errno=%d", res->ai_family, res->ai_socktype, res->ai_protocol, errno); freeaddrinfo(res); return -errno; } rval = android_setsocknetwork(handle, fd); - ALOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", handle, fd, rval, errno); if (rval != 0) { close(fd); @@ -430,7 +433,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( char addrstr[kSockaddrStrLen+1]; sockaddr_ntop(res->ai_addr, res->ai_addrlen, addrstr, sizeof(addrstr)); - ALOGD("Attempting connect() to %s ...", addrstr); + LOGD("Attempting connect() to %s ...", addrstr); rval = connect(fd, res->ai_addr, res->ai_addrlen); if (rval != 0) { @@ -447,7 +450,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -errno; } sockaddr_ntop((const struct sockaddr *)&src_addr, sizeof(src_addr), addrstr, sizeof(addrstr)); - ALOGD("... from %s", addrstr); + LOGD("... from %s", addrstr); // Don't let reads or writes block indefinitely. const struct timeval timeo = { 2, 0 }; // 2 seconds @@ -479,7 +482,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( sent = send(fd, quic_packet, sizeof(quic_packet), 0); if (sent < (ssize_t)sizeof(quic_packet)) { errnum = errno; - ALOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum); + LOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum); close(fd); return -errnum; } @@ -489,14 +492,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( break; } else { errnum = errno; - ALOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d", + LOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d", i + 1, MAX_RETRIES, rcvd, errnum); } } if (rcvd < 9) { - ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); + LOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { - ALOGD("Does this network block UDP port %s?", kPort); + LOGD("Does this network block UDP port %s?", kPort); } close(fd); return -EPROTO; @@ -504,7 +507,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); if (conn_id_cmp != 0) { - ALOGD("sent and received connection IDs do not match"); + LOGD("sent and received connection IDs do not match"); close(fd); return -EPROTO; } diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 0a80047fdf..9d357055d1 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -18,15 +18,17 @@ package android.net.cts; import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import android.content.Context; import android.net.ConnectivityDiagnosticsManager; import android.net.NetworkRequest; +import android.os.Build; import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; @@ -34,7 +36,8 @@ import org.junit.runner.RunWith; import java.util.concurrent.Executor; -@RunWith(AndroidJUnit4.class) +@RunWith(DevSdkIgnoreRunner.class) +@IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q public class ConnectivityDiagnosticsManagerTest { private static final Executor INLINE_EXECUTOR = x -> x.run(); private static final NetworkRequest DEFAULT_REQUEST = new NetworkRequest.Builder().build(); diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 89d3dff66c..03b961bc4b 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -180,7 +180,7 @@ class NetworkAgentTest { } private open class TestableNetworkAgent( - val looper: Looper, + looper: Looper, val nc: NetworkCapabilities, val lp: LinkProperties, conf: NetworkAgentConfig From e3711ae3178ec598430c834efd60f2c43417a5ef Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 25 Jun 2019 14:17:35 -0700 Subject: [PATCH 0989/1415] Pull service dumps to help debug test failures. + Convert tests to use Junit4 + Add annotations to specify required conditions for the test to run. Bug: 137859686 Test: atest hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Test: atest hostsidetests/net/src/com/android/cts/net/HostsideNetworkCallbackTests.java Change-Id: I93317c201a0ea06732e29154ab7e140735381f59 Merged-In: I93317c201a0ea06732e29154ab7e140735381f59 --- tests/cts/hostside/AndroidTest.xml | 5 + tests/cts/hostside/app/Android.bp | 2 + tests/cts/hostside/app/AndroidManifest.xml | 3 +- .../net/hostside/AbstractAppIdleTestCase.java | 76 ++-- .../AbstractBatterySaverModeTestCase.java | 68 +--- .../hostside/AbstractDozeModeTestCase.java | 66 +--- ...ractRestrictBackgroundNetworkTestCase.java | 361 ++---------------- .../cts/net/hostside/AppIdleMeteredTest.java | 13 +- .../net/hostside/AppIdleNonMeteredTest.java | 7 +- .../hostside/BatterySaverModeMeteredTest.java | 13 +- .../BatterySaverModeNonMeteredTest.java | 9 +- .../cts/net/hostside/DataSaverModeTest.java | 66 ++-- .../cts/net/hostside/DozeModeMeteredTest.java | 13 +- .../net/hostside/DozeModeNonMeteredTest.java | 8 +- .../cts/net/hostside/DumpOnFailureRule.java | 91 +++++ .../MeterednessConfigurationRule.java | 60 +++ .../cts/net/hostside/MixedModesTest.java | 230 +++++------ .../cts/net/hostside/NetworkCallbackTest.java | 173 +++++---- .../net/hostside/NetworkPolicyTestUtils.java | 255 +++++++++++++ .../android/cts/net/hostside/Property.java | 70 ++++ .../cts/net/hostside/RequiredProperties.java | 31 ++ .../net/hostside/RequiredPropertiesRule.java | 90 +++++ .../cts/net/HostsideNetworkCallbackTests.java | 8 +- .../cts/net/HostsideNetworkTestCase.java | 3 +- 24 files changed, 939 insertions(+), 782 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index dbff1794e9..5479c51a4c 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -31,4 +31,9 @@

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - - /** - * Resets the (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void tearDownMeteredNetwork() throws Exception { + setBatterySaverMode(false); } + @Test public void testBackgroundNetworkAccess_enabled() throws Exception { - if (!isSupported()) return; - setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -118,9 +80,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { - if (!isSupported()) return; - setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -140,9 +101,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_disabled() throws Exception { - if (!isSupported()) return; - assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index f20f1d1c4d..6f32c563c1 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -16,20 +16,25 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE; + import android.os.SystemClock; -import android.util.Log; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Base class for metered and non-metered Doze Mode tests. */ +@RequiredProperties({DOZE_MODE}) abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { - @Override - protected final void setUp() throws Exception { + @Before + public final void setUp() throws Exception { super.setUp(); - if (!isSupported()) return; - // Set initial state. removePowerSaveModeWhitelist(TEST_APP2_PKG); removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); @@ -38,48 +43,15 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor registerBroadcastReceiver(); } - @Override - protected final void tearDown() throws Exception { + @After + public final void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - - try { - tearDownMeteredNetwork(); - } finally { - setDozeMode(false); - } - } - - @Override - protected boolean isSupported() throws Exception { - boolean supported = isDozeModeEnabled(); - if (!supported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); - } - return supported; - } - - /** - * Sets the initial (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - - /** - * Resets the (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void tearDownMeteredNetwork() throws Exception { + setDozeMode(false); } + @Test public void testBackgroundNetworkAccess_enabled() throws Exception { - if (!isSupported()) return; - setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -96,9 +68,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { - if (!isSupported()) return; - setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -118,19 +89,18 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_disabled() throws Exception { - if (!isSupported()) return; - assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(true); } + @RequiredProperties({NOT_LOW_RAM_DEVICE}) + @Test public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() throws Exception { - if (!isSupported() || isLowRamDevice()) return; - setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); try { registerNotificationListenerService(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 40d7e34fcc..57b7bb4f8d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -17,14 +17,22 @@ package com.android.cts.net.hostside; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static android.os.BatteryManager.BATTERY_PLUGGED_AC; import static android.os.BatteryManager.BATTERY_PLUGGED_USB; import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; -import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.app.ActivityManager; import android.app.Instrumentation; @@ -34,9 +42,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; @@ -44,24 +50,27 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; -import android.os.SystemProperties; import android.provider.Settings; import android.service.notification.NotificationListenerService; -import android.test.InstrumentationTestCase; -import android.text.TextUtils; import android.util.Log; -import com.android.compatibility.common.util.BatteryUtils; +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.runner.RunWith; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + /** * Superclass for tests related to background network restrictions. */ -abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase { - protected static final String TAG = "RestrictBackgroundNetworkTests"; +@RunWith(AndroidJUnit4.class) +public abstract class AbstractRestrictBackgroundNetworkTestCase { + public static final String TAG = "RestrictBackgroundNetworkTests"; protected static final String TEST_PKG = "com.android.cts.net.hostside"; protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; @@ -98,8 +107,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static int PROCESS_STATE_FOREGROUND_SERVICE; - private static final int PROCESS_STATE_TOP = 2; - private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; protected static final int TYPE_COMPONENT_ACTIVTIY = 0; @@ -126,22 +133,23 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private int mMyUid; - private String mMeteredWifi; private MyServiceClient mServiceClient; private String mDeviceIdleConstantsSetting; - private boolean mSupported; private boolean mIsLocationOn; - @Override + @Rule + public final RuleChain mRuleChain = RuleChain.outerRule(new DumpOnFailureRule()) + .around(new RequiredPropertiesRule()) + .around(new MeterednessConfigurationRule()); + protected void setUp() throws Exception { - super.setUp(); PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null); mInstrumentation = getInstrumentation(); - mContext = mInstrumentation.getContext(); - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mContext = getContext(); + mCm = getConnectivityManager(); + mWfm = getWifiManager(); mUid = getUid(TEST_APP2_PKG); mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); @@ -151,10 +159,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (!mIsLocationOn) { enableLocation(); } - mSupported = setUpActiveNetworkMeteringState(); setAppIdle(false); - Log.i(TAG, "Apps status on " + getName() + ":\n" + Log.i(TAG, "Apps status:\n" + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -165,16 +172,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final String currentConstants = executeShellCommand("settings get global app_idle_constants"); assertEquals(appIdleConstants, currentConstants); - } + } - @Override protected void tearDown() throws Exception { if (!mIsLocationOn) { disableLocation(); } mServiceClient.unbind(); - - super.tearDown(); } private void enableLocation() throws Exception { @@ -259,23 +263,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { final String status = mServiceClient.getRestrictBackgroundStatus(); assertNotNull("didn't get API status from app2", status); - final String actualStatus = toString(Integer.parseInt(status)); - assertEquals("wrong status", toString(expectedStatus), actualStatus); - } - - protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { - final int actualStatus = mCm.getRestrictBackgroundStatus(); - assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); - } - - protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { - final int actualStatus = mCm.getRestrictBackgroundStatus(); - if (expectedStatus != actualStatus) { - Log.d(TAG, "Expected: " + toString(expectedStatus) - + " but actual: " + toString(actualStatus)); - return false; - } - return true; + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(Integer.parseInt(status))); } protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { @@ -297,28 +286,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */); } - /** - * Whether this device suport this type of test. - * - *

    Should be overridden when necessary (but always calling - * {@code super.isSupported()} first), and explicitly used before each test - * Example: - * - *

    
    -     * public void testSomething() {
    -     *    if (!isSupported()) return;
    -     * 
    - * - * @return {@code true} by default. - */ - protected boolean isSupported() throws Exception { - return mSupported; - } - - protected boolean isBatterySaverSupported() { - return BatteryUtils.isBatterySaverSupported(); - } - /** * Asserts that an app always have access while on foreground or running a foreground service. * @@ -387,23 +354,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state ); } - /** - * As per CDD requirements, if the device doesn't support data saver mode then - * ConnectivityManager.getRestrictBackgroundStatus() will always return - * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if - * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns - * RESTRICT_BACKGROUND_STATUS_DISABLED or not. - */ - protected boolean isDataSaverSupported() throws Exception { - assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - try { - setRestrictBackground(true); - return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - } finally { - setRestrictBackground(false); - } - } - /** * Returns whether an app state should be considered "background" for restriction purposes. */ @@ -443,40 +393,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // Exponential back-off. timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS); } - dumpOnFailure(); fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries + " attempts.\nLast error: " + error); } - private void dumpOnFailure() throws Exception { - dumpAllNetworkRules(); - Log.d(TAG, "Usagestats dump: " + getUsageStatsDump()); - executeShellCommand("settings get global app_idle_constants"); - } - - private void dumpAllNetworkRules() throws Exception { - final String networkManagementDump = runShellCommand(mInstrumentation, - "dumpsys network_management").trim(); - final String networkPolicyDump = runShellCommand(mInstrumentation, - "dumpsys netpolicy").trim(); - TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); - splitter.setString(networkManagementDump); - String next; - Log.d(TAG, ">>> Begin network_management dump"); - while (splitter.hasNext()) { - next = splitter.next(); - Log.d(TAG, next); - } - Log.d(TAG, "<<< End network_management dump"); - splitter.setString(networkPolicyDump); - Log.d(TAG, ">>> Begin netpolicy dump"); - while (splitter.hasNext()) { - next = splitter.next(); - Log.d(TAG, next); - } - Log.d(TAG, "<<< End netpolicy dump"); - } - /** * Checks whether the network is available as expected. * @@ -528,22 +448,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return errors.toString(); } - protected boolean isLowRamDevice() { - final ActivityManager am = (ActivityManager) mContext.getSystemService( - Context.ACTIVITY_SERVICE); - return am.isLowRamDevice(); - } - - protected String executeShellCommand(String command) throws Exception { - final String result = runShellCommand(mInstrumentation, command).trim(); - if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'"); - return result; - } - /** * Runs a Shell command which is not expected to generate output. */ - protected void executeSilentShellCommand(String command) throws Exception { + protected void executeSilentShellCommand(String command) { final String result = executeShellCommand(command); assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty()); } @@ -572,10 +480,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation }); } - protected void assertDelayedShellCommand(String command, ExpectResultChecker checker) - throws Exception { - assertDelayedShellCommand(command, 5, 1, checker); - } protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, ExpectResultChecker checker) throws Exception { String result = ""; @@ -592,159 +496,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation + " attempts. Last result: '" + result + "'"); } - /** - * Sets the initial metering state for the active network. - * - *

    It's called on setup and by default does nothing - it's up to the - * subclasses to override. - * - * @return whether the tests in the subclass are supported on this device. - */ - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return true; - } - - /** - * Makes sure the active network is not metered. - * - *

    If the device does not supoprt un-metered networks (for example if it - * only has cellular data but not wi-fi), it should return {@code false}; - * otherwise, it should return {@code true} (or fail if the un-metered - * network could not be set). - * - * @return {@code true} if the network is now unmetered. - */ - protected boolean setUnmeteredNetwork() throws Exception { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - assertNotNull("Could not get active network", info); - if (!mCm.isActiveNetworkMetered()) { - Log.d(TAG, "Active network is not metered: " + info); - } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { - Log.i(TAG, "Setting active WI-FI network as not metered: " + info ); - setWifiMeteredStatus(false); - } else { - Log.d(TAG, "Active network cannot be set to un-metered: " + info); - return false; - } - assertActiveNetworkMetered(false); // Sanity check. - return true; - } - - /** - * Enables metering on the active network if supported. - * - *

    If the device does not support metered networks it should return - * {@code false}; otherwise, it should return {@code true} (or fail if the - * metered network could not be set). - * - * @return {@code true} if the network is now metered. - */ - protected boolean setMeteredNetwork() throws Exception { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - final boolean metered = mCm.isActiveNetworkMetered(); - if (metered) { - Log.d(TAG, "Active network already metered: " + info); - return true; - } else if (info.getType() != ConnectivityManager.TYPE_WIFI) { - Log.w(TAG, "Active network does not support metering: " + info); - return false; - } else { - Log.w(TAG, "Active network not metered: " + info); - } - final String netId = setWifiMeteredStatus(true); - - // Set flag so status is reverted on resetMeteredNetwork(); - mMeteredWifi = netId; - // Sanity check. - assertWifiMeteredStatus(netId, true); - assertActiveNetworkMetered(true); - return true; - } - - /** - * Resets the device metering state to what it was before the test started. - * - *

    This reverts any metering changes made by {@code setMeteredNetwork}. - */ - protected void resetMeteredNetwork() throws Exception { - if (mMeteredWifi != null) { - Log.i(TAG, "resetMeteredNetwork(): SID '" + mMeteredWifi - + "' was set as metered by test case; resetting it"); - setWifiMeteredStatus(mMeteredWifi, false); - assertActiveNetworkMetered(false); // Sanity check. - } - } - - private void assertActiveNetworkMetered(boolean expected) throws Exception { - final int maxTries = 5; - NetworkInfo info = null; - for (int i = 1; i <= maxTries; i++) { - info = mCm.getActiveNetworkInfo(); - if (info == null) { - Log.v(TAG, "No active network info on attempt #" + i - + "; sleeping 1s before polling again"); - } else if (mCm.isActiveNetworkMetered() != expected) { - Log.v(TAG, "Wrong metered status for active network " + info + "; expected=" - + expected + "; sleeping 1s before polling again"); - } else { - break; - } - Thread.sleep(SECOND_IN_MS); - } - assertNotNull("No active network after " + maxTries + " attempts", info); - assertEquals("Wrong metered status for active network " + info, expected, - mCm.isActiveNetworkMetered()); - } - - private String setWifiMeteredStatus(boolean metered) throws Exception { - // We could call setWifiEnabled() here, but it might take sometime to be in a consistent - // state (for example, if one of the saved network is not properly authenticated), so it's - // better to let the hostside test take care of that. - assertTrue("wi-fi is disabled", mWfm.isWifiEnabled()); - // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests - // to make the actual verification of restrictions optional. - final String ssid = mWfm.getConnectionInfo().getSSID(); - return setWifiMeteredStatus(ssid, metered); - } - - private String setWifiMeteredStatus(String ssid, boolean metered) throws Exception { - assertNotNull("null SSID", ssid); - final String netId = ssid.trim().replaceAll("\"", ""); // remove quotes, if any. - assertFalse("empty SSID", ssid.isEmpty()); - - Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); - final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered; - assertDelayedShellCommand(setCommand, ""); - - return netId; - } - - private void assertWifiMeteredStatus(String netId, boolean status) throws Exception { - final String command = "cmd netpolicy list wifi-networks"; - final String expectedLine = netId + ";" + status; - assertDelayedShellCommand(command, new ExpectResultChecker() { - - @Override - public boolean isExpected(String result) { - return result.contains(expectedLine); - } - - @Override - public String getExpected() { - return "line containing " + expectedLine; - } - }); - } - - protected void setRestrictBackground(boolean enabled) throws Exception { - executeShellCommand("cmd netpolicy set restrict-background " + enabled); - final String output = executeShellCommand("cmd netpolicy get restrict-background "); - final String expectedSuffix = enabled ? "enabled" : "disabled"; - // TODO: use MoreAsserts? - assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", - output.endsWith(expectedSuffix)); - } - protected void addRestrictBackgroundWhitelist(int uid) throws Exception { executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); @@ -924,7 +675,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void setDozeMode(boolean enabled) throws Exception { // Sanity check, since tests should check beforehand.... - assertTrue("Device does not support Doze Mode", isDozeModeEnabled()); + assertTrue("Device does not support Doze Mode", isDozeModeSupported()); Log.i(TAG, "Setting Doze Mode to " + enabled); if (enabled) { @@ -944,43 +695,16 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE"); } - protected boolean isDozeModeEnabled() throws Exception { - final String result = executeShellCommand("cmd deviceidle enabled deep").trim(); - return result.equals("1"); - } - protected void setAppIdle(boolean enabled) throws Exception { Log.i(TAG, "Setting app idle to " + enabled); executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); assertAppIdle(enabled); // Sanity check } - private String getUsageStatsDump() throws Exception { - final String output = runShellCommand(mInstrumentation, "dumpsys usagestats").trim(); - final StringBuilder sb = new StringBuilder(); - final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); - splitter.setString(output); - String str; - while (splitter.hasNext()) { - str = splitter.next(); - if (str.contains("package=") - && !str.contains(TEST_PKG) && !str.contains(TEST_APP2_PKG)) { - continue; - } - if (str.trim().startsWith("config=") || str.trim().startsWith("time=")) { - continue; - } - sb.append(str).append('\n'); - } - return sb.toString(); - } - protected void assertAppIdle(boolean enabled) throws Exception { try { assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled); } catch (Throwable e) { - Log.d(TAG, "UsageStats dump:\n" + getUsageStatsDump()); - executeShellCommand("settings get global app_idle_constants"); throw e; } } @@ -1061,12 +785,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // App didn't come to foreground when the activity is started, so try again. assertForegroundNetworkAccess(); } else { - dumpOnFailure(); fail("Network is not available for app2 (" + mUid + "): " + errors[0]); } } } else { - dumpOnFailure(); fail("Timed out waiting for network availability status from app2 (" + mUid + ")"); } } else { @@ -1150,19 +872,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } } - private String toString(int status) { - switch (status) { - case RESTRICT_BACKGROUND_STATUS_DISABLED: - return "DISABLED"; - case RESTRICT_BACKGROUND_STATUS_WHITELISTED: - return "WHITELISTED"; - case RESTRICT_BACKGROUND_STATUS_ENABLED: - return "ENABLED"; - default: - return "UNKNOWN_STATUS_" + status; - } - } - private ProcessState getProcessStateByUid(int uid) throws Exception { return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid)); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java index 622d99361f..f1858d65a5 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class AppIdleMeteredTest extends AbstractAppIdleTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java index bde71f9100..e737a6dabe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java @@ -16,9 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase { - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java index 3071cfe3f1..c78ca2ec77 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index 6d3076fe0e..fb52a540d8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -16,10 +16,9 @@ package com.android.cts.net.hostside; -public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) +public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index cfe6a73a0f..aa2c914e02 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,24 +20,33 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -import android.util.Log; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE; + +import static org.junit.Assert.fail; import com.android.compatibility.common.util.CddTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import androidx.test.filters.LargeTest; + +@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK}) +@LargeTest public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { "com.android.providers.downloads" }; - private boolean mIsDataSaverSupported; - - @Override + @Before public void setUp() throws Exception { super.setUp(); - mIsDataSaverSupported = isDataSaverSupported(); - // Set initial state. setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); @@ -47,36 +56,15 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(0); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - - try { - resetMeteredNetwork(); - } finally { - setRestrictBackground(false); - } - } - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected boolean isSupported() throws Exception { - if (!mIsDataSaverSupported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Data Saver Mode"); - } - return mIsDataSaverSupported && super.isSupported(); + setRestrictBackground(false); } + @Test public void testGetRestrictBackgroundStatus_disabled() throws Exception { - if (!isSupported()) return; - assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted @@ -88,9 +76,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); } + @Test public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { - if (!isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -107,9 +94,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); } + @Test public void testGetRestrictBackgroundStatus_enabled() throws Exception { - if (!isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -142,9 +128,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertBackgroundNetworkAccess(false); } + @Test public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { - if (!isSupported()) return; - addRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -180,9 +165,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); } + @Test public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { - if (!isSupported()) return; - final StringBuilder error = new StringBuilder(); for (String packageName : REQUIRED_WHITELISTED_PACKAGES) { int uid = -1; @@ -202,10 +186,10 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } } + @RequiredProperties({NO_DATA_SAVER_MODE}) @CddTest(requirement="7.4.7/C-2-2") + @Test public void testBroadcastNotSentOnUnsupportedDevices() throws Exception { - if (isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(0); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java index e4189af587..4306c991c2 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class DozeModeMeteredTest extends AbstractDozeModeTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java index edbbb9e1ce..1e89f158a3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java @@ -16,10 +16,8 @@ package com.android.cts.net.hostside; -public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } +@RequiredProperties({NON_METERED_NETWORK}) +public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java new file mode 100644 index 0000000000..cedd62a0bc --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG; + +import android.os.Environment; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import com.android.compatibility.common.util.OnFailureRule; + +import org.junit.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class DumpOnFailureRule extends OnFailureRule { + private File mDumpDir = new File(Environment.getExternalStorageDirectory(), + "CtsHostsideNetworkTests"); + + @Override + public void onTestFailure(Statement base, Description description, Throwable throwable) { + final String testName = description.getClassName() + "_" + description.getMethodName(); + + if (throwable instanceof AssumptionViolatedException) { + Log.d(TAG, "Skipping test " + testName + ": " + throwable); + return; + } + + prepareDumpRootDir(); + final File dumpFile = new File(mDumpDir, "dump-" + testName); + Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath()); + try (FileOutputStream out = new FileOutputStream(dumpFile)) { + for (String cmd : new String[] { + "dumpsys netpolicy", + "dumpsys network_management", + "dumpsys usagestats " + TEST_PKG, + "dumpsys usagestats appstandby", + }) { + dumpCommandOutput(out, cmd); + } + } catch (FileNotFoundException e) { + Log.e(TAG, "Error opening file: " + dumpFile, e); + } catch (IOException e) { + Log.e(TAG, "Error closing file: " + dumpFile, e); + } + } + + void dumpCommandOutput(FileOutputStream out, String cmd) { + final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation() + .getUiAutomation().executeShellCommand(cmd); + try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8)); + FileUtils.copy(in, out); + out.write("\n\n=================================================================\n\n" + .getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + Log.e(TAG, "Error dumping '" + cmd + "'", e); + } + } + + void prepareDumpRootDir() { + if (!mDumpDir.exists() && !mDumpDir.mkdir()) { + Log.e(TAG, "Error creating " + mDumpDir); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java new file mode 100644 index 0000000000..8fadf9e295 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.resetMeteredNetwork; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupMeteredNetwork; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +import android.util.ArraySet; +import android.util.Pair; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class MeterednessConfigurationRule extends BeforeAfterRule { + private Pair mSsidAndInitialMeteredness; + + @Override + public void onBefore(Statement base, Description description) throws Throwable { + final ArraySet requiredProperties + = RequiredPropertiesRule.getRequiredProperties(); + if (requiredProperties.contains(METERED_NETWORK)) { + configureNetworkMeteredness(true); + } else if (requiredProperties.contains(NON_METERED_NETWORK)) { + configureNetworkMeteredness(false); + } + } + + @Override + public void onAfter(Statement base, Description description) throws Throwable { + resetNetworkMeteredness(); + } + + public void configureNetworkMeteredness(boolean metered) throws Exception { + mSsidAndInitialMeteredness = setupMeteredNetwork(metered); + } + + public void resetNetworkMeteredness() throws Exception { + if (mSsidAndInitialMeteredness != null) { + resetMeteredNetwork(mSsidAndInitialMeteredness.first, + mSsidAndInitialMeteredness.second); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index b1a21867b3..c9edda6e0b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -15,9 +15,21 @@ */ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + import android.os.SystemClock; import android.util.Log; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + /** * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode * and Data Saver Mode) are applied simultaneously. @@ -29,12 +41,10 @@ import android.util.Log; public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String TAG = "MixedModesTest"; - @Override + @Before public void setUp() throws Exception { super.setUp(); - if (!isSupported()) return; - // Set initial state. removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); @@ -44,12 +54,10 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { registerBroadcastReceiver(); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - try { setRestrictBackground(false); } finally { @@ -57,34 +65,15 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } - @Override - public boolean isSupported() throws Exception { - if (!isDozeModeEnabled()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); - return false; - } - return true; - } - /** * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, METERED_NETWORK}) + @Test public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) return; - - Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); - if (!setMeteredNetwork()) { - Log.w(TAG, "testDataAndBatterySaverModes_meteredNetwork() skipped because " - + "device cannot use a metered network"); - return; - } - + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); try { setRestrictBackground(true); setBatterySaverMode(true); @@ -137,7 +126,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { removeRestrictBackgroundBlacklist(mUid); removePowerSaveModeWhitelist(TEST_APP2_PKG); } finally { - resetMeteredNetwork(); + meterednessConfiguration.resetNetworkMeteredness(); } } @@ -145,86 +134,75 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered * networks. */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, NON_METERED_NETWORK}) + @Test public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + setRestrictBackground(true); + setBatterySaverMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); } - if (!isSupported()) return; - - if (!setUnmeteredNetwork()) { - Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network" - + " is metered"); - return; - } - Log.i(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() tests"); - setRestrictBackground(true); - setBatterySaverMode(true); - - Log.v(TAG, "Not whitelisted for any."); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - - Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); - addRestrictBackgroundWhitelist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - - Log.v(TAG, "Whitelisted for both."); - addRestrictBackgroundWhitelist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundBlacklist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removeRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); } /** * Tests that powersave whitelists works as expected when doze and battery saver modes * are enabled. */ + @RequiredProperties({DOZE_MODE, BATTERY_SAVER_MODE}) + @Test public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setDozeMode(true); @@ -250,11 +228,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests that powersave whitelists works as expected when doze and appIdle modes * are enabled. */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -276,11 +252,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -299,16 +273,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setAppIdle(true); @@ -330,11 +297,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { /** * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled. */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -353,11 +318,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -380,16 +343,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setAppIdle(true); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index 24dde9d356..ed397b91fc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -16,15 +16,26 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import android.net.Network; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.Objects; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase { - private boolean mIsDataSaverSupported; private Network mNetwork; private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback(); @@ -132,108 +143,122 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } } - @Override + @Before public void setUp() throws Exception { super.setUp(); - mIsDataSaverSupported = isDataSaverSupported(); - mNetwork = mCm.getActiveNetwork(); - // Set initial state. - setBatterySaverMode(false); registerBroadcastReceiver(); - if (!mIsDataSaverSupported) return; - setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(0); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!mIsDataSaverSupported) return; + setRestrictBackground(false); + setBatterySaverMode(false); + } + @RequiredProperties({DATA_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_dataSaver() throws Exception { + // Initial state + setBatterySaverMode(false); + setRestrictBackground(false); + + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); try { - resetMeteredNetwork(); + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable restrict background + setRestrictBackground(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Add to whitelist + addRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Remove from whitelist + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } + + // Set to non-metered network + meterednessConfiguration.configureNetworkMeteredness(false); + try { + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Disable restrict background, should not trigger callback setRestrictBackground(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.assertNoCallback(); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); } } - public void testOnBlockedStatusChanged_data_saver() throws Exception { - if (!mIsDataSaverSupported) return; - - // Prepare metered wifi - if (!setMeteredNetwork()) return; - - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable restrict background - setRestrictBackground(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Add to whitelist - addRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Remove from whitelist - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Set to non-metered network - setUnmeteredNetwork(); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Disable restrict background, should not trigger callback + @RequiredProperties({BATTERY_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_powerSaver() throws Exception { + // Set initial state. + setBatterySaverMode(false); setRestrictBackground(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.assertNoCallback(); - } + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); + try { + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - public void testOnBlockedStatusChanged_power_saver() throws Exception { - // Prepare metered wifi - if (!setMeteredNetwork()) return; + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } // Set to non-metered network - setUnmeteredNetwork(); - mTestNetworkCallback.assertNoCallback(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + mTestNetworkCallback.assertNoCallback(); - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } } // TODO: 1. test against VPN lockdown. diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java new file mode 100644 index 0000000000..ca2864c0b8 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.ActivityManager; +import android.app.Instrumentation; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.wifi.WifiManager; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; + +import com.android.compatibility.common.util.AppStandbyUtils; +import com.android.compatibility.common.util.BatteryUtils; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class NetworkPolicyTestUtils { + + private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 5000; + + private static ConnectivityManager mCm; + private static WifiManager mWm; + + private static Boolean mBatterySaverSupported; + private static Boolean mDataSaverSupported; + private static Boolean mDozeModeSupported; + private static Boolean mAppStandbySupported; + + private NetworkPolicyTestUtils() {} + + public static boolean isBatterySaverSupported() { + if (mBatterySaverSupported == null) { + mBatterySaverSupported = BatteryUtils.isBatterySaverSupported(); + } + return mBatterySaverSupported; + } + + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + public static boolean isDataSaverSupported() { + if (mDataSaverSupported == null) { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + mDataSaverSupported = !isMyRestrictBackgroundStatus( + RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + return mDataSaverSupported; + } + + public static boolean isDozeModeSupported() { + if (mDozeModeSupported == null) { + final String result = executeShellCommand("cmd deviceidle enabled deep"); + mDozeModeSupported = result.equals("1"); + } + return mDozeModeSupported; + } + + public static boolean isAppStandbySupported() { + if (mAppStandbySupported == null) { + mAppStandbySupported = AppStandbyUtils.isAppStandbyEnabled(); + } + return mAppStandbySupported; + } + + public static boolean isLowRamDevice() { + final ActivityManager am = (ActivityManager) getContext().getSystemService( + Context.ACTIVITY_SERVICE); + return am.isLowRamDevice(); + } + + public static boolean isActiveNetworkMetered(boolean metered) { + return getConnectivityManager().isActiveNetworkMetered() == metered; + } + + public static boolean canChangeActiveNetworkMeteredness() { + final Network activeNetwork = getConnectivityManager().getActiveNetwork(); + final NetworkCapabilities networkCapabilities + = getConnectivityManager().getNetworkCapabilities(activeNetwork); + return networkCapabilities.hasTransport(TRANSPORT_WIFI); + } + + public static Pair setupMeteredNetwork(boolean metered) throws Exception { + if (isActiveNetworkMetered(metered)) { + return null; + } + final String ssid = unquoteSSID(getWifiManager().getConnectionInfo().getSSID()); + setWifiMeteredStatus(ssid, metered); + return Pair.create(ssid, !metered); + } + + public static void resetMeteredNetwork(String ssid, boolean metered) throws Exception { + setWifiMeteredStatus(ssid, metered); + } + + public static void setWifiMeteredStatus(String ssid, boolean metered) throws Exception { + assertFalse("SSID should not be empty", TextUtils.isEmpty(ssid)); + final String cmd = "cmd netpolicy set metered-network " + ssid + " " + metered; + executeShellCommand(cmd); + assertWifiMeteredStatus(ssid, metered); + assertActiveNetworkMetered(metered); + } + + public static void assertWifiMeteredStatus(String ssid, boolean expectedMeteredStatus) { + final String result = executeShellCommand("cmd netpolicy list wifi-networks"); + final String expectedLine = ssid + ";" + expectedMeteredStatus; + assertTrue("Expected line: " + expectedLine + "; Actual result: " + result, + result.contains(expectedLine)); + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + public static void assertActiveNetworkMetered(boolean expectedMeteredStatus) throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final NetworkCallback networkCallback = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); + if (metered == expectedMeteredStatus) { + latch.countDown(); + } + } + }; + // Registering a callback here guarantees onCapabilitiesChanged is called immediately + // with the current setting. Therefore, if the setting has already been changed, + // this method will return right away, and if not it will wait for the setting to change. + getConnectivityManager().registerDefaultNetworkCallback(networkCallback); + if (!latch.await(TIMEOUT_CHANGE_METEREDNESS_MS, TimeUnit.MILLISECONDS)) { + fail("Timed out waiting for active network metered status to change to " + + expectedMeteredStatus + " ; network = " + + getConnectivityManager().getActiveNetwork()); + } + getConnectivityManager().unregisterNetworkCallback(networkCallback); + } + + public static void setRestrictBackground(boolean enabled) { + executeShellCommand("cmd netpolicy set restrict-background " + enabled); + final String output = executeShellCommand("cmd netpolicy get restrict-background"); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + + public static boolean isMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "MyRestrictBackgroundStatus: " + + "Expected: " + restrictBackgroundValueToString(expectedStatus) + + "; Actual: " + restrictBackgroundValueToString(actualStatus)); + return false; + } + return true; + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + private static String unquoteSSID(String ssid) { + // SSID is returned surrounded by quotes if it can be decoded as UTF-8. + // Otherwise it's guaranteed not to start with a quote. + if (ssid.charAt(0) == '"') { + return ssid.substring(1, ssid.length() - 1); + } else { + return ssid; + } + } + + public static String restrictBackgroundValueToString(int status) { + switch (status) { + case RESTRICT_BACKGROUND_STATUS_DISABLED: + return "DISABLED"; + case RESTRICT_BACKGROUND_STATUS_WHITELISTED: + return "WHITELISTED"; + case RESTRICT_BACKGROUND_STATUS_ENABLED: + return "ENABLED"; + default: + return "UNKNOWN_STATUS_" + status; + } + } + + public static String executeShellCommand(String command) { + final String result = runShellCommand(command).trim(); + Log.d(TAG, "Output of '" + command + "': '" + result + "'"); + return result; + } + + public static void assertMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(actualStatus)); + } + + public static ConnectivityManager getConnectivityManager() { + if (mCm == null) { + mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + } + return mCm; + } + + public static WifiManager getWifiManager() { + if (mWm == null) { + mWm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + } + return mWm; + } + + public static Context getContext() { + return getInstrumentation().getContext(); + } + + public static Instrumentation getInstrumentation() { + return InstrumentationRegistry.getInstrumentation(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java new file mode 100644 index 0000000000..18805f9613 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDataSaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isLowRamDevice; + +public enum Property { + BATTERY_SAVER_MODE(1 << 0) { + public boolean isSupported() { return isBatterySaverSupported(); } + }, + + DATA_SAVER_MODE(1 << 1) { + public boolean isSupported() { return isDataSaverSupported(); } + }, + + NO_DATA_SAVER_MODE(~DATA_SAVER_MODE.getValue()) { + public boolean isSupported() { return !isDataSaverSupported(); } + }, + + DOZE_MODE(1 << 2) { + public boolean isSupported() { return isDozeModeSupported(); } + }, + + APP_STANDBY_MODE(1 << 3) { + public boolean isSupported() { return isAppStandbySupported(); } + }, + + NOT_LOW_RAM_DEVICE(1 << 4) { + public boolean isSupported() { return !isLowRamDevice(); } + }, + + METERED_NETWORK(1 << 5) { + public boolean isSupported() { + return isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness(); + } + }, + + NON_METERED_NETWORK(~METERED_NETWORK.getValue()) { + public boolean isSupported() { + return isActiveNetworkMetered(false) || canChangeActiveNetworkMeteredness(); + } + }; + + private int mValue; + + Property(int value) { mValue = value; } + + public int getValue() { return mValue; } + + abstract boolean isSupported(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java new file mode 100644 index 0000000000..96838bba0a --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({METHOD, TYPE}) +@Inherited +public @interface RequiredProperties { + Property[] value(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java new file mode 100644 index 0000000000..1e333200db --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.Log; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.Assume; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.util.ArrayList; +import java.util.Collections; + +public class RequiredPropertiesRule extends BeforeAfterRule { + + private static ArraySet mRequiredProperties; + + @Override + public void onBefore(Statement base, Description description) { + mRequiredProperties = getAllRequiredProperties(description); + + final String testName = description.getClassName() + "#" + description.getMethodName(); + assertTestIsValid(testName, mRequiredProperties); + Log.i(TAG, "Running test " + testName + " with required properties: " + + propertiesToString(mRequiredProperties)); + } + + private ArraySet getAllRequiredProperties(Description description) { + final ArraySet allRequiredProperties = new ArraySet<>(); + RequiredProperties requiredProperties = description.getAnnotation(RequiredProperties.class); + if (requiredProperties != null) { + Collections.addAll(allRequiredProperties, requiredProperties.value()); + } + + for (Class clazz = description.getTestClass(); + clazz != null; clazz = clazz.getSuperclass()) { + requiredProperties = clazz.getDeclaredAnnotation(RequiredProperties.class); + if (requiredProperties == null) { + continue; + } + for (Property requiredProperty : requiredProperties.value()) { + if (!allRequiredProperties.contains(~requiredProperty.getValue())) { + allRequiredProperties.add(requiredProperty); + } + } + } + return allRequiredProperties; + } + + private void assertTestIsValid(String testName, ArraySet requiredProperies) { + if (requiredProperies == null) { + return; + } + final ArrayList unsupportedProperties = new ArrayList<>(); + for (Property property : requiredProperies) { + if (!property.isSupported()) { + unsupportedProperties.add(property); + } + } + Assume.assumeTrue("Unsupported properties: " + + propertiesToString(unsupportedProperties), unsupportedProperties.isEmpty()); + } + + public static ArraySet getRequiredProperties() { + return mRequiredProperties; + } + + private static String propertiesToString(Iterable properties) { + return "[" + TextUtils.join(",", properties) + "]"; + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java index 8d6c4acd7d..1312085478 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java @@ -29,14 +29,14 @@ public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase { uninstallPackage(TEST_APP2_PKG, true); } - public void testOnBlockedStatusChanged_data_saver() throws Exception { + public void testOnBlockedStatusChanged_dataSaver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_data_saver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_dataSaver"); } - public void testOnBlockedStatusChanged_power_saver() throws Exception { + public void testOnBlockedStatusChanged_powerSaver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_power_saver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_powerSaver"); } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index a2443b391a..ce203795f9 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -79,7 +79,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void installPackage(String apk) throws FileNotFoundException, DeviceNotAvailableException { CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); - assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false)); + assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), + false /* reinstall */, true /* grantPermissions */)); } protected void uninstallPackage(String packageName, boolean shouldSucceed) From 9d364b6aeade9e883cf5720914abc66708609de7 Mon Sep 17 00:00:00 2001 From: evitayan Date: Thu, 2 Apr 2020 18:29:00 -0700 Subject: [PATCH 0990/1415] Add CTS for EapSessionConfig Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I54dedff0555bdfcaae390ddde7b05d24dfabe9b0 --- .../net/eap/cts/EapSessionConfigTest.java | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java diff --git a/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java b/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java new file mode 100644 index 0000000000..c24379dae0 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java @@ -0,0 +1,98 @@ +/* + * 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.eap.cts; + +import static android.telephony.TelephonyManager.APPTYPE_USIM; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.net.eap.EapSessionConfig; +import android.net.eap.EapSessionConfig.EapAkaConfig; +import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; +import android.net.eap.EapSessionConfig.EapMsChapV2Config; +import android.net.eap.EapSessionConfig.EapSimConfig; +import android.net.eap.EapSessionConfig.EapUiccConfig; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class EapSessionConfigTest { + // These constants are IANA-defined values and are copies of hidden constants in + // frameworks/opt/net/ike/src/java/com/android/internal/net/eap/message/EapData.java. + private static final int EAP_TYPE_SIM = 18; + private static final int EAP_TYPE_AKA = 23; + private static final int EAP_TYPE_MSCHAP_V2 = 26; + private static final int EAP_TYPE_AKA_PRIME = 50; + + private static final int SUB_ID = 1; + private static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); + private static final String NETWORK_NAME = "android.net"; + private static final String EAP_MSCHAPV2_USERNAME = "username"; + private static final String EAP_MSCHAPV2_PASSWORD = "password"; + + @Test + public void testBuildWithAllEapMethods() { + EapSessionConfig result = + new EapSessionConfig.Builder() + .setEapIdentity(EAP_IDENTITY) + .setEapSimConfig(SUB_ID, APPTYPE_USIM) + .setEapAkaConfig(SUB_ID, APPTYPE_USIM) + .setEapAkaPrimeConfig( + SUB_ID, + APPTYPE_USIM, + NETWORK_NAME, + true /* allowMismatchedNetworkNames */) + .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) + .build(); + + assertArrayEquals(EAP_IDENTITY, result.getEapIdentity()); + + EapSimConfig eapSimConfig = result.getEapSimConfig(); + assertNotNull(eapSimConfig); + assertEquals(EAP_TYPE_SIM, eapSimConfig.getMethodType()); + verifyEapUiccConfigCommon(eapSimConfig); + + EapAkaConfig eapAkaConfig = result.getEapAkaConfig(); + assertNotNull(eapAkaConfig); + assertEquals(EAP_TYPE_AKA, eapAkaConfig.getMethodType()); + verifyEapUiccConfigCommon(eapAkaConfig); + + EapAkaPrimeConfig eapAkaPrimeConfig = result.getEapAkaPrimeConfig(); + assertNotNull(eapAkaPrimeConfig); + assertEquals(EAP_TYPE_AKA_PRIME, eapAkaPrimeConfig.getMethodType()); + assertEquals(NETWORK_NAME, eapAkaPrimeConfig.getNetworkName()); + assertTrue(NETWORK_NAME, eapAkaPrimeConfig.allowsMismatchedNetworkNames()); + verifyEapUiccConfigCommon(eapAkaPrimeConfig); + + EapMsChapV2Config eapMsChapV2Config = result.getEapMsChapV2onfig(); + assertNotNull(eapMsChapV2Config); + assertEquals(EAP_TYPE_MSCHAP_V2, eapMsChapV2Config.getMethodType()); + assertEquals(EAP_MSCHAPV2_USERNAME, eapMsChapV2Config.getUsername()); + assertEquals(EAP_MSCHAPV2_PASSWORD, eapMsChapV2Config.getPassword()); + } + + private void verifyEapUiccConfigCommon(EapUiccConfig config) { + assertEquals(SUB_ID, config.getSubId()); + assertEquals(APPTYPE_USIM, config.getAppType()); + } +} From b94bb42096a6f47968ae36b4f6e27531739e38b5 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Tue, 24 Mar 2020 15:57:49 -0700 Subject: [PATCH 0991/1415] Set attributionTag for noteOp(WRITE_SETTINGS) calls Test: atest FrameworksNetTests Bug: 136595429 Change-Id: I33f787644c44d7b0e5ce17a433820cfcd985cdfb Exempt-From-Owner-Approval: Merge from AOSP --- .../src/android/net/ITetheringConnector.aidl | 28 +++++--- .../src/android/net/TetheringManager.java | 43 +++++++----- .../tethering/TetheringService.java | 68 ++++++++++++------- .../tethering/TetheringServiceTest.java | 20 +++--- 4 files changed, 101 insertions(+), 58 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl index 8be79645bd..cf094aac2c 100644 --- a/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl +++ b/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl @@ -22,25 +22,31 @@ import android.os.ResultReceiver; /** @hide */ oneway interface ITetheringConnector { - void tether(String iface, String callerPkg, IIntResultListener receiver); - - void untether(String iface, String callerPkg, IIntResultListener receiver); - - void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver); - - void startTethering(in TetheringRequestParcel request, String callerPkg, + void tether(String iface, String callerPkg, String callingAttributionTag, IIntResultListener receiver); - void stopTethering(int type, String callerPkg, IIntResultListener receiver); + void untether(String iface, String callerPkg, String callingAttributionTag, + IIntResultListener receiver); + + void setUsbTethering(boolean enable, String callerPkg, + String callingAttributionTag, IIntResultListener receiver); + + void startTethering(in TetheringRequestParcel request, String callerPkg, + String callingAttributionTag, IIntResultListener receiver); + + void stopTethering(int type, String callerPkg, String callingAttributionTag, + IIntResultListener receiver); void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver, - boolean showEntitlementUi, String callerPkg); + boolean showEntitlementUi, String callerPkg, String callingAttributionTag); void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); - void isTetheringSupported(String callerPkg, IIntResultListener receiver); + void isTetheringSupported(String callerPkg, String callingAttributionTag, + IIntResultListener receiver); - void stopAllTethering(String callerPkg, IIntResultListener receiver); + void stopAllTethering(String callerPkg, String callingAttributionTag, + IIntResultListener receiver); } diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index cc095a0bb4..4a8ccea5f2 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -484,13 +484,20 @@ public class TetheringManager { return dispatcher.waitForResult((connector, listener) -> { try { - connector.tether(iface, callerPkg, listener); + connector.tether(iface, callerPkg, getAttributionTag(), listener); } catch (RemoteException e) { throw new IllegalStateException(e); } }); } + /** + * @return the context's attribution tag + */ + private @Nullable String getAttributionTag() { + return mContext.getAttributionTag(); + } + /** * Stop tethering the named interface. * @@ -509,7 +516,7 @@ public class TetheringManager { return dispatcher.waitForResult((connector, listener) -> { try { - connector.untether(iface, callerPkg, listener); + connector.untether(iface, callerPkg, getAttributionTag(), listener); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -536,7 +543,8 @@ public class TetheringManager { return dispatcher.waitForResult((connector, listener) -> { try { - connector.setUsbTethering(enable, callerPkg, listener); + connector.setUsbTethering(enable, callerPkg, getAttributionTag(), + listener); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -735,7 +743,8 @@ public class TetheringManager { }); } }; - getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener)); + getConnector(c -> c.startTethering(request.getParcel(), callerPkg, + getAttributionTag(), listener)); } /** @@ -775,7 +784,8 @@ public class TetheringManager { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "stopTethering caller:" + callerPkg); - getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() { + getConnector(c -> c.stopTethering(type, callerPkg, getAttributionTag(), + new IIntResultListener.Stub() { @Override public void onResult(int resultCode) { // TODO: provide an API to obtain result @@ -861,7 +871,7 @@ public class TetheringManager { Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg); getConnector(c -> c.requestLatestTetheringEntitlementResult( - type, receiver, showEntitlementUi, callerPkg)); + type, receiver, showEntitlementUi, callerPkg, getAttributionTag())); } /** @@ -1312,7 +1322,7 @@ public class TetheringManager { final RequestDispatcher dispatcher = new RequestDispatcher(); final int ret = dispatcher.waitForResult((connector, listener) -> { try { - connector.isTetheringSupported(callerPkg, listener); + connector.isTetheringSupported(callerPkg, getAttributionTag(), listener); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -1335,14 +1345,15 @@ public class TetheringManager { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "stopAllTethering caller:" + callerPkg); - getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() { - @Override - public void onResult(int resultCode) { - // TODO: add an API parameter to send result to caller. - // This has never been possible as stopAllTethering has always been void and never - // taken a callback object. The only indication that callers have is if the call - // results in a TETHER_STATE_CHANGE broadcast. - } - })); + getConnector(c -> c.stopAllTethering(callerPkg, getAttributionTag(), + new IIntResultListener.Stub() { + @Override + public void onResult(int resultCode) { + // TODO: add an API parameter to send result to caller. + // This has never been possible as stopAllTethering has always been void + // and never taken a callback object. The only indication that callers have + // is if the call results in a TETHER_STATE_CHANGE broadcast. + } + })); } } diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java index 3ed211520d..08011f0497 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -119,8 +119,9 @@ public class TetheringService extends Service { } @Override - public void tether(String iface, String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void tether(String iface, String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { listener.onResult(mTethering.tether(iface)); @@ -128,8 +129,9 @@ public class TetheringService extends Service { } @Override - public void untether(String iface, String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void untether(String iface, String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { listener.onResult(mTethering.untether(iface)); @@ -137,8 +139,9 @@ public class TetheringService extends Service { } @Override - public void setUsbTethering(boolean enable, String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void setUsbTethering(boolean enable, String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { listener.onResult(mTethering.setUsbTethering(enable)); @@ -147,15 +150,16 @@ public class TetheringService extends Service { @Override public void startTethering(TetheringRequestParcel request, String callerPkg, - IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + String callingAttributionTag, IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; mTethering.startTethering(request, listener); } @Override - public void stopTethering(int type, String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void stopTethering(int type, String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { mTethering.stopTethering(type); @@ -165,8 +169,8 @@ public class TetheringService extends Service { @Override public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, - boolean showEntitlementUi, String callerPkg) { - if (checkAndNotifyCommonError(callerPkg, receiver)) return; + boolean showEntitlementUi, String callerPkg, String callingAttributionTag) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, receiver)) return; mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); } @@ -196,8 +200,9 @@ public class TetheringService extends Service { } @Override - public void stopAllTethering(String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void stopAllTethering(String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { mTethering.untetherAll(); @@ -206,8 +211,9 @@ public class TetheringService extends Service { } @Override - public void isTetheringSupported(String callerPkg, IIntResultListener listener) { - if (checkAndNotifyCommonError(callerPkg, listener)) return; + public void isTetheringSupported(String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; try { listener.onResult(TETHER_ERROR_NO_ERROR); @@ -220,9 +226,10 @@ public class TetheringService extends Service { mTethering.dump(fd, writer, args); } - private boolean checkAndNotifyCommonError(String callerPkg, IIntResultListener listener) { + private boolean checkAndNotifyCommonError(String callerPkg, String callingAttributionTag, + IIntResultListener listener) { try { - if (!mService.hasTetherChangePermission(callerPkg)) { + if (!mService.hasTetherChangePermission(callerPkg, callingAttributionTag)) { listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); return true; } @@ -237,8 +244,9 @@ public class TetheringService extends Service { return false; } - private boolean checkAndNotifyCommonError(String callerPkg, ResultReceiver receiver) { - if (!mService.hasTetherChangePermission(callerPkg)) { + private boolean checkAndNotifyCommonError(String callerPkg, String callingAttributionTag, + ResultReceiver receiver) { + if (!mService.hasTetherChangePermission(callerPkg, callingAttributionTag)) { receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null); return true; } @@ -266,7 +274,7 @@ public class TetheringService extends Service { return tetherEnabledInSettings && mTethering.hasTetherableConfiguration(); } - private boolean hasTetherChangePermission(String callerPkg) { + private boolean hasTetherChangePermission(String callerPkg, String callingAttributionTag) { if (checkCallingOrSelfPermission( android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) { return true; @@ -278,14 +286,28 @@ public class TetheringService extends Service { int uid = Binder.getCallingUid(); // If callerPkg's uid is not same as Binder.getCallingUid(), // checkAndNoteWriteSettingsOperation will return false and the operation will be denied. - if (Settings.checkAndNoteWriteSettingsOperation(mContext, uid, callerPkg, - false /* throwException */)) { + if (checkAndNoteWriteSettingsOperation(mContext, uid, callerPkg, + callingAttributionTag, false /* throwException */)) { return true; } return false; } + /** + * Check if the package is a allowed to write settings. This also accounts that such an access + * happened. + * + * @return {@code true} iff the package is allowed to write settings. + */ + // TODO: Remove method and replace with direct call once R code is pushed to AOSP + private static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, + @NonNull String callingPackage, @Nullable String callingAttributionTag, + boolean throwException) { + return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage, + callingAttributionTag, throwException); + } + private boolean hasTetherAccessPermission() { if (checkCallingOrSelfPermission( android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) { diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index 51bad9af23..7df9fc6850 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -52,6 +52,7 @@ import org.mockito.MockitoAnnotations; public final class TetheringServiceTest { private static final String TEST_IFACE_NAME = "test_wlan0"; private static final String TEST_CALLER_PKG = "test_pkg"; + private static final String TEST_ATTRIBUTION_TAG = null; @Mock private ITetheringEventCallback mITetheringEventCallback; @Rule public ServiceTestRule mServiceTestRule; private Tethering mTethering; @@ -95,7 +96,7 @@ public final class TetheringServiceTest { public void testTether() throws Exception { when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).tether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); @@ -106,7 +107,8 @@ public final class TetheringServiceTest { public void testUntether() throws Exception { when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).untether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); @@ -117,7 +119,8 @@ public final class TetheringServiceTest { public void testSetUsbTethering() throws Exception { when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR); final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, + TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).setUsbTethering(true /* enable */); verifyNoMoreInteractions(mTethering); @@ -129,7 +132,7 @@ public final class TetheringServiceTest { final TestTetheringResult result = new TestTetheringResult(); final TetheringRequestParcel request = new TetheringRequestParcel(); request.tetheringType = TETHERING_WIFI; - mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).startTethering(eq(request), eq(result)); verifyNoMoreInteractions(mTethering); @@ -138,7 +141,8 @@ public final class TetheringServiceTest { @Test public void testStopTethering() throws Exception { final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result); + mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).stopTethering(TETHERING_WIFI); verifyNoMoreInteractions(mTethering); @@ -149,7 +153,7 @@ public final class TetheringServiceTest { public void testRequestLatestTetheringEntitlementResult() throws Exception { final ResultReceiver result = new ResultReceiver(null); mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, - true /* showEntitlementUi */, TEST_CALLER_PKG); + true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI), eq(result), eq(true) /* showEntitlementUi */); @@ -176,7 +180,7 @@ public final class TetheringServiceTest { @Test public void testStopAllTethering() throws Exception { final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result); + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verify(mTethering).untetherAll(); verifyNoMoreInteractions(mTethering); @@ -186,7 +190,7 @@ public final class TetheringServiceTest { @Test public void testIsTetheringSupported() throws Exception { final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result); + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).hasTetherableConfiguration(); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); From 6f203abeab18e0086f451ff65c19c1cec50bbe24 Mon Sep 17 00:00:00 2001 From: paulhu Date: Wed, 22 Apr 2020 10:25:11 +0800 Subject: [PATCH 0992/1415] Add TetheringCommonTests to CtsTetheringTest Bug: 153614365 Bug: 153613717 Test: atest CtsTetheringTest Change-Id: I26c06d522ef2935deb2b1abbd3c5b6be97a48a27 --- tests/cts/tethering/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 63de301d69..37894ec4dc 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -25,6 +25,7 @@ android_test { ], static_libs: [ + "TetheringCommonTests", "TetheringIntegrationTestsLib", "compatibility-device-util-axt", "ctstestrunner-axt", From 89099548f8ea46046095ccac1e82c2c88d1d0bee Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Wed, 22 Apr 2020 04:31:43 +0000 Subject: [PATCH 0993/1415] Revert "Pull service dumps to help debug test failures." This reverts commit e3711ae3178ec598430c834efd60f2c43417a5ef. Reason for revert: Might cause build break on errorprone branch Change-Id: Iddece3edf4b1e96fafb8b36282f58410a2476025 --- tests/cts/hostside/AndroidTest.xml | 5 - tests/cts/hostside/app/Android.bp | 2 - tests/cts/hostside/app/AndroidManifest.xml | 3 +- .../net/hostside/AbstractAppIdleTestCase.java | 76 ++-- .../AbstractBatterySaverModeTestCase.java | 68 +++- .../hostside/AbstractDozeModeTestCase.java | 66 +++- ...ractRestrictBackgroundNetworkTestCase.java | 361 ++++++++++++++++-- .../cts/net/hostside/AppIdleMeteredTest.java | 13 +- .../net/hostside/AppIdleNonMeteredTest.java | 7 +- .../hostside/BatterySaverModeMeteredTest.java | 13 +- .../BatterySaverModeNonMeteredTest.java | 9 +- .../cts/net/hostside/DataSaverModeTest.java | 66 ++-- .../cts/net/hostside/DozeModeMeteredTest.java | 13 +- .../net/hostside/DozeModeNonMeteredTest.java | 8 +- .../cts/net/hostside/DumpOnFailureRule.java | 91 ----- .../MeterednessConfigurationRule.java | 60 --- .../cts/net/hostside/MixedModesTest.java | 230 ++++++----- .../cts/net/hostside/NetworkCallbackTest.java | 175 ++++----- .../net/hostside/NetworkPolicyTestUtils.java | 255 ------------- .../android/cts/net/hostside/Property.java | 70 ---- .../cts/net/hostside/RequiredProperties.java | 31 -- .../net/hostside/RequiredPropertiesRule.java | 90 ----- .../cts/net/HostsideNetworkCallbackTests.java | 8 +- .../cts/net/HostsideNetworkTestCase.java | 3 +- 24 files changed, 783 insertions(+), 940 deletions(-) delete mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java delete mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java delete mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java delete mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java delete mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java delete mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 5479c51a4c..dbff1794e9 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -31,9 +31,4 @@

    By default is empty - it's up to subclasses to override. + */ + protected void setUpMeteredNetwork() throws Exception { + } + + /** + * Resets the (non) metered network state. + * + *

    By default is empty - it's up to subclasses to override. + */ + protected void tearDownMeteredNetwork() throws Exception { } - @Test public void testBackgroundNetworkAccess_enabled() throws Exception { + if (!isSupported()) return; + setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -80,8 +118,9 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } - @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { + if (!isSupported()) return; + setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -101,8 +140,9 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } - @Test public void testBackgroundNetworkAccess_disabled() throws Exception { + if (!isSupported()) return; + assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index 6f32c563c1..f20f1d1c4d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -16,25 +16,20 @@ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.Property.DOZE_MODE; -import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE; - import android.os.SystemClock; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import android.util.Log; /** * Base class for metered and non-metered Doze Mode tests. */ -@RequiredProperties({DOZE_MODE}) abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { - @Before - public final void setUp() throws Exception { + @Override + protected final void setUp() throws Exception { super.setUp(); + if (!isSupported()) return; + // Set initial state. removePowerSaveModeWhitelist(TEST_APP2_PKG); removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); @@ -43,15 +38,48 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor registerBroadcastReceiver(); } - @After - public final void tearDown() throws Exception { + @Override + protected final void tearDown() throws Exception { super.tearDown(); - setDozeMode(false); + if (!isSupported()) return; + + try { + tearDownMeteredNetwork(); + } finally { + setDozeMode(false); + } + } + + @Override + protected boolean isSupported() throws Exception { + boolean supported = isDozeModeEnabled(); + if (!supported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Doze Mode"); + } + return supported; + } + + /** + * Sets the initial (non) metered network state. + * + *

    By default is empty - it's up to subclasses to override. + */ + protected void setUpMeteredNetwork() throws Exception { + } + + /** + * Resets the (non) metered network state. + * + *

    By default is empty - it's up to subclasses to override. + */ + protected void tearDownMeteredNetwork() throws Exception { } - @Test public void testBackgroundNetworkAccess_enabled() throws Exception { + if (!isSupported()) return; + setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -68,8 +96,9 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } - @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { + if (!isSupported()) return; + setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -89,18 +118,19 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } - @Test public void testBackgroundNetworkAccess_disabled() throws Exception { + if (!isSupported()) return; + assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(true); } - @RequiredProperties({NOT_LOW_RAM_DEVICE}) - @Test public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() throws Exception { + if (!isSupported() || isLowRamDevice()) return; + setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); try { registerNotificationListenerService(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 57b7bb4f8d..40d7e34fcc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -17,22 +17,14 @@ package com.android.cts.net.hostside; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static android.os.BatteryManager.BATTERY_PLUGGED_AC; import static android.os.BatteryManager.BATTERY_PLUGGED_USB; import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import android.app.ActivityManager; import android.app.Instrumentation; @@ -42,7 +34,9 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; @@ -50,27 +44,24 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; +import android.os.SystemProperties; import android.provider.Settings; import android.service.notification.NotificationListenerService; +import android.test.InstrumentationTestCase; +import android.text.TextUtils; import android.util.Log; -import org.junit.Rule; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; +import com.android.compatibility.common.util.BatteryUtils; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - /** * Superclass for tests related to background network restrictions. */ -@RunWith(AndroidJUnit4.class) -public abstract class AbstractRestrictBackgroundNetworkTestCase { - public static final String TAG = "RestrictBackgroundNetworkTests"; +abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase { + protected static final String TAG = "RestrictBackgroundNetworkTests"; protected static final String TEST_PKG = "com.android.cts.net.hostside"; protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; @@ -107,6 +98,8 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static int PROCESS_STATE_FOREGROUND_SERVICE; + private static final int PROCESS_STATE_TOP = 2; + private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; protected static final int TYPE_COMPONENT_ACTIVTIY = 0; @@ -133,23 +126,22 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { protected WifiManager mWfm; protected int mUid; private int mMyUid; + private String mMeteredWifi; private MyServiceClient mServiceClient; private String mDeviceIdleConstantsSetting; + private boolean mSupported; private boolean mIsLocationOn; - @Rule - public final RuleChain mRuleChain = RuleChain.outerRule(new DumpOnFailureRule()) - .around(new RequiredPropertiesRule()) - .around(new MeterednessConfigurationRule()); - + @Override protected void setUp() throws Exception { + super.setUp(); PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null); mInstrumentation = getInstrumentation(); - mContext = getContext(); - mCm = getConnectivityManager(); - mWfm = getWifiManager(); + mContext = mInstrumentation.getContext(); + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); @@ -159,9 +151,10 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { if (!mIsLocationOn) { enableLocation(); } + mSupported = setUpActiveNetworkMeteringState(); setAppIdle(false); - Log.i(TAG, "Apps status:\n" + Log.i(TAG, "Apps status on " + getName() + ":\n" + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -172,13 +165,16 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { final String currentConstants = executeShellCommand("settings get global app_idle_constants"); assertEquals(appIdleConstants, currentConstants); - } + } + @Override protected void tearDown() throws Exception { if (!mIsLocationOn) { disableLocation(); } mServiceClient.unbind(); + + super.tearDown(); } private void enableLocation() throws Exception { @@ -263,8 +259,23 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { final String status = mServiceClient.getRestrictBackgroundStatus(); assertNotNull("didn't get API status from app2", status); - assertEquals(restrictBackgroundValueToString(expectedStatus), - restrictBackgroundValueToString(Integer.parseInt(status))); + final String actualStatus = toString(Integer.parseInt(status)); + assertEquals("wrong status", toString(expectedStatus), actualStatus); + } + + protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); + } + + protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "Expected: " + toString(expectedStatus) + + " but actual: " + toString(actualStatus)); + return false; + } + return true; } protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { @@ -286,6 +297,28 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */); } + /** + * Whether this device suport this type of test. + * + *

    Should be overridden when necessary (but always calling + * {@code super.isSupported()} first), and explicitly used before each test + * Example: + * + *

    
    +     * public void testSomething() {
    +     *    if (!isSupported()) return;
    +     * 
    + * + * @return {@code true} by default. + */ + protected boolean isSupported() throws Exception { + return mSupported; + } + + protected boolean isBatterySaverSupported() { + return BatteryUtils.isBatterySaverSupported(); + } + /** * Asserts that an app always have access while on foreground or running a foreground service. * @@ -354,6 +387,23 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state ); } + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + protected boolean isDataSaverSupported() throws Exception { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + /** * Returns whether an app state should be considered "background" for restriction purposes. */ @@ -393,10 +443,40 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { // Exponential back-off. timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS); } + dumpOnFailure(); fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries + " attempts.\nLast error: " + error); } + private void dumpOnFailure() throws Exception { + dumpAllNetworkRules(); + Log.d(TAG, "Usagestats dump: " + getUsageStatsDump()); + executeShellCommand("settings get global app_idle_constants"); + } + + private void dumpAllNetworkRules() throws Exception { + final String networkManagementDump = runShellCommand(mInstrumentation, + "dumpsys network_management").trim(); + final String networkPolicyDump = runShellCommand(mInstrumentation, + "dumpsys netpolicy").trim(); + TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); + splitter.setString(networkManagementDump); + String next; + Log.d(TAG, ">>> Begin network_management dump"); + while (splitter.hasNext()) { + next = splitter.next(); + Log.d(TAG, next); + } + Log.d(TAG, "<<< End network_management dump"); + splitter.setString(networkPolicyDump); + Log.d(TAG, ">>> Begin netpolicy dump"); + while (splitter.hasNext()) { + next = splitter.next(); + Log.d(TAG, next); + } + Log.d(TAG, "<<< End netpolicy dump"); + } + /** * Checks whether the network is available as expected. * @@ -448,10 +528,22 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { return errors.toString(); } + protected boolean isLowRamDevice() { + final ActivityManager am = (ActivityManager) mContext.getSystemService( + Context.ACTIVITY_SERVICE); + return am.isLowRamDevice(); + } + + protected String executeShellCommand(String command) throws Exception { + final String result = runShellCommand(mInstrumentation, command).trim(); + if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'"); + return result; + } + /** * Runs a Shell command which is not expected to generate output. */ - protected void executeSilentShellCommand(String command) { + protected void executeSilentShellCommand(String command) throws Exception { final String result = executeShellCommand(command); assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty()); } @@ -480,6 +572,10 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { }); } + protected void assertDelayedShellCommand(String command, ExpectResultChecker checker) + throws Exception { + assertDelayedShellCommand(command, 5, 1, checker); + } protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, ExpectResultChecker checker) throws Exception { String result = ""; @@ -496,6 +592,159 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { + " attempts. Last result: '" + result + "'"); } + /** + * Sets the initial metering state for the active network. + * + *

    It's called on setup and by default does nothing - it's up to the + * subclasses to override. + * + * @return whether the tests in the subclass are supported on this device. + */ + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return true; + } + + /** + * Makes sure the active network is not metered. + * + *

    If the device does not supoprt un-metered networks (for example if it + * only has cellular data but not wi-fi), it should return {@code false}; + * otherwise, it should return {@code true} (or fail if the un-metered + * network could not be set). + * + * @return {@code true} if the network is now unmetered. + */ + protected boolean setUnmeteredNetwork() throws Exception { + final NetworkInfo info = mCm.getActiveNetworkInfo(); + assertNotNull("Could not get active network", info); + if (!mCm.isActiveNetworkMetered()) { + Log.d(TAG, "Active network is not metered: " + info); + } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { + Log.i(TAG, "Setting active WI-FI network as not metered: " + info ); + setWifiMeteredStatus(false); + } else { + Log.d(TAG, "Active network cannot be set to un-metered: " + info); + return false; + } + assertActiveNetworkMetered(false); // Sanity check. + return true; + } + + /** + * Enables metering on the active network if supported. + * + *

    If the device does not support metered networks it should return + * {@code false}; otherwise, it should return {@code true} (or fail if the + * metered network could not be set). + * + * @return {@code true} if the network is now metered. + */ + protected boolean setMeteredNetwork() throws Exception { + final NetworkInfo info = mCm.getActiveNetworkInfo(); + final boolean metered = mCm.isActiveNetworkMetered(); + if (metered) { + Log.d(TAG, "Active network already metered: " + info); + return true; + } else if (info.getType() != ConnectivityManager.TYPE_WIFI) { + Log.w(TAG, "Active network does not support metering: " + info); + return false; + } else { + Log.w(TAG, "Active network not metered: " + info); + } + final String netId = setWifiMeteredStatus(true); + + // Set flag so status is reverted on resetMeteredNetwork(); + mMeteredWifi = netId; + // Sanity check. + assertWifiMeteredStatus(netId, true); + assertActiveNetworkMetered(true); + return true; + } + + /** + * Resets the device metering state to what it was before the test started. + * + *

    This reverts any metering changes made by {@code setMeteredNetwork}. + */ + protected void resetMeteredNetwork() throws Exception { + if (mMeteredWifi != null) { + Log.i(TAG, "resetMeteredNetwork(): SID '" + mMeteredWifi + + "' was set as metered by test case; resetting it"); + setWifiMeteredStatus(mMeteredWifi, false); + assertActiveNetworkMetered(false); // Sanity check. + } + } + + private void assertActiveNetworkMetered(boolean expected) throws Exception { + final int maxTries = 5; + NetworkInfo info = null; + for (int i = 1; i <= maxTries; i++) { + info = mCm.getActiveNetworkInfo(); + if (info == null) { + Log.v(TAG, "No active network info on attempt #" + i + + "; sleeping 1s before polling again"); + } else if (mCm.isActiveNetworkMetered() != expected) { + Log.v(TAG, "Wrong metered status for active network " + info + "; expected=" + + expected + "; sleeping 1s before polling again"); + } else { + break; + } + Thread.sleep(SECOND_IN_MS); + } + assertNotNull("No active network after " + maxTries + " attempts", info); + assertEquals("Wrong metered status for active network " + info, expected, + mCm.isActiveNetworkMetered()); + } + + private String setWifiMeteredStatus(boolean metered) throws Exception { + // We could call setWifiEnabled() here, but it might take sometime to be in a consistent + // state (for example, if one of the saved network is not properly authenticated), so it's + // better to let the hostside test take care of that. + assertTrue("wi-fi is disabled", mWfm.isWifiEnabled()); + // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests + // to make the actual verification of restrictions optional. + final String ssid = mWfm.getConnectionInfo().getSSID(); + return setWifiMeteredStatus(ssid, metered); + } + + private String setWifiMeteredStatus(String ssid, boolean metered) throws Exception { + assertNotNull("null SSID", ssid); + final String netId = ssid.trim().replaceAll("\"", ""); // remove quotes, if any. + assertFalse("empty SSID", ssid.isEmpty()); + + Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); + final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered; + assertDelayedShellCommand(setCommand, ""); + + return netId; + } + + private void assertWifiMeteredStatus(String netId, boolean status) throws Exception { + final String command = "cmd netpolicy list wifi-networks"; + final String expectedLine = netId + ";" + status; + assertDelayedShellCommand(command, new ExpectResultChecker() { + + @Override + public boolean isExpected(String result) { + return result.contains(expectedLine); + } + + @Override + public String getExpected() { + return "line containing " + expectedLine; + } + }); + } + + protected void setRestrictBackground(boolean enabled) throws Exception { + executeShellCommand("cmd netpolicy set restrict-background " + enabled); + final String output = executeShellCommand("cmd netpolicy get restrict-background "); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + // TODO: use MoreAsserts? + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + protected void addRestrictBackgroundWhitelist(int uid) throws Exception { executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); @@ -675,7 +924,7 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { protected void setDozeMode(boolean enabled) throws Exception { // Sanity check, since tests should check beforehand.... - assertTrue("Device does not support Doze Mode", isDozeModeSupported()); + assertTrue("Device does not support Doze Mode", isDozeModeEnabled()); Log.i(TAG, "Setting Doze Mode to " + enabled); if (enabled) { @@ -695,16 +944,43 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE"); } + protected boolean isDozeModeEnabled() throws Exception { + final String result = executeShellCommand("cmd deviceidle enabled deep").trim(); + return result.equals("1"); + } + protected void setAppIdle(boolean enabled) throws Exception { Log.i(TAG, "Setting app idle to " + enabled); executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); assertAppIdle(enabled); // Sanity check } + private String getUsageStatsDump() throws Exception { + final String output = runShellCommand(mInstrumentation, "dumpsys usagestats").trim(); + final StringBuilder sb = new StringBuilder(); + final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); + splitter.setString(output); + String str; + while (splitter.hasNext()) { + str = splitter.next(); + if (str.contains("package=") + && !str.contains(TEST_PKG) && !str.contains(TEST_APP2_PKG)) { + continue; + } + if (str.trim().startsWith("config=") || str.trim().startsWith("time=")) { + continue; + } + sb.append(str).append('\n'); + } + return sb.toString(); + } + protected void assertAppIdle(boolean enabled) throws Exception { try { assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled); } catch (Throwable e) { + Log.d(TAG, "UsageStats dump:\n" + getUsageStatsDump()); + executeShellCommand("settings get global app_idle_constants"); throw e; } } @@ -785,10 +1061,12 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { // App didn't come to foreground when the activity is started, so try again. assertForegroundNetworkAccess(); } else { + dumpOnFailure(); fail("Network is not available for app2 (" + mUid + "): " + errors[0]); } } } else { + dumpOnFailure(); fail("Timed out waiting for network availability status from app2 (" + mUid + ")"); } } else { @@ -872,6 +1150,19 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { } } + private String toString(int status) { + switch (status) { + case RESTRICT_BACKGROUND_STATUS_DISABLED: + return "DISABLED"; + case RESTRICT_BACKGROUND_STATUS_WHITELISTED: + return "WHITELISTED"; + case RESTRICT_BACKGROUND_STATUS_ENABLED: + return "ENABLED"; + default: + return "UNKNOWN_STATUS_" + status; + } + } + private ProcessState getProcessStateByUid(int uid) throws Exception { return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid)); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java index f1858d65a5..622d99361f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java @@ -16,8 +16,15 @@ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.Property.METERED_NETWORK; - -@RequiredProperties({METERED_NETWORK}) public class AppIdleMeteredTest extends AbstractAppIdleTestCase { + + @Override + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setMeteredNetwork(); + } + + @Override + protected void tearDownMeteredNetwork() throws Exception { + resetMeteredNetwork(); + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java index e737a6dabe..bde71f9100 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java @@ -16,8 +16,9 @@ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - -@RequiredProperties({NON_METERED_NETWORK}) public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase { + @Override + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setUnmeteredNetwork(); + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java index c78ca2ec77..3071cfe3f1 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java @@ -16,8 +16,15 @@ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.Property.METERED_NETWORK; - -@RequiredProperties({METERED_NETWORK}) public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase { + + @Override + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setMeteredNetwork(); + } + + @Override + protected void tearDownMeteredNetwork() throws Exception { + resetMeteredNetwork(); + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index fb52a540d8..6d3076fe0e 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -16,9 +16,10 @@ package com.android.cts.net.hostside; - -import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - -@RequiredProperties({NON_METERED_NETWORK}) public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { + + @Override + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setUnmeteredNetwork(); + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index aa2c914e02..cfe6a73a0f 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,33 +20,24 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; -import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; -import static com.android.cts.net.hostside.Property.METERED_NETWORK; -import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE; - -import static org.junit.Assert.fail; +import android.util.Log; import com.android.compatibility.common.util.CddTest; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import androidx.test.filters.LargeTest; - -@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK}) -@LargeTest public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { "com.android.providers.downloads" }; - @Before + private boolean mIsDataSaverSupported; + + @Override public void setUp() throws Exception { super.setUp(); + mIsDataSaverSupported = isDataSaverSupported(); + // Set initial state. setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); @@ -56,15 +47,36 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(0); } - @After - public void tearDown() throws Exception { + @Override + protected void tearDown() throws Exception { super.tearDown(); - setRestrictBackground(false); + if (!isSupported()) return; + + try { + resetMeteredNetwork(); + } finally { + setRestrictBackground(false); + } + } + + @Override + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setMeteredNetwork(); + } + + @Override + protected boolean isSupported() throws Exception { + if (!mIsDataSaverSupported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Data Saver Mode"); + } + return mIsDataSaverSupported && super.isSupported(); } - @Test public void testGetRestrictBackgroundStatus_disabled() throws Exception { + if (!isSupported()) return; + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted @@ -76,8 +88,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); } - @Test public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { + if (!isSupported()) return; + setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -94,8 +107,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); } - @Test public void testGetRestrictBackgroundStatus_enabled() throws Exception { + if (!isSupported()) return; + setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -128,8 +142,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertBackgroundNetworkAccess(false); } - @Test public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { + if (!isSupported()) return; + addRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -165,8 +180,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); } - @Test public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { + if (!isSupported()) return; + final StringBuilder error = new StringBuilder(); for (String packageName : REQUIRED_WHITELISTED_PACKAGES) { int uid = -1; @@ -186,10 +202,10 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } } - @RequiredProperties({NO_DATA_SAVER_MODE}) @CddTest(requirement="7.4.7/C-2-2") - @Test public void testBroadcastNotSentOnUnsupportedDevices() throws Exception { + if (isSupported()) return; + setRestrictBackground(true); assertRestrictBackgroundChangedReceived(0); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java index 4306c991c2..e4189af587 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java @@ -16,8 +16,15 @@ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.Property.METERED_NETWORK; - -@RequiredProperties({METERED_NETWORK}) public class DozeModeMeteredTest extends AbstractDozeModeTestCase { + + @Override + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setMeteredNetwork(); + } + + @Override + protected void tearDownMeteredNetwork() throws Exception { + resetMeteredNetwork(); + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java index 1e89f158a3..edbbb9e1ce 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java @@ -16,8 +16,10 @@ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - -@RequiredProperties({NON_METERED_NETWORK}) public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { + + @Override + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return setUnmeteredNetwork(); + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java deleted file mode 100644 index cedd62a0bc..0000000000 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.cts.net.hostside; - -import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; -import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG; - -import android.os.Environment; -import android.os.FileUtils; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -import com.android.compatibility.common.util.OnFailureRule; - -import org.junit.AssumptionViolatedException; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import androidx.test.platform.app.InstrumentationRegistry; - -public class DumpOnFailureRule extends OnFailureRule { - private File mDumpDir = new File(Environment.getExternalStorageDirectory(), - "CtsHostsideNetworkTests"); - - @Override - public void onTestFailure(Statement base, Description description, Throwable throwable) { - final String testName = description.getClassName() + "_" + description.getMethodName(); - - if (throwable instanceof AssumptionViolatedException) { - Log.d(TAG, "Skipping test " + testName + ": " + throwable); - return; - } - - prepareDumpRootDir(); - final File dumpFile = new File(mDumpDir, "dump-" + testName); - Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath()); - try (FileOutputStream out = new FileOutputStream(dumpFile)) { - for (String cmd : new String[] { - "dumpsys netpolicy", - "dumpsys network_management", - "dumpsys usagestats " + TEST_PKG, - "dumpsys usagestats appstandby", - }) { - dumpCommandOutput(out, cmd); - } - } catch (FileNotFoundException e) { - Log.e(TAG, "Error opening file: " + dumpFile, e); - } catch (IOException e) { - Log.e(TAG, "Error closing file: " + dumpFile, e); - } - } - - void dumpCommandOutput(FileOutputStream out, String cmd) { - final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation() - .getUiAutomation().executeShellCommand(cmd); - try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { - out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8)); - FileUtils.copy(in, out); - out.write("\n\n=================================================================\n\n" - .getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - Log.e(TAG, "Error dumping '" + cmd + "'", e); - } - } - - void prepareDumpRootDir() { - if (!mDumpDir.exists() && !mDumpDir.mkdir()) { - Log.e(TAG, "Error creating " + mDumpDir); - } - } -} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java deleted file mode 100644 index 8fadf9e295..0000000000 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.cts.net.hostside; - -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.resetMeteredNetwork; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupMeteredNetwork; -import static com.android.cts.net.hostside.Property.METERED_NETWORK; -import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - -import android.util.ArraySet; -import android.util.Pair; - -import com.android.compatibility.common.util.BeforeAfterRule; - -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -public class MeterednessConfigurationRule extends BeforeAfterRule { - private Pair mSsidAndInitialMeteredness; - - @Override - public void onBefore(Statement base, Description description) throws Throwable { - final ArraySet requiredProperties - = RequiredPropertiesRule.getRequiredProperties(); - if (requiredProperties.contains(METERED_NETWORK)) { - configureNetworkMeteredness(true); - } else if (requiredProperties.contains(NON_METERED_NETWORK)) { - configureNetworkMeteredness(false); - } - } - - @Override - public void onAfter(Statement base, Description description) throws Throwable { - resetNetworkMeteredness(); - } - - public void configureNetworkMeteredness(boolean metered) throws Exception { - mSsidAndInitialMeteredness = setupMeteredNetwork(metered); - } - - public void resetNetworkMeteredness() throws Exception { - if (mSsidAndInitialMeteredness != null) { - resetMeteredNetwork(mSsidAndInitialMeteredness.first, - mSsidAndInitialMeteredness.second); - } - } -} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index c9edda6e0b..b1a21867b3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -15,21 +15,9 @@ */ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; -import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE; -import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; -import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; -import static com.android.cts.net.hostside.Property.DOZE_MODE; -import static com.android.cts.net.hostside.Property.METERED_NETWORK; -import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - import android.os.SystemClock; import android.util.Log; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - /** * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode * and Data Saver Mode) are applied simultaneously. @@ -41,10 +29,12 @@ import org.junit.Test; public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String TAG = "MixedModesTest"; - @Before + @Override public void setUp() throws Exception { super.setUp(); + if (!isSupported()) return; + // Set initial state. removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); @@ -54,10 +44,12 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { registerBroadcastReceiver(); } - @After - public void tearDown() throws Exception { + @Override + protected void tearDown() throws Exception { super.tearDown(); + if (!isSupported()) return; + try { setRestrictBackground(false); } finally { @@ -65,15 +57,34 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @Override + public boolean isSupported() throws Exception { + if (!isDozeModeEnabled()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Doze Mode"); + return false; + } + return true; + } + /** * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ - @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, METERED_NETWORK}) - @Test public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { - final MeterednessConfigurationRule meterednessConfiguration - = new MeterednessConfigurationRule(); - meterednessConfiguration.configureNetworkMeteredness(true); + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } + if (!isSupported()) return; + + Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); + if (!setMeteredNetwork()) { + Log.w(TAG, "testDataAndBatterySaverModes_meteredNetwork() skipped because " + + "device cannot use a metered network"); + return; + } + try { setRestrictBackground(true); setBatterySaverMode(true); @@ -126,7 +137,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { removeRestrictBackgroundBlacklist(mUid); removePowerSaveModeWhitelist(TEST_APP2_PKG); } finally { - meterednessConfiguration.resetNetworkMeteredness(); + resetMeteredNetwork(); } } @@ -134,75 +145,86 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered * networks. */ - @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, NON_METERED_NETWORK}) - @Test public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { - final MeterednessConfigurationRule meterednessConfiguration - = new MeterednessConfigurationRule(); - meterednessConfiguration.configureNetworkMeteredness(false); - try { - setRestrictBackground(true); - setBatterySaverMode(true); - - Log.v(TAG, "Not whitelisted for any."); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - - Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); - addRestrictBackgroundWhitelist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - - Log.v(TAG, "Whitelisted for both."); - addRestrictBackgroundWhitelist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundBlacklist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removeRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - } finally { - meterednessConfiguration.resetNetworkMeteredness(); + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; } + if (!isSupported()) return; + + if (!setUnmeteredNetwork()) { + Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network" + + " is metered"); + return; + } + Log.i(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() tests"); + setRestrictBackground(true); + setBatterySaverMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); } /** * Tests that powersave whitelists works as expected when doze and battery saver modes * are enabled. */ - @RequiredProperties({DOZE_MODE, BATTERY_SAVER_MODE}) - @Test public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } + if (!isSupported()) { + return; + } + setBatterySaverMode(true); setDozeMode(true); @@ -228,9 +250,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests that powersave whitelists works as expected when doze and appIdle modes * are enabled. */ - @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) - @Test public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception { + if (!isSupported()) { + return; + } + setDozeMode(true); setAppIdle(true); @@ -252,9 +276,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } - @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) - @Test public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception { + if (!isSupported()) { + return; + } + setDozeMode(true); setAppIdle(true); @@ -273,9 +299,16 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } - @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) - @Test public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } + if (!isSupported()) { + return; + } + setBatterySaverMode(true); setAppIdle(true); @@ -297,9 +330,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { /** * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled. */ - @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) - @Test public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { + if (!isSupported()) { + return; + } + setDozeMode(true); setAppIdle(true); @@ -318,9 +353,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } - @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) - @Test public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { + if (!isSupported()) { + return; + } + setDozeMode(true); setAppIdle(true); @@ -343,9 +380,16 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } - @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) - @Test public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } + if (!isSupported()) { + return; + } + setBatterySaverMode(true); setAppIdle(true); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index ed397b91fc..24dde9d356 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -16,26 +16,15 @@ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; -import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; -import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import android.net.Network; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import java.util.Objects; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase { + private boolean mIsDataSaverSupported; private Network mNetwork; private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback(); @@ -143,122 +132,108 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } } - @Before + @Override public void setUp() throws Exception { super.setUp(); + mIsDataSaverSupported = isDataSaverSupported(); + mNetwork = mCm.getActiveNetwork(); + // Set initial state. + setBatterySaverMode(false); registerBroadcastReceiver(); + if (!mIsDataSaverSupported) return; + setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(0); } - @After - public void tearDown() throws Exception { + @Override + protected void tearDown() throws Exception { super.tearDown(); - setRestrictBackground(false); - setBatterySaverMode(false); - } + if (!mIsDataSaverSupported) return; - @RequiredProperties({DATA_SAVER_MODE}) - @Test - public void testOnBlockedStatusChanged_dataSaver() throws Exception { - // Initial state - setBatterySaverMode(false); - setRestrictBackground(false); - - final MeterednessConfigurationRule meterednessConfiguration - = new MeterednessConfigurationRule(); - meterednessConfiguration.configureNetworkMeteredness(true); try { - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable restrict background - setRestrictBackground(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Add to whitelist - addRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Remove from whitelist - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + resetMeteredNetwork(); } finally { - meterednessConfiguration.resetNetworkMeteredness(); - } - - // Set to non-metered network - meterednessConfiguration.configureNetworkMeteredness(false); - try { - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Disable restrict background, should not trigger callback setRestrictBackground(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.assertNoCallback(); - } finally { - meterednessConfiguration.resetNetworkMeteredness(); } } - @RequiredProperties({BATTERY_SAVER_MODE}) - @Test - public void testOnBlockedStatusChanged_powerSaver() throws Exception { - // Set initial state. - setBatterySaverMode(false); - setRestrictBackground(false); + public void testOnBlockedStatusChanged_data_saver() throws Exception { + if (!mIsDataSaverSupported) return; - final MeterednessConfigurationRule meterednessConfiguration - = new MeterednessConfigurationRule(); - meterednessConfiguration.configureNetworkMeteredness(true); - try { - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Prepare metered wifi + if (!setMeteredNetwork()) return; - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - } finally { - meterednessConfiguration.resetNetworkMeteredness(); - } + // Enable restrict background + setRestrictBackground(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Add to whitelist + addRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Remove from whitelist + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); // Set to non-metered network - meterednessConfiguration.configureNetworkMeteredness(false); - try { - mTestNetworkCallback.assertNoCallback(); + setUnmeteredNetwork(); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + // Disable restrict background, should not trigger callback + setRestrictBackground(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.assertNoCallback(); + } - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - } finally { - meterednessConfiguration.resetNetworkMeteredness(); - } + + public void testOnBlockedStatusChanged_power_saver() throws Exception { + // Prepare metered wifi + if (!setMeteredNetwork()) return; + + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Set to non-metered network + setUnmeteredNetwork(); + mTestNetworkCallback.assertNoCallback(); + + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); } // TODO: 1. test against VPN lockdown. diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java deleted file mode 100644 index ca2864c0b8..0000000000 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.cts.net.hostside; - -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; - -import static com.android.compatibility.common.util.SystemUtil.runShellCommand; -import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import android.app.ActivityManager; -import android.app.Instrumentation; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.wifi.WifiManager; -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; - -import com.android.compatibility.common.util.AppStandbyUtils; -import com.android.compatibility.common.util.BatteryUtils; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import androidx.test.platform.app.InstrumentationRegistry; - -public class NetworkPolicyTestUtils { - - private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 5000; - - private static ConnectivityManager mCm; - private static WifiManager mWm; - - private static Boolean mBatterySaverSupported; - private static Boolean mDataSaverSupported; - private static Boolean mDozeModeSupported; - private static Boolean mAppStandbySupported; - - private NetworkPolicyTestUtils() {} - - public static boolean isBatterySaverSupported() { - if (mBatterySaverSupported == null) { - mBatterySaverSupported = BatteryUtils.isBatterySaverSupported(); - } - return mBatterySaverSupported; - } - - /** - * As per CDD requirements, if the device doesn't support data saver mode then - * ConnectivityManager.getRestrictBackgroundStatus() will always return - * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if - * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns - * RESTRICT_BACKGROUND_STATUS_DISABLED or not. - */ - public static boolean isDataSaverSupported() { - if (mDataSaverSupported == null) { - assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - try { - setRestrictBackground(true); - mDataSaverSupported = !isMyRestrictBackgroundStatus( - RESTRICT_BACKGROUND_STATUS_DISABLED); - } finally { - setRestrictBackground(false); - } - } - return mDataSaverSupported; - } - - public static boolean isDozeModeSupported() { - if (mDozeModeSupported == null) { - final String result = executeShellCommand("cmd deviceidle enabled deep"); - mDozeModeSupported = result.equals("1"); - } - return mDozeModeSupported; - } - - public static boolean isAppStandbySupported() { - if (mAppStandbySupported == null) { - mAppStandbySupported = AppStandbyUtils.isAppStandbyEnabled(); - } - return mAppStandbySupported; - } - - public static boolean isLowRamDevice() { - final ActivityManager am = (ActivityManager) getContext().getSystemService( - Context.ACTIVITY_SERVICE); - return am.isLowRamDevice(); - } - - public static boolean isActiveNetworkMetered(boolean metered) { - return getConnectivityManager().isActiveNetworkMetered() == metered; - } - - public static boolean canChangeActiveNetworkMeteredness() { - final Network activeNetwork = getConnectivityManager().getActiveNetwork(); - final NetworkCapabilities networkCapabilities - = getConnectivityManager().getNetworkCapabilities(activeNetwork); - return networkCapabilities.hasTransport(TRANSPORT_WIFI); - } - - public static Pair setupMeteredNetwork(boolean metered) throws Exception { - if (isActiveNetworkMetered(metered)) { - return null; - } - final String ssid = unquoteSSID(getWifiManager().getConnectionInfo().getSSID()); - setWifiMeteredStatus(ssid, metered); - return Pair.create(ssid, !metered); - } - - public static void resetMeteredNetwork(String ssid, boolean metered) throws Exception { - setWifiMeteredStatus(ssid, metered); - } - - public static void setWifiMeteredStatus(String ssid, boolean metered) throws Exception { - assertFalse("SSID should not be empty", TextUtils.isEmpty(ssid)); - final String cmd = "cmd netpolicy set metered-network " + ssid + " " + metered; - executeShellCommand(cmd); - assertWifiMeteredStatus(ssid, metered); - assertActiveNetworkMetered(metered); - } - - public static void assertWifiMeteredStatus(String ssid, boolean expectedMeteredStatus) { - final String result = executeShellCommand("cmd netpolicy list wifi-networks"); - final String expectedLine = ssid + ";" + expectedMeteredStatus; - assertTrue("Expected line: " + expectedLine + "; Actual result: " + result, - result.contains(expectedLine)); - } - - // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java - public static void assertActiveNetworkMetered(boolean expectedMeteredStatus) throws Exception { - final CountDownLatch latch = new CountDownLatch(1); - final NetworkCallback networkCallback = new NetworkCallback() { - @Override - public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { - final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); - if (metered == expectedMeteredStatus) { - latch.countDown(); - } - } - }; - // Registering a callback here guarantees onCapabilitiesChanged is called immediately - // with the current setting. Therefore, if the setting has already been changed, - // this method will return right away, and if not it will wait for the setting to change. - getConnectivityManager().registerDefaultNetworkCallback(networkCallback); - if (!latch.await(TIMEOUT_CHANGE_METEREDNESS_MS, TimeUnit.MILLISECONDS)) { - fail("Timed out waiting for active network metered status to change to " - + expectedMeteredStatus + " ; network = " - + getConnectivityManager().getActiveNetwork()); - } - getConnectivityManager().unregisterNetworkCallback(networkCallback); - } - - public static void setRestrictBackground(boolean enabled) { - executeShellCommand("cmd netpolicy set restrict-background " + enabled); - final String output = executeShellCommand("cmd netpolicy get restrict-background"); - final String expectedSuffix = enabled ? "enabled" : "disabled"; - assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", - output.endsWith(expectedSuffix)); - } - - public static boolean isMyRestrictBackgroundStatus(int expectedStatus) { - final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); - if (expectedStatus != actualStatus) { - Log.d(TAG, "MyRestrictBackgroundStatus: " - + "Expected: " + restrictBackgroundValueToString(expectedStatus) - + "; Actual: " + restrictBackgroundValueToString(actualStatus)); - return false; - } - return true; - } - - // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java - private static String unquoteSSID(String ssid) { - // SSID is returned surrounded by quotes if it can be decoded as UTF-8. - // Otherwise it's guaranteed not to start with a quote. - if (ssid.charAt(0) == '"') { - return ssid.substring(1, ssid.length() - 1); - } else { - return ssid; - } - } - - public static String restrictBackgroundValueToString(int status) { - switch (status) { - case RESTRICT_BACKGROUND_STATUS_DISABLED: - return "DISABLED"; - case RESTRICT_BACKGROUND_STATUS_WHITELISTED: - return "WHITELISTED"; - case RESTRICT_BACKGROUND_STATUS_ENABLED: - return "ENABLED"; - default: - return "UNKNOWN_STATUS_" + status; - } - } - - public static String executeShellCommand(String command) { - final String result = runShellCommand(command).trim(); - Log.d(TAG, "Output of '" + command + "': '" + result + "'"); - return result; - } - - public static void assertMyRestrictBackgroundStatus(int expectedStatus) { - final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); - assertEquals(restrictBackgroundValueToString(expectedStatus), - restrictBackgroundValueToString(actualStatus)); - } - - public static ConnectivityManager getConnectivityManager() { - if (mCm == null) { - mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); - } - return mCm; - } - - public static WifiManager getWifiManager() { - if (mWm == null) { - mWm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - } - return mWm; - } - - public static Context getContext() { - return getInstrumentation().getContext(); - } - - public static Instrumentation getInstrumentation() { - return InstrumentationRegistry.getInstrumentation(); - } -} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java deleted file mode 100644 index 18805f9613..0000000000 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.cts.net.hostside; - -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDataSaverSupported; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isLowRamDevice; - -public enum Property { - BATTERY_SAVER_MODE(1 << 0) { - public boolean isSupported() { return isBatterySaverSupported(); } - }, - - DATA_SAVER_MODE(1 << 1) { - public boolean isSupported() { return isDataSaverSupported(); } - }, - - NO_DATA_SAVER_MODE(~DATA_SAVER_MODE.getValue()) { - public boolean isSupported() { return !isDataSaverSupported(); } - }, - - DOZE_MODE(1 << 2) { - public boolean isSupported() { return isDozeModeSupported(); } - }, - - APP_STANDBY_MODE(1 << 3) { - public boolean isSupported() { return isAppStandbySupported(); } - }, - - NOT_LOW_RAM_DEVICE(1 << 4) { - public boolean isSupported() { return !isLowRamDevice(); } - }, - - METERED_NETWORK(1 << 5) { - public boolean isSupported() { - return isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness(); - } - }, - - NON_METERED_NETWORK(~METERED_NETWORK.getValue()) { - public boolean isSupported() { - return isActiveNetworkMetered(false) || canChangeActiveNetworkMeteredness(); - } - }; - - private int mValue; - - Property(int value) { mValue = value; } - - public int getValue() { return mValue; } - - abstract boolean isSupported(); -} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java deleted file mode 100644 index 96838bba0a..0000000000 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.cts.net.hostside; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -@Retention(RUNTIME) -@Target({METHOD, TYPE}) -@Inherited -public @interface RequiredProperties { - Property[] value(); -} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java deleted file mode 100644 index 1e333200db..0000000000 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.cts.net.hostside; - -import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; - -import android.text.TextUtils; -import android.util.ArraySet; -import android.util.Log; - -import com.android.compatibility.common.util.BeforeAfterRule; - -import org.junit.Assume; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import java.util.ArrayList; -import java.util.Collections; - -public class RequiredPropertiesRule extends BeforeAfterRule { - - private static ArraySet mRequiredProperties; - - @Override - public void onBefore(Statement base, Description description) { - mRequiredProperties = getAllRequiredProperties(description); - - final String testName = description.getClassName() + "#" + description.getMethodName(); - assertTestIsValid(testName, mRequiredProperties); - Log.i(TAG, "Running test " + testName + " with required properties: " - + propertiesToString(mRequiredProperties)); - } - - private ArraySet getAllRequiredProperties(Description description) { - final ArraySet allRequiredProperties = new ArraySet<>(); - RequiredProperties requiredProperties = description.getAnnotation(RequiredProperties.class); - if (requiredProperties != null) { - Collections.addAll(allRequiredProperties, requiredProperties.value()); - } - - for (Class clazz = description.getTestClass(); - clazz != null; clazz = clazz.getSuperclass()) { - requiredProperties = clazz.getDeclaredAnnotation(RequiredProperties.class); - if (requiredProperties == null) { - continue; - } - for (Property requiredProperty : requiredProperties.value()) { - if (!allRequiredProperties.contains(~requiredProperty.getValue())) { - allRequiredProperties.add(requiredProperty); - } - } - } - return allRequiredProperties; - } - - private void assertTestIsValid(String testName, ArraySet requiredProperies) { - if (requiredProperies == null) { - return; - } - final ArrayList unsupportedProperties = new ArrayList<>(); - for (Property property : requiredProperies) { - if (!property.isSupported()) { - unsupportedProperties.add(property); - } - } - Assume.assumeTrue("Unsupported properties: " - + propertiesToString(unsupportedProperties), unsupportedProperties.isEmpty()); - } - - public static ArraySet getRequiredProperties() { - return mRequiredProperties; - } - - private static String propertiesToString(Iterable properties) { - return "[" + TextUtils.join(",", properties) + "]"; - } -} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java index 1312085478..8d6c4acd7d 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java @@ -29,14 +29,14 @@ public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase { uninstallPackage(TEST_APP2_PKG, true); } - public void testOnBlockedStatusChanged_dataSaver() throws Exception { + public void testOnBlockedStatusChanged_data_saver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_dataSaver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_data_saver"); } - public void testOnBlockedStatusChanged_powerSaver() throws Exception { + public void testOnBlockedStatusChanged_power_saver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_powerSaver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_power_saver"); } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index ce203795f9..a2443b391a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -79,8 +79,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void installPackage(String apk) throws FileNotFoundException, DeviceNotAvailableException { CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); - assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), - false /* reinstall */, true /* grantPermissions */)); + assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false)); } protected void uninstallPackage(String packageName, boolean shouldSucceed) From 6aac2067f63989e22cb95488da8a5ef7ac806737 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 22 Apr 2020 11:01:25 +0800 Subject: [PATCH 0994/1415] Check target transport type for meterness change When test case updates the wifi network from unmetered to metered, test case will wait for wifi network reconnect. However, if other metered networks are also connected at the same time, test case may mis-take the network as the target network. Thus, add transport type check to ensure the transport type of the network is the expected one. Bug: 153400606 Test: atest CtsNetTestCasesLatestSdk:\ android.net.cts.ConnectivityManagerTest#\ testGetMultipathPreference Change-Id: I75dab1a00bbe1a1c75b548a6ce4ae3eacd325d92 --- .../src/android/net/cts/ConnectivityManagerTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 3a52ee60a3..1ee08ffa7a 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -639,11 +639,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } - private void waitForActiveNetworkMetered(boolean requestedMeteredness) throws Exception { + private void waitForActiveNetworkMetered(int targetTransportType, boolean requestedMeteredness) + throws Exception { final CountDownLatch latch = new CountDownLatch(1); final NetworkCallback networkCallback = new NetworkCallback() { @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + if (!nc.hasTransport(targetTransportType)) return; + final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); if (metered == requestedMeteredness) { latch.countDown(); @@ -720,10 +723,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, Integer.toString(newMeteredPreference)); setWifiMeteredStatus(ssid, "true"); - waitForActiveNetworkMetered(true); + waitForActiveNetworkMetered(TRANSPORT_WIFI, true); // Wifi meterness changes from unmetered to metered will disconnect and reconnect since // R. - final Network network = mCm.getActiveNetwork(); + final Network network = ensureWifiConnected(); assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID())); assertEquals(mCm.getNetworkCapabilities(network).hasCapability( NET_CAPABILITY_NOT_METERED), false); @@ -741,7 +744,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { setWifiMeteredStatus(ssid, "false"); // No disconnect from unmetered to metered. - waitForActiveNetworkMetered(false); + waitForActiveNetworkMetered(TRANSPORT_WIFI, false); assertEquals(mCm.getNetworkCapabilities(network).hasCapability( NET_CAPABILITY_NOT_METERED), true); assertMultipathPreferenceIsEventually(network, newMeteredPreference, From 1136e51d551fe34b3675e40790c77d86bfbcfbbd Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 22 Apr 2020 07:45:16 +0000 Subject: [PATCH 0995/1415] Check target transport type for meterness change When test case updates the wifi network from unmetered to metered, test case will wait for wifi network reconnect. However, if other metered networks are also connected at the same time, test case may mis-take the network as the target network. Thus, add transport type check to ensure the transport type of the network is the expected one. Bug: 153400606 Test: atest CtsNetTestCasesLatestSdk:\ android.net.cts.ConnectivityManagerTest#\ testGetMultipathPreference Change-Id: I75dab1a00bbe1a1c75b548a6ce4ae3eacd325d92 Merged-In: I75dab1a00bbe1a1c75b548a6ce4ae3eacd325d92 (cherry picked from commit 495971d7b6abc65e6d506072038f499682f59f4d) --- .../src/android/net/cts/ConnectivityManagerTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 3a52ee60a3..1ee08ffa7a 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -639,11 +639,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } - private void waitForActiveNetworkMetered(boolean requestedMeteredness) throws Exception { + private void waitForActiveNetworkMetered(int targetTransportType, boolean requestedMeteredness) + throws Exception { final CountDownLatch latch = new CountDownLatch(1); final NetworkCallback networkCallback = new NetworkCallback() { @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + if (!nc.hasTransport(targetTransportType)) return; + final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); if (metered == requestedMeteredness) { latch.countDown(); @@ -720,10 +723,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, Integer.toString(newMeteredPreference)); setWifiMeteredStatus(ssid, "true"); - waitForActiveNetworkMetered(true); + waitForActiveNetworkMetered(TRANSPORT_WIFI, true); // Wifi meterness changes from unmetered to metered will disconnect and reconnect since // R. - final Network network = mCm.getActiveNetwork(); + final Network network = ensureWifiConnected(); assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID())); assertEquals(mCm.getNetworkCapabilities(network).hasCapability( NET_CAPABILITY_NOT_METERED), false); @@ -741,7 +744,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { setWifiMeteredStatus(ssid, "false"); // No disconnect from unmetered to metered. - waitForActiveNetworkMetered(false); + waitForActiveNetworkMetered(TRANSPORT_WIFI, false); assertEquals(mCm.getNetworkCapabilities(network).hasCapability( NET_CAPABILITY_NOT_METERED), true); assertMultipathPreferenceIsEventually(network, newMeteredPreference, From 7e514020b552ccd5f3ea9c71bd86ad8410649952 Mon Sep 17 00:00:00 2001 From: paulhu Date: Wed, 22 Apr 2020 10:24:19 +0800 Subject: [PATCH 0996/1415] Add TetheringCommonTests Bug: 153614365 Bug: 153613717 Test: atest TetheringTests TetheringCoverageTests Change-Id: If7c933ec0c72943312cd37bfc66918f10a5504a9 --- Tethering/tests/unit/Android.bp | 21 +++++++++++++++++++ .../android/net/TetheredClientTest.kt | 0 2 files changed, 21 insertions(+) rename Tethering/tests/unit/{src => common}/android/net/TetheredClientTest.kt (100%) diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp index 499ac0e188..9b7d68309f 100644 --- a/Tethering/tests/unit/Android.bp +++ b/Tethering/tests/unit/Android.bp @@ -14,6 +14,26 @@ // limitations under the License. // +// Tests in this folder are included both in unit tests and CTS. +java_library { + name: "TetheringCommonTests", + srcs: [ + "common/**/*.java", + "common/**/*.kt" + ], + static_libs: [ + "androidx.test.rules", + "net-tests-utils", + ], + // TODO(b/147200698) change sdk_version to module-current and remove framework-minus-apex + sdk_version: "core_platform", + libs: [ + "framework-minus-apex", + "framework-tethering", + ], + visibility: ["//cts/tests/tests/tethering"], +} + java_defaults { name: "TetheringTestsDefaults", srcs: [ @@ -22,6 +42,7 @@ java_defaults { ], static_libs: [ "TetheringApiCurrentLib", + "TetheringCommonTests", "androidx.test.rules", "frameworks-base-testutils", "mockito-target-extended-minus-junit4", diff --git a/Tethering/tests/unit/src/android/net/TetheredClientTest.kt b/Tethering/tests/unit/common/android/net/TetheredClientTest.kt similarity index 100% rename from Tethering/tests/unit/src/android/net/TetheredClientTest.kt rename to Tethering/tests/unit/common/android/net/TetheredClientTest.kt From 898156313733ec24f7b82f2977330d23134718c3 Mon Sep 17 00:00:00 2001 From: paulhu Date: Wed, 22 Apr 2020 11:32:32 +0800 Subject: [PATCH 0997/1415] Add TetheredClient tests Test APIs below: getAddresses() getMacAddress() getTetheringType() AddressInfo.getAddress() AddressInfo.getHostname() AddressInfo.writeToParcel(android.os.Parcel, int) Bug: 153614365 Bug: 153613717 Test: atest TetheringTests Change-Id: Ic7cbebe54a38af5b5c4639eb7641a20de6864a26 --- .../common/android/net/TetheredClientTest.kt | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Tethering/tests/unit/common/android/net/TetheredClientTest.kt b/Tethering/tests/unit/common/android/net/TetheredClientTest.kt index a20a0dfd9c..55c59dd08f 100644 --- a/Tethering/tests/unit/common/android/net/TetheredClientTest.kt +++ b/Tethering/tests/unit/common/android/net/TetheredClientTest.kt @@ -33,7 +33,9 @@ private val TEST_MACADDR = MacAddress.fromBytes(byteArrayOf(12, 23, 34, 45, 56, private val TEST_OTHER_MACADDR = MacAddress.fromBytes(byteArrayOf(23, 34, 45, 56, 67, 78)) private val TEST_ADDR1 = makeLinkAddress("192.168.113.3", prefixLength = 24, expTime = 123L) private val TEST_ADDR2 = makeLinkAddress("fe80::1:2:3", prefixLength = 64, expTime = 456L) -private val TEST_ADDRINFO1 = AddressInfo(TEST_ADDR1, "test_hostname") +private val TEST_HOSTNAME = "test_hostname" +private val TEST_OTHER_HOSTNAME = "test_other_hostname" +private val TEST_ADDRINFO1 = AddressInfo(TEST_ADDR1, TEST_HOSTNAME) private val TEST_ADDRINFO2 = AddressInfo(TEST_ADDR2, null) private fun makeLinkAddress(addr: String, prefixLength: Int, expTime: Long) = LinkAddress( @@ -49,6 +51,7 @@ private fun makeLinkAddress(addr: String, prefixLength: Int, expTime: Long) = Li class TetheredClientTest { @Test fun testParceling() { + assertParcelSane(TEST_ADDRINFO1, fieldCount = 2) assertParcelSane(makeTestClient(), fieldCount = 3) } @@ -65,7 +68,7 @@ class TetheredClientTest { // Different hostname assertNotEquals(makeTestClient(), TetheredClient( TEST_MACADDR, - listOf(AddressInfo(TEST_ADDR1, "test_other_hostname"), TEST_ADDRINFO2), + listOf(AddressInfo(TEST_ADDR1, TEST_OTHER_HOSTNAME), TEST_ADDRINFO2), TETHERING_BLUETOOTH)) // Null hostname @@ -97,6 +100,21 @@ class TetheredClientTest { TETHERING_USB), client1.addAddresses(client2)) } + @Test + fun testGetters() { + assertEquals(TEST_MACADDR, makeTestClient().macAddress) + assertEquals(listOf(TEST_ADDRINFO1, TEST_ADDRINFO2), makeTestClient().addresses) + assertEquals(TETHERING_BLUETOOTH, makeTestClient().tetheringType) + } + + @Test + fun testAddressInfo_Getters() { + assertEquals(TEST_ADDR1, TEST_ADDRINFO1.address) + assertEquals(TEST_ADDR2, TEST_ADDRINFO2.address) + assertEquals(TEST_HOSTNAME, TEST_ADDRINFO1.hostname) + assertEquals(null, TEST_ADDRINFO2.hostname) + } + private fun makeTestClient() = TetheredClient( TEST_MACADDR, listOf(TEST_ADDRINFO1, TEST_ADDRINFO2), From 6f63ef0e470914e87edfa379f93c83c4afab2f76 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 22 Apr 2020 22:15:09 +0800 Subject: [PATCH 0998/1415] Update logic for checking NetworkSpecifier We cannot test using WifiNetworkSpecifier, because the matching behaviour for null WifiNetworkSpecifier changed between Q and R. Replace WifiNetworkSpecifier with MatchAllNetworkSpecifier and TelephonyNetworkSpecifier that behave the same in both Q and R to verify. Bug: 154451660 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkRequestTest on aosp and internal build Change-Id: I14e2a5e629051e243f3b892b608cb1c6195cd8ed --- .../android/net/cts/NetworkRequestTest.java | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index 6a1d9de6f6..5e92b410f5 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -29,9 +29,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.net.MacAddress; +import android.net.MatchAllNetworkSpecifier; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.NetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiNetworkSpecifier; import android.os.Build; import android.os.Process; @@ -127,39 +129,54 @@ public class NetworkRequestTest { @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testCanBeSatisfiedBy() { - final WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() - .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL)) - .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + final TelephonyNetworkSpecifier specifier1 = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(1234 /* subId */) .build(); - final WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() - .setSsidPattern(new PatternMatcher(OTHER_SSID, PatternMatcher.PATTERN_LITERAL)) - .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + final TelephonyNetworkSpecifier specifier2 = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(5678 /* subId */) .build(); final NetworkCapabilities cap = new NetworkCapabilities() - .addTransportType(TRANSPORT_WIFI) - .addCapability(NET_CAPABILITY_INTERNET); - final NetworkCapabilities capWithSp = - new NetworkCapabilities(cap).setNetworkSpecifier(specifier1); - final NetworkCapabilities cellCap = new NetworkCapabilities() .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_MMS) .addCapability(NET_CAPABILITY_INTERNET); - final NetworkRequest request = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_WIFI) + final NetworkCapabilities capDualTransport = new NetworkCapabilities(cap) + .addTransportType(TRANSPORT_VPN); + final NetworkCapabilities capWithSpecifier1 = + new NetworkCapabilities(cap).setNetworkSpecifier(specifier1); + final NetworkCapabilities capDiffTransportWithSpecifier1 = new NetworkCapabilities() + .addCapability(NET_CAPABILITY_INTERNET) + .addTransportType(TRANSPORT_VPN) + .setNetworkSpecifier(specifier1); + + final NetworkRequest requestWithSpecifier1 = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_INTERNET) .setNetworkSpecifier(specifier1) .build(); - assertFalse(request.canBeSatisfiedBy(null)); - assertFalse(request.canBeSatisfiedBy(new NetworkCapabilities())); - assertTrue(request.canBeSatisfiedBy(cap)); - assertTrue(request.canBeSatisfiedBy( - new NetworkCapabilities(cap).addTransportType(TRANSPORT_VPN))); - assertTrue(request.canBeSatisfiedBy(capWithSp)); - assertFalse(request.canBeSatisfiedBy( + assertFalse(requestWithSpecifier1.canBeSatisfiedBy(null)); + assertFalse(requestWithSpecifier1.canBeSatisfiedBy(new NetworkCapabilities())); + assertTrue(requestWithSpecifier1.canBeSatisfiedBy(new NetworkCapabilities(cap) + .setNetworkSpecifier(new MatchAllNetworkSpecifier()))); + assertTrue(requestWithSpecifier1.canBeSatisfiedBy(cap)); + assertTrue(requestWithSpecifier1.canBeSatisfiedBy(capWithSpecifier1)); + assertTrue(requestWithSpecifier1.canBeSatisfiedBy(capDualTransport)); + assertFalse(requestWithSpecifier1.canBeSatisfiedBy( new NetworkCapabilities(cap).setNetworkSpecifier(specifier2))); - assertFalse(request.canBeSatisfiedBy(cellCap)); - assertEquals(request.canBeSatisfiedBy(capWithSp), - new NetworkCapabilities(capWithSp).satisfiedByNetworkCapabilities(capWithSp)); + + final NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + assertTrue(request.canBeSatisfiedBy(cap)); + assertTrue(request.canBeSatisfiedBy(capWithSpecifier1)); + assertTrue(request.canBeSatisfiedBy( + new NetworkCapabilities(cap).setNetworkSpecifier(specifier2))); + assertFalse(request.canBeSatisfiedBy(capDiffTransportWithSpecifier1)); + assertTrue(request.canBeSatisfiedBy(capDualTransport)); + + assertEquals(requestWithSpecifier1.canBeSatisfiedBy(capWithSpecifier1), + new NetworkCapabilities(capWithSpecifier1) + .satisfiedByNetworkCapabilities(capWithSpecifier1)); } @Test @IgnoreUpTo(Build.VERSION_CODES.Q) From 03142a0568e42eccd342311523fcfac4ef7e0887 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 20 Apr 2020 19:35:46 +0800 Subject: [PATCH 0999/1415] [TNU09] Adjust restricted notification 1. Let restricted notification that can be dismissed. 2. Only put up restricted notification when any of tethering is activating. Bug: 154214549 Test: atest TetheringTests Change-Id: Ib980aca154036828abdab35e3bb11d42f85ff610 --- .../networkstack/tethering/Tethering.java | 18 ++++--- .../TetheringNotificationUpdater.java | 12 ++--- .../networkstack/tethering/TetheringTest.java | 50 +++++++++---------- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 97b19466b3..44eacb410d 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -1006,6 +1006,11 @@ public class Tethering { } } + @VisibleForTesting + boolean isTetheringActive() { + return mActiveTetheringRequests.size() > 0; + } + @VisibleForTesting protected static class UserRestrictionActionListener { private final UserManager mUserManager; @@ -1043,13 +1048,14 @@ public class Tethering { return; } - // Restricted notification is shown when tethering function is disallowed on - // user's device. - mNotificationUpdater.notifyTetheringDisabledByRestriction(); - - // Untether from all downstreams since tethering is disallowed. - mWrapper.untetherAll(); + if (mWrapper.isTetheringActive()) { + // Restricted notification is shown when tethering function is disallowed on + // user's device. + mNotificationUpdater.notifyTetheringDisabledByRestriction(); + // Untether from all downstreams since tethering is disallowed. + mWrapper.untetherAll(); + } // TODO(b/148139325): send tetheringSupported on restriction change } } diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index 7fd6b61ccd..d03deda37f 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -267,7 +267,7 @@ public class TetheringNotificationUpdater { null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, - RESTRICTED_NOTIFICATION_ID, pi, new Action[0]); + RESTRICTED_NOTIFICATION_ID, false /* ongoing */, pi, new Action[0]); } private void notifyTetheringNoUpstream() { @@ -288,7 +288,7 @@ public class TetheringNotificationUpdater { final Action action = new Action.Builder(NO_ICON_ID, disableButton, pi).build(); showNotification(R.drawable.stat_sys_tether_general, title, message, - NO_UPSTREAM_NOTIFICATION_ID, null /* pendingIntent */, action); + NO_UPSTREAM_NOTIFICATION_ID, true /* ongoing */, null /* pendingIntent */, action); } private boolean setupRoamingNotification() { @@ -310,7 +310,7 @@ public class TetheringNotificationUpdater { null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, - ROAMING_NOTIFICATION_ID, pi, new Action[0]); + ROAMING_NOTIFICATION_ID, true /* ongoing */, pi, new Action[0]); return NOTIFY_DONE; } @@ -327,14 +327,14 @@ public class TetheringNotificationUpdater { } private void showNotification(@DrawableRes final int iconId, @NonNull final String title, - @NonNull final String message, @NotificationId final int id, @Nullable PendingIntent pi, - @NonNull final Action... actions) { + @NonNull final String message, @NotificationId final int id, final boolean ongoing, + @Nullable PendingIntent pi, @NonNull final Action... actions) { final Notification notification = new Notification.Builder(mContext, mChannel.getId()) .setSmallIcon(iconId) .setContentTitle(title) .setContentText(message) - .setOngoing(true) + .setOngoing(ongoing) .setColor(mContext.getColor( android.R.color.system_notification_accent_color)) .setVisibility(Notification.VISIBILITY_PUBLIC) diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 28bfae0ced..43946db847 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -1079,12 +1079,12 @@ public class TetheringTest { } private void runUserRestrictionsChange( - boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList, + boolean currentDisallow, boolean nextDisallow, boolean isTetheringActive, int expectedInteractionsWithShowNotification) throws Exception { final Bundle newRestrictions = new Bundle(); newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow); final Tethering mockTethering = mock(Tethering.class); - when(mockTethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList); + when(mockTethering.isTetheringActive()).thenReturn(isTetheringActive); when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions); final Tethering.UserRestrictionActionListener ural = @@ -1100,63 +1100,63 @@ public class TetheringTest { } @Test - public void testDisallowTetheringWhenNoTetheringInterfaceIsActive() throws Exception { - final String[] emptyActiveIfacesList = new String[]{}; + public void testDisallowTetheringWhenTetheringIsNotActive() throws Exception { + final boolean isTetheringActive = false; + final boolean currDisallow = false; + final boolean nextDisallow = true; + final int expectedInteractionsWithShowNotification = 0; + + runUserRestrictionsChange(currDisallow, nextDisallow, isTetheringActive, + expectedInteractionsWithShowNotification); + } + + @Test + public void testDisallowTetheringWhenTetheringIsActive() throws Exception { + final boolean isTetheringActive = true; final boolean currDisallow = false; final boolean nextDisallow = true; final int expectedInteractionsWithShowNotification = 1; - runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, isTetheringActive, expectedInteractionsWithShowNotification); } @Test - public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception { - final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME}; - final boolean currDisallow = false; - final boolean nextDisallow = true; - final int expectedInteractionsWithShowNotification = 1; - - runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, - expectedInteractionsWithShowNotification); - } - - @Test - public void testAllowTetheringWhenNoTetheringInterfaceIsActive() throws Exception { - final String[] nonEmptyActiveIfacesList = new String[]{}; + public void testAllowTetheringWhenTetheringIsNotActive() throws Exception { + final boolean isTetheringActive = false; final boolean currDisallow = true; final boolean nextDisallow = false; final int expectedInteractionsWithShowNotification = 0; - runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, isTetheringActive, expectedInteractionsWithShowNotification); } @Test - public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception { - final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME}; + public void testAllowTetheringWhenTetheringIsActive() throws Exception { + final boolean isTetheringActive = true; final boolean currDisallow = true; final boolean nextDisallow = false; final int expectedInteractionsWithShowNotification = 0; - runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, isTetheringActive, expectedInteractionsWithShowNotification); } @Test public void testDisallowTetheringUnchanged() throws Exception { - final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME}; + final boolean isTetheringActive = true; final int expectedInteractionsWithShowNotification = 0; boolean currDisallow = true; boolean nextDisallow = true; - runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, isTetheringActive, expectedInteractionsWithShowNotification); currDisallow = false; nextDisallow = false; - runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, isTetheringActive, expectedInteractionsWithShowNotification); } From afb99630b2eb9de44b864779c5e448052ede4027 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Wed, 22 Apr 2020 10:48:56 -0700 Subject: [PATCH 1000/1415] Import translations. DO NOT MERGE BUG:154701280 Change-Id: I835551e4708735d28e0316e6284f69a9eed45cd4 Auto-generated-cl: translation import --- Tethering/res/values-af/strings.xml | 2 -- Tethering/res/values-am/strings.xml | 2 -- Tethering/res/values-ar/strings.xml | 2 -- Tethering/res/values-as/strings.xml | 2 -- Tethering/res/values-az/strings.xml | 2 -- Tethering/res/values-b+sr+Latn/strings.xml | 2 -- Tethering/res/values-be/strings.xml | 2 -- Tethering/res/values-bg/strings.xml | 2 -- Tethering/res/values-bn/strings.xml | 2 -- Tethering/res/values-bs/strings.xml | 2 -- Tethering/res/values-ca/strings.xml | 2 -- Tethering/res/values-cs/strings.xml | 2 -- Tethering/res/values-da/strings.xml | 2 -- Tethering/res/values-de/strings.xml | 2 -- Tethering/res/values-el/strings.xml | 2 -- Tethering/res/values-en-rAU/strings.xml | 2 -- Tethering/res/values-en-rCA/strings.xml | 2 -- Tethering/res/values-en-rGB/strings.xml | 2 -- Tethering/res/values-en-rIN/strings.xml | 2 -- Tethering/res/values-en-rXC/strings.xml | 2 -- Tethering/res/values-es-rUS/strings.xml | 2 -- Tethering/res/values-es/strings.xml | 2 -- Tethering/res/values-et/strings.xml | 2 -- Tethering/res/values-eu/strings.xml | 6 ++---- Tethering/res/values-fa/strings.xml | 2 -- Tethering/res/values-fi/strings.xml | 2 -- Tethering/res/values-fr-rCA/strings.xml | 2 -- Tethering/res/values-fr/strings.xml | 2 -- Tethering/res/values-gl/strings.xml | 2 -- Tethering/res/values-gu/strings.xml | 2 -- Tethering/res/values-hi/strings.xml | 2 -- Tethering/res/values-hr/strings.xml | 2 -- Tethering/res/values-hu/strings.xml | 2 -- Tethering/res/values-hy/strings.xml | 2 -- Tethering/res/values-in/strings.xml | 2 -- Tethering/res/values-is/strings.xml | 2 -- Tethering/res/values-it/strings.xml | 2 -- Tethering/res/values-iw/strings.xml | 2 -- Tethering/res/values-ja/strings.xml | 2 -- Tethering/res/values-ka/strings.xml | 2 -- Tethering/res/values-kk/strings.xml | 2 -- Tethering/res/values-km/strings.xml | 2 -- Tethering/res/values-kn/strings.xml | 2 -- Tethering/res/values-ko/strings.xml | 2 -- Tethering/res/values-ky/strings.xml | 2 -- Tethering/res/values-lo/strings.xml | 2 -- Tethering/res/values-lt/strings.xml | 2 -- Tethering/res/values-lv/strings.xml | 2 -- Tethering/res/values-mcc310-mnc004-af/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-am/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ar/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-as/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-az/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-b+sr+Latn/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-be/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-bg/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-bn/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-bs/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ca/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-cs/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-da/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-de/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-el/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rAU/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rCA/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rGB/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rIN/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rXC/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-es-rUS/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-es/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-et/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-eu/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-fa/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-fi/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-fr-rCA/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-fr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-gl/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-gu/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-hi/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-hr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-hu/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-hy/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-in/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-is/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-it/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-iw/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ja/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ka/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-kk/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-km/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-kn/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ko/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ky/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-lo/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-lt/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-lv/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-mk/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ml/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-mn/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-mr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ms/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-my/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-nb/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 13 ++++++++----- Tethering/res/values-mcc310-mnc004-nl/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-or/strings.xml | 13 ++++++++----- Tethering/res/values-mcc310-mnc004-pa/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-pl/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-pt-rBR/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-pt-rPT/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-pt/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ro/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ru/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-si/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sk/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sl/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sq/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sv/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sw/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ta/strings.xml | 13 ++++++++----- Tethering/res/values-mcc310-mnc004-te/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-th/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-tl/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-tr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-uk/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ur/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-uz/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-vi/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rCN/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rHK/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rTW/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-zu/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-af/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-am/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ar/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-as/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-az/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-b+sr+Latn/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-be/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-bg/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-bn/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-bs/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ca/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-cs/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-da/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-de/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-el/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rAU/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rCA/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rGB/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rIN/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rXC/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-es-rUS/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-es/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-et/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-eu/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-fa/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-fi/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-fr-rCA/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-fr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-gl/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-gu/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-hi/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-hr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-hu/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-hy/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-in/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-is/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-it/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-iw/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ja/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ka/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-kk/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-km/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-kn/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ko/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ky/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-lo/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-lt/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-lv/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-mk/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ml/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-mn/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-mr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ms/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-my/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-nb/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 13 ++++++++----- Tethering/res/values-mcc311-mnc480-nl/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-or/strings.xml | 13 ++++++++----- Tethering/res/values-mcc311-mnc480-pa/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-pl/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-pt-rBR/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-pt-rPT/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-pt/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ro/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ru/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-si/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sk/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sl/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sq/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sv/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sw/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ta/strings.xml | 13 ++++++++----- Tethering/res/values-mcc311-mnc480-te/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-th/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-tl/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-tr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-uk/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ur/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-uz/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-vi/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rCN/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rHK/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rTW/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-zu/strings.xml | 9 ++++----- Tethering/res/values-mk/strings.xml | 2 -- Tethering/res/values-ml/strings.xml | 2 -- Tethering/res/values-mn/strings.xml | 2 -- Tethering/res/values-mr/strings.xml | 2 -- Tethering/res/values-ms/strings.xml | 2 -- Tethering/res/values-my/strings.xml | 2 -- Tethering/res/values-nb/strings.xml | 2 -- Tethering/res/values-ne/strings.xml | 2 -- Tethering/res/values-nl/strings.xml | 2 -- Tethering/res/values-or/strings.xml | 2 -- Tethering/res/values-pa/strings.xml | 2 -- Tethering/res/values-pl/strings.xml | 2 -- Tethering/res/values-pt-rBR/strings.xml | 2 -- Tethering/res/values-pt-rPT/strings.xml | 2 -- Tethering/res/values-pt/strings.xml | 2 -- Tethering/res/values-ro/strings.xml | 2 -- Tethering/res/values-ru/strings.xml | 2 -- Tethering/res/values-si/strings.xml | 2 -- Tethering/res/values-sk/strings.xml | 2 -- Tethering/res/values-sl/strings.xml | 2 -- Tethering/res/values-sq/strings.xml | 2 -- Tethering/res/values-sr/strings.xml | 2 -- Tethering/res/values-sv/strings.xml | 2 -- Tethering/res/values-sw/strings.xml | 2 -- Tethering/res/values-ta/strings.xml | 2 -- Tethering/res/values-te/strings.xml | 2 -- Tethering/res/values-th/strings.xml | 2 -- Tethering/res/values-tl/strings.xml | 2 -- Tethering/res/values-tr/strings.xml | 2 -- Tethering/res/values-uk/strings.xml | 2 -- Tethering/res/values-ur/strings.xml | 2 -- Tethering/res/values-uz/strings.xml | 2 -- Tethering/res/values-vi/strings.xml | 2 -- Tethering/res/values-zh-rCN/strings.xml | 2 -- Tethering/res/values-zh-rHK/strings.xml | 2 -- Tethering/res/values-zh-rTW/strings.xml | 2 -- Tethering/res/values-zu/strings.xml | 2 -- 255 files changed, 706 insertions(+), 1022 deletions(-) diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index f4c43b16a2..056168b12e 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Verbinding of warmkol is aktief" "Tik om op te stel." - "Verbinding is gedeaktiveer" "Kontak jou administrateur vir besonderhede" "Warmkol- en verbindingstatus" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 3a8de1200e..ac468dd144 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 355f59f096..7d5bad34da 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "النطاق نشط أو نقطة الاتصال نشطة" "انقر للإعداد." - "التوصيل متوقف." "تواصَل مع المشرف للحصول على التفاصيل." "حالة نقطة الاتصال والتوصيل" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index f44cec0be8..091350455b 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" "ছেট আপ কৰিবলৈ টিপক।" - "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index afd29dffbd..dce70da178 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Birləşmə və ya hotspot aktivdir" "Ayarlamaq üçün toxunun." - "Birləşmə deaktivdir" "Detallar üçün adminlə əlaqə saxlayın" "Hotspot & birləşmə statusu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 3ec6b75b34..b0774ec9a8 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Privezivanje ili hotspot je aktivan" "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" "Potražite detalje od administratora" "Status hotspota i privezivanja" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 577c1d7bdd..a8acebe2e9 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Мадэм або хот-спот актыўныя" "Дакраніцеся, каб наладзіць." - "Рэжым мадэма выключаны" "Звярніцеся да адміністратара па падрабязную інфармацыю" "Стан \"Хот-спот і мадэм\"" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index 9956a6191b..94fb2d8f17 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Има активна споделена връзка или точка за достъп" "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" "Свържете се с администратора си за подробности" "Състояние на функцията за точка за достъп и тетъринг" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 44d8dc6191..aea02b9ddf 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "টিথারিং বা হটস্পট চালু আছে" "সেট-আপ করতে ট্যাপ করুন।" - "টিথারিং বন্ধ করা আছে" "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" "হটস্পট ও টিথারিং স্ট্যাটাস" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index bf0395b7ea..de232724c5 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktivno je povezivanje putem mobitela ili pristupna tačka" "Dodirnite da postavite." - "Povezivanje putem mobitela je onemogućeno" "Kontaktirajte svog administratora za detalje" "Status pristupne tačke i povezivanja putem mobitela" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index cbc161a4e9..88b795c1f8 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Compartició de xarxa o punt d\'accés Wi‑Fi actius" "Toca per configurar." - "La compartició de xarxa està desactivada" "Contacta amb el teu administrador per obtenir més informació" "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5c21603987..8c1b83bf3e 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering nebo hotspot je aktivní" "Klepnutím zahájíte nastavení." - "Tethering je zakázán" "O podrobnosti požádejte administrátora" "Stav hotspotu a tetheringu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 741c7e2d79..f413e70548 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Netdeling eller hotspot er aktivt" "Tryk for at konfigurere." - "Netdeling er deaktiveret" "Kontakt din administrator for at få oplysninger" "Status for hotspot og netdeling" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 980a062674..f057d7824e 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering oder Hotspot aktiv" "Zum Einrichten tippen." - "Tethering ist deaktiviert" "Bitte wende dich für weitere Informationen an den Administrator" "Hotspot- und Tethering-Status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3d8ad1efef..b3c986bdaf 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 23866e0db1..f1674bed4e 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index 0bf6c4ed09..63689f4399 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión a red o hotspot conectados" "Presiona para configurar esta opción." - "Se inhabilitó la conexión mediante dispositivo portátil" "Para obtener más información, comunícate con el administrador" "Estado del hotspot y la conexión mediante dispositivo portátil" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 195868b5d0..9a34ed5e38 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión compartida o punto de acceso activos" "Toca para configurar." - "La conexión compartida está inhabilitada" "Solicita más información a tu administrador" "Estado del punto de acceso y de la conexión compartida" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index c4700a9638..0970341ab0 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Jagamine või kuumkoht on aktiivne" "Puudutage seadistamiseks." - "Jagamine on keelatud" "Lisateabe saamiseks võtke ühendust oma administraatoriga" "Kuumkoha ja jagamise olek" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index bcb92d96be..632019e2ef 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -16,16 +16,14 @@ - "Konexioa partekatzea edo sare publikoa aktibo" + "Konexioa partekatzea edo wifi-gunea aktibo dago" "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" - "Sare publikoaren eta konexioa partekatzeko eginbidearen egoera" + "Wifi-gunearen eta konexioa partekatzeko eginbidearen egoera" - diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index 51c3d731c0..2e21c85fa1 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" "برای جزئیات، با سرپرستتان تماس بگیرید" "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index 7a54e16157..413db3f0f8 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Yhteyden jakaminen tai hotspot käytössä" "Ota käyttöön napauttamalla." - "Yhteyden jakaminen on poistettu käytöstä" "Pyydä lisätietoja järjestelmänvalvojalta" "Hotspotin ja yhteyden jakamisen tila" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 556748f5f7..eb2e4ba540 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Partage de connexion ou point d\'accès sans fil activé" "Touchez pour configurer." - "Le partage de connexion est désactivé" "Communiquez avec votre administrateur pour obtenir plus de détails" "Point d\'accès et partage de connexion" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index 9fe55a2394..22259c52ab 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Partage de connexion ou point d\'accès activé" "Appuyez pour effectuer la configuration." - "Le partage de connexion est désactivé" "Pour en savoir plus, contactez votre administrateur" "État du point d\'accès et du partage de connexion" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 474371a128..ded82fcd54 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión compartida ou zona wifi activada" "Toca para configurar." - "A conexión compartida está desactivada" "Contacta co administrador para obter información" "Estado da zona wifi e da conexión compartida" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index cdb830a79a..7cbbc2de3d 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" "સેટઅપ કરવા માટે ટૅપ કરો." - "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index f9e157c9f5..08af81b826 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिंग या हॉटस्पॉट चालू है" "सेट अप करने के लिए टैप करें." - "टेदरिंग बंद है" "जानकारी के लिए अपने एडमिन से संपर्क करें" "हॉटस्पॉट और टेदरिंग की स्थिति" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index 9a99c6457c..827c135f20 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Modemsko povezivanje ili žarišna točka aktivni" "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" "Obratite se administratoru da biste saznali pojedinosti" "Status žarišne točke i modemskog povezivanja" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index f27c1c3e63..eb68d6babf 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Megosztás vagy aktív hotspot" "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" "A részletekért forduljon rendszergazdájához" "Hotspot és internetmegosztás állapota" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index b8b95ea5f9..912941e538 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Մոդեմի ռեժիմը միացված է" "Հպեք՝ կարգավորելու համար։" - "Մոդեմի ռեժիմն անջատված է" "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 24ead4eb3c..a4e175a439 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering atau hotspot aktif" "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" "Hubungi admin untuk mengetahui detailnya" "Status hotspot & tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index 839b0b96fc..e9f6670bcd 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kveikt á tjóðrun eða aðgangsstað" "Ýttu til að setja upp." - "Slökkt er á tjóðrun" "Hafðu samband við kerfisstjórann til að fá upplýsingar" "Staða heits reits og tjóðrunar" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index 31e2b73cf6..ffb9196f5e 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Hotspot o tethering attivo" "Tocca per impostare." - "Tethering disattivato" "Contatta il tuo amministratore per avere informazioni dettagliate" "Stato hotspot e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c97064b8d2..7adcb47350 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" "יש להקיש כדי להגדיר." - "שיתוף האינטרנט בין מכשירים מושבת" "לפרטים, יש לפנות למנהל המערכת" "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index c65f6e2f71..f68a73010b 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "テザリングまたはアクセス ポイントが有効です" "タップしてセットアップします。" - "テザリングは無効に設定されています" "詳しくは、管理者にお問い合わせください" "アクセス ポイントとテザリングのステータス" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 0dca3763f6..7c22e82bd3 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ტეტერინგი ან უსადენო ქსელი აქტიურია" "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" "უსადენო ქსელის და ტეტერინგის სტატუსი" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 9b4423536b..0857d06de2 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Тетеринг немесе хотспот қосулы" "Реттеу үшін түртіңіз." - "Тетеринг өшірілді." "Мәліметтерді әкімшіден алыңыз." "Хотспот және тетеринг күйі" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 7a6ab98d88..536e3d1703 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" "ចុច​ដើម្បី​រៀបចំ។" - "ការភ្ជាប់​ត្រូវបានបិទ" "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index 7c744b83e4..32f54926f4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index ecbddf5fdc..156b24786d 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "테더링 또는 핫스팟 사용" "설정하려면 탭하세요." - "테더링이 사용 중지됨" "자세한 정보는 관리자에게 문의하세요." "핫스팟 및 테더링 상태" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 7b9c0f5714..18ee5fd357 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем режими күйүп турат" "Жөндөө үчүн таптап коюңуз." - "Телефонду модем катары колдонууга болбойт" "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" "Байланыш түйүнүнүн жана модем режиминин статусу" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index d85b1bd096..b12767018c 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index 9a875932ff..8427baf39f 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" "Jei reikia išsamios informacijos, susisiekite su administratoriumi" "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index bb32ab41b1..aa2d6990e0 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Piesaiste vai tīklājs ir aktīvs." "Pieskarieties, lai to iestatītu." - "Piesaiste ir atspējota" "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." "Tīklāja un piesaistes statuss" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml index 8f16cd19ac..19d659c6ce 100644 --- a/Tethering/res/values-mcc310-mnc004-af/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -16,10 +16,9 @@ - "Warmkol het nie internet nie" - "Toestelle kan nie aan internet koppel nie" - "Skakel warmkol af" - "Warmkol is aan" + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" "Bykomende heffings kan geld terwyl jy swerf" - "Gaan voort" diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml index d064fd81d5..8995430b4f 100644 --- a/Tethering/res/values-mcc310-mnc004-am/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -16,10 +16,9 @@ - "መገናኛ ነጥቡ በይነመረብ የለውም" - "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" - "መገናኛ ነጥብ ያጥፉ" - "የመገናኛ ነጥብ በርቷል" + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" - "ቀጥል" diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml index f4b4c176e7..54f3b5389a 100644 --- a/Tethering/res/values-mcc310-mnc004-ar/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -16,10 +16,9 @@ - "نقطة الاتصال غير متصلة بالإنترنت." - "لا يمكن للأجهزة الاتصال بالإنترنت." - "إيقاف نقطة الاتصال" - "نقطة الاتصال مفعّلة" + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" "قد يتم تطبيق رسوم إضافية أثناء التجوال." - "متابعة" diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml index 5bcadfd7fc..e215141c9e 100644 --- a/Tethering/res/values-mcc310-mnc004-as/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" - "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" - "হটস্পট অফ কৰক" - "হটস্পট অন হৈ আছে" + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" - "অব্যাহত ৰাখক" diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml index 41c018eec1..1fd8e4c963 100644 --- a/Tethering/res/values-mcc310-mnc004-az/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -16,10 +16,9 @@ - "Hotspotun internetə girişi yoxdur" - "Cihazlar internetə qoşula bilmir" - "Hotspot\'u deaktiv edin" - "Hotspot aktivdir" + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" - "Davam edin" diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml index 8acc587975..1abe4f3aa3 100644 --- a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nema pristup internetu" - "Uređaji ne mogu da se povežu na internet" - "Isključi hotspot" - "Hotspot je uključen" + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" "Možda važe dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml index b03379a899..38dbd1e391 100644 --- a/Tethering/res/values-mcc310-mnc004-be/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -16,10 +16,9 @@ - "Хот-спот не падключаны да інтэрнэту" - "Прылады не могуць падключацца да інтэрнэту" - "Выключыць хот-спот" - "Хот-спот уключаны" + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" - "Працягнуць" diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml index 122bdb69c6..04b44db5c1 100644 --- a/Tethering/res/values-mcc310-mnc004-bg/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -16,10 +16,9 @@ - "Точката за достъп няма връзка с интернет" - "Устройствата не могат да се свържат с интернет" - "Изключване на точката за достъп" - "Точката за достъп е включена" + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" "Възможно е да ви бъдат начислени допълнителни такси при роуминг" - "Напред" diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml index 7a8d1e173e..579d1be1c1 100644 --- a/Tethering/res/values-mcc310-mnc004-bn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" - "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" - "হটস্পট বন্ধ করুন" - "হটস্পট চালু আছে" + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" - "চালিয়ে যান" diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml index a4ec581fe9..9ce3efe6c3 100644 --- a/Tethering/res/values-mcc310-mnc004-bs/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -16,10 +16,9 @@ - "Pristupna tačka nema internet" - "Uređaji se ne mogu povezati na internet" - "Isključi pristupnu tačku" - "Pristupna tačka je uključena" + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" "Mogu nastati dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml index 9c46426601..46d4c35b9b 100644 --- a/Tethering/res/values-mcc310-mnc004-ca/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -16,10 +16,9 @@ - "El punt d\'accés Wi‑Fi no té accés a Internet" - "Els dispositius no es poden connectar a Internet" - "Desactiva el punt d\'accés Wi‑Fi" - "El punt d\'accés Wi‑Fi està activat" + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" "És possible que s\'apliquin costos addicionals en itinerància" - "Continua" diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml index 66e4dfb3da..cc13860b3d 100644 --- a/Tethering/res/values-mcc310-mnc004-cs/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá připojení k internetu" - "Zařízení se nemohou připojit k internetu" - "Vypnout hotspot" - "Hotspot je aktivní" + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" "Při roamingu mohou být účtovány dodatečné poplatky" - "Pokračovat" diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml index 04a48a77c4..92c3ae1156 100644 --- a/Tethering/res/values-mcc310-mnc004-da/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -16,10 +16,9 @@ - "Hotspottet har intet internet" - "Enheder kan ikke oprette forbindelse til internettet" - "Deaktiver hotspot" - "Hotspottet er aktiveret" + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" "Der opkræves muligvis yderligere gebyrer ved roaming" - "Fortsæt" diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml index a9136784e9..967eb4db2e 100644 --- a/Tethering/res/values-mcc310-mnc004-de/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -16,10 +16,9 @@ - "Hotspot ist nicht mit dem Internet verbunden" - "Geräte können nicht mit dem Internet verbunden werden" - "Hotspot deaktivieren" - "Hotspot aktiviert" + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" "Für das Roaming können zusätzliche Gebühren anfallen" - "Weiter" diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml index 19be3c7077..5fb497451f 100644 --- a/Tethering/res/values-mcc310-mnc004-el/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -16,10 +16,9 @@ - "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." - "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." - "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" - "Σημείο πρόσβασης Wi-Fi ενεργό" + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." - "Συνέχεια" diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml index 6384e89ce0..7877074afc 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -16,10 +16,9 @@ - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎Turn off hotspot‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎Continue‎‏‎‎‏‎" diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml index 91368bf011..08edd81a6b 100644 --- a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -16,10 +16,9 @@ - "El hotspot no tiene conexión a Internet" - "Los dispositivos no pueden conectarse a Internet" - "Desactiva el hotspot" - "El hotspot está activado" + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" "Es posible que se apliquen cargos adicionales por roaming" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml index c717033145..79f51d00e2 100644 --- a/Tethering/res/values-mcc310-mnc004-es/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -16,10 +16,9 @@ - "El punto de acceso no tiene conexión a Internet" - "Los dispositivos no se pueden conectar a Internet" - "Desactivar punto de acceso" - "Punto de acceso activado" + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" "Puede que se apliquen cargos adicionales en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml index 271f82ad6a..2da5f8a6d6 100644 --- a/Tethering/res/values-mcc310-mnc004-et/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -16,10 +16,9 @@ - "Kuumkohal puudub Interneti-ühendus" - "Seadmed ei saa Internetiga ühendust luua" - "Lülita kuumkoht välja" - "Kuumkoht on sees" + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" "Rändluse kasutamisega võivad kaasneda lisatasud" - "Jätka" diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml index 09de71f8bc..2073f2806c 100644 --- a/Tethering/res/values-mcc310-mnc004-eu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -16,10 +16,9 @@ - "Sare publikoak ez du Interneteko konexiorik" - "Gailuak ezin dira konektatu Internetera" - "Desaktibatu sare publikoa" - "Sare publikoa aktibatuta dago" + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" - "Egin aurrera" diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml index b370e0fd81..e21b2a0852 100644 --- a/Tethering/res/values-mcc310-mnc004-fa/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -16,10 +16,9 @@ - "نقطه اتصال به اینترنت دسترسی ندارد" - "دستگاه‌ها به اینترنت متصل نشدند" - "نقطه اتصال را خاموش کنید" - "نقطه اتصال روشن است" + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" - "ادامه" diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml index da86391ee9..88b0b13eb4 100644 --- a/Tethering/res/values-mcc310-mnc004-fi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -16,10 +16,9 @@ - "Hotspotilla ei ole internetyhteyttä" - "Laitteet eivät voi yhdistää internetiin" - "Laita hotspot pois päältä" - "Hotspot on päällä" + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" "Roaming voi aiheuttaa lisämaksuja" - "Jatka" diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml index 6ffd8116e8..3b781bc8db 100644 --- a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml index 6ffd8116e8..51d7203c36 100644 --- a/Tethering/res/values-mcc310-mnc004-fr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml index 9e7f00cbe0..008ccb475d 100644 --- a/Tethering/res/values-mcc310-mnc004-gl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -16,10 +16,9 @@ - "A zona wifi non ten acceso a Internet" - "Os dispositivos non se poden conectar a Internet" - "Desactivar zona wifi" - "A zona wifi está activada" + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" "Pódense aplicar cargos adicionais en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml index 580f3c5cbf..f2e3b4df78 100644 --- a/Tethering/res/values-mcc310-mnc004-gu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -16,10 +16,9 @@ - "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" - "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" - "હૉટસ્પૉટ બંધ કરો" - "હૉટસ્પૉટ ચાલુ છે" + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" - "આગળ વધો" diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml index b6faa3a0f7..b11839d760 100644 --- a/Tethering/res/values-mcc310-mnc004-hi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉट से इंटरनेट नहीं चल रहा" - "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" - "हॉटस्पॉट बंद करें" - "हॉटस्पॉट चालू है" + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" - "जारी रखें" diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml index 86b58ded22..0a5aca25b1 100644 --- a/Tethering/res/values-mcc310-mnc004-hr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -16,10 +16,9 @@ - "Žarišna točka nema pristup internetu" - "Uređaji se ne mogu povezati s internetom" - "Isključi žarišnu točku" - "Žarišna je točka uključena" + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" "U roamingu su mogući dodatni troškovi" - "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml index 27ddabf29d..21c689a44e 100644 --- a/Tethering/res/values-mcc310-mnc004-hu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -16,10 +16,9 @@ - "A hotspot nem csatlakozik az internethez" - "Az eszközök nem tudnak csatlakozni az internethez" - "Hotspot kikapcsolása" - "A hotspot be van kapcsolva" + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" "Roaming során további díjak léphetnek fel" - "Tovább" diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml index abdb207626..689d92870e 100644 --- a/Tethering/res/values-mcc310-mnc004-hy/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -16,10 +16,9 @@ - "Թեժ կետը միացված չէ ինտերնետին" - "Սարքերը չեն կարողանում միանալ ինտերնետին" - "Անջատել թեժ կետը" - "Թեժ կետը միացված է" + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" - "Շարունակել" diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml index bef3fc59d3..a5f4d19abf 100644 --- a/Tethering/res/values-mcc310-mnc004-in/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -16,10 +16,9 @@ - "Hotspot tidak memiliki koneksi internet" - "Perangkat tidak dapat tersambung ke internet" - "Nonaktifkan hotspot" - "Hotspot aktif" + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" "Biaya tambahan mungkin berlaku saat roaming" - "Lanjutkan" diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml index f4e5dd4ad3..fc7e8aaf4e 100644 --- a/Tethering/res/values-mcc310-mnc004-is/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -16,10 +16,9 @@ - "Heitur reitur er ekki nettengdur" - "Tæki geta ekki tengst við internetið" - "Slökkva á heitum reit" - "Kveikt er á heitum reit" + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" "Viðbótargjöld kunna að eiga við í reiki" - "Halda áfram" diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml index cc5a6a5cda..6456dd1b80 100644 --- a/Tethering/res/values-mcc310-mnc004-it/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -16,10 +16,9 @@ - "L\'hotspot non ha accesso a Internet" - "I dispositivi non possono connettersi a Internet" - "Disattiva l\'hotspot" - "Hotspot attivo" + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" "Potrebbero essere applicati costi aggiuntivi durante il roaming" - "Continua" diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml index 0922ee9e4d..46b24bd3c5 100644 --- a/Tethering/res/values-mcc310-mnc004-iw/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -16,10 +16,9 @@ - "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" - "המכשירים לא יכולים להתחבר לאינטרנט" - "כיבוי הנקודה לשיתוף אינטרנט" - "הנקודה לשיתוף אינטרנט פועלת" + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" "ייתכנו חיובים נוספים בעת נדידה" - "המשך" diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml index 63ddc476e6..e6eb277b90 100644 --- a/Tethering/res/values-mcc310-mnc004-ja/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -16,10 +16,9 @@ - "アクセス ポイントがインターネットに接続されていません" - "デバイスをインターネットに接続できません" - "アクセス ポイントを OFF にする" - "アクセス ポイント: ON" + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" "ローミング時に追加料金が発生することがあります" - "続行" diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml index 4f20c76a12..aeddd7101d 100644 --- a/Tethering/res/values-mcc310-mnc004-ka/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -16,10 +16,9 @@ - "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" - "მოწყობილობები ვერ უკავშირდება ინტერნეტს" - "გამორთეთ უსადენო ქსელი" - "უსადენო ქსელი ჩართულია" + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" - "გაგრძელება" diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml index 11e293416b..255f0a276f 100644 --- a/Tethering/res/values-mcc310-mnc004-kk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -16,10 +16,9 @@ - "Хотспотта интернет жоқ" - "Құрылғылар интернетке қосылмайды" - "Хотспотты өшіру" - "Хотспот қосулы" + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" "Роуминг кезінде қосымша ақы алынуы мүмкін." - "Жалғастыру" diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml index b8d94d40a3..2bceb1cf77 100644 --- a/Tethering/res/values-mcc310-mnc004-km/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -16,10 +16,9 @@ - "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" - "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" - "បិទ​ហតស្ប៉ត" - "ហតស្ប៉ត​ត្រូវបានបើក" + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" - "បន្ត" diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml index 8044c9f5f6..ed769305a6 100644 --- a/Tethering/res/values-mcc310-mnc004-kn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -16,10 +16,9 @@ - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" - "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" - "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml index 59de04c55d..6e504941eb 100644 --- a/Tethering/res/values-mcc310-mnc004-ko/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -16,10 +16,9 @@ - "핫스팟이 인터넷에 연결되지 않음" - "기기를 인터넷에 연결할 수 없음" - "핫스팟 사용 중지" - "핫스팟 사용 중" + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" "로밍 중에는 추가 요금이 발생할 수 있습니다." - "계속" diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml index 860c3e41f1..d68128b9a5 100644 --- a/Tethering/res/values-mcc310-mnc004-ky/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -16,10 +16,9 @@ - "Байланыш түйүнүндө Интернет жок" - "Түзмөктөр Интернетке туташпай жатат" - "Туташуу түйүнүн өчүрүү" - "Кошулуу түйүнү күйүк" + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" "Роумингде кошумча акы алынышы мүмкүн" - "Улантуу" diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml index b6b8252164..03e134a0fc 100644 --- a/Tethering/res/values-mcc310-mnc004-lo/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -16,10 +16,9 @@ - "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" - "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" - "ປິດຮັອດສະປອດ" - "ຮັອດສະປອດເປີດຢູ່" + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" - "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml index aa15bfe1f5..652cedc6e6 100644 --- a/Tethering/res/values-mcc310-mnc004-lt/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -16,10 +16,9 @@ - "Nėra viešosios interneto prieigos taško interneto ryšio" - "Įrenginiams nepavyksta prisijungti prie interneto" - "Išjungti viešosios interneto prieigos tašką" - "Viešosios interneto prieigos taškas įjungtas" + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" - "Tęsti" diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml index 1e0d2f1c6f..221972298c 100644 --- a/Tethering/res/values-mcc310-mnc004-lv/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -16,10 +16,9 @@ - "Tīklājam nav interneta savienojuma" - "Ierīces nevar izveidot savienojumu ar internetu" - "Izslēgt tīklāju" - "Tīklājs ir ieslēgts" + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" "Viesabonēšanas laikā var tikt piemērota papildu samaksa" - "Tālāk" diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml index 5fe2a49af6..227f9e3466 100644 --- a/Tethering/res/values-mcc310-mnc004-mk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -16,10 +16,9 @@ - "Точката на пристап нема интернет" - "Уредите не може да се поврзат на интернет" - "Исклучи ја точката на пристап" - "Точката на пристап е вклучена" + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" "При роаминг може да се наплатат дополнителни трошоци" - "Продолжи" diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml index b8fdda0991..ec43885126 100644 --- a/Tethering/res/values-mcc310-mnc004-ml/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -16,10 +16,9 @@ - "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" - "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" - "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" - "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" - "തുടരുക" diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml index 462e73f7a4..e263573799 100644 --- a/Tethering/res/values-mcc310-mnc004-mn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -16,10 +16,9 @@ - "Сүлжээний цэг дээр интернэт алга байна" - "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" - "Сүлжээний цэгийг унтраах" - "Сүлжээний цэг асаалттай байна" + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" - "Үргэлжлүүлэх" diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml index b1d9b8505b..adf845d078 100644 --- a/Tethering/res/values-mcc310-mnc004-mr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉटला इंटरनेट नाही" - "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" - "हॉटस्पॉट बंद करा" - "हॉटस्पॉट सुरू आहे" + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" - "सुरू ठेवा" diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml index 936629ca14..f65c451e4c 100644 --- a/Tethering/res/values-mcc310-mnc004-ms/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -16,10 +16,9 @@ - "Tempat liputan tiada Internet" - "Peranti tidak dapat menyambung kepada Internet" - "Matikan tempat liputan" - "Tempat liputan dihidupkan" + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" "Caj tambahan mungkin digunakan semasa perayauan" - "Teruskan" diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml index 052df883eb..4118e775cd 100644 --- a/Tethering/res/values-mcc310-mnc004-my/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -16,10 +16,9 @@ - "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" - "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" - "ဟော့စပေါ့ ပိတ်ရန်" - "ဟော့စပေါ့ ဖွင့်ထားသည်" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" - "ရှေ့ဆက်ရန်" diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml index 09012cbfec..36853583ce 100644 --- a/Tethering/res/values-mcc310-mnc004-nb/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -16,10 +16,9 @@ - "Wi-Fi-sonen har ikke internettilgang" - "Enheter kan ikke koble til internett" - "Slå av Wi-Fi-sonen" - "Wi-Fi-sonen er på" + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" "Ytterligere kostnader kan påløpe under roaming" - "Fortsett" diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index 86c070500f..2a7330098f 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,10 +16,13 @@ - "हटस्पटमा इन्टरनेट छैन" - "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" - "हटस्पट निष्क्रिय पार्नुहोस्" - "हटस्पट सक्रिय छ" + + + + + + + + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" - "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml index 912290cb67..1d888942f4 100644 --- a/Tethering/res/values-mcc310-mnc004-nl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot heeft geen internet" - "Apparaten kunnen geen verbinding maken met internet" - "Hotspot uitschakelen" - "Hotspot is ingeschakeld" + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" "Er kunnen extra kosten voor roaming in rekening worden gebracht." - "Doorgaan" diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml index 5509a54b2f..919721d91c 100644 --- a/Tethering/res/values-mcc310-mnc004-or/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -16,10 +16,13 @@ - "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" - "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" - "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" - "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + + + + + + + + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" - "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml index 790fced58e..819833eab0 100644 --- a/Tethering/res/values-mcc310-mnc004-pa/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -16,10 +16,9 @@ - "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" - "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" - "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" - "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" - "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml index 51d5c3fd7e..65e4380e39 100644 --- a/Tethering/res/values-mcc310-mnc004-pl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nie ma internetu" - "Urządzenia nie mogą połączyć się z internetem" - "Wyłącz hotspot" - "Hotspot jest włączony" + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" - "Dalej" diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml index 6e605797d0..d8866170c1 100644 --- a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml index 79957977dc..bfd45ca0a3 100644 --- a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -16,10 +16,9 @@ - "A zona Wi-Fi não tem Internet" - "Não é possível ligar os dispositivos à Internet" - "Desativar zona Wi-Fi" - "A zona Wi-Fi está ativada" + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" "Podem aplicar-se custos adicionais em roaming." - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml index 6e605797d0..d8866170c1 100644 --- a/Tethering/res/values-mcc310-mnc004-pt/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml index 7be2f72195..8d87a9e516 100644 --- a/Tethering/res/values-mcc310-mnc004-ro/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -16,10 +16,9 @@ - "Hotspotul nu are internet" - "Dispozitivele nu se pot conecta la internet" - "Dezactivați hotspotul" - "Hotspotul este activ" + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" "Se pot aplica taxe suplimentare pentru roaming" - "Continuați" diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml index 1ff63cf967..dbdb9ebe49 100644 --- a/Tethering/res/values-mcc310-mnc004-ru/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -16,10 +16,9 @@ - "Точка доступа не подключена к Интернету" - "Устройства не могут подключаться к Интернету" - "Отключить точку доступа" - "Точка доступа включена" + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" "За использование услуг связи в роуминге может взиматься дополнительная плата." - "Продолжить" diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml index 357dd904ac..d8301e41c2 100644 --- a/Tethering/res/values-mcc310-mnc004-si/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -16,10 +16,9 @@ - "හොට්ස්පොට් හට අන්තර්ජාලය නැත" - "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" - "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" - "හොට්ස්පොට් ක්‍රියාත්මකයි" + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" - "ඉදිරියට යන්න" diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml index 276e5797ee..bef71363f4 100644 --- a/Tethering/res/values-mcc310-mnc004-sk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá internetové pripojenie" - "Zariadenia sa nedajú pripojiť k internetu" - "Vypnúť hotspot" - "Hotspot je zapnutý" + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" "Počas roamingu vám môžu byť účtované ďalšie poplatky" - "Pokračovať" diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml index 884bddd292..3202c62e8a 100644 --- a/Tethering/res/values-mcc310-mnc004-sl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -16,10 +16,9 @@ - "Dostopna točka nima internetne povezave" - "Naprave ne morejo vzpostaviti internetne povezave" - "Izklopi dostopno točko" - "Dostopna točka je vklopljena" + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" "Med gostovanjem lahko nastanejo dodatni stroški" - "Naprej" diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml index a2caddf667..37f6ad2868 100644 --- a/Tethering/res/values-mcc310-mnc004-sq/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -16,10 +16,9 @@ - "Zona e qasjes për internet nuk ka internet" - "Pajisjet nuk mund të lidhen me internetin" - "Çaktivizo zonën e qasjes për internet" - "Zona e qasjes për internet është aktive" + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" "Mund të zbatohen tarifime shtesë kur je në roaming" - "Vazhdo" diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml index 7745923331..5566d03ed1 100644 --- a/Tethering/res/values-mcc310-mnc004-sr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -16,10 +16,9 @@ - "Хотспот нема приступ интернету" - "Уређаји не могу да се повежу на интернет" - "Искључи хотспот" - "Хотспот је укључен" + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" "Можда важе додатни трошкови у ромингу" - "Настави" diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml index 906862aa17..9765acd0cf 100644 --- a/Tethering/res/values-mcc310-mnc004-sv/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -16,10 +16,9 @@ - "Surfzonen har ingen internetanslutning" - "Enheterna har ingen internetanslutning" - "Inaktivera surfzon" - "Surfzonen är aktiverad" + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" "Ytterligare avgifter kan tillkomma vid roaming" - "Fortsätt" diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml index 00e99bdf5f..cf850c9cd2 100644 --- a/Tethering/res/values-mcc310-mnc004-sw/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -16,10 +16,9 @@ - "Mtandao pepe hauna intaneti" - "Vifaa vimeshindwa kuunganisha kwenye intaneti" - "Zima mtandao pepe" - "Mtandao pepe umewashwa" + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" - "Endelea" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index 416d73f2d7..ea04821e33 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,10 +16,13 @@ - "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" - "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" - "ஹாட்ஸ்பாட்டை ஆஃப் செய்" - "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + + + + + + + + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" - "தொடர்க" diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml index 864f726b94..937d34d520 100644 --- a/Tethering/res/values-mcc310-mnc004-te/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -16,10 +16,9 @@ - "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" - "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" - "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" - "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" - "కొనసాగించు" diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml index 44114e5891..f781fae525 100644 --- a/Tethering/res/values-mcc310-mnc004-th/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -16,10 +16,9 @@ - "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" - "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" - "ปิดฮอตสปอต" - "ฮอตสปอตเปิดอยู่" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" - "ต่อไป" diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml index 440999014c..8d5d465373 100644 --- a/Tethering/res/values-mcc310-mnc004-tl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -16,10 +16,9 @@ - "Walang internet ang hotspot" - "Hindi makakonekta sa internet ang mga device" - "I-off ang hotspot" - "Naka-on ang hotspot" + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" - "Ituloy" diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml index d21ad95181..80cab33ac0 100644 --- a/Tethering/res/values-mcc310-mnc004-tr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -16,10 +16,9 @@ - "Hotspot\'un internet bağlantısı yok" - "Cihazlar internete bağlanamıyor" - "Hotspot\'u kapat" - "Hotspot açık" + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" "Dolaşım sırasında ek ücretler uygulanabilir" - "Devam" diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml index e7b8c68eb1..c05932a5ae 100644 --- a/Tethering/res/values-mcc310-mnc004-uk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -16,10 +16,9 @@ - "Точка доступу не підключена до Інтернету" - "Не вдається підключити пристрої до Інтернету" - "Вимкнути точку доступу" - "Точку доступу ввімкнено" + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" "У роумінгу може стягуватися додаткова плата" - "Продовжити" diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml index 08edfcffeb..d820eee8ba 100644 --- a/Tethering/res/values-mcc310-mnc004-ur/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -16,10 +16,9 @@ - "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" - "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" - "ہاٹ اسپاٹ آف کریں" - "ہاٹ اسپاٹ آن ہے" + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" - "جاری رکھیں" diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml index 167b41a7ed..726148aaee 100644 --- a/Tethering/res/values-mcc310-mnc004-uz/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -16,10 +16,9 @@ - "Hotspot internetga ulanmagan" - "Qurilmalar internetga ulana olmayapti" - "Hotspotni faolsizlantirish" - "Hotspot yoniq" + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" "Rouming vaqtida qoʻshimcha haq olinishi mumkin" - "Davom etish" diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml index e4f818bf42..b7cb0456b6 100644 --- a/Tethering/res/values-mcc310-mnc004-vi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -16,10 +16,9 @@ - "Điểm phát sóng không có kết nối Internet" - "Các thiết bị không thể kết nối Internet" - "Tắt điểm phát sóng" - "Điểm phát sóng đang bật" + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" - "Tiếp tục" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml index 570d793c44..af91afff9a 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -16,10 +16,9 @@ - "热点没有网络连接" - "设备无法连接到互联网" - "关闭热点" - "热点已开启" + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" "漫游时可能会产生额外的费用" - "继续" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml index 05321db9f2..28e6b80c01 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -16,10 +16,9 @@ - "熱點沒有互聯網連線" - "裝置無法連線至互聯網" - "關閉熱點" - "已開啟熱點" + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" "漫遊時可能需要支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml index 57b9e0de3b..05b90692ea 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -16,10 +16,9 @@ - "無線基地台沒有網際網路連線" - "裝置無法連上網際網路" - "關閉無線基地台" - "無線基地台已開啟" + "無法透過數據連線連上網際網路" + "裝置無法連線" + "關閉數據連線" + "無線基地台或數據連線已開啟" "使用漫遊服務可能須支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml index 7e899705af..11eb666219 100644 --- a/Tethering/res/values-mcc310-mnc004-zu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -16,10 +16,9 @@ - "I-Hotspot ayina-inthanethi" - "Amadivayisi awakwazi ukuxhuma ku-inthanethi" - "Vala i-hotspot" - "I-Hotspot ivuliwe" + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" "Kungaba nezinkokhelo ezengeziwe uma uzula" - "Qhubeka" diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml index 6fc432256a..9bfa5317a9 100644 --- a/Tethering/res/values-mcc311-mnc480-af/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -16,10 +16,9 @@ - "Warmkol het nie internet nie" - "Toestelle kan nie aan internet koppel nie" - "Skakel warmkol af" - "Warmkol is aan" + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" "Bykomende heffings kan geld terwyl jy swerf" - "Gaan voort" diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml index 749cb54022..5949dfa776 100644 --- a/Tethering/res/values-mcc311-mnc480-am/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -16,10 +16,9 @@ - "መገናኛ ነጥቡ በይነመረብ የለውም" - "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" - "መገናኛ ነጥብ ያጥፉ" - "የመገናኛ ነጥብ በርቷል" + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" - "ቀጥል" diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml index 15e5605d13..8467f9b1f5 100644 --- a/Tethering/res/values-mcc311-mnc480-ar/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -16,10 +16,9 @@ - "نقطة الاتصال غير متصلة بالإنترنت." - "لا يمكن للأجهزة الاتصال بالإنترنت." - "إيقاف نقطة الاتصال" - "نقطة الاتصال مفعّلة" + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" "قد يتم تطبيق رسوم إضافية أثناء التجوال." - "متابعة" diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml index e18e4ec67d..9776bd89da 100644 --- a/Tethering/res/values-mcc311-mnc480-as/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" - "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" - "হটস্পট অফ কৰক" - "হটস্পট অন হৈ আছে" + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" - "অব্যাহত ৰাখক" diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml index 77740cb6c6..e6d3eaf9f0 100644 --- a/Tethering/res/values-mcc311-mnc480-az/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -16,10 +16,9 @@ - "Hotspotun internetə girişi yoxdur" - "Cihazlar internetə qoşula bilmir" - "Hotspot\'u deaktiv edin" - "Hotspot aktivdir" + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" - "Davam edin" diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml index 7170c06662..4c8a1df8ee 100644 --- a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nema pristup internetu" - "Uređaji ne mogu da se povežu na internet" - "Isključi hotspot" - "Hotspot je uključen" + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" "Možda važe dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml index 7388d218fd..edfa41e1ff 100644 --- a/Tethering/res/values-mcc311-mnc480-be/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -16,10 +16,9 @@ - "Хот-спот не падключаны да інтэрнэту" - "Прылады не могуць падключацца да інтэрнэту" - "Выключыць хот-спот" - "Хот-спот уключаны" + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" - "Працягнуць" diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml index aa7a40bfa1..f56398196f 100644 --- a/Tethering/res/values-mcc311-mnc480-bg/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -16,10 +16,9 @@ - "Точката за достъп няма връзка с интернет" - "Устройствата не могат да се свържат с интернет" - "Изключване на точката за достъп" - "Точката за достъп е включена" + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" "Възможно е да ви бъдат начислени допълнителни такси при роуминг" - "Напред" diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml index 4058f719c9..d8ecd2e988 100644 --- a/Tethering/res/values-mcc311-mnc480-bn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" - "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" - "হটস্পট বন্ধ করুন" - "হটস্পট চালু আছে" + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" - "চালিয়ে যান" diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml index ccfb199cee..b85fd5e285 100644 --- a/Tethering/res/values-mcc311-mnc480-bs/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -16,10 +16,9 @@ - "Pristupna tačka nema internet" - "Uređaji se ne mogu povezati na internet" - "Isključi pristupnu tačku" - "Pristupna tačka je uključena" + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" "Mogu nastati dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml index 43c9e137bb..a3572151be 100644 --- a/Tethering/res/values-mcc311-mnc480-ca/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -16,10 +16,9 @@ - "El punt d\'accés Wi‑Fi no té accés a Internet" - "Els dispositius no es poden connectar a Internet" - "Desactiva el punt d\'accés Wi‑Fi" - "El punt d\'accés Wi‑Fi està activat" + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" "És possible que s\'apliquin costos addicionals en itinerància" - "Continua" diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml index c9210f7f40..91196be9e5 100644 --- a/Tethering/res/values-mcc311-mnc480-cs/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá připojení k internetu" - "Zařízení se nemohou připojit k internetu" - "Vypnout hotspot" - "Hotspot je aktivní" + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" "Při roamingu mohou být účtovány dodatečné poplatky" - "Pokračovat" diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml index 3615ff49ff..196890011d 100644 --- a/Tethering/res/values-mcc311-mnc480-da/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -16,10 +16,9 @@ - "Hotspottet har intet internet" - "Enheder kan ikke oprette forbindelse til internettet" - "Deaktiver hotspot" - "Hotspottet er aktiveret" + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" "Der opkræves muligvis yderligere gebyrer ved roaming" - "Fortsæt" diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml index ee8809d80b..eb3f8c52c0 100644 --- a/Tethering/res/values-mcc311-mnc480-de/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -16,10 +16,9 @@ - "Hotspot ist nicht mit dem Internet verbunden" - "Geräte können nicht mit dem Internet verbunden werden" - "Hotspot deaktivieren" - "Hotspot aktiviert" + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" "Für das Roaming können zusätzliche Gebühren anfallen" - "Weiter" diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml index 3a79be8735..56c3d81b63 100644 --- a/Tethering/res/values-mcc311-mnc480-el/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -16,10 +16,9 @@ - "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." - "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." - "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" - "Σημείο πρόσβασης Wi-Fi ενεργό" + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." - "Συνέχεια" diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml index 2daad6ad1c..d3347aae20 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -16,10 +16,9 @@ - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎Turn off hotspot‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml index 522fb5fc72..2f0504f07d 100644 --- a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -16,10 +16,9 @@ - "El hotspot no tiene conexión a Internet" - "Los dispositivos no pueden conectarse a Internet" - "Desactiva el hotspot" - "El hotspot está activado" + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" "Es posible que se apliquen cargos adicionales por roaming" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml index e2e30ee934..2d8f882425 100644 --- a/Tethering/res/values-mcc311-mnc480-es/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -16,10 +16,9 @@ - "El punto de acceso no tiene conexión a Internet" - "Los dispositivos no se pueden conectar a Internet" - "Desactivar punto de acceso" - "Punto de acceso activado" + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" "Puede que se apliquen cargos adicionales en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml index e59e12e71d..8493c47071 100644 --- a/Tethering/res/values-mcc311-mnc480-et/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -16,10 +16,9 @@ - "Kuumkohal puudub Interneti-ühendus" - "Seadmed ei saa Internetiga ühendust luua" - "Lülita kuumkoht välja" - "Kuumkoht on sees" + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" "Rändluse kasutamisega võivad kaasneda lisatasud" - "Jätka" diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml index 34c36bb056..33bccab3e8 100644 --- a/Tethering/res/values-mcc311-mnc480-eu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -16,10 +16,9 @@ - "Sare publikoak ez du Interneteko konexiorik" - "Gailuak ezin dira konektatu Internetera" - "Desaktibatu sare publikoa" - "Sare publikoa aktibatuta dago" + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" - "Egin aurrera" diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml index a2324d84f0..cf8a0cc277 100644 --- a/Tethering/res/values-mcc311-mnc480-fa/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -16,10 +16,9 @@ - "نقطه اتصال به اینترنت دسترسی ندارد" - "دستگاه‌ها به اینترنت متصل نشدند" - "نقطه اتصال را خاموش کنید" - "نقطه اتصال روشن است" + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" - "ادامه" diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml index ec6ac929fb..6a3ab806db 100644 --- a/Tethering/res/values-mcc311-mnc480-fi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -16,10 +16,9 @@ - "Hotspotilla ei ole internetyhteyttä" - "Laitteet eivät voi yhdistää internetiin" - "Laita hotspot pois päältä" - "Hotspot on päällä" + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" "Roaming voi aiheuttaa lisämaksuja" - "Jatka" diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml index eeaf8f3ad4..ffb9bf6047 100644 --- a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml index eeaf8f3ad4..768bce3f0a 100644 --- a/Tethering/res/values-mcc311-mnc480-fr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml index 56b3a9b79d..0c4195a7ca 100644 --- a/Tethering/res/values-mcc311-mnc480-gl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -16,10 +16,9 @@ - "A zona wifi non ten acceso a Internet" - "Os dispositivos non se poden conectar a Internet" - "Desactivar zona wifi" - "A zona wifi está activada" + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" "Pódense aplicar cargos adicionais en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml index 13f74ac93d..e9d33a7db2 100644 --- a/Tethering/res/values-mcc311-mnc480-gu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -16,10 +16,9 @@ - "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" - "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" - "હૉટસ્પૉટ બંધ કરો" - "હૉટસ્પૉટ ચાલુ છે" + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" - "આગળ વધો" diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml index 8bb5fb29ae..aa418ac5d3 100644 --- a/Tethering/res/values-mcc311-mnc480-hi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉट से इंटरनेट नहीं चल रहा" - "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" - "हॉटस्पॉट बंद करें" - "हॉटस्पॉट चालू है" + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" - "जारी रखें" diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml index 551b1b36fe..51c524afbc 100644 --- a/Tethering/res/values-mcc311-mnc480-hr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -16,10 +16,9 @@ - "Žarišna točka nema pristup internetu" - "Uređaji se ne mogu povezati s internetom" - "Isključi žarišnu točku" - "Žarišna je točka uključena" + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" "U roamingu su mogući dodatni troškovi" - "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml index 4113195c19..164e45edd1 100644 --- a/Tethering/res/values-mcc311-mnc480-hu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -16,10 +16,9 @@ - "A hotspot nem csatlakozik az internethez" - "Az eszközök nem tudnak csatlakozni az internethez" - "Hotspot kikapcsolása" - "A hotspot be van kapcsolva" + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" "Roaming során további díjak léphetnek fel" - "Tovább" diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml index 393eac056c..e76c0a4c80 100644 --- a/Tethering/res/values-mcc311-mnc480-hy/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -16,10 +16,9 @@ - "Թեժ կետը միացված չէ ինտերնետին" - "Սարքերը չեն կարողանում միանալ ինտերնետին" - "Անջատել թեժ կետը" - "Թեժ կետը միացված է" + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" - "Շարունակել" diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml index 16efe936ef..2b817f8abd 100644 --- a/Tethering/res/values-mcc311-mnc480-in/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -16,10 +16,9 @@ - "Hotspot tidak memiliki koneksi internet" - "Perangkat tidak dapat tersambung ke internet" - "Nonaktifkan hotspot" - "Hotspot aktif" + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" "Biaya tambahan mungkin berlaku saat roaming" - "Lanjutkan" diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml index d28383f51b..a338d9c7ca 100644 --- a/Tethering/res/values-mcc311-mnc480-is/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -16,10 +16,9 @@ - "Heitur reitur er ekki nettengdur" - "Tæki geta ekki tengst við internetið" - "Slökkva á heitum reit" - "Kveikt er á heitum reit" + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" "Viðbótargjöld kunna að eiga við í reiki" - "Halda áfram" diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml index 6ffa05bf93..77769c2ac5 100644 --- a/Tethering/res/values-mcc311-mnc480-it/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -16,10 +16,9 @@ - "L\'hotspot non ha accesso a Internet" - "I dispositivi non possono connettersi a Internet" - "Disattiva l\'hotspot" - "Hotspot attivo" + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" "Potrebbero essere applicati costi aggiuntivi durante il roaming" - "Continua" diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml index bbc379501c..5267b51264 100644 --- a/Tethering/res/values-mcc311-mnc480-iw/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -16,10 +16,9 @@ - "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" - "המכשירים לא יכולים להתחבר לאינטרנט" - "כיבוי הנקודה לשיתוף אינטרנט" - "הנקודה לשיתוף אינטרנט פועלת" + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" "ייתכנו חיובים נוספים בעת נדידה" - "המשך" diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml index d7cb66b1dd..66a9a6dd35 100644 --- a/Tethering/res/values-mcc311-mnc480-ja/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -16,10 +16,9 @@ - "アクセス ポイントがインターネットに接続されていません" - "デバイスをインターネットに接続できません" - "アクセス ポイントを OFF にする" - "アクセス ポイント: ON" + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" "ローミング時に追加料金が発生することがあります" - "続行" diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml index 9651a563bd..d8ad880849 100644 --- a/Tethering/res/values-mcc311-mnc480-ka/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -16,10 +16,9 @@ - "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" - "მოწყობილობები ვერ უკავშირდება ინტერნეტს" - "გამორთეთ უსადენო ქსელი" - "უსადენო ქსელი ჩართულია" + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" - "გაგრძელება" diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml index f2db66b11e..1ddd6b419b 100644 --- a/Tethering/res/values-mcc311-mnc480-kk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -16,10 +16,9 @@ - "Хотспотта интернет жоқ" - "Құрылғылар интернетке қосылмайды" - "Хотспотты өшіру" - "Хотспот қосулы" + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" "Роуминг кезінде қосымша ақы алынуы мүмкін." - "Жалғастыру" diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml index 16699c5a0a..cf5a1379cc 100644 --- a/Tethering/res/values-mcc311-mnc480-km/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -16,10 +16,9 @@ - "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" - "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" - "បិទ​ហតស្ប៉ត" - "ហតស្ប៉ត​ត្រូវបានបើក" + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" - "បន្ត" diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml index cc401b1775..68ae68bc19 100644 --- a/Tethering/res/values-mcc311-mnc480-kn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -16,10 +16,9 @@ - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" - "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" - "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml index 3892bc36a9..17185ba2d0 100644 --- a/Tethering/res/values-mcc311-mnc480-ko/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -16,10 +16,9 @@ - "핫스팟이 인터넷에 연결되지 않음" - "기기를 인터넷에 연결할 수 없음" - "핫스팟 사용 중지" - "핫스팟 사용 중" + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" "로밍 중에는 추가 요금이 발생할 수 있습니다." - "계속" diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml index cbae0056fe..6a9fb9810c 100644 --- a/Tethering/res/values-mcc311-mnc480-ky/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -16,10 +16,9 @@ - "Байланыш түйүнүндө Интернет жок" - "Түзмөктөр Интернетке туташпай жатат" - "Туташуу түйүнүн өчүрүү" - "Кошулуу түйүнү күйүк" + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" "Роумингде кошумча акы алынышы мүмкүн" - "Улантуу" diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml index 33b03f8690..bcc4b57626 100644 --- a/Tethering/res/values-mcc311-mnc480-lo/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -16,10 +16,9 @@ - "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" - "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" - "ປິດຮັອດສະປອດ" - "ຮັອດສະປອດເປີດຢູ່" + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" - "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml index 83aabd176f..011c2c11fb 100644 --- a/Tethering/res/values-mcc311-mnc480-lt/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -16,10 +16,9 @@ - "Nėra viešosios interneto prieigos taško interneto ryšio" - "Įrenginiams nepavyksta prisijungti prie interneto" - "Išjungti viešosios interneto prieigos tašką" - "Viešosios interneto prieigos taškas įjungtas" + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" - "Tęsti" diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml index 83feb11f8a..5cb2f3b7aa 100644 --- a/Tethering/res/values-mcc311-mnc480-lv/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -16,10 +16,9 @@ - "Tīklājam nav interneta savienojuma" - "Ierīces nevar izveidot savienojumu ar internetu" - "Izslēgt tīklāju" - "Tīklājs ir ieslēgts" + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" "Viesabonēšanas laikā var tikt piemērota papildu samaksa" - "Tālāk" diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml index 040e2a5d8e..4cbfd887c5 100644 --- a/Tethering/res/values-mcc311-mnc480-mk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -16,10 +16,9 @@ - "Точката на пристап нема интернет" - "Уредите не може да се поврзат на интернет" - "Исклучи ја точката на пристап" - "Точката на пристап е вклучена" + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" "При роаминг може да се наплатат дополнителни трошоци" - "Продолжи" diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml index 9e5336e46d..9cf4eaf34a 100644 --- a/Tethering/res/values-mcc311-mnc480-ml/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -16,10 +16,9 @@ - "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" - "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" - "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" - "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" - "തുടരുക" diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml index e5a845051d..47c82c14d9 100644 --- a/Tethering/res/values-mcc311-mnc480-mn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -16,10 +16,9 @@ - "Сүлжээний цэг дээр интернэт алга байна" - "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" - "Сүлжээний цэгийг унтраах" - "Сүлжээний цэг асаалттай байна" + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" - "Үргэлжлүүлэх" diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml index c7f1cc6c66..ad9e809ab2 100644 --- a/Tethering/res/values-mcc311-mnc480-mr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉटला इंटरनेट नाही" - "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" - "हॉटस्पॉट बंद करा" - "हॉटस्पॉट सुरू आहे" + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" - "सुरू ठेवा" diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml index 35d36f69f1..e708cb8717 100644 --- a/Tethering/res/values-mcc311-mnc480-ms/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -16,10 +16,9 @@ - "Tempat liputan tiada Internet" - "Peranti tidak dapat menyambung kepada Internet" - "Matikan tempat liputan" - "Tempat liputan dihidupkan" + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" "Caj tambahan mungkin digunakan semasa perayauan" - "Teruskan" diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml index bc374725ae..ba5462250b 100644 --- a/Tethering/res/values-mcc311-mnc480-my/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -16,10 +16,9 @@ - "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" - "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" - "ဟော့စပေါ့ ပိတ်ရန်" - "ဟော့စပေါ့ ဖွင့်ထားသည်" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" - "ရှေ့ဆက်ရန်" diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml index 413e165c0f..57db484a25 100644 --- a/Tethering/res/values-mcc311-mnc480-nb/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -16,10 +16,9 @@ - "Wi-Fi-sonen har ikke internettilgang" - "Enheter kan ikke koble til internett" - "Slå av Wi-Fi-sonen" - "Wi-Fi-sonen er på" + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" "Ytterligere kostnader kan påløpe under roaming" - "Fortsett" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 2d7cf4d316..617c50dd0c 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,10 +16,13 @@ - "हटस्पटमा इन्टरनेट छैन" - "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" - "हटस्पट निष्क्रिय पार्नुहोस्" - "हटस्पट सक्रिय छ" + + + + + + + + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" - "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml index 7f7f39187f..b08133f4e5 100644 --- a/Tethering/res/values-mcc311-mnc480-nl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot heeft geen internet" - "Apparaten kunnen geen verbinding maken met internet" - "Hotspot uitschakelen" - "Hotspot is ingeschakeld" + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" "Er kunnen extra kosten voor roaming in rekening worden gebracht." - "Doorgaan" diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml index e4c2458f44..4ea223cc2e 100644 --- a/Tethering/res/values-mcc311-mnc480-or/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -16,10 +16,13 @@ - "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" - "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" - "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" - "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + + + + + + + + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" - "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml index 642befbd64..88def563d8 100644 --- a/Tethering/res/values-mcc311-mnc480-pa/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -16,10 +16,9 @@ - "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" - "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" - "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" - "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" - "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml index c578b278d9..f9890abdc2 100644 --- a/Tethering/res/values-mcc311-mnc480-pl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nie ma internetu" - "Urządzenia nie mogą połączyć się z internetem" - "Wyłącz hotspot" - "Hotspot jest włączony" + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" - "Dalej" diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml index 502b5ddb7d..ce3b88479f 100644 --- a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml index a477516145..7e883ea576 100644 --- a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -16,10 +16,9 @@ - "A zona Wi-Fi não tem Internet" - "Não é possível ligar os dispositivos à Internet" - "Desativar zona Wi-Fi" - "A zona Wi-Fi está ativada" + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" "Podem aplicar-se custos adicionais em roaming." - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml index 502b5ddb7d..ce3b88479f 100644 --- a/Tethering/res/values-mcc311-mnc480-pt/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml index d6808b04e6..1009417316 100644 --- a/Tethering/res/values-mcc311-mnc480-ro/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -16,10 +16,9 @@ - "Hotspotul nu are internet" - "Dispozitivele nu se pot conecta la internet" - "Dezactivați hotspotul" - "Hotspotul este activ" + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" "Se pot aplica taxe suplimentare pentru roaming" - "Continuați" diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml index fb2caa9428..88683bed95 100644 --- a/Tethering/res/values-mcc311-mnc480-ru/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -16,10 +16,9 @@ - "Точка доступа не подключена к Интернету" - "Устройства не могут подключаться к Интернету" - "Отключить точку доступа" - "Точка доступа включена" + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" "За использование услуг связи в роуминге может взиматься дополнительная плата." - "Продолжить" diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml index 5008b7326c..176bcdb797 100644 --- a/Tethering/res/values-mcc311-mnc480-si/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -16,10 +16,9 @@ - "හොට්ස්පොට් හට අන්තර්ජාලය නැත" - "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" - "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" - "හොට්ස්පොට් ක්‍රියාත්මකයි" + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" - "ඉදිරියට යන්න" diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml index 010677d1d6..b9e2127fa8 100644 --- a/Tethering/res/values-mcc311-mnc480-sk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá internetové pripojenie" - "Zariadenia sa nedajú pripojiť k internetu" - "Vypnúť hotspot" - "Hotspot je zapnutý" + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" "Počas roamingu vám môžu byť účtované ďalšie poplatky" - "Pokračovať" diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml index 3662ca9e2a..e8140e686a 100644 --- a/Tethering/res/values-mcc311-mnc480-sl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -16,10 +16,9 @@ - "Dostopna točka nima internetne povezave" - "Naprave ne morejo vzpostaviti internetne povezave" - "Izklopi dostopno točko" - "Dostopna točka je vklopljena" + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" "Med gostovanjem lahko nastanejo dodatni stroški" - "Naprej" diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml index 5453d54fd9..61e698d6e8 100644 --- a/Tethering/res/values-mcc311-mnc480-sq/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -16,10 +16,9 @@ - "Zona e qasjes për internet nuk ka internet" - "Pajisjet nuk mund të lidhen me internetin" - "Çaktivizo zonën e qasjes për internet" - "Zona e qasjes për internet është aktive" + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" "Mund të zbatohen tarifime shtesë kur je në roaming" - "Vazhdo" diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml index f52cbf387e..b4c411c354 100644 --- a/Tethering/res/values-mcc311-mnc480-sr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -16,10 +16,9 @@ - "Хотспот нема приступ интернету" - "Уређаји не могу да се повежу на интернет" - "Искључи хотспот" - "Хотспот је укључен" + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" "Можда важе додатни трошкови у ромингу" - "Настави" diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml index 8474342f26..4f543e47b9 100644 --- a/Tethering/res/values-mcc311-mnc480-sv/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -16,10 +16,9 @@ - "Surfzonen har ingen internetanslutning" - "Enheterna har ingen internetanslutning" - "Inaktivera surfzon" - "Surfzonen är aktiverad" + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" "Ytterligare avgifter kan tillkomma vid roaming" - "Fortsätt" diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml index e3bb799a6b..ac347ab485 100644 --- a/Tethering/res/values-mcc311-mnc480-sw/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -16,10 +16,9 @@ - "Mtandao pepe hauna intaneti" - "Vifaa vimeshindwa kuunganisha kwenye intaneti" - "Zima mtandao pepe" - "Mtandao pepe umewashwa" + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" - "Endelea" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 4fa3f03e82..0e437593ee 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,10 +16,13 @@ - "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" - "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" - "ஹாட்ஸ்பாட்டை ஆஃப் செய்" - "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + + + + + + + + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" - "தொடர்க" diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml index 49d7687178..9360297dd8 100644 --- a/Tethering/res/values-mcc311-mnc480-te/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -16,10 +16,9 @@ - "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" - "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" - "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" - "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" - "కొనసాగించు" diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml index a26ac0403b..9c4d7e08f2 100644 --- a/Tethering/res/values-mcc311-mnc480-th/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -16,10 +16,9 @@ - "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" - "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" - "ปิดฮอตสปอต" - "ฮอตสปอตเปิดอยู่" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" - "ต่อไป" diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml index 6e98146cd5..a7c78a5932 100644 --- a/Tethering/res/values-mcc311-mnc480-tl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -16,10 +16,9 @@ - "Walang internet ang hotspot" - "Hindi makakonekta sa internet ang mga device" - "I-off ang hotspot" - "Naka-on ang hotspot" + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" - "Ituloy" diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml index 423bd76689..93da2c3f79 100644 --- a/Tethering/res/values-mcc311-mnc480-tr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -16,10 +16,9 @@ - "Hotspot\'un internet bağlantısı yok" - "Cihazlar internete bağlanamıyor" - "Hotspot\'u kapat" - "Hotspot açık" + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" "Dolaşım sırasında ek ücretler uygulanabilir" - "Devam" diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml index 193b3c348b..ee0dcd2c4b 100644 --- a/Tethering/res/values-mcc311-mnc480-uk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -16,10 +16,9 @@ - "Точка доступу не підключена до Інтернету" - "Не вдається підключити пристрої до Інтернету" - "Вимкнути точку доступу" - "Точку доступу ввімкнено" + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" "У роумінгу може стягуватися додаткова плата" - "Продовжити" diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml index 3564ead361..41cd28eef9 100644 --- a/Tethering/res/values-mcc311-mnc480-ur/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -16,10 +16,9 @@ - "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" - "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" - "ہاٹ اسپاٹ آف کریں" - "ہاٹ اسپاٹ آن ہے" + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" - "جاری رکھیں" diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml index c6bd803e3f..c847bc943b 100644 --- a/Tethering/res/values-mcc311-mnc480-uz/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -16,10 +16,9 @@ - "Hotspot internetga ulanmagan" - "Qurilmalar internetga ulana olmayapti" - "Hotspotni faolsizlantirish" - "Hotspot yoniq" + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" "Rouming vaqtida qoʻshimcha haq olinishi mumkin" - "Davom etish" diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml index 998ebe4d7b..a74326f09e 100644 --- a/Tethering/res/values-mcc311-mnc480-vi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -16,10 +16,9 @@ - "Điểm phát sóng không có kết nối Internet" - "Các thiết bị không thể kết nối Internet" - "Tắt điểm phát sóng" - "Điểm phát sóng đang bật" + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" - "Tiếp tục" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml index eae5865b0c..d7370036e3 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -16,10 +16,9 @@ - "热点没有网络连接" - "设备无法连接到互联网" - "关闭热点" - "热点已开启" + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" "漫游时可能会产生额外的费用" - "继续" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml index 7f7453c306..f378a9dc2c 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -16,10 +16,9 @@ - "熱點沒有互聯網連線" - "裝置無法連線至互聯網" - "關閉熱點" - "已開啟熱點" + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" "漫遊時可能需要支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml index 4b4afc017e..ea01b943fb 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -16,10 +16,9 @@ - "無線基地台沒有網際網路連線" - "裝置無法連上網際網路" - "關閉無線基地台" - "無線基地台已開啟" + "無法透過數據連線連上網際網路" + "裝置無法連線" + "關閉數據連線" + "無線基地台或數據連線已開啟" "使用漫遊服務可能須支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml index 48ac295ebc..32f6df56f1 100644 --- a/Tethering/res/values-mcc311-mnc480-zu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -16,10 +16,9 @@ - "I-Hotspot ayina-inthanethi" - "Amadivayisi awakwazi ukuxhuma ku-inthanethi" - "Vala i-hotspot" - "I-Hotspot ivuliwe" + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" "Kungaba nezinkokhelo ezengeziwe uma uzula" - "Qhubeka" diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 04f0fa8c71..9ad9b9a589 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Активно е врзување или точка на пристап" "Допрете за поставување." - "Врзувањето е оневозможено" "Контактирајте со администраторот за детали" "Статус на точката на пристап и врзувањето" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index 2d14f8e0f5..9db79ce220 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4f3334c8e3..42d1edbace 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" "Тохируулахын тулд товшино уу." - "Модем болгохыг идэвхгүй болгосон" "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" "Сүлжээний цэг болон модем болгох төлөв" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index ba9f324982..13995b6b8a 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद केले आहे" "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" "हॉटस्पॉट आणि टेदरिंगची स्थिती" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index c343e311f4..d6a67f37b1 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Penambatan atau tempat liputan aktif" "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" "Status tempat liputan & penambatan" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 84bcdb4c07..49f6b88a75 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 877c128c2d..9594e0a70a 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Internettdeling eller Wi-Fi-sone er aktiv" "Trykk for å konfigurere." - "Internettdeling er slått av" "Ta kontakt med administratoren din for å få mer informasjon" "Status for Wi-Fi-sone og internettdeling" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index d50fe240c4..72ae3a80a9 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिङ वा हटस्पट सक्रिय छ" "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङ सुविधा असक्षम पारिएको छ" "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" "हटस्पट तथा टेदरिङको स्थिति" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 6950c239ab..18b2bbfc76 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering of hotspot actief" "Tik om in te stellen." - "Tethering is uitgeschakeld" "Neem contact op met je beheerder voor meer informatie" "Status van hotspot en tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 2500a6f66b..a15a6db42a 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" - "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index 1fd496f968..a8235e423e 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index df1d5aeffa..ccb017d43f 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktywny tethering lub punkt dostępu" "Kliknij, by skonfigurować" - "Tethering został wyłączony" "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" "Hotspot i tethering – stan" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 2c3757d6de..a0a4745f93 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ponto de acesso ou tethering ativo" "Toque para configurar." - "Tethering desativado" "Fale com seu administrador para saber detalhes" "Status de ponto de acesso e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 5af2d22a57..e3f03fcc69 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." "Contacte o administrador para obter detalhes." "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 2c3757d6de..a0a4745f93 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ponto de acesso ou tethering ativo" "Toque para configurar." - "Tethering desativado" "Fale com seu administrador para saber detalhes" "Status de ponto de acesso e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index 1dad542d4f..5706a4a69c 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering sau hotspot activ" "Atingeți ca să configurați." - "Tetheringul este dezactivat" "Contactați administratorul pentru detalii" "Starea hotspotului și a tetheringului" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 4d31484229..7cb6f7db3f 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Включен режим модема или точка доступа" "Нажмите, чтобы настроить." - "Использование телефона в качестве модема запрещено" "Чтобы узнать подробности, обратитесь к администратору." "Статус хот-спота и режима модема" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index d21f2b5388..ec34c22de7 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index f2242b93b3..43e787c84f 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering alebo prístupový bod je aktívny" "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" "O podrobnosti požiadajte svojho správcu" "Stav hotspotu a tetheringu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index c01cace360..59433626a1 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" "Za podrobnosti se obrnite na skrbnika" "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index f7e2a7be74..21e11558bb 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ndarja e internetit ose zona e qasjes së internetit është aktive" "Trokit për ta konfiguruar." - "Ndarja e internetit është çaktivizuar" "Kontakto me administratorin për detaje" "Statusi i zonës së qasjes dhe ndarjes së internetit" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index c5f84eb45d..e2e4dc6361 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Привезивање или хотспот је активан" "Додирните да бисте подесили." - "Привезивање је онемогућено" "Потражите детаље од администратора" "Статус хотспота и привезивања" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index d745dad2ff..72702c2858 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Internetdelning eller surfzon har aktiverats" "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" "Kontakta administratören om du vill veta mer" "Trådlös surfzon och internetdelning har inaktiverats" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index beaa306374..65e4aa8ceb 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kusambaza mtandao au mtandaopepe umewashwa" "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" "Wasiliana na msimamizi wako ili upate maelezo zaidi" "Mtandaopepe na hali ya kusambaza mtandao" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index bc8957e096..4aba62d4ab 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" "அமைக்க, தட்டவும்." - "டெதெரிங் முடக்கப்பட்டுள்ளது" "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index b7afdb4cad..1f91791341 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" "సెటప్ చేయడానికి ట్యాప్ చేయండి." - "టెథరింగ్ డిజేబుల్ చేయబడింది" "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index e60d43496e..44171c0db8 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 79523bb0f4..7347dd3e62 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktibo ang pag-tether o hotspot" "I-tap para i-set up." - "Naka-disable ang pag-tether" "Makipag-ugnayan sa iyong admin para sa mga detalye" "Status ng hotspot at pag-tether" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index cf100a42e2..32030f1765 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering veya hotspot etkin" "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" "Ayrıntılı bilgi için yöneticinize başvurun" "Hotspot ve tethering durumu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 0a8ceddad7..1ca89b3f78 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем чи точка доступу активні" "Натисніть, щоб налаштувати." - "Використання телефона як модема вимкнено" "Щоб дізнатися більше, зв\'яжіться з адміністратором" "Статус точки доступу та модема" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 043dba3161..d72c7d4195 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ٹیدرنگ یا ہاٹ اسپاٹ فعال" "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 5b9d62afd9..af3b2ebb35 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Modem rejimi yoki hotspot yoniq" "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" "Tafsilotlari uchun administratoringizga murojaat qiling" "Hotspot va modem rejimi holati" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 156ab2d383..21a0735922 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" "Hãy nhấn để thiết lập." - "Đã tắt tính năng chia sẻ Internet" "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" "Trạng thái điểm phát sóng và chia sẻ Internet" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index d137df5f33..98e3b4b46f 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "网络共享或热点已启用" "点按即可设置。" - "网络共享已停用" "如需了解详情,请与您的管理员联系" "热点和网络共享状态" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 12c071091b..9cafd42dd4 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "網絡共享或熱點已啟用" "輕按即可設定。" - "網絡共享已停用" "請聯絡您的管理員以瞭解詳情" "熱點和網絡共享狀態" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 24fb76e824..9d738a76eb 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "數據連線或無線基地台已啟用" "輕觸即可進行設定。" - "數據連線已停用" "詳情請洽你的管理員" "無線基地台與數據連線狀態" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index f4859aa195..f210f8726e 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" "Xhumana nomphathi wakho ukuze uthole imininingwane" "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" @@ -27,5 +26,4 @@ - From 2b48e1941849c460e009eaf4a17c242977e4d37a Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Wed, 22 Apr 2020 12:03:48 -0700 Subject: [PATCH 1001/1415] Import translations. DO NOT MERGE Change-Id: I44c343149dc88a88c94327cdd6d5ac26ce7a6816 Auto-generated-cl: translation import --- Tethering/res/values-af/strings.xml | 2 -- Tethering/res/values-am/strings.xml | 2 -- Tethering/res/values-ar/strings.xml | 2 -- Tethering/res/values-as/strings.xml | 2 -- Tethering/res/values-az/strings.xml | 2 -- Tethering/res/values-b+sr+Latn/strings.xml | 2 -- Tethering/res/values-be/strings.xml | 2 -- Tethering/res/values-bg/strings.xml | 2 -- Tethering/res/values-bn/strings.xml | 2 -- Tethering/res/values-bs/strings.xml | 2 -- Tethering/res/values-ca/strings.xml | 2 -- Tethering/res/values-cs/strings.xml | 2 -- Tethering/res/values-da/strings.xml | 2 -- Tethering/res/values-de/strings.xml | 2 -- Tethering/res/values-el/strings.xml | 2 -- Tethering/res/values-en-rAU/strings.xml | 2 -- Tethering/res/values-en-rCA/strings.xml | 2 -- Tethering/res/values-en-rGB/strings.xml | 2 -- Tethering/res/values-en-rIN/strings.xml | 2 -- Tethering/res/values-en-rXC/strings.xml | 2 -- Tethering/res/values-es-rUS/strings.xml | 2 -- Tethering/res/values-es/strings.xml | 2 -- Tethering/res/values-et/strings.xml | 2 -- Tethering/res/values-eu/strings.xml | 6 ++---- Tethering/res/values-fa/strings.xml | 2 -- Tethering/res/values-fi/strings.xml | 2 -- Tethering/res/values-fr-rCA/strings.xml | 2 -- Tethering/res/values-fr/strings.xml | 2 -- Tethering/res/values-gl/strings.xml | 2 -- Tethering/res/values-gu/strings.xml | 2 -- Tethering/res/values-hi/strings.xml | 2 -- Tethering/res/values-hr/strings.xml | 2 -- Tethering/res/values-hu/strings.xml | 2 -- Tethering/res/values-hy/strings.xml | 2 -- Tethering/res/values-in/strings.xml | 2 -- Tethering/res/values-is/strings.xml | 2 -- Tethering/res/values-it/strings.xml | 2 -- Tethering/res/values-iw/strings.xml | 2 -- Tethering/res/values-ja/strings.xml | 2 -- Tethering/res/values-ka/strings.xml | 2 -- Tethering/res/values-kk/strings.xml | 2 -- Tethering/res/values-km/strings.xml | 2 -- Tethering/res/values-kn/strings.xml | 2 -- Tethering/res/values-ko/strings.xml | 2 -- Tethering/res/values-ky/strings.xml | 8 +++----- Tethering/res/values-lo/strings.xml | 2 -- Tethering/res/values-lt/strings.xml | 2 -- Tethering/res/values-lv/strings.xml | 2 -- .../res/values-mcc310-mnc004-af/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-am/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ar/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-as/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-az/strings.xml | 9 ++++----- .../values-mcc310-mnc004-b+sr+Latn/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-be/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-bg/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-bn/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-bs/strings.xml | 11 +++++------ .../res/values-mcc310-mnc004-ca/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-cs/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-da/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-de/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-el/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rAU/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rCA/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rGB/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rIN/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rXC/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-es-rUS/strings.xml | 11 +++++------ .../res/values-mcc310-mnc004-es/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-et/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-eu/strings.xml | 11 +++++------ .../res/values-mcc310-mnc004-fa/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-fi/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-fr-rCA/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-fr/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-gl/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-gu/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-hi/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-hr/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-hu/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-hy/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-in/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-is/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-it/strings.xml | 11 +++++------ .../res/values-mcc310-mnc004-iw/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ja/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ka/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-kk/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-km/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-kn/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-ko/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ky/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-lo/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-lt/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-lv/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-mk/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ml/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-mn/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-mr/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ms/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-my/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-nb/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ne/strings.xml | 12 +++++------- .../res/values-mcc310-mnc004-nl/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-or/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-pa/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-pl/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-pt-rBR/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-pt-rPT/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-pt/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ro/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ru/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-si/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-sk/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-sl/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-sq/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-sr/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-sv/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-sw/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ta/strings.xml | 12 +++++------- .../res/values-mcc310-mnc004-te/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-th/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-tl/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-tr/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-uk/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-ur/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-uz/strings.xml | 16 +++++----------- .../res/values-mcc310-mnc004-vi/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rCN/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rHK/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rTW/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zu/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-af/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-am/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ar/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-as/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-az/strings.xml | 9 ++++----- .../values-mcc311-mnc480-b+sr+Latn/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-be/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-bg/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-bn/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-bs/strings.xml | 11 +++++------ .../res/values-mcc311-mnc480-ca/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-cs/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-da/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-de/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-el/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rAU/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rCA/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rGB/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rIN/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rXC/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-es-rUS/strings.xml | 11 +++++------ .../res/values-mcc311-mnc480-es/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-et/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-eu/strings.xml | 11 +++++------ .../res/values-mcc311-mnc480-fa/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-fi/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-fr-rCA/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-fr/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-gl/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-gu/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-hi/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-hr/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-hu/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-hy/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-in/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-is/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-it/strings.xml | 11 +++++------ .../res/values-mcc311-mnc480-iw/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ja/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ka/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-kk/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-km/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-kn/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-ko/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ky/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-lo/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-lt/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-lv/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-mk/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ml/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-mn/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-mr/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ms/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-my/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-nb/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ne/strings.xml | 12 +++++------- .../res/values-mcc311-mnc480-nl/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-or/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-pa/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-pl/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-pt-rBR/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-pt-rPT/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-pt/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ro/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ru/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-si/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-sk/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-sl/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-sq/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-sr/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-sv/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-sw/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ta/strings.xml | 12 +++++------- .../res/values-mcc311-mnc480-te/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-th/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-tl/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-tr/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-uk/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-ur/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-uz/strings.xml | 16 +++++----------- .../res/values-mcc311-mnc480-vi/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rCN/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rHK/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rTW/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zu/strings.xml | 9 ++++----- Tethering/res/values-mk/strings.xml | 2 -- Tethering/res/values-ml/strings.xml | 2 -- Tethering/res/values-mn/strings.xml | 2 -- Tethering/res/values-mr/strings.xml | 2 -- Tethering/res/values-ms/strings.xml | 2 -- Tethering/res/values-my/strings.xml | 2 -- Tethering/res/values-nb/strings.xml | 2 -- Tethering/res/values-ne/strings.xml | 2 -- Tethering/res/values-nl/strings.xml | 2 -- Tethering/res/values-or/strings.xml | 2 -- Tethering/res/values-pa/strings.xml | 2 -- Tethering/res/values-pl/strings.xml | 2 -- Tethering/res/values-pt-rBR/strings.xml | 2 -- Tethering/res/values-pt-rPT/strings.xml | 2 -- Tethering/res/values-pt/strings.xml | 2 -- Tethering/res/values-ro/strings.xml | 2 -- Tethering/res/values-ru/strings.xml | 2 -- Tethering/res/values-si/strings.xml | 2 -- Tethering/res/values-sk/strings.xml | 2 -- Tethering/res/values-sl/strings.xml | 2 -- Tethering/res/values-sq/strings.xml | 2 -- Tethering/res/values-sr/strings.xml | 2 -- Tethering/res/values-sv/strings.xml | 2 -- Tethering/res/values-sw/strings.xml | 2 -- Tethering/res/values-ta/strings.xml | 2 -- Tethering/res/values-te/strings.xml | 2 -- Tethering/res/values-th/strings.xml | 2 -- Tethering/res/values-tl/strings.xml | 2 -- Tethering/res/values-tr/strings.xml | 2 -- Tethering/res/values-uk/strings.xml | 2 -- Tethering/res/values-ur/strings.xml | 2 -- Tethering/res/values-uz/strings.xml | 2 -- Tethering/res/values-vi/strings.xml | 8 +++----- Tethering/res/values-zh-rCN/strings.xml | 2 -- Tethering/res/values-zh-rHK/strings.xml | 2 -- Tethering/res/values-zh-rTW/strings.xml | 2 -- Tethering/res/values-zu/strings.xml | 2 -- 255 files changed, 720 insertions(+), 1164 deletions(-) diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index f4c43b16a2..056168b12e 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Verbinding of warmkol is aktief" "Tik om op te stel." - "Verbinding is gedeaktiveer" "Kontak jou administrateur vir besonderhede" "Warmkol- en verbindingstatus" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 3a8de1200e..ac468dd144 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 355f59f096..7d5bad34da 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "النطاق نشط أو نقطة الاتصال نشطة" "انقر للإعداد." - "التوصيل متوقف." "تواصَل مع المشرف للحصول على التفاصيل." "حالة نقطة الاتصال والتوصيل" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index f44cec0be8..091350455b 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" "ছেট আপ কৰিবলৈ টিপক।" - "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index afd29dffbd..dce70da178 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Birləşmə və ya hotspot aktivdir" "Ayarlamaq üçün toxunun." - "Birləşmə deaktivdir" "Detallar üçün adminlə əlaqə saxlayın" "Hotspot & birləşmə statusu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 3ec6b75b34..b0774ec9a8 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Privezivanje ili hotspot je aktivan" "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" "Potražite detalje od administratora" "Status hotspota i privezivanja" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 577c1d7bdd..a8acebe2e9 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Мадэм або хот-спот актыўныя" "Дакраніцеся, каб наладзіць." - "Рэжым мадэма выключаны" "Звярніцеся да адміністратара па падрабязную інфармацыю" "Стан \"Хот-спот і мадэм\"" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index 9956a6191b..94fb2d8f17 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Има активна споделена връзка или точка за достъп" "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" "Свържете се с администратора си за подробности" "Състояние на функцията за точка за достъп и тетъринг" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 44d8dc6191..aea02b9ddf 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "টিথারিং বা হটস্পট চালু আছে" "সেট-আপ করতে ট্যাপ করুন।" - "টিথারিং বন্ধ করা আছে" "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" "হটস্পট ও টিথারিং স্ট্যাটাস" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index bf0395b7ea..de232724c5 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktivno je povezivanje putem mobitela ili pristupna tačka" "Dodirnite da postavite." - "Povezivanje putem mobitela je onemogućeno" "Kontaktirajte svog administratora za detalje" "Status pristupne tačke i povezivanja putem mobitela" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index cbc161a4e9..88b795c1f8 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Compartició de xarxa o punt d\'accés Wi‑Fi actius" "Toca per configurar." - "La compartició de xarxa està desactivada" "Contacta amb el teu administrador per obtenir més informació" "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5c21603987..8c1b83bf3e 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering nebo hotspot je aktivní" "Klepnutím zahájíte nastavení." - "Tethering je zakázán" "O podrobnosti požádejte administrátora" "Stav hotspotu a tetheringu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 741c7e2d79..f413e70548 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Netdeling eller hotspot er aktivt" "Tryk for at konfigurere." - "Netdeling er deaktiveret" "Kontakt din administrator for at få oplysninger" "Status for hotspot og netdeling" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 980a062674..f057d7824e 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering oder Hotspot aktiv" "Zum Einrichten tippen." - "Tethering ist deaktiviert" "Bitte wende dich für weitere Informationen an den Administrator" "Hotspot- und Tethering-Status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3d8ad1efef..b3c986bdaf 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 23866e0db1..f1674bed4e 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index 0bf6c4ed09..63689f4399 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión a red o hotspot conectados" "Presiona para configurar esta opción." - "Se inhabilitó la conexión mediante dispositivo portátil" "Para obtener más información, comunícate con el administrador" "Estado del hotspot y la conexión mediante dispositivo portátil" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 195868b5d0..9a34ed5e38 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión compartida o punto de acceso activos" "Toca para configurar." - "La conexión compartida está inhabilitada" "Solicita más información a tu administrador" "Estado del punto de acceso y de la conexión compartida" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index c4700a9638..0970341ab0 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Jagamine või kuumkoht on aktiivne" "Puudutage seadistamiseks." - "Jagamine on keelatud" "Lisateabe saamiseks võtke ühendust oma administraatoriga" "Kuumkoha ja jagamise olek" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index bcb92d96be..632019e2ef 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -16,16 +16,14 @@ - "Konexioa partekatzea edo sare publikoa aktibo" + "Konexioa partekatzea edo wifi-gunea aktibo dago" "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" - "Sare publikoaren eta konexioa partekatzeko eginbidearen egoera" + "Wifi-gunearen eta konexioa partekatzeko eginbidearen egoera" - diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index 51c3d731c0..2e21c85fa1 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" "برای جزئیات، با سرپرستتان تماس بگیرید" "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index 7a54e16157..413db3f0f8 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Yhteyden jakaminen tai hotspot käytössä" "Ota käyttöön napauttamalla." - "Yhteyden jakaminen on poistettu käytöstä" "Pyydä lisätietoja järjestelmänvalvojalta" "Hotspotin ja yhteyden jakamisen tila" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 556748f5f7..eb2e4ba540 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Partage de connexion ou point d\'accès sans fil activé" "Touchez pour configurer." - "Le partage de connexion est désactivé" "Communiquez avec votre administrateur pour obtenir plus de détails" "Point d\'accès et partage de connexion" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index 9fe55a2394..22259c52ab 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Partage de connexion ou point d\'accès activé" "Appuyez pour effectuer la configuration." - "Le partage de connexion est désactivé" "Pour en savoir plus, contactez votre administrateur" "État du point d\'accès et du partage de connexion" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 474371a128..ded82fcd54 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión compartida ou zona wifi activada" "Toca para configurar." - "A conexión compartida está desactivada" "Contacta co administrador para obter información" "Estado da zona wifi e da conexión compartida" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index cdb830a79a..7cbbc2de3d 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" "સેટઅપ કરવા માટે ટૅપ કરો." - "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index f9e157c9f5..08af81b826 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिंग या हॉटस्पॉट चालू है" "सेट अप करने के लिए टैप करें." - "टेदरिंग बंद है" "जानकारी के लिए अपने एडमिन से संपर्क करें" "हॉटस्पॉट और टेदरिंग की स्थिति" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index 9a99c6457c..827c135f20 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Modemsko povezivanje ili žarišna točka aktivni" "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" "Obratite se administratoru da biste saznali pojedinosti" "Status žarišne točke i modemskog povezivanja" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index f27c1c3e63..eb68d6babf 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Megosztás vagy aktív hotspot" "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" "A részletekért forduljon rendszergazdájához" "Hotspot és internetmegosztás állapota" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index b8b95ea5f9..912941e538 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Մոդեմի ռեժիմը միացված է" "Հպեք՝ կարգավորելու համար։" - "Մոդեմի ռեժիմն անջատված է" "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 24ead4eb3c..a4e175a439 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering atau hotspot aktif" "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" "Hubungi admin untuk mengetahui detailnya" "Status hotspot & tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index 839b0b96fc..e9f6670bcd 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kveikt á tjóðrun eða aðgangsstað" "Ýttu til að setja upp." - "Slökkt er á tjóðrun" "Hafðu samband við kerfisstjórann til að fá upplýsingar" "Staða heits reits og tjóðrunar" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index 31e2b73cf6..ffb9196f5e 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Hotspot o tethering attivo" "Tocca per impostare." - "Tethering disattivato" "Contatta il tuo amministratore per avere informazioni dettagliate" "Stato hotspot e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c97064b8d2..7adcb47350 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" "יש להקיש כדי להגדיר." - "שיתוף האינטרנט בין מכשירים מושבת" "לפרטים, יש לפנות למנהל המערכת" "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index c65f6e2f71..f68a73010b 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "テザリングまたはアクセス ポイントが有効です" "タップしてセットアップします。" - "テザリングは無効に設定されています" "詳しくは、管理者にお問い合わせください" "アクセス ポイントとテザリングのステータス" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 0dca3763f6..7c22e82bd3 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ტეტერინგი ან უსადენო ქსელი აქტიურია" "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" "უსადენო ქსელის და ტეტერინგის სტატუსი" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 9b4423536b..0857d06de2 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Тетеринг немесе хотспот қосулы" "Реттеу үшін түртіңіз." - "Тетеринг өшірілді." "Мәліметтерді әкімшіден алыңыз." "Хотспот және тетеринг күйі" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 7a6ab98d88..536e3d1703 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" "ចុច​ដើម្បី​រៀបចំ។" - "ការភ្ជាប់​ត្រូវបានបិទ" "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index 7c744b83e4..32f54926f4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index ecbddf5fdc..156b24786d 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "테더링 또는 핫스팟 사용" "설정하려면 탭하세요." - "테더링이 사용 중지됨" "자세한 정보는 관리자에게 문의하세요." "핫스팟 및 테더링 상태" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index f763bf3ff0..18ee5fd357 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -16,16 +16,14 @@ - "Жалгаштыруу же хотспот жандырылган" + "Модем режими күйүп турат" "Жөндөө үчүн таптап коюңуз." - - "Жалгаштыруу функциясы өчүрүлгөн" + "Телефонду модем катары колдонууга болбойт" "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" - "Хотспот жана байланыш түйүнүүн статусу" + "Байланыш түйүнүнүн жана модем режиминин статусу" - diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index d85b1bd096..b12767018c 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index 9a875932ff..8427baf39f 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" "Jei reikia išsamios informacijos, susisiekite su administratoriumi" "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index bb32ab41b1..aa2d6990e0 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Piesaiste vai tīklājs ir aktīvs." "Pieskarieties, lai to iestatītu." - "Piesaiste ir atspējota" "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." "Tīklāja un piesaistes statuss" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml index 8f16cd19ac..19d659c6ce 100644 --- a/Tethering/res/values-mcc310-mnc004-af/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -16,10 +16,9 @@ - "Warmkol het nie internet nie" - "Toestelle kan nie aan internet koppel nie" - "Skakel warmkol af" - "Warmkol is aan" + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" "Bykomende heffings kan geld terwyl jy swerf" - "Gaan voort" diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml index d064fd81d5..8995430b4f 100644 --- a/Tethering/res/values-mcc310-mnc004-am/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -16,10 +16,9 @@ - "መገናኛ ነጥቡ በይነመረብ የለውም" - "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" - "መገናኛ ነጥብ ያጥፉ" - "የመገናኛ ነጥብ በርቷል" + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" - "ቀጥል" diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml index e5e7e5e03d..54f3b5389a 100644 --- a/Tethering/res/values-mcc310-mnc004-ar/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "متابعة" + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml index 5bcadfd7fc..e215141c9e 100644 --- a/Tethering/res/values-mcc310-mnc004-as/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" - "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" - "হটস্পট অফ কৰক" - "হটস্পট অন হৈ আছে" + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" - "অব্যাহত ৰাখক" diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml index 41c018eec1..1fd8e4c963 100644 --- a/Tethering/res/values-mcc310-mnc004-az/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -16,10 +16,9 @@ - "Hotspotun internetə girişi yoxdur" - "Cihazlar internetə qoşula bilmir" - "Hotspot\'u deaktiv edin" - "Hotspot aktivdir" + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" - "Davam edin" diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml index 8acc587975..1abe4f3aa3 100644 --- a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nema pristup internetu" - "Uređaji ne mogu da se povežu na internet" - "Isključi hotspot" - "Hotspot je uključen" + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" "Možda važe dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml index b03379a899..38dbd1e391 100644 --- a/Tethering/res/values-mcc310-mnc004-be/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -16,10 +16,9 @@ - "Хот-спот не падключаны да інтэрнэту" - "Прылады не могуць падключацца да інтэрнэту" - "Выключыць хот-спот" - "Хот-спот уключаны" + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" - "Працягнуць" diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml index 122bdb69c6..04b44db5c1 100644 --- a/Tethering/res/values-mcc310-mnc004-bg/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -16,10 +16,9 @@ - "Точката за достъп няма връзка с интернет" - "Устройствата не могат да се свържат с интернет" - "Изключване на точката за достъп" - "Точката за достъп е включена" + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" "Възможно е да ви бъдат начислени допълнителни такси при роуминг" - "Напред" diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml index d5ee1a91ce..579d1be1c1 100644 --- a/Tethering/res/values-mcc310-mnc004-bn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "চালিয়ে যান" + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml index ae86e0aa8e..9ce3efe6c3 100644 --- a/Tethering/res/values-mcc310-mnc004-bs/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -16,10 +16,9 @@ - "Pristupna tačka nema internet" - "Uređaji se ne mogu povezati na internet" - "Isključi pristupnu tačku" - "Pristupna tačka je uključena" - "Primjenjuju se dodatne tarife u romingu" - "Nastavi" + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml index 9c46426601..46d4c35b9b 100644 --- a/Tethering/res/values-mcc310-mnc004-ca/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -16,10 +16,9 @@ - "El punt d\'accés Wi‑Fi no té accés a Internet" - "Els dispositius no es poden connectar a Internet" - "Desactiva el punt d\'accés Wi‑Fi" - "El punt d\'accés Wi‑Fi està activat" + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" "És possible que s\'apliquin costos addicionals en itinerància" - "Continua" diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml index 66e4dfb3da..cc13860b3d 100644 --- a/Tethering/res/values-mcc310-mnc004-cs/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá připojení k internetu" - "Zařízení se nemohou připojit k internetu" - "Vypnout hotspot" - "Hotspot je aktivní" + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" "Při roamingu mohou být účtovány dodatečné poplatky" - "Pokračovat" diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml index 04a48a77c4..92c3ae1156 100644 --- a/Tethering/res/values-mcc310-mnc004-da/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -16,10 +16,9 @@ - "Hotspottet har intet internet" - "Enheder kan ikke oprette forbindelse til internettet" - "Deaktiver hotspot" - "Hotspottet er aktiveret" + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" "Der opkræves muligvis yderligere gebyrer ved roaming" - "Fortsæt" diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml index a9136784e9..967eb4db2e 100644 --- a/Tethering/res/values-mcc310-mnc004-de/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -16,10 +16,9 @@ - "Hotspot ist nicht mit dem Internet verbunden" - "Geräte können nicht mit dem Internet verbunden werden" - "Hotspot deaktivieren" - "Hotspot aktiviert" + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" "Für das Roaming können zusätzliche Gebühren anfallen" - "Weiter" diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml index 19be3c7077..5fb497451f 100644 --- a/Tethering/res/values-mcc310-mnc004-el/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -16,10 +16,9 @@ - "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." - "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." - "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" - "Σημείο πρόσβασης Wi-Fi ενεργό" + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." - "Συνέχεια" diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml index 6384e89ce0..7877074afc 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -16,10 +16,9 @@ - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎Turn off hotspot‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎Continue‎‏‎‎‏‎" diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml index d4b6937881..08edd81a6b 100644 --- a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -16,10 +16,9 @@ - "El hotspot no tiene Internet" - "Los dispositivos no pueden conectarse a Internet" - "Desactiva el hotspot" - "El hotspot está activado" - "Es posible que apliquen cargos adicionales por roaming" - "Continuar" + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml index 158fd86296..79f51d00e2 100644 --- a/Tethering/res/values-mcc310-mnc004-es/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -16,10 +16,9 @@ - "El punto de acceso no tiene conexión a Internet" - "Los dispositivos no se pueden conectar a Internet" - "Desactivar punto de acceso" - "Zona Wi-Fi activada" + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" "Puede que se apliquen cargos adicionales en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml index 271f82ad6a..2da5f8a6d6 100644 --- a/Tethering/res/values-mcc310-mnc004-et/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -16,10 +16,9 @@ - "Kuumkohal puudub Interneti-ühendus" - "Seadmed ei saa Internetiga ühendust luua" - "Lülita kuumkoht välja" - "Kuumkoht on sees" + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" "Rändluse kasutamisega võivad kaasneda lisatasud" - "Jätka" diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml index 7a2b99e028..2073f2806c 100644 --- a/Tethering/res/values-mcc310-mnc004-eu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -16,10 +16,9 @@ - "Sare publikoak ez du Interneteko konexiorik" - "Gailuak ezin dira konektatu Internetera" - "Desaktibatu sare publikoa" - "Sare publikoa aktibatuta dago" - "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" - "Egin aurrera" + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml index b370e0fd81..e21b2a0852 100644 --- a/Tethering/res/values-mcc310-mnc004-fa/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -16,10 +16,9 @@ - "نقطه اتصال به اینترنت دسترسی ندارد" - "دستگاه‌ها به اینترنت متصل نشدند" - "نقطه اتصال را خاموش کنید" - "نقطه اتصال روشن است" + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" - "ادامه" diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml index da86391ee9..88b0b13eb4 100644 --- a/Tethering/res/values-mcc310-mnc004-fi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -16,10 +16,9 @@ - "Hotspotilla ei ole internetyhteyttä" - "Laitteet eivät voi yhdistää internetiin" - "Laita hotspot pois päältä" - "Hotspot on päällä" + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" "Roaming voi aiheuttaa lisämaksuja" - "Jatka" diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml index 6ffd8116e8..3b781bc8db 100644 --- a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml index 6ffd8116e8..51d7203c36 100644 --- a/Tethering/res/values-mcc310-mnc004-fr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml index 9e7f00cbe0..008ccb475d 100644 --- a/Tethering/res/values-mcc310-mnc004-gl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -16,10 +16,9 @@ - "A zona wifi non ten acceso a Internet" - "Os dispositivos non se poden conectar a Internet" - "Desactivar zona wifi" - "A zona wifi está activada" + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" "Pódense aplicar cargos adicionais en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml index e85c00c648..f2e3b4df78 100644 --- a/Tethering/res/values-mcc310-mnc004-gu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "આગળ વધો" + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml index b6faa3a0f7..b11839d760 100644 --- a/Tethering/res/values-mcc310-mnc004-hi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉट से इंटरनेट नहीं चल रहा" - "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" - "हॉटस्पॉट बंद करें" - "हॉटस्पॉट चालू है" + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" - "जारी रखें" diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml index 86b58ded22..0a5aca25b1 100644 --- a/Tethering/res/values-mcc310-mnc004-hr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -16,10 +16,9 @@ - "Žarišna točka nema pristup internetu" - "Uređaji se ne mogu povezati s internetom" - "Isključi žarišnu točku" - "Žarišna je točka uključena" + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" "U roamingu su mogući dodatni troškovi" - "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml index 27ddabf29d..21c689a44e 100644 --- a/Tethering/res/values-mcc310-mnc004-hu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -16,10 +16,9 @@ - "A hotspot nem csatlakozik az internethez" - "Az eszközök nem tudnak csatlakozni az internethez" - "Hotspot kikapcsolása" - "A hotspot be van kapcsolva" + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" "Roaming során további díjak léphetnek fel" - "Tovább" diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml index abdb207626..689d92870e 100644 --- a/Tethering/res/values-mcc310-mnc004-hy/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -16,10 +16,9 @@ - "Թեժ կետը միացված չէ ինտերնետին" - "Սարքերը չեն կարողանում միանալ ինտերնետին" - "Անջատել թեժ կետը" - "Թեժ կետը միացված է" + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" - "Շարունակել" diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml index 513d2fb040..a5f4d19abf 100644 --- a/Tethering/res/values-mcc310-mnc004-in/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -16,10 +16,9 @@ - "Hotspot tidak memiliki internet" - "Perangkat tidak dapat tersambung ke internet" - "Nonaktifkan hotspot" - "Hotspot aktif" + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" "Biaya tambahan mungkin berlaku saat roaming" - "Lanjutkan" diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml index f4e5dd4ad3..fc7e8aaf4e 100644 --- a/Tethering/res/values-mcc310-mnc004-is/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -16,10 +16,9 @@ - "Heitur reitur er ekki nettengdur" - "Tæki geta ekki tengst við internetið" - "Slökkva á heitum reit" - "Kveikt er á heitum reit" + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" "Viðbótargjöld kunna að eiga við í reiki" - "Halda áfram" diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml index b82363270b..6456dd1b80 100644 --- a/Tethering/res/values-mcc310-mnc004-it/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -16,10 +16,9 @@ - "L\'hotspot non ha accesso a Internet" - "I dispositivi non possono connettersi a Internet" - "Disattiva l\'hotspot" - "Hotspot attivo" - "Potrebbero essere addebitati costi aggiuntivi durante il roaming" - "Continua" + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml index 0922ee9e4d..46b24bd3c5 100644 --- a/Tethering/res/values-mcc310-mnc004-iw/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -16,10 +16,9 @@ - "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" - "המכשירים לא יכולים להתחבר לאינטרנט" - "כיבוי הנקודה לשיתוף אינטרנט" - "הנקודה לשיתוף אינטרנט פועלת" + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" "ייתכנו חיובים נוספים בעת נדידה" - "המשך" diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml index 63ddc476e6..e6eb277b90 100644 --- a/Tethering/res/values-mcc310-mnc004-ja/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -16,10 +16,9 @@ - "アクセス ポイントがインターネットに接続されていません" - "デバイスをインターネットに接続できません" - "アクセス ポイントを OFF にする" - "アクセス ポイント: ON" + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" "ローミング時に追加料金が発生することがあります" - "続行" diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml index 4f20c76a12..aeddd7101d 100644 --- a/Tethering/res/values-mcc310-mnc004-ka/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -16,10 +16,9 @@ - "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" - "მოწყობილობები ვერ უკავშირდება ინტერნეტს" - "გამორთეთ უსადენო ქსელი" - "უსადენო ქსელი ჩართულია" + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" - "გაგრძელება" diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml index 11e293416b..255f0a276f 100644 --- a/Tethering/res/values-mcc310-mnc004-kk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -16,10 +16,9 @@ - "Хотспотта интернет жоқ" - "Құрылғылар интернетке қосылмайды" - "Хотспотты өшіру" - "Хотспот қосулы" + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" "Роуминг кезінде қосымша ақы алынуы мүмкін." - "Жалғастыру" diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml index b8d94d40a3..2bceb1cf77 100644 --- a/Tethering/res/values-mcc310-mnc004-km/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -16,10 +16,9 @@ - "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" - "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" - "បិទ​ហតស្ប៉ត" - "ហតស្ប៉ត​ត្រូវបានបើក" + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" - "បន្ត" diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml index 3e8aaebbe9..ed769305a6 100644 --- a/Tethering/res/values-mcc310-mnc004-kn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "ಮುಂದುವರಿಸಿ" + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml index 59de04c55d..6e504941eb 100644 --- a/Tethering/res/values-mcc310-mnc004-ko/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -16,10 +16,9 @@ - "핫스팟이 인터넷에 연결되지 않음" - "기기를 인터넷에 연결할 수 없음" - "핫스팟 사용 중지" - "핫스팟 사용 중" + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" "로밍 중에는 추가 요금이 발생할 수 있습니다." - "계속" diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml index 7ecb6970e7..d68128b9a5 100644 --- a/Tethering/res/values-mcc310-mnc004-ky/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -16,10 +16,9 @@ - "Хотспоттун Интернети жок" - "Түзмөктөр Интернетке туташпай жатат" - "Туташуу түйүнүн өчүрүү" - "Кошулуу түйүнү күйүк" + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" "Роумингде кошумча акы алынышы мүмкүн" - "Улантуу" diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml index 5d1766707c..03e134a0fc 100644 --- a/Tethering/res/values-mcc310-mnc004-lo/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "ສືບຕໍ່" + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml index aa15bfe1f5..652cedc6e6 100644 --- a/Tethering/res/values-mcc310-mnc004-lt/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -16,10 +16,9 @@ - "Nėra viešosios interneto prieigos taško interneto ryšio" - "Įrenginiams nepavyksta prisijungti prie interneto" - "Išjungti viešosios interneto prieigos tašką" - "Viešosios interneto prieigos taškas įjungtas" + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" - "Tęsti" diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml index 1e0d2f1c6f..221972298c 100644 --- a/Tethering/res/values-mcc310-mnc004-lv/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -16,10 +16,9 @@ - "Tīklājam nav interneta savienojuma" - "Ierīces nevar izveidot savienojumu ar internetu" - "Izslēgt tīklāju" - "Tīklājs ir ieslēgts" + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" "Viesabonēšanas laikā var tikt piemērota papildu samaksa" - "Tālāk" diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml index 5fe2a49af6..227f9e3466 100644 --- a/Tethering/res/values-mcc310-mnc004-mk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -16,10 +16,9 @@ - "Точката на пристап нема интернет" - "Уредите не може да се поврзат на интернет" - "Исклучи ја точката на пристап" - "Точката на пристап е вклучена" + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" "При роаминг може да се наплатат дополнителни трошоци" - "Продолжи" diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml index 930ffa184e..ec43885126 100644 --- a/Tethering/res/values-mcc310-mnc004-ml/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "തുടരുക" + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml index 462e73f7a4..e263573799 100644 --- a/Tethering/res/values-mcc310-mnc004-mn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -16,10 +16,9 @@ - "Сүлжээний цэг дээр интернэт алга байна" - "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" - "Сүлжээний цэгийг унтраах" - "Сүлжээний цэг асаалттай байна" + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" - "Үргэлжлүүлэх" diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml index b1d9b8505b..adf845d078 100644 --- a/Tethering/res/values-mcc310-mnc004-mr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉटला इंटरनेट नाही" - "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" - "हॉटस्पॉट बंद करा" - "हॉटस्पॉट सुरू आहे" + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" - "सुरू ठेवा" diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml index 936629ca14..f65c451e4c 100644 --- a/Tethering/res/values-mcc310-mnc004-ms/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -16,10 +16,9 @@ - "Tempat liputan tiada Internet" - "Peranti tidak dapat menyambung kepada Internet" - "Matikan tempat liputan" - "Tempat liputan dihidupkan" + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" "Caj tambahan mungkin digunakan semasa perayauan" - "Teruskan" diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml index 052df883eb..4118e775cd 100644 --- a/Tethering/res/values-mcc310-mnc004-my/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -16,10 +16,9 @@ - "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" - "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" - "ဟော့စပေါ့ ပိတ်ရန်" - "ဟော့စပေါ့ ဖွင့်ထားသည်" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" - "ရှေ့ဆက်ရန်" diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml index 09012cbfec..36853583ce 100644 --- a/Tethering/res/values-mcc310-mnc004-nb/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -16,10 +16,9 @@ - "Wi-Fi-sonen har ikke internettilgang" - "Enheter kan ikke koble til internett" - "Slå av Wi-Fi-sonen" - "Wi-Fi-sonen er på" + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" "Ytterligere kostnader kan påløpe under roaming" - "Fortsett" diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index e1770b3f77..2a7330098f 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,15 +16,13 @@ - + - + - + - + - - - "जारी राख्नुहोस्" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml index 912290cb67..1d888942f4 100644 --- a/Tethering/res/values-mcc310-mnc004-nl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot heeft geen internet" - "Apparaten kunnen geen verbinding maken met internet" - "Hotspot uitschakelen" - "Hotspot is ingeschakeld" + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" "Er kunnen extra kosten voor roaming in rekening worden gebracht." - "Doorgaan" diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml index 6a842428e0..8038815fe8 100644 --- a/Tethering/res/values-mcc310-mnc004-or/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "ଜାରି ରଖନ୍ତୁ" + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml index bb1479d3fb..819833eab0 100644 --- a/Tethering/res/values-mcc310-mnc004-pa/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "ਜਾਰੀ ਰੱਖੋ" + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml index 51d5c3fd7e..65e4380e39 100644 --- a/Tethering/res/values-mcc310-mnc004-pl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nie ma internetu" - "Urządzenia nie mogą połączyć się z internetem" - "Wyłącz hotspot" - "Hotspot jest włączony" + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" - "Dalej" diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml index 6e605797d0..d8866170c1 100644 --- a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml index 79957977dc..bfd45ca0a3 100644 --- a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -16,10 +16,9 @@ - "A zona Wi-Fi não tem Internet" - "Não é possível ligar os dispositivos à Internet" - "Desativar zona Wi-Fi" - "A zona Wi-Fi está ativada" + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" "Podem aplicar-se custos adicionais em roaming." - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml index 6e605797d0..d8866170c1 100644 --- a/Tethering/res/values-mcc310-mnc004-pt/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml index 7be2f72195..8d87a9e516 100644 --- a/Tethering/res/values-mcc310-mnc004-ro/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -16,10 +16,9 @@ - "Hotspotul nu are internet" - "Dispozitivele nu se pot conecta la internet" - "Dezactivați hotspotul" - "Hotspotul este activ" + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" "Se pot aplica taxe suplimentare pentru roaming" - "Continuați" diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml index 6ab396d50d..dbdb9ebe49 100644 --- a/Tethering/res/values-mcc310-mnc004-ru/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -16,10 +16,9 @@ - "Точка доступа не подключена к Интернету" - "Не удается подключить устройства к Интернету" - "Отключить точку доступа" - "Точка доступа включена" + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" "За использование услуг связи в роуминге может взиматься дополнительная плата." - "Продолжить" diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml index 357dd904ac..d8301e41c2 100644 --- a/Tethering/res/values-mcc310-mnc004-si/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -16,10 +16,9 @@ - "හොට්ස්පොට් හට අන්තර්ජාලය නැත" - "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" - "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" - "හොට්ස්පොට් ක්‍රියාත්මකයි" + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" - "ඉදිරියට යන්න" diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml index 276e5797ee..bef71363f4 100644 --- a/Tethering/res/values-mcc310-mnc004-sk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá internetové pripojenie" - "Zariadenia sa nedajú pripojiť k internetu" - "Vypnúť hotspot" - "Hotspot je zapnutý" + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" "Počas roamingu vám môžu byť účtované ďalšie poplatky" - "Pokračovať" diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml index 884bddd292..3202c62e8a 100644 --- a/Tethering/res/values-mcc310-mnc004-sl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -16,10 +16,9 @@ - "Dostopna točka nima internetne povezave" - "Naprave ne morejo vzpostaviti internetne povezave" - "Izklopi dostopno točko" - "Dostopna točka je vklopljena" + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" "Med gostovanjem lahko nastanejo dodatni stroški" - "Naprej" diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml index a2caddf667..37f6ad2868 100644 --- a/Tethering/res/values-mcc310-mnc004-sq/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -16,10 +16,9 @@ - "Zona e qasjes për internet nuk ka internet" - "Pajisjet nuk mund të lidhen me internetin" - "Çaktivizo zonën e qasjes për internet" - "Zona e qasjes për internet është aktive" + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" "Mund të zbatohen tarifime shtesë kur je në roaming" - "Vazhdo" diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml index 7745923331..5566d03ed1 100644 --- a/Tethering/res/values-mcc310-mnc004-sr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -16,10 +16,9 @@ - "Хотспот нема приступ интернету" - "Уређаји не могу да се повежу на интернет" - "Искључи хотспот" - "Хотспот је укључен" + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" "Можда важе додатни трошкови у ромингу" - "Настави" diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml index 906862aa17..9765acd0cf 100644 --- a/Tethering/res/values-mcc310-mnc004-sv/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -16,10 +16,9 @@ - "Surfzonen har ingen internetanslutning" - "Enheterna har ingen internetanslutning" - "Inaktivera surfzon" - "Surfzonen är aktiverad" + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" "Ytterligare avgifter kan tillkomma vid roaming" - "Fortsätt" diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml index 0eb922fff6..cf850c9cd2 100644 --- a/Tethering/res/values-mcc310-mnc004-sw/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -16,10 +16,9 @@ - "Mtandao pepe hauna intaneti" - "Vifaa vimeshindwa kuunganisha kwenye intaneti" - "Zima mtandao pepe" - "Mtandaopepe umewashwa" + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" - "Endelea" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index 1d66c6d689..ea04821e33 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,15 +16,13 @@ - + - + - + - + - - - "தொடர்க" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml index 2ee0fa8dda..937d34d520 100644 --- a/Tethering/res/values-mcc310-mnc004-te/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "కొనసాగించు" + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml index 44114e5891..f781fae525 100644 --- a/Tethering/res/values-mcc310-mnc004-th/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -16,10 +16,9 @@ - "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" - "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" - "ปิดฮอตสปอต" - "ฮอตสปอตเปิดอยู่" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" - "ต่อไป" diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml index 440999014c..8d5d465373 100644 --- a/Tethering/res/values-mcc310-mnc004-tl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -16,10 +16,9 @@ - "Walang internet ang hotspot" - "Hindi makakonekta sa internet ang mga device" - "I-off ang hotspot" - "Naka-on ang hotspot" + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" - "Ituloy" diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml index d21ad95181..80cab33ac0 100644 --- a/Tethering/res/values-mcc310-mnc004-tr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -16,10 +16,9 @@ - "Hotspot\'un internet bağlantısı yok" - "Cihazlar internete bağlanamıyor" - "Hotspot\'u kapat" - "Hotspot açık" + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" "Dolaşım sırasında ek ücretler uygulanabilir" - "Devam" diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml index e7b8c68eb1..c05932a5ae 100644 --- a/Tethering/res/values-mcc310-mnc004-uk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -16,10 +16,9 @@ - "Точка доступу не підключена до Інтернету" - "Не вдається підключити пристрої до Інтернету" - "Вимкнути точку доступу" - "Точку доступу ввімкнено" + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" "У роумінгу може стягуватися додаткова плата" - "Продовжити" diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml index 08edfcffeb..d820eee8ba 100644 --- a/Tethering/res/values-mcc310-mnc004-ur/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -16,10 +16,9 @@ - "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" - "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" - "ہاٹ اسپاٹ آف کریں" - "ہاٹ اسپاٹ آن ہے" + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" - "جاری رکھیں" diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml index 9def0a1b06..726148aaee 100644 --- a/Tethering/res/values-mcc310-mnc004-uz/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "Davom etish" + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml index e4f818bf42..b7cb0456b6 100644 --- a/Tethering/res/values-mcc310-mnc004-vi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -16,10 +16,9 @@ - "Điểm phát sóng không có kết nối Internet" - "Các thiết bị không thể kết nối Internet" - "Tắt điểm phát sóng" - "Điểm phát sóng đang bật" + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" - "Tiếp tục" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml index cee4682e7d..af91afff9a 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -16,10 +16,9 @@ - "热点无法访问互联网" - "设备无法连接到互联网" - "关闭热点" - "热点已开启" + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" "漫游时可能会产生额外的费用" - "继续" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml index 05321db9f2..28e6b80c01 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -16,10 +16,9 @@ - "熱點沒有互聯網連線" - "裝置無法連線至互聯網" - "關閉熱點" - "已開啟熱點" + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" "漫遊時可能需要支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml index 57b9e0de3b..05b90692ea 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -16,10 +16,9 @@ - "無線基地台沒有網際網路連線" - "裝置無法連上網際網路" - "關閉無線基地台" - "無線基地台已開啟" + "無法透過數據連線連上網際網路" + "裝置無法連線" + "關閉數據連線" + "無線基地台或數據連線已開啟" "使用漫遊服務可能須支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml index 7e899705af..11eb666219 100644 --- a/Tethering/res/values-mcc310-mnc004-zu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -16,10 +16,9 @@ - "I-Hotspot ayina-inthanethi" - "Amadivayisi awakwazi ukuxhuma ku-inthanethi" - "Vala i-hotspot" - "I-Hotspot ivuliwe" + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" "Kungaba nezinkokhelo ezengeziwe uma uzula" - "Qhubeka" diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml index 6fc432256a..9bfa5317a9 100644 --- a/Tethering/res/values-mcc311-mnc480-af/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -16,10 +16,9 @@ - "Warmkol het nie internet nie" - "Toestelle kan nie aan internet koppel nie" - "Skakel warmkol af" - "Warmkol is aan" + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" "Bykomende heffings kan geld terwyl jy swerf" - "Gaan voort" diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml index 749cb54022..5949dfa776 100644 --- a/Tethering/res/values-mcc311-mnc480-am/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -16,10 +16,9 @@ - "መገናኛ ነጥቡ በይነመረብ የለውም" - "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" - "መገናኛ ነጥብ ያጥፉ" - "የመገናኛ ነጥብ በርቷል" + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" - "ቀጥል" diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml index 9460023663..8467f9b1f5 100644 --- a/Tethering/res/values-mcc311-mnc480-ar/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "متابعة" + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml index e18e4ec67d..9776bd89da 100644 --- a/Tethering/res/values-mcc311-mnc480-as/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" - "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" - "হটস্পট অফ কৰক" - "হটস্পট অন হৈ আছে" + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" - "অব্যাহত ৰাখক" diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml index 77740cb6c6..e6d3eaf9f0 100644 --- a/Tethering/res/values-mcc311-mnc480-az/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -16,10 +16,9 @@ - "Hotspotun internetə girişi yoxdur" - "Cihazlar internetə qoşula bilmir" - "Hotspot\'u deaktiv edin" - "Hotspot aktivdir" + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" - "Davam edin" diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml index 7170c06662..4c8a1df8ee 100644 --- a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nema pristup internetu" - "Uređaji ne mogu da se povežu na internet" - "Isključi hotspot" - "Hotspot je uključen" + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" "Možda važe dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml index 7388d218fd..edfa41e1ff 100644 --- a/Tethering/res/values-mcc311-mnc480-be/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -16,10 +16,9 @@ - "Хот-спот не падключаны да інтэрнэту" - "Прылады не могуць падключацца да інтэрнэту" - "Выключыць хот-спот" - "Хот-спот уключаны" + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" - "Працягнуць" diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml index aa7a40bfa1..f56398196f 100644 --- a/Tethering/res/values-mcc311-mnc480-bg/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -16,10 +16,9 @@ - "Точката за достъп няма връзка с интернет" - "Устройствата не могат да се свържат с интернет" - "Изключване на точката за достъп" - "Точката за достъп е включена" + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" "Възможно е да ви бъдат начислени допълнителни такси при роуминг" - "Напред" diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml index 00bac782ed..d8ecd2e988 100644 --- a/Tethering/res/values-mcc311-mnc480-bn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "চালিয়ে যান" + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml index 907821260b..b85fd5e285 100644 --- a/Tethering/res/values-mcc311-mnc480-bs/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -16,10 +16,9 @@ - "Pristupna tačka nema internet" - "Uređaji se ne mogu povezati na internet" - "Isključi pristupnu tačku" - "Pristupna tačka je uključena" - "Primjenjuju se dodatne tarife u romingu" - "Nastavi" + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml index 43c9e137bb..a3572151be 100644 --- a/Tethering/res/values-mcc311-mnc480-ca/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -16,10 +16,9 @@ - "El punt d\'accés Wi‑Fi no té accés a Internet" - "Els dispositius no es poden connectar a Internet" - "Desactiva el punt d\'accés Wi‑Fi" - "El punt d\'accés Wi‑Fi està activat" + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" "És possible que s\'apliquin costos addicionals en itinerància" - "Continua" diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml index c9210f7f40..91196be9e5 100644 --- a/Tethering/res/values-mcc311-mnc480-cs/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá připojení k internetu" - "Zařízení se nemohou připojit k internetu" - "Vypnout hotspot" - "Hotspot je aktivní" + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" "Při roamingu mohou být účtovány dodatečné poplatky" - "Pokračovat" diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml index 3615ff49ff..196890011d 100644 --- a/Tethering/res/values-mcc311-mnc480-da/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -16,10 +16,9 @@ - "Hotspottet har intet internet" - "Enheder kan ikke oprette forbindelse til internettet" - "Deaktiver hotspot" - "Hotspottet er aktiveret" + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" "Der opkræves muligvis yderligere gebyrer ved roaming" - "Fortsæt" diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml index ee8809d80b..eb3f8c52c0 100644 --- a/Tethering/res/values-mcc311-mnc480-de/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -16,10 +16,9 @@ - "Hotspot ist nicht mit dem Internet verbunden" - "Geräte können nicht mit dem Internet verbunden werden" - "Hotspot deaktivieren" - "Hotspot aktiviert" + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" "Für das Roaming können zusätzliche Gebühren anfallen" - "Weiter" diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml index 3a79be8735..56c3d81b63 100644 --- a/Tethering/res/values-mcc311-mnc480-el/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -16,10 +16,9 @@ - "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." - "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." - "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" - "Σημείο πρόσβασης Wi-Fi ενεργό" + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." - "Συνέχεια" diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml index 2daad6ad1c..d3347aae20 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -16,10 +16,9 @@ - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎Turn off hotspot‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml index 68d5fc26de..2f0504f07d 100644 --- a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -16,10 +16,9 @@ - "El hotspot no tiene Internet" - "Los dispositivos no pueden conectarse a Internet" - "Desactiva el hotspot" - "El hotspot está activado" - "Es posible que apliquen cargos adicionales por roaming" - "Continuar" + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml index 930e088642..2d8f882425 100644 --- a/Tethering/res/values-mcc311-mnc480-es/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -16,10 +16,9 @@ - "El punto de acceso no tiene conexión a Internet" - "Los dispositivos no se pueden conectar a Internet" - "Desactivar punto de acceso" - "Zona Wi-Fi activada" + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" "Puede que se apliquen cargos adicionales en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml index e59e12e71d..8493c47071 100644 --- a/Tethering/res/values-mcc311-mnc480-et/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -16,10 +16,9 @@ - "Kuumkohal puudub Interneti-ühendus" - "Seadmed ei saa Internetiga ühendust luua" - "Lülita kuumkoht välja" - "Kuumkoht on sees" + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" "Rändluse kasutamisega võivad kaasneda lisatasud" - "Jätka" diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml index 4358266323..33bccab3e8 100644 --- a/Tethering/res/values-mcc311-mnc480-eu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -16,10 +16,9 @@ - "Sare publikoak ez du Interneteko konexiorik" - "Gailuak ezin dira konektatu Internetera" - "Desaktibatu sare publikoa" - "Sare publikoa aktibatuta dago" - "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritza moduan" - "Egin aurrera" + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml index a2324d84f0..cf8a0cc277 100644 --- a/Tethering/res/values-mcc311-mnc480-fa/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -16,10 +16,9 @@ - "نقطه اتصال به اینترنت دسترسی ندارد" - "دستگاه‌ها به اینترنت متصل نشدند" - "نقطه اتصال را خاموش کنید" - "نقطه اتصال روشن است" + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" - "ادامه" diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml index ec6ac929fb..6a3ab806db 100644 --- a/Tethering/res/values-mcc311-mnc480-fi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -16,10 +16,9 @@ - "Hotspotilla ei ole internetyhteyttä" - "Laitteet eivät voi yhdistää internetiin" - "Laita hotspot pois päältä" - "Hotspot on päällä" + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" "Roaming voi aiheuttaa lisämaksuja" - "Jatka" diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml index eeaf8f3ad4..ffb9bf6047 100644 --- a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml index eeaf8f3ad4..768bce3f0a 100644 --- a/Tethering/res/values-mcc311-mnc480-fr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml index 56b3a9b79d..0c4195a7ca 100644 --- a/Tethering/res/values-mcc311-mnc480-gl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -16,10 +16,9 @@ - "A zona wifi non ten acceso a Internet" - "Os dispositivos non se poden conectar a Internet" - "Desactivar zona wifi" - "A zona wifi está activada" + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" "Pódense aplicar cargos adicionais en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml index c2af9a6688..e9d33a7db2 100644 --- a/Tethering/res/values-mcc311-mnc480-gu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "આગળ વધો" + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml index 8bb5fb29ae..aa418ac5d3 100644 --- a/Tethering/res/values-mcc311-mnc480-hi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉट से इंटरनेट नहीं चल रहा" - "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" - "हॉटस्पॉट बंद करें" - "हॉटस्पॉट चालू है" + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" - "जारी रखें" diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml index 551b1b36fe..51c524afbc 100644 --- a/Tethering/res/values-mcc311-mnc480-hr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -16,10 +16,9 @@ - "Žarišna točka nema pristup internetu" - "Uređaji se ne mogu povezati s internetom" - "Isključi žarišnu točku" - "Žarišna je točka uključena" + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" "U roamingu su mogući dodatni troškovi" - "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml index 4113195c19..164e45edd1 100644 --- a/Tethering/res/values-mcc311-mnc480-hu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -16,10 +16,9 @@ - "A hotspot nem csatlakozik az internethez" - "Az eszközök nem tudnak csatlakozni az internethez" - "Hotspot kikapcsolása" - "A hotspot be van kapcsolva" + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" "Roaming során további díjak léphetnek fel" - "Tovább" diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml index 393eac056c..e76c0a4c80 100644 --- a/Tethering/res/values-mcc311-mnc480-hy/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -16,10 +16,9 @@ - "Թեժ կետը միացված չէ ինտերնետին" - "Սարքերը չեն կարողանում միանալ ինտերնետին" - "Անջատել թեժ կետը" - "Թեժ կետը միացված է" + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" - "Շարունակել" diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml index e2538328cf..2b817f8abd 100644 --- a/Tethering/res/values-mcc311-mnc480-in/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -16,10 +16,9 @@ - "Hotspot tidak memiliki internet" - "Perangkat tidak dapat tersambung ke internet" - "Nonaktifkan hotspot" - "Hotspot aktif" + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" "Biaya tambahan mungkin berlaku saat roaming" - "Lanjutkan" diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml index d28383f51b..a338d9c7ca 100644 --- a/Tethering/res/values-mcc311-mnc480-is/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -16,10 +16,9 @@ - "Heitur reitur er ekki nettengdur" - "Tæki geta ekki tengst við internetið" - "Slökkva á heitum reit" - "Kveikt er á heitum reit" + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" "Viðbótargjöld kunna að eiga við í reiki" - "Halda áfram" diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml index 388aa7a2c5..77769c2ac5 100644 --- a/Tethering/res/values-mcc311-mnc480-it/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -16,10 +16,9 @@ - "L\'hotspot non ha accesso a Internet" - "I dispositivi non possono connettersi a Internet" - "Disattiva l\'hotspot" - "Hotspot attivo" - "Potrebbero essere addebitati costi aggiuntivi durante il roaming" - "Continua" + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml index bbc379501c..5267b51264 100644 --- a/Tethering/res/values-mcc311-mnc480-iw/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -16,10 +16,9 @@ - "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" - "המכשירים לא יכולים להתחבר לאינטרנט" - "כיבוי הנקודה לשיתוף אינטרנט" - "הנקודה לשיתוף אינטרנט פועלת" + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" "ייתכנו חיובים נוספים בעת נדידה" - "המשך" diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml index d7cb66b1dd..66a9a6dd35 100644 --- a/Tethering/res/values-mcc311-mnc480-ja/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -16,10 +16,9 @@ - "アクセス ポイントがインターネットに接続されていません" - "デバイスをインターネットに接続できません" - "アクセス ポイントを OFF にする" - "アクセス ポイント: ON" + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" "ローミング時に追加料金が発生することがあります" - "続行" diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml index 9651a563bd..d8ad880849 100644 --- a/Tethering/res/values-mcc311-mnc480-ka/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -16,10 +16,9 @@ - "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" - "მოწყობილობები ვერ უკავშირდება ინტერნეტს" - "გამორთეთ უსადენო ქსელი" - "უსადენო ქსელი ჩართულია" + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" - "გაგრძელება" diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml index f2db66b11e..1ddd6b419b 100644 --- a/Tethering/res/values-mcc311-mnc480-kk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -16,10 +16,9 @@ - "Хотспотта интернет жоқ" - "Құрылғылар интернетке қосылмайды" - "Хотспотты өшіру" - "Хотспот қосулы" + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" "Роуминг кезінде қосымша ақы алынуы мүмкін." - "Жалғастыру" diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml index 16699c5a0a..cf5a1379cc 100644 --- a/Tethering/res/values-mcc311-mnc480-km/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -16,10 +16,9 @@ - "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" - "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" - "បិទ​ហតស្ប៉ត" - "ហតស្ប៉ត​ត្រូវបានបើក" + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" - "បន្ត" diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml index 3c75b1205b..68ae68bc19 100644 --- a/Tethering/res/values-mcc311-mnc480-kn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "ಮುಂದುವರಿಸಿ" + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml index 3892bc36a9..17185ba2d0 100644 --- a/Tethering/res/values-mcc311-mnc480-ko/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -16,10 +16,9 @@ - "핫스팟이 인터넷에 연결되지 않음" - "기기를 인터넷에 연결할 수 없음" - "핫스팟 사용 중지" - "핫스팟 사용 중" + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" "로밍 중에는 추가 요금이 발생할 수 있습니다." - "계속" diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml index 85e92e0a3c..6a9fb9810c 100644 --- a/Tethering/res/values-mcc311-mnc480-ky/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -16,10 +16,9 @@ - "Хотспоттун Интернети жок" - "Түзмөктөр Интернетке туташпай жатат" - "Туташуу түйүнүн өчүрүү" - "Кошулуу түйүнү күйүк" + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" "Роумингде кошумча акы алынышы мүмкүн" - "Улантуу" diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml index 881e05c5e0..bcc4b57626 100644 --- a/Tethering/res/values-mcc311-mnc480-lo/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "ສືບຕໍ່" + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml index 83aabd176f..011c2c11fb 100644 --- a/Tethering/res/values-mcc311-mnc480-lt/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -16,10 +16,9 @@ - "Nėra viešosios interneto prieigos taško interneto ryšio" - "Įrenginiams nepavyksta prisijungti prie interneto" - "Išjungti viešosios interneto prieigos tašką" - "Viešosios interneto prieigos taškas įjungtas" + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" - "Tęsti" diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml index 83feb11f8a..5cb2f3b7aa 100644 --- a/Tethering/res/values-mcc311-mnc480-lv/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -16,10 +16,9 @@ - "Tīklājam nav interneta savienojuma" - "Ierīces nevar izveidot savienojumu ar internetu" - "Izslēgt tīklāju" - "Tīklājs ir ieslēgts" + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" "Viesabonēšanas laikā var tikt piemērota papildu samaksa" - "Tālāk" diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml index 040e2a5d8e..4cbfd887c5 100644 --- a/Tethering/res/values-mcc311-mnc480-mk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -16,10 +16,9 @@ - "Точката на пристап нема интернет" - "Уредите не може да се поврзат на интернет" - "Исклучи ја точката на пристап" - "Точката на пристап е вклучена" + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" "При роаминг може да се наплатат дополнителни трошоци" - "Продолжи" diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml index c9b12cd706..9cf4eaf34a 100644 --- a/Tethering/res/values-mcc311-mnc480-ml/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "തുടരുക" + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml index e5a845051d..47c82c14d9 100644 --- a/Tethering/res/values-mcc311-mnc480-mn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -16,10 +16,9 @@ - "Сүлжээний цэг дээр интернэт алга байна" - "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" - "Сүлжээний цэгийг унтраах" - "Сүлжээний цэг асаалттай байна" + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" - "Үргэлжлүүлэх" diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml index c7f1cc6c66..ad9e809ab2 100644 --- a/Tethering/res/values-mcc311-mnc480-mr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉटला इंटरनेट नाही" - "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" - "हॉटस्पॉट बंद करा" - "हॉटस्पॉट सुरू आहे" + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" - "सुरू ठेवा" diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml index 35d36f69f1..e708cb8717 100644 --- a/Tethering/res/values-mcc311-mnc480-ms/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -16,10 +16,9 @@ - "Tempat liputan tiada Internet" - "Peranti tidak dapat menyambung kepada Internet" - "Matikan tempat liputan" - "Tempat liputan dihidupkan" + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" "Caj tambahan mungkin digunakan semasa perayauan" - "Teruskan" diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml index bc374725ae..ba5462250b 100644 --- a/Tethering/res/values-mcc311-mnc480-my/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -16,10 +16,9 @@ - "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" - "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" - "ဟော့စပေါ့ ပိတ်ရန်" - "ဟော့စပေါ့ ဖွင့်ထားသည်" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" - "ရှေ့ဆက်ရန်" diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml index 413e165c0f..57db484a25 100644 --- a/Tethering/res/values-mcc311-mnc480-nb/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -16,10 +16,9 @@ - "Wi-Fi-sonen har ikke internettilgang" - "Enheter kan ikke koble til internett" - "Slå av Wi-Fi-sonen" - "Wi-Fi-sonen er på" + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" "Ytterligere kostnader kan påløpe under roaming" - "Fortsett" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 9b2256abfc..617c50dd0c 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,15 +16,13 @@ - + - + - + - + - - - "जारी राख्नुहोस्" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml index 7f7f39187f..b08133f4e5 100644 --- a/Tethering/res/values-mcc311-mnc480-nl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot heeft geen internet" - "Apparaten kunnen geen verbinding maken met internet" - "Hotspot uitschakelen" - "Hotspot is ingeschakeld" + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" "Er kunnen extra kosten voor roaming in rekening worden gebracht." - "Doorgaan" diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml index b478d1393b..1ad4ca354a 100644 --- a/Tethering/res/values-mcc311-mnc480-or/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "ଜାରି ରଖନ୍ତୁ" + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml index e0940a518d..88def563d8 100644 --- a/Tethering/res/values-mcc311-mnc480-pa/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "ਜਾਰੀ ਰੱਖੋ" + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml index c578b278d9..f9890abdc2 100644 --- a/Tethering/res/values-mcc311-mnc480-pl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nie ma internetu" - "Urządzenia nie mogą połączyć się z internetem" - "Wyłącz hotspot" - "Hotspot jest włączony" + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" - "Dalej" diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml index 502b5ddb7d..ce3b88479f 100644 --- a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml index a477516145..7e883ea576 100644 --- a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -16,10 +16,9 @@ - "A zona Wi-Fi não tem Internet" - "Não é possível ligar os dispositivos à Internet" - "Desativar zona Wi-Fi" - "A zona Wi-Fi está ativada" + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" "Podem aplicar-se custos adicionais em roaming." - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml index 502b5ddb7d..ce3b88479f 100644 --- a/Tethering/res/values-mcc311-mnc480-pt/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml index d6808b04e6..1009417316 100644 --- a/Tethering/res/values-mcc311-mnc480-ro/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -16,10 +16,9 @@ - "Hotspotul nu are internet" - "Dispozitivele nu se pot conecta la internet" - "Dezactivați hotspotul" - "Hotspotul este activ" + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" "Se pot aplica taxe suplimentare pentru roaming" - "Continuați" diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml index 22dcfcf42d..88683bed95 100644 --- a/Tethering/res/values-mcc311-mnc480-ru/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -16,10 +16,9 @@ - "Точка доступа не подключена к Интернету" - "Не удается подключить устройства к Интернету" - "Отключить точку доступа" - "Точка доступа включена" + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" "За использование услуг связи в роуминге может взиматься дополнительная плата." - "Продолжить" diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml index 5008b7326c..176bcdb797 100644 --- a/Tethering/res/values-mcc311-mnc480-si/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -16,10 +16,9 @@ - "හොට්ස්පොට් හට අන්තර්ජාලය නැත" - "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" - "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" - "හොට්ස්පොට් ක්‍රියාත්මකයි" + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" - "ඉදිරියට යන්න" diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml index 010677d1d6..b9e2127fa8 100644 --- a/Tethering/res/values-mcc311-mnc480-sk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá internetové pripojenie" - "Zariadenia sa nedajú pripojiť k internetu" - "Vypnúť hotspot" - "Hotspot je zapnutý" + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" "Počas roamingu vám môžu byť účtované ďalšie poplatky" - "Pokračovať" diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml index 3662ca9e2a..e8140e686a 100644 --- a/Tethering/res/values-mcc311-mnc480-sl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -16,10 +16,9 @@ - "Dostopna točka nima internetne povezave" - "Naprave ne morejo vzpostaviti internetne povezave" - "Izklopi dostopno točko" - "Dostopna točka je vklopljena" + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" "Med gostovanjem lahko nastanejo dodatni stroški" - "Naprej" diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml index 5453d54fd9..61e698d6e8 100644 --- a/Tethering/res/values-mcc311-mnc480-sq/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -16,10 +16,9 @@ - "Zona e qasjes për internet nuk ka internet" - "Pajisjet nuk mund të lidhen me internetin" - "Çaktivizo zonën e qasjes për internet" - "Zona e qasjes për internet është aktive" + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" "Mund të zbatohen tarifime shtesë kur je në roaming" - "Vazhdo" diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml index f52cbf387e..b4c411c354 100644 --- a/Tethering/res/values-mcc311-mnc480-sr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -16,10 +16,9 @@ - "Хотспот нема приступ интернету" - "Уређаји не могу да се повежу на интернет" - "Искључи хотспот" - "Хотспот је укључен" + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" "Можда важе додатни трошкови у ромингу" - "Настави" diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml index 8474342f26..4f543e47b9 100644 --- a/Tethering/res/values-mcc311-mnc480-sv/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -16,10 +16,9 @@ - "Surfzonen har ingen internetanslutning" - "Enheterna har ingen internetanslutning" - "Inaktivera surfzon" - "Surfzonen är aktiverad" + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" "Ytterligare avgifter kan tillkomma vid roaming" - "Fortsätt" diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml index 5a812e3f0c..ac347ab485 100644 --- a/Tethering/res/values-mcc311-mnc480-sw/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -16,10 +16,9 @@ - "Mtandao pepe hauna intaneti" - "Vifaa vimeshindwa kuunganisha kwenye intaneti" - "Zima mtandao pepe" - "Mtandaopepe umewashwa" + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" - "Endelea" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 315403135d..0e437593ee 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,15 +16,13 @@ - + - + - + - + - - - "தொடர்க" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml index 414def5963..9360297dd8 100644 --- a/Tethering/res/values-mcc311-mnc480-te/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "కొనసాగించు" + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml index a26ac0403b..9c4d7e08f2 100644 --- a/Tethering/res/values-mcc311-mnc480-th/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -16,10 +16,9 @@ - "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" - "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" - "ปิดฮอตสปอต" - "ฮอตสปอตเปิดอยู่" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" - "ต่อไป" diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml index 6e98146cd5..a7c78a5932 100644 --- a/Tethering/res/values-mcc311-mnc480-tl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -16,10 +16,9 @@ - "Walang internet ang hotspot" - "Hindi makakonekta sa internet ang mga device" - "I-off ang hotspot" - "Naka-on ang hotspot" + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" - "Ituloy" diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml index 423bd76689..93da2c3f79 100644 --- a/Tethering/res/values-mcc311-mnc480-tr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -16,10 +16,9 @@ - "Hotspot\'un internet bağlantısı yok" - "Cihazlar internete bağlanamıyor" - "Hotspot\'u kapat" - "Hotspot açık" + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" "Dolaşım sırasında ek ücretler uygulanabilir" - "Devam" diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml index 193b3c348b..ee0dcd2c4b 100644 --- a/Tethering/res/values-mcc311-mnc480-uk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -16,10 +16,9 @@ - "Точка доступу не підключена до Інтернету" - "Не вдається підключити пристрої до Інтернету" - "Вимкнути точку доступу" - "Точку доступу ввімкнено" + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" "У роумінгу може стягуватися додаткова плата" - "Продовжити" diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml index 3564ead361..41cd28eef9 100644 --- a/Tethering/res/values-mcc311-mnc480-ur/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -16,10 +16,9 @@ - "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" - "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" - "ہاٹ اسپاٹ آف کریں" - "ہاٹ اسپاٹ آن ہے" + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" - "جاری رکھیں" diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml index 769cc2c385..c847bc943b 100644 --- a/Tethering/res/values-mcc311-mnc480-uz/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -16,15 +16,9 @@ - - - - - - - - - - - "Davom etish" + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml index 998ebe4d7b..a74326f09e 100644 --- a/Tethering/res/values-mcc311-mnc480-vi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -16,10 +16,9 @@ - "Điểm phát sóng không có kết nối Internet" - "Các thiết bị không thể kết nối Internet" - "Tắt điểm phát sóng" - "Điểm phát sóng đang bật" + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" - "Tiếp tục" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml index 75786086b6..d7370036e3 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -16,10 +16,9 @@ - "热点无法访问互联网" - "设备无法连接到互联网" - "关闭热点" - "热点已开启" + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" "漫游时可能会产生额外的费用" - "继续" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml index 7f7453c306..f378a9dc2c 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -16,10 +16,9 @@ - "熱點沒有互聯網連線" - "裝置無法連線至互聯網" - "關閉熱點" - "已開啟熱點" + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" "漫遊時可能需要支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml index 4b4afc017e..ea01b943fb 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -16,10 +16,9 @@ - "無線基地台沒有網際網路連線" - "裝置無法連上網際網路" - "關閉無線基地台" - "無線基地台已開啟" + "無法透過數據連線連上網際網路" + "裝置無法連線" + "關閉數據連線" + "無線基地台或數據連線已開啟" "使用漫遊服務可能須支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml index 48ac295ebc..32f6df56f1 100644 --- a/Tethering/res/values-mcc311-mnc480-zu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -16,10 +16,9 @@ - "I-Hotspot ayina-inthanethi" - "Amadivayisi awakwazi ukuxhuma ku-inthanethi" - "Vala i-hotspot" - "I-Hotspot ivuliwe" + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" "Kungaba nezinkokhelo ezengeziwe uma uzula" - "Qhubeka" diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 04f0fa8c71..9ad9b9a589 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Активно е врзување или точка на пристап" "Допрете за поставување." - "Врзувањето е оневозможено" "Контактирајте со администраторот за детали" "Статус на точката на пристап и врзувањето" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index 2d14f8e0f5..9db79ce220 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4f3334c8e3..42d1edbace 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" "Тохируулахын тулд товшино уу." - "Модем болгохыг идэвхгүй болгосон" "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" "Сүлжээний цэг болон модем болгох төлөв" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index ba9f324982..13995b6b8a 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद केले आहे" "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" "हॉटस्पॉट आणि टेदरिंगची स्थिती" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index c343e311f4..d6a67f37b1 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Penambatan atau tempat liputan aktif" "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" "Status tempat liputan & penambatan" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 84bcdb4c07..49f6b88a75 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 877c128c2d..9594e0a70a 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Internettdeling eller Wi-Fi-sone er aktiv" "Trykk for å konfigurere." - "Internettdeling er slått av" "Ta kontakt med administratoren din for å få mer informasjon" "Status for Wi-Fi-sone og internettdeling" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index d50fe240c4..72ae3a80a9 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिङ वा हटस्पट सक्रिय छ" "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङ सुविधा असक्षम पारिएको छ" "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" "हटस्पट तथा टेदरिङको स्थिति" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 6950c239ab..18b2bbfc76 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering of hotspot actief" "Tik om in te stellen." - "Tethering is uitgeschakeld" "Neem contact op met je beheerder voor meer informatie" "Status van hotspot en tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 2500a6f66b..a15a6db42a 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" - "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index 1fd496f968..a8235e423e 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index df1d5aeffa..ccb017d43f 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktywny tethering lub punkt dostępu" "Kliknij, by skonfigurować" - "Tethering został wyłączony" "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" "Hotspot i tethering – stan" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 2c3757d6de..a0a4745f93 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ponto de acesso ou tethering ativo" "Toque para configurar." - "Tethering desativado" "Fale com seu administrador para saber detalhes" "Status de ponto de acesso e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 5af2d22a57..e3f03fcc69 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." "Contacte o administrador para obter detalhes." "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 2c3757d6de..a0a4745f93 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ponto de acesso ou tethering ativo" "Toque para configurar." - "Tethering desativado" "Fale com seu administrador para saber detalhes" "Status de ponto de acesso e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index 1dad542d4f..5706a4a69c 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering sau hotspot activ" "Atingeți ca să configurați." - "Tetheringul este dezactivat" "Contactați administratorul pentru detalii" "Starea hotspotului și a tetheringului" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 4d31484229..7cb6f7db3f 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Включен режим модема или точка доступа" "Нажмите, чтобы настроить." - "Использование телефона в качестве модема запрещено" "Чтобы узнать подробности, обратитесь к администратору." "Статус хот-спота и режима модема" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index d21f2b5388..ec34c22de7 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index f2242b93b3..43e787c84f 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering alebo prístupový bod je aktívny" "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" "O podrobnosti požiadajte svojho správcu" "Stav hotspotu a tetheringu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index c01cace360..59433626a1 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" "Za podrobnosti se obrnite na skrbnika" "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index f7e2a7be74..21e11558bb 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ndarja e internetit ose zona e qasjes së internetit është aktive" "Trokit për ta konfiguruar." - "Ndarja e internetit është çaktivizuar" "Kontakto me administratorin për detaje" "Statusi i zonës së qasjes dhe ndarjes së internetit" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index c5f84eb45d..e2e4dc6361 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Привезивање или хотспот је активан" "Додирните да бисте подесили." - "Привезивање је онемогућено" "Потражите детаље од администратора" "Статус хотспота и привезивања" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index d745dad2ff..72702c2858 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Internetdelning eller surfzon har aktiverats" "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" "Kontakta administratören om du vill veta mer" "Trådlös surfzon och internetdelning har inaktiverats" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index beaa306374..65e4aa8ceb 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kusambaza mtandao au mtandaopepe umewashwa" "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" "Wasiliana na msimamizi wako ili upate maelezo zaidi" "Mtandaopepe na hali ya kusambaza mtandao" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index bc8957e096..4aba62d4ab 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" "அமைக்க, தட்டவும்." - "டெதெரிங் முடக்கப்பட்டுள்ளது" "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index b7afdb4cad..1f91791341 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" "సెటప్ చేయడానికి ట్యాప్ చేయండి." - "టెథరింగ్ డిజేబుల్ చేయబడింది" "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index e60d43496e..44171c0db8 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 79523bb0f4..7347dd3e62 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktibo ang pag-tether o hotspot" "I-tap para i-set up." - "Naka-disable ang pag-tether" "Makipag-ugnayan sa iyong admin para sa mga detalye" "Status ng hotspot at pag-tether" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index cf100a42e2..32030f1765 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering veya hotspot etkin" "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" "Ayrıntılı bilgi için yöneticinize başvurun" "Hotspot ve tethering durumu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 0a8ceddad7..1ca89b3f78 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем чи точка доступу активні" "Натисніть, щоб налаштувати." - "Використання телефона як модема вимкнено" "Щоб дізнатися більше, зв\'яжіться з адміністратором" "Статус точки доступу та модема" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 043dba3161..d72c7d4195 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ٹیدرنگ یا ہاٹ اسپاٹ فعال" "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 5b9d62afd9..af3b2ebb35 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Modem rejimi yoki hotspot yoniq" "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" "Tafsilotlari uchun administratoringizga murojaat qiling" "Hotspot va modem rejimi holati" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 19240700ee..21a0735922 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -16,16 +16,14 @@ - "Tính năng chia sẻ kết nối hoặc điểm phát sóng đang hoạt động" + "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" "Hãy nhấn để thiết lập." - - "Đã tắt tính năng chia sẻ kết nối" + "Đã tắt tính năng chia sẻ Internet" "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" - "Trạng thái điểm phát sóng và trạng thái chia sẻ kết nối" + "Trạng thái điểm phát sóng và chia sẻ Internet" - diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index d137df5f33..98e3b4b46f 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "网络共享或热点已启用" "点按即可设置。" - "网络共享已停用" "如需了解详情,请与您的管理员联系" "热点和网络共享状态" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 12c071091b..9cafd42dd4 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "網絡共享或熱點已啟用" "輕按即可設定。" - "網絡共享已停用" "請聯絡您的管理員以瞭解詳情" "熱點和網絡共享狀態" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 24fb76e824..9d738a76eb 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "數據連線或無線基地台已啟用" "輕觸即可進行設定。" - "數據連線已停用" "詳情請洽你的管理員" "無線基地台與數據連線狀態" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index f4859aa195..f210f8726e 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" "Xhumana nomphathi wakho ukuze uthole imininingwane" "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" @@ -27,5 +26,4 @@ - From 1206400ccf0616667a65e2c9c1e67f50d3b6e430 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 22 Apr 2020 12:25:23 -0700 Subject: [PATCH 1002/1415] Reland "Pull service dumps to help debug test failures." + Convert tests to use Junit4 + Add annotations to specify required conditions for the test to run. This reverts commit 89099548f8ea46046095ccac1e82c2c88d1d0bee. Bug: 137859686 Change-Id: I7bb2a7e4b2dca3696761e7c030f3380b9226b676 Merged-In: I93317c201a0ea06732e29154ab7e140735381f59 --- tests/cts/hostside/AndroidTest.xml | 5 + tests/cts/hostside/app/Android.bp | 2 + tests/cts/hostside/app/AndroidManifest.xml | 3 +- .../net/hostside/AbstractAppIdleTestCase.java | 76 ++-- .../AbstractBatterySaverModeTestCase.java | 68 +--- .../hostside/AbstractDozeModeTestCase.java | 66 +--- ...ractRestrictBackgroundNetworkTestCase.java | 361 ++---------------- .../cts/net/hostside/AppIdleMeteredTest.java | 13 +- .../net/hostside/AppIdleNonMeteredTest.java | 7 +- .../hostside/BatterySaverModeMeteredTest.java | 13 +- .../BatterySaverModeNonMeteredTest.java | 9 +- .../cts/net/hostside/DataSaverModeTest.java | 66 ++-- .../cts/net/hostside/DozeModeMeteredTest.java | 13 +- .../net/hostside/DozeModeNonMeteredTest.java | 8 +- .../cts/net/hostside/DumpOnFailureRule.java | 91 +++++ .../MeterednessConfigurationRule.java | 60 +++ .../cts/net/hostside/MixedModesTest.java | 230 +++++------ .../cts/net/hostside/NetworkCallbackTest.java | 173 +++++---- .../net/hostside/NetworkPolicyTestUtils.java | 255 +++++++++++++ .../android/cts/net/hostside/Property.java | 70 ++++ .../cts/net/hostside/RequiredProperties.java | 31 ++ .../net/hostside/RequiredPropertiesRule.java | 90 +++++ .../cts/net/HostsideNetworkCallbackTests.java | 8 +- .../cts/net/HostsideNetworkTestCase.java | 3 +- 24 files changed, 939 insertions(+), 782 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index dbff1794e9..5479c51a4c 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -31,4 +31,9 @@

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - - /** - * Resets the (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void tearDownMeteredNetwork() throws Exception { + setBatterySaverMode(false); } + @Test public void testBackgroundNetworkAccess_enabled() throws Exception { - if (!isSupported()) return; - setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -118,9 +80,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { - if (!isSupported()) return; - setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -140,9 +101,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_disabled() throws Exception { - if (!isSupported()) return; - assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index f20f1d1c4d..6f32c563c1 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -16,20 +16,25 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE; + import android.os.SystemClock; -import android.util.Log; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Base class for metered and non-metered Doze Mode tests. */ +@RequiredProperties({DOZE_MODE}) abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { - @Override - protected final void setUp() throws Exception { + @Before + public final void setUp() throws Exception { super.setUp(); - if (!isSupported()) return; - // Set initial state. removePowerSaveModeWhitelist(TEST_APP2_PKG); removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); @@ -38,48 +43,15 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor registerBroadcastReceiver(); } - @Override - protected final void tearDown() throws Exception { + @After + public final void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - - try { - tearDownMeteredNetwork(); - } finally { - setDozeMode(false); - } - } - - @Override - protected boolean isSupported() throws Exception { - boolean supported = isDozeModeEnabled(); - if (!supported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); - } - return supported; - } - - /** - * Sets the initial (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - - /** - * Resets the (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void tearDownMeteredNetwork() throws Exception { + setDozeMode(false); } + @Test public void testBackgroundNetworkAccess_enabled() throws Exception { - if (!isSupported()) return; - setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -96,9 +68,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { - if (!isSupported()) return; - setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -118,19 +89,18 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_disabled() throws Exception { - if (!isSupported()) return; - assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(true); } + @RequiredProperties({NOT_LOW_RAM_DEVICE}) + @Test public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() throws Exception { - if (!isSupported() || isLowRamDevice()) return; - setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); try { registerNotificationListenerService(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 40d7e34fcc..57b7bb4f8d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -17,14 +17,22 @@ package com.android.cts.net.hostside; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static android.os.BatteryManager.BATTERY_PLUGGED_AC; import static android.os.BatteryManager.BATTERY_PLUGGED_USB; import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; -import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.app.ActivityManager; import android.app.Instrumentation; @@ -34,9 +42,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; @@ -44,24 +50,27 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; -import android.os.SystemProperties; import android.provider.Settings; import android.service.notification.NotificationListenerService; -import android.test.InstrumentationTestCase; -import android.text.TextUtils; import android.util.Log; -import com.android.compatibility.common.util.BatteryUtils; +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.runner.RunWith; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + /** * Superclass for tests related to background network restrictions. */ -abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase { - protected static final String TAG = "RestrictBackgroundNetworkTests"; +@RunWith(AndroidJUnit4.class) +public abstract class AbstractRestrictBackgroundNetworkTestCase { + public static final String TAG = "RestrictBackgroundNetworkTests"; protected static final String TEST_PKG = "com.android.cts.net.hostside"; protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; @@ -98,8 +107,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static int PROCESS_STATE_FOREGROUND_SERVICE; - private static final int PROCESS_STATE_TOP = 2; - private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; protected static final int TYPE_COMPONENT_ACTIVTIY = 0; @@ -126,22 +133,23 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private int mMyUid; - private String mMeteredWifi; private MyServiceClient mServiceClient; private String mDeviceIdleConstantsSetting; - private boolean mSupported; private boolean mIsLocationOn; - @Override + @Rule + public final RuleChain mRuleChain = RuleChain.outerRule(new DumpOnFailureRule()) + .around(new RequiredPropertiesRule()) + .around(new MeterednessConfigurationRule()); + protected void setUp() throws Exception { - super.setUp(); PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null); mInstrumentation = getInstrumentation(); - mContext = mInstrumentation.getContext(); - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mContext = getContext(); + mCm = getConnectivityManager(); + mWfm = getWifiManager(); mUid = getUid(TEST_APP2_PKG); mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); @@ -151,10 +159,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (!mIsLocationOn) { enableLocation(); } - mSupported = setUpActiveNetworkMeteringState(); setAppIdle(false); - Log.i(TAG, "Apps status on " + getName() + ":\n" + Log.i(TAG, "Apps status:\n" + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -165,16 +172,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final String currentConstants = executeShellCommand("settings get global app_idle_constants"); assertEquals(appIdleConstants, currentConstants); - } + } - @Override protected void tearDown() throws Exception { if (!mIsLocationOn) { disableLocation(); } mServiceClient.unbind(); - - super.tearDown(); } private void enableLocation() throws Exception { @@ -259,23 +263,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { final String status = mServiceClient.getRestrictBackgroundStatus(); assertNotNull("didn't get API status from app2", status); - final String actualStatus = toString(Integer.parseInt(status)); - assertEquals("wrong status", toString(expectedStatus), actualStatus); - } - - protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { - final int actualStatus = mCm.getRestrictBackgroundStatus(); - assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); - } - - protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { - final int actualStatus = mCm.getRestrictBackgroundStatus(); - if (expectedStatus != actualStatus) { - Log.d(TAG, "Expected: " + toString(expectedStatus) - + " but actual: " + toString(actualStatus)); - return false; - } - return true; + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(Integer.parseInt(status))); } protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { @@ -297,28 +286,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */); } - /** - * Whether this device suport this type of test. - * - *

    Should be overridden when necessary (but always calling - * {@code super.isSupported()} first), and explicitly used before each test - * Example: - * - *

    
    -     * public void testSomething() {
    -     *    if (!isSupported()) return;
    -     * 
    - * - * @return {@code true} by default. - */ - protected boolean isSupported() throws Exception { - return mSupported; - } - - protected boolean isBatterySaverSupported() { - return BatteryUtils.isBatterySaverSupported(); - } - /** * Asserts that an app always have access while on foreground or running a foreground service. * @@ -387,23 +354,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state ); } - /** - * As per CDD requirements, if the device doesn't support data saver mode then - * ConnectivityManager.getRestrictBackgroundStatus() will always return - * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if - * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns - * RESTRICT_BACKGROUND_STATUS_DISABLED or not. - */ - protected boolean isDataSaverSupported() throws Exception { - assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - try { - setRestrictBackground(true); - return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - } finally { - setRestrictBackground(false); - } - } - /** * Returns whether an app state should be considered "background" for restriction purposes. */ @@ -443,40 +393,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // Exponential back-off. timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS); } - dumpOnFailure(); fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries + " attempts.\nLast error: " + error); } - private void dumpOnFailure() throws Exception { - dumpAllNetworkRules(); - Log.d(TAG, "Usagestats dump: " + getUsageStatsDump()); - executeShellCommand("settings get global app_idle_constants"); - } - - private void dumpAllNetworkRules() throws Exception { - final String networkManagementDump = runShellCommand(mInstrumentation, - "dumpsys network_management").trim(); - final String networkPolicyDump = runShellCommand(mInstrumentation, - "dumpsys netpolicy").trim(); - TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); - splitter.setString(networkManagementDump); - String next; - Log.d(TAG, ">>> Begin network_management dump"); - while (splitter.hasNext()) { - next = splitter.next(); - Log.d(TAG, next); - } - Log.d(TAG, "<<< End network_management dump"); - splitter.setString(networkPolicyDump); - Log.d(TAG, ">>> Begin netpolicy dump"); - while (splitter.hasNext()) { - next = splitter.next(); - Log.d(TAG, next); - } - Log.d(TAG, "<<< End netpolicy dump"); - } - /** * Checks whether the network is available as expected. * @@ -528,22 +448,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return errors.toString(); } - protected boolean isLowRamDevice() { - final ActivityManager am = (ActivityManager) mContext.getSystemService( - Context.ACTIVITY_SERVICE); - return am.isLowRamDevice(); - } - - protected String executeShellCommand(String command) throws Exception { - final String result = runShellCommand(mInstrumentation, command).trim(); - if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'"); - return result; - } - /** * Runs a Shell command which is not expected to generate output. */ - protected void executeSilentShellCommand(String command) throws Exception { + protected void executeSilentShellCommand(String command) { final String result = executeShellCommand(command); assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty()); } @@ -572,10 +480,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation }); } - protected void assertDelayedShellCommand(String command, ExpectResultChecker checker) - throws Exception { - assertDelayedShellCommand(command, 5, 1, checker); - } protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, ExpectResultChecker checker) throws Exception { String result = ""; @@ -592,159 +496,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation + " attempts. Last result: '" + result + "'"); } - /** - * Sets the initial metering state for the active network. - * - *

    It's called on setup and by default does nothing - it's up to the - * subclasses to override. - * - * @return whether the tests in the subclass are supported on this device. - */ - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return true; - } - - /** - * Makes sure the active network is not metered. - * - *

    If the device does not supoprt un-metered networks (for example if it - * only has cellular data but not wi-fi), it should return {@code false}; - * otherwise, it should return {@code true} (or fail if the un-metered - * network could not be set). - * - * @return {@code true} if the network is now unmetered. - */ - protected boolean setUnmeteredNetwork() throws Exception { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - assertNotNull("Could not get active network", info); - if (!mCm.isActiveNetworkMetered()) { - Log.d(TAG, "Active network is not metered: " + info); - } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { - Log.i(TAG, "Setting active WI-FI network as not metered: " + info ); - setWifiMeteredStatus(false); - } else { - Log.d(TAG, "Active network cannot be set to un-metered: " + info); - return false; - } - assertActiveNetworkMetered(false); // Sanity check. - return true; - } - - /** - * Enables metering on the active network if supported. - * - *

    If the device does not support metered networks it should return - * {@code false}; otherwise, it should return {@code true} (or fail if the - * metered network could not be set). - * - * @return {@code true} if the network is now metered. - */ - protected boolean setMeteredNetwork() throws Exception { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - final boolean metered = mCm.isActiveNetworkMetered(); - if (metered) { - Log.d(TAG, "Active network already metered: " + info); - return true; - } else if (info.getType() != ConnectivityManager.TYPE_WIFI) { - Log.w(TAG, "Active network does not support metering: " + info); - return false; - } else { - Log.w(TAG, "Active network not metered: " + info); - } - final String netId = setWifiMeteredStatus(true); - - // Set flag so status is reverted on resetMeteredNetwork(); - mMeteredWifi = netId; - // Sanity check. - assertWifiMeteredStatus(netId, true); - assertActiveNetworkMetered(true); - return true; - } - - /** - * Resets the device metering state to what it was before the test started. - * - *

    This reverts any metering changes made by {@code setMeteredNetwork}. - */ - protected void resetMeteredNetwork() throws Exception { - if (mMeteredWifi != null) { - Log.i(TAG, "resetMeteredNetwork(): SID '" + mMeteredWifi - + "' was set as metered by test case; resetting it"); - setWifiMeteredStatus(mMeteredWifi, false); - assertActiveNetworkMetered(false); // Sanity check. - } - } - - private void assertActiveNetworkMetered(boolean expected) throws Exception { - final int maxTries = 5; - NetworkInfo info = null; - for (int i = 1; i <= maxTries; i++) { - info = mCm.getActiveNetworkInfo(); - if (info == null) { - Log.v(TAG, "No active network info on attempt #" + i - + "; sleeping 1s before polling again"); - } else if (mCm.isActiveNetworkMetered() != expected) { - Log.v(TAG, "Wrong metered status for active network " + info + "; expected=" - + expected + "; sleeping 1s before polling again"); - } else { - break; - } - Thread.sleep(SECOND_IN_MS); - } - assertNotNull("No active network after " + maxTries + " attempts", info); - assertEquals("Wrong metered status for active network " + info, expected, - mCm.isActiveNetworkMetered()); - } - - private String setWifiMeteredStatus(boolean metered) throws Exception { - // We could call setWifiEnabled() here, but it might take sometime to be in a consistent - // state (for example, if one of the saved network is not properly authenticated), so it's - // better to let the hostside test take care of that. - assertTrue("wi-fi is disabled", mWfm.isWifiEnabled()); - // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests - // to make the actual verification of restrictions optional. - final String ssid = mWfm.getConnectionInfo().getSSID(); - return setWifiMeteredStatus(ssid, metered); - } - - private String setWifiMeteredStatus(String ssid, boolean metered) throws Exception { - assertNotNull("null SSID", ssid); - final String netId = ssid.trim().replaceAll("\"", ""); // remove quotes, if any. - assertFalse("empty SSID", ssid.isEmpty()); - - Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); - final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered; - assertDelayedShellCommand(setCommand, ""); - - return netId; - } - - private void assertWifiMeteredStatus(String netId, boolean status) throws Exception { - final String command = "cmd netpolicy list wifi-networks"; - final String expectedLine = netId + ";" + status; - assertDelayedShellCommand(command, new ExpectResultChecker() { - - @Override - public boolean isExpected(String result) { - return result.contains(expectedLine); - } - - @Override - public String getExpected() { - return "line containing " + expectedLine; - } - }); - } - - protected void setRestrictBackground(boolean enabled) throws Exception { - executeShellCommand("cmd netpolicy set restrict-background " + enabled); - final String output = executeShellCommand("cmd netpolicy get restrict-background "); - final String expectedSuffix = enabled ? "enabled" : "disabled"; - // TODO: use MoreAsserts? - assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", - output.endsWith(expectedSuffix)); - } - protected void addRestrictBackgroundWhitelist(int uid) throws Exception { executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); @@ -924,7 +675,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void setDozeMode(boolean enabled) throws Exception { // Sanity check, since tests should check beforehand.... - assertTrue("Device does not support Doze Mode", isDozeModeEnabled()); + assertTrue("Device does not support Doze Mode", isDozeModeSupported()); Log.i(TAG, "Setting Doze Mode to " + enabled); if (enabled) { @@ -944,43 +695,16 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE"); } - protected boolean isDozeModeEnabled() throws Exception { - final String result = executeShellCommand("cmd deviceidle enabled deep").trim(); - return result.equals("1"); - } - protected void setAppIdle(boolean enabled) throws Exception { Log.i(TAG, "Setting app idle to " + enabled); executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); assertAppIdle(enabled); // Sanity check } - private String getUsageStatsDump() throws Exception { - final String output = runShellCommand(mInstrumentation, "dumpsys usagestats").trim(); - final StringBuilder sb = new StringBuilder(); - final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); - splitter.setString(output); - String str; - while (splitter.hasNext()) { - str = splitter.next(); - if (str.contains("package=") - && !str.contains(TEST_PKG) && !str.contains(TEST_APP2_PKG)) { - continue; - } - if (str.trim().startsWith("config=") || str.trim().startsWith("time=")) { - continue; - } - sb.append(str).append('\n'); - } - return sb.toString(); - } - protected void assertAppIdle(boolean enabled) throws Exception { try { assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled); } catch (Throwable e) { - Log.d(TAG, "UsageStats dump:\n" + getUsageStatsDump()); - executeShellCommand("settings get global app_idle_constants"); throw e; } } @@ -1061,12 +785,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // App didn't come to foreground when the activity is started, so try again. assertForegroundNetworkAccess(); } else { - dumpOnFailure(); fail("Network is not available for app2 (" + mUid + "): " + errors[0]); } } } else { - dumpOnFailure(); fail("Timed out waiting for network availability status from app2 (" + mUid + ")"); } } else { @@ -1150,19 +872,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } } - private String toString(int status) { - switch (status) { - case RESTRICT_BACKGROUND_STATUS_DISABLED: - return "DISABLED"; - case RESTRICT_BACKGROUND_STATUS_WHITELISTED: - return "WHITELISTED"; - case RESTRICT_BACKGROUND_STATUS_ENABLED: - return "ENABLED"; - default: - return "UNKNOWN_STATUS_" + status; - } - } - private ProcessState getProcessStateByUid(int uid) throws Exception { return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid)); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java index 622d99361f..f1858d65a5 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class AppIdleMeteredTest extends AbstractAppIdleTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java index bde71f9100..e737a6dabe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java @@ -16,9 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase { - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java index 3071cfe3f1..c78ca2ec77 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index 6d3076fe0e..fb52a540d8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -16,10 +16,9 @@ package com.android.cts.net.hostside; -public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) +public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index cfe6a73a0f..aa2c914e02 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,24 +20,33 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -import android.util.Log; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE; + +import static org.junit.Assert.fail; import com.android.compatibility.common.util.CddTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import androidx.test.filters.LargeTest; + +@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK}) +@LargeTest public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { "com.android.providers.downloads" }; - private boolean mIsDataSaverSupported; - - @Override + @Before public void setUp() throws Exception { super.setUp(); - mIsDataSaverSupported = isDataSaverSupported(); - // Set initial state. setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); @@ -47,36 +56,15 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(0); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - - try { - resetMeteredNetwork(); - } finally { - setRestrictBackground(false); - } - } - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected boolean isSupported() throws Exception { - if (!mIsDataSaverSupported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Data Saver Mode"); - } - return mIsDataSaverSupported && super.isSupported(); + setRestrictBackground(false); } + @Test public void testGetRestrictBackgroundStatus_disabled() throws Exception { - if (!isSupported()) return; - assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted @@ -88,9 +76,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); } + @Test public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { - if (!isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -107,9 +94,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); } + @Test public void testGetRestrictBackgroundStatus_enabled() throws Exception { - if (!isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -142,9 +128,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertBackgroundNetworkAccess(false); } + @Test public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { - if (!isSupported()) return; - addRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -180,9 +165,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); } + @Test public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { - if (!isSupported()) return; - final StringBuilder error = new StringBuilder(); for (String packageName : REQUIRED_WHITELISTED_PACKAGES) { int uid = -1; @@ -202,10 +186,10 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } } + @RequiredProperties({NO_DATA_SAVER_MODE}) @CddTest(requirement="7.4.7/C-2-2") + @Test public void testBroadcastNotSentOnUnsupportedDevices() throws Exception { - if (isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(0); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java index e4189af587..4306c991c2 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class DozeModeMeteredTest extends AbstractDozeModeTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java index edbbb9e1ce..1e89f158a3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java @@ -16,10 +16,8 @@ package com.android.cts.net.hostside; -public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } +@RequiredProperties({NON_METERED_NETWORK}) +public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java new file mode 100644 index 0000000000..cedd62a0bc --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG; + +import android.os.Environment; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import com.android.compatibility.common.util.OnFailureRule; + +import org.junit.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class DumpOnFailureRule extends OnFailureRule { + private File mDumpDir = new File(Environment.getExternalStorageDirectory(), + "CtsHostsideNetworkTests"); + + @Override + public void onTestFailure(Statement base, Description description, Throwable throwable) { + final String testName = description.getClassName() + "_" + description.getMethodName(); + + if (throwable instanceof AssumptionViolatedException) { + Log.d(TAG, "Skipping test " + testName + ": " + throwable); + return; + } + + prepareDumpRootDir(); + final File dumpFile = new File(mDumpDir, "dump-" + testName); + Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath()); + try (FileOutputStream out = new FileOutputStream(dumpFile)) { + for (String cmd : new String[] { + "dumpsys netpolicy", + "dumpsys network_management", + "dumpsys usagestats " + TEST_PKG, + "dumpsys usagestats appstandby", + }) { + dumpCommandOutput(out, cmd); + } + } catch (FileNotFoundException e) { + Log.e(TAG, "Error opening file: " + dumpFile, e); + } catch (IOException e) { + Log.e(TAG, "Error closing file: " + dumpFile, e); + } + } + + void dumpCommandOutput(FileOutputStream out, String cmd) { + final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation() + .getUiAutomation().executeShellCommand(cmd); + try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8)); + FileUtils.copy(in, out); + out.write("\n\n=================================================================\n\n" + .getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + Log.e(TAG, "Error dumping '" + cmd + "'", e); + } + } + + void prepareDumpRootDir() { + if (!mDumpDir.exists() && !mDumpDir.mkdir()) { + Log.e(TAG, "Error creating " + mDumpDir); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java new file mode 100644 index 0000000000..8fadf9e295 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.resetMeteredNetwork; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupMeteredNetwork; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +import android.util.ArraySet; +import android.util.Pair; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class MeterednessConfigurationRule extends BeforeAfterRule { + private Pair mSsidAndInitialMeteredness; + + @Override + public void onBefore(Statement base, Description description) throws Throwable { + final ArraySet requiredProperties + = RequiredPropertiesRule.getRequiredProperties(); + if (requiredProperties.contains(METERED_NETWORK)) { + configureNetworkMeteredness(true); + } else if (requiredProperties.contains(NON_METERED_NETWORK)) { + configureNetworkMeteredness(false); + } + } + + @Override + public void onAfter(Statement base, Description description) throws Throwable { + resetNetworkMeteredness(); + } + + public void configureNetworkMeteredness(boolean metered) throws Exception { + mSsidAndInitialMeteredness = setupMeteredNetwork(metered); + } + + public void resetNetworkMeteredness() throws Exception { + if (mSsidAndInitialMeteredness != null) { + resetMeteredNetwork(mSsidAndInitialMeteredness.first, + mSsidAndInitialMeteredness.second); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index b1a21867b3..c9edda6e0b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -15,9 +15,21 @@ */ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + import android.os.SystemClock; import android.util.Log; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + /** * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode * and Data Saver Mode) are applied simultaneously. @@ -29,12 +41,10 @@ import android.util.Log; public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String TAG = "MixedModesTest"; - @Override + @Before public void setUp() throws Exception { super.setUp(); - if (!isSupported()) return; - // Set initial state. removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); @@ -44,12 +54,10 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { registerBroadcastReceiver(); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - try { setRestrictBackground(false); } finally { @@ -57,34 +65,15 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } - @Override - public boolean isSupported() throws Exception { - if (!isDozeModeEnabled()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); - return false; - } - return true; - } - /** * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, METERED_NETWORK}) + @Test public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) return; - - Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); - if (!setMeteredNetwork()) { - Log.w(TAG, "testDataAndBatterySaverModes_meteredNetwork() skipped because " - + "device cannot use a metered network"); - return; - } - + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); try { setRestrictBackground(true); setBatterySaverMode(true); @@ -137,7 +126,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { removeRestrictBackgroundBlacklist(mUid); removePowerSaveModeWhitelist(TEST_APP2_PKG); } finally { - resetMeteredNetwork(); + meterednessConfiguration.resetNetworkMeteredness(); } } @@ -145,86 +134,75 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered * networks. */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, NON_METERED_NETWORK}) + @Test public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + setRestrictBackground(true); + setBatterySaverMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); } - if (!isSupported()) return; - - if (!setUnmeteredNetwork()) { - Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network" - + " is metered"); - return; - } - Log.i(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() tests"); - setRestrictBackground(true); - setBatterySaverMode(true); - - Log.v(TAG, "Not whitelisted for any."); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - - Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); - addRestrictBackgroundWhitelist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - - Log.v(TAG, "Whitelisted for both."); - addRestrictBackgroundWhitelist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundBlacklist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removeRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); } /** * Tests that powersave whitelists works as expected when doze and battery saver modes * are enabled. */ + @RequiredProperties({DOZE_MODE, BATTERY_SAVER_MODE}) + @Test public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setDozeMode(true); @@ -250,11 +228,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests that powersave whitelists works as expected when doze and appIdle modes * are enabled. */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -276,11 +252,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -299,16 +273,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setAppIdle(true); @@ -330,11 +297,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { /** * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled. */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -353,11 +318,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -380,16 +343,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setAppIdle(true); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index 24dde9d356..ed397b91fc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -16,15 +16,26 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import android.net.Network; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.Objects; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase { - private boolean mIsDataSaverSupported; private Network mNetwork; private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback(); @@ -132,108 +143,122 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } } - @Override + @Before public void setUp() throws Exception { super.setUp(); - mIsDataSaverSupported = isDataSaverSupported(); - mNetwork = mCm.getActiveNetwork(); - // Set initial state. - setBatterySaverMode(false); registerBroadcastReceiver(); - if (!mIsDataSaverSupported) return; - setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(0); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!mIsDataSaverSupported) return; + setRestrictBackground(false); + setBatterySaverMode(false); + } + @RequiredProperties({DATA_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_dataSaver() throws Exception { + // Initial state + setBatterySaverMode(false); + setRestrictBackground(false); + + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); try { - resetMeteredNetwork(); + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable restrict background + setRestrictBackground(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Add to whitelist + addRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Remove from whitelist + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } + + // Set to non-metered network + meterednessConfiguration.configureNetworkMeteredness(false); + try { + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Disable restrict background, should not trigger callback setRestrictBackground(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.assertNoCallback(); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); } } - public void testOnBlockedStatusChanged_data_saver() throws Exception { - if (!mIsDataSaverSupported) return; - - // Prepare metered wifi - if (!setMeteredNetwork()) return; - - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable restrict background - setRestrictBackground(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Add to whitelist - addRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Remove from whitelist - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Set to non-metered network - setUnmeteredNetwork(); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Disable restrict background, should not trigger callback + @RequiredProperties({BATTERY_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_powerSaver() throws Exception { + // Set initial state. + setBatterySaverMode(false); setRestrictBackground(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.assertNoCallback(); - } + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); + try { + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - public void testOnBlockedStatusChanged_power_saver() throws Exception { - // Prepare metered wifi - if (!setMeteredNetwork()) return; + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } // Set to non-metered network - setUnmeteredNetwork(); - mTestNetworkCallback.assertNoCallback(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + mTestNetworkCallback.assertNoCallback(); - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } } // TODO: 1. test against VPN lockdown. diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java new file mode 100644 index 0000000000..ca2864c0b8 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.ActivityManager; +import android.app.Instrumentation; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.wifi.WifiManager; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; + +import com.android.compatibility.common.util.AppStandbyUtils; +import com.android.compatibility.common.util.BatteryUtils; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class NetworkPolicyTestUtils { + + private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 5000; + + private static ConnectivityManager mCm; + private static WifiManager mWm; + + private static Boolean mBatterySaverSupported; + private static Boolean mDataSaverSupported; + private static Boolean mDozeModeSupported; + private static Boolean mAppStandbySupported; + + private NetworkPolicyTestUtils() {} + + public static boolean isBatterySaverSupported() { + if (mBatterySaverSupported == null) { + mBatterySaverSupported = BatteryUtils.isBatterySaverSupported(); + } + return mBatterySaverSupported; + } + + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + public static boolean isDataSaverSupported() { + if (mDataSaverSupported == null) { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + mDataSaverSupported = !isMyRestrictBackgroundStatus( + RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + return mDataSaverSupported; + } + + public static boolean isDozeModeSupported() { + if (mDozeModeSupported == null) { + final String result = executeShellCommand("cmd deviceidle enabled deep"); + mDozeModeSupported = result.equals("1"); + } + return mDozeModeSupported; + } + + public static boolean isAppStandbySupported() { + if (mAppStandbySupported == null) { + mAppStandbySupported = AppStandbyUtils.isAppStandbyEnabled(); + } + return mAppStandbySupported; + } + + public static boolean isLowRamDevice() { + final ActivityManager am = (ActivityManager) getContext().getSystemService( + Context.ACTIVITY_SERVICE); + return am.isLowRamDevice(); + } + + public static boolean isActiveNetworkMetered(boolean metered) { + return getConnectivityManager().isActiveNetworkMetered() == metered; + } + + public static boolean canChangeActiveNetworkMeteredness() { + final Network activeNetwork = getConnectivityManager().getActiveNetwork(); + final NetworkCapabilities networkCapabilities + = getConnectivityManager().getNetworkCapabilities(activeNetwork); + return networkCapabilities.hasTransport(TRANSPORT_WIFI); + } + + public static Pair setupMeteredNetwork(boolean metered) throws Exception { + if (isActiveNetworkMetered(metered)) { + return null; + } + final String ssid = unquoteSSID(getWifiManager().getConnectionInfo().getSSID()); + setWifiMeteredStatus(ssid, metered); + return Pair.create(ssid, !metered); + } + + public static void resetMeteredNetwork(String ssid, boolean metered) throws Exception { + setWifiMeteredStatus(ssid, metered); + } + + public static void setWifiMeteredStatus(String ssid, boolean metered) throws Exception { + assertFalse("SSID should not be empty", TextUtils.isEmpty(ssid)); + final String cmd = "cmd netpolicy set metered-network " + ssid + " " + metered; + executeShellCommand(cmd); + assertWifiMeteredStatus(ssid, metered); + assertActiveNetworkMetered(metered); + } + + public static void assertWifiMeteredStatus(String ssid, boolean expectedMeteredStatus) { + final String result = executeShellCommand("cmd netpolicy list wifi-networks"); + final String expectedLine = ssid + ";" + expectedMeteredStatus; + assertTrue("Expected line: " + expectedLine + "; Actual result: " + result, + result.contains(expectedLine)); + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + public static void assertActiveNetworkMetered(boolean expectedMeteredStatus) throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final NetworkCallback networkCallback = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); + if (metered == expectedMeteredStatus) { + latch.countDown(); + } + } + }; + // Registering a callback here guarantees onCapabilitiesChanged is called immediately + // with the current setting. Therefore, if the setting has already been changed, + // this method will return right away, and if not it will wait for the setting to change. + getConnectivityManager().registerDefaultNetworkCallback(networkCallback); + if (!latch.await(TIMEOUT_CHANGE_METEREDNESS_MS, TimeUnit.MILLISECONDS)) { + fail("Timed out waiting for active network metered status to change to " + + expectedMeteredStatus + " ; network = " + + getConnectivityManager().getActiveNetwork()); + } + getConnectivityManager().unregisterNetworkCallback(networkCallback); + } + + public static void setRestrictBackground(boolean enabled) { + executeShellCommand("cmd netpolicy set restrict-background " + enabled); + final String output = executeShellCommand("cmd netpolicy get restrict-background"); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + + public static boolean isMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "MyRestrictBackgroundStatus: " + + "Expected: " + restrictBackgroundValueToString(expectedStatus) + + "; Actual: " + restrictBackgroundValueToString(actualStatus)); + return false; + } + return true; + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + private static String unquoteSSID(String ssid) { + // SSID is returned surrounded by quotes if it can be decoded as UTF-8. + // Otherwise it's guaranteed not to start with a quote. + if (ssid.charAt(0) == '"') { + return ssid.substring(1, ssid.length() - 1); + } else { + return ssid; + } + } + + public static String restrictBackgroundValueToString(int status) { + switch (status) { + case RESTRICT_BACKGROUND_STATUS_DISABLED: + return "DISABLED"; + case RESTRICT_BACKGROUND_STATUS_WHITELISTED: + return "WHITELISTED"; + case RESTRICT_BACKGROUND_STATUS_ENABLED: + return "ENABLED"; + default: + return "UNKNOWN_STATUS_" + status; + } + } + + public static String executeShellCommand(String command) { + final String result = runShellCommand(command).trim(); + Log.d(TAG, "Output of '" + command + "': '" + result + "'"); + return result; + } + + public static void assertMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(actualStatus)); + } + + public static ConnectivityManager getConnectivityManager() { + if (mCm == null) { + mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + } + return mCm; + } + + public static WifiManager getWifiManager() { + if (mWm == null) { + mWm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + } + return mWm; + } + + public static Context getContext() { + return getInstrumentation().getContext(); + } + + public static Instrumentation getInstrumentation() { + return InstrumentationRegistry.getInstrumentation(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java new file mode 100644 index 0000000000..18805f9613 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDataSaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isLowRamDevice; + +public enum Property { + BATTERY_SAVER_MODE(1 << 0) { + public boolean isSupported() { return isBatterySaverSupported(); } + }, + + DATA_SAVER_MODE(1 << 1) { + public boolean isSupported() { return isDataSaverSupported(); } + }, + + NO_DATA_SAVER_MODE(~DATA_SAVER_MODE.getValue()) { + public boolean isSupported() { return !isDataSaverSupported(); } + }, + + DOZE_MODE(1 << 2) { + public boolean isSupported() { return isDozeModeSupported(); } + }, + + APP_STANDBY_MODE(1 << 3) { + public boolean isSupported() { return isAppStandbySupported(); } + }, + + NOT_LOW_RAM_DEVICE(1 << 4) { + public boolean isSupported() { return !isLowRamDevice(); } + }, + + METERED_NETWORK(1 << 5) { + public boolean isSupported() { + return isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness(); + } + }, + + NON_METERED_NETWORK(~METERED_NETWORK.getValue()) { + public boolean isSupported() { + return isActiveNetworkMetered(false) || canChangeActiveNetworkMeteredness(); + } + }; + + private int mValue; + + Property(int value) { mValue = value; } + + public int getValue() { return mValue; } + + abstract boolean isSupported(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java new file mode 100644 index 0000000000..96838bba0a --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({METHOD, TYPE}) +@Inherited +public @interface RequiredProperties { + Property[] value(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java new file mode 100644 index 0000000000..1e333200db --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.Log; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.Assume; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.util.ArrayList; +import java.util.Collections; + +public class RequiredPropertiesRule extends BeforeAfterRule { + + private static ArraySet mRequiredProperties; + + @Override + public void onBefore(Statement base, Description description) { + mRequiredProperties = getAllRequiredProperties(description); + + final String testName = description.getClassName() + "#" + description.getMethodName(); + assertTestIsValid(testName, mRequiredProperties); + Log.i(TAG, "Running test " + testName + " with required properties: " + + propertiesToString(mRequiredProperties)); + } + + private ArraySet getAllRequiredProperties(Description description) { + final ArraySet allRequiredProperties = new ArraySet<>(); + RequiredProperties requiredProperties = description.getAnnotation(RequiredProperties.class); + if (requiredProperties != null) { + Collections.addAll(allRequiredProperties, requiredProperties.value()); + } + + for (Class clazz = description.getTestClass(); + clazz != null; clazz = clazz.getSuperclass()) { + requiredProperties = clazz.getDeclaredAnnotation(RequiredProperties.class); + if (requiredProperties == null) { + continue; + } + for (Property requiredProperty : requiredProperties.value()) { + if (!allRequiredProperties.contains(~requiredProperty.getValue())) { + allRequiredProperties.add(requiredProperty); + } + } + } + return allRequiredProperties; + } + + private void assertTestIsValid(String testName, ArraySet requiredProperies) { + if (requiredProperies == null) { + return; + } + final ArrayList unsupportedProperties = new ArrayList<>(); + for (Property property : requiredProperies) { + if (!property.isSupported()) { + unsupportedProperties.add(property); + } + } + Assume.assumeTrue("Unsupported properties: " + + propertiesToString(unsupportedProperties), unsupportedProperties.isEmpty()); + } + + public static ArraySet getRequiredProperties() { + return mRequiredProperties; + } + + private static String propertiesToString(Iterable properties) { + return "[" + TextUtils.join(",", properties) + "]"; + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java index 8d6c4acd7d..1312085478 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java @@ -29,14 +29,14 @@ public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase { uninstallPackage(TEST_APP2_PKG, true); } - public void testOnBlockedStatusChanged_data_saver() throws Exception { + public void testOnBlockedStatusChanged_dataSaver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_data_saver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_dataSaver"); } - public void testOnBlockedStatusChanged_power_saver() throws Exception { + public void testOnBlockedStatusChanged_powerSaver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_power_saver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_powerSaver"); } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index a2443b391a..ce203795f9 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -79,7 +79,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void installPackage(String apk) throws FileNotFoundException, DeviceNotAvailableException { CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); - assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false)); + assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), + false /* reinstall */, true /* grantPermissions */)); } protected void uninstallPackage(String packageName, boolean shouldSucceed) From b953c0189009e2076cad6eaa16fcf1a7b5eb865b Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Wed, 22 Apr 2020 13:18:34 -0700 Subject: [PATCH 1003/1415] Import translations. DO NOT MERGE Change-Id: Ida094af29a7153c19432b3e9e66290c31b54bd3d Auto-generated-cl: translation import --- Tethering/res/values-af/strings.xml | 2 -- Tethering/res/values-am/strings.xml | 2 -- Tethering/res/values-ar/strings.xml | 2 -- Tethering/res/values-as/strings.xml | 2 -- Tethering/res/values-az/strings.xml | 2 -- Tethering/res/values-b+sr+Latn/strings.xml | 2 -- Tethering/res/values-be/strings.xml | 2 -- Tethering/res/values-bg/strings.xml | 2 -- Tethering/res/values-bn/strings.xml | 2 -- Tethering/res/values-bs/strings.xml | 2 -- Tethering/res/values-ca/strings.xml | 2 -- Tethering/res/values-cs/strings.xml | 2 -- Tethering/res/values-da/strings.xml | 2 -- Tethering/res/values-de/strings.xml | 2 -- Tethering/res/values-el/strings.xml | 2 -- Tethering/res/values-en-rAU/strings.xml | 2 -- Tethering/res/values-en-rCA/strings.xml | 2 -- Tethering/res/values-en-rGB/strings.xml | 2 -- Tethering/res/values-en-rIN/strings.xml | 2 -- Tethering/res/values-en-rXC/strings.xml | 2 -- Tethering/res/values-es-rUS/strings.xml | 2 -- Tethering/res/values-es/strings.xml | 2 -- Tethering/res/values-et/strings.xml | 2 -- Tethering/res/values-eu/strings.xml | 6 ++---- Tethering/res/values-fa/strings.xml | 2 -- Tethering/res/values-fi/strings.xml | 2 -- Tethering/res/values-fr-rCA/strings.xml | 2 -- Tethering/res/values-fr/strings.xml | 2 -- Tethering/res/values-gl/strings.xml | 2 -- Tethering/res/values-gu/strings.xml | 2 -- Tethering/res/values-hi/strings.xml | 2 -- Tethering/res/values-hr/strings.xml | 2 -- Tethering/res/values-hu/strings.xml | 2 -- Tethering/res/values-hy/strings.xml | 2 -- Tethering/res/values-in/strings.xml | 2 -- Tethering/res/values-is/strings.xml | 2 -- Tethering/res/values-it/strings.xml | 2 -- Tethering/res/values-iw/strings.xml | 2 -- Tethering/res/values-ja/strings.xml | 2 -- Tethering/res/values-ka/strings.xml | 2 -- Tethering/res/values-kk/strings.xml | 2 -- Tethering/res/values-km/strings.xml | 2 -- Tethering/res/values-kn/strings.xml | 2 -- Tethering/res/values-ko/strings.xml | 2 -- Tethering/res/values-ky/strings.xml | 2 -- Tethering/res/values-lo/strings.xml | 2 -- Tethering/res/values-lt/strings.xml | 2 -- Tethering/res/values-lv/strings.xml | 2 -- Tethering/res/values-mcc310-mnc004-af/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-am/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ar/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-as/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-az/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-b+sr+Latn/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-be/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-bg/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-bn/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-bs/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ca/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-cs/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-da/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-de/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-el/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rAU/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rCA/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rGB/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rIN/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-en-rXC/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-es-rUS/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-es/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-et/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-eu/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-fa/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-fi/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-fr-rCA/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-fr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-gl/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-gu/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-hi/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-hr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-hu/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-hy/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-in/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-is/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-it/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-iw/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ja/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ka/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-kk/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-km/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-kn/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ko/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ky/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-lo/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-lt/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-lv/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-mk/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ml/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-mn/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-mr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ms/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-my/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-nb/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 13 ++++++++----- Tethering/res/values-mcc310-mnc004-nl/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-or/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-pa/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-pl/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-pt-rBR/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-pt-rPT/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-pt/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ro/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ru/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-si/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sk/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sl/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sq/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sv/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-sw/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ta/strings.xml | 13 ++++++++----- Tethering/res/values-mcc310-mnc004-te/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-th/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-tl/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-tr/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-uk/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-ur/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-uz/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-vi/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rCN/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rHK/strings.xml | 9 ++++----- .../res/values-mcc310-mnc004-zh-rTW/strings.xml | 9 ++++----- Tethering/res/values-mcc310-mnc004-zu/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-af/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-am/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ar/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-as/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-az/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-b+sr+Latn/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-be/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-bg/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-bn/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-bs/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ca/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-cs/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-da/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-de/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-el/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rAU/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rCA/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rGB/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rIN/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-en-rXC/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-es-rUS/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-es/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-et/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-eu/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-fa/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-fi/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-fr-rCA/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-fr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-gl/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-gu/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-hi/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-hr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-hu/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-hy/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-in/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-is/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-it/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-iw/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ja/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ka/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-kk/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-km/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-kn/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ko/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ky/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-lo/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-lt/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-lv/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-mk/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ml/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-mn/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-mr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ms/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-my/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-nb/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 13 ++++++++----- Tethering/res/values-mcc311-mnc480-nl/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-or/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-pa/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-pl/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-pt-rBR/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-pt-rPT/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-pt/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ro/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ru/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-si/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sk/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sl/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sq/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sv/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-sw/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ta/strings.xml | 13 ++++++++----- Tethering/res/values-mcc311-mnc480-te/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-th/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-tl/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-tr/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-uk/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-ur/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-uz/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-vi/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rCN/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rHK/strings.xml | 9 ++++----- .../res/values-mcc311-mnc480-zh-rTW/strings.xml | 9 ++++----- Tethering/res/values-mcc311-mnc480-zu/strings.xml | 9 ++++----- Tethering/res/values-mk/strings.xml | 2 -- Tethering/res/values-ml/strings.xml | 2 -- Tethering/res/values-mn/strings.xml | 2 -- Tethering/res/values-mr/strings.xml | 2 -- Tethering/res/values-ms/strings.xml | 2 -- Tethering/res/values-my/strings.xml | 2 -- Tethering/res/values-nb/strings.xml | 2 -- Tethering/res/values-ne/strings.xml | 2 -- Tethering/res/values-nl/strings.xml | 2 -- Tethering/res/values-or/strings.xml | 2 -- Tethering/res/values-pa/strings.xml | 2 -- Tethering/res/values-pl/strings.xml | 2 -- Tethering/res/values-pt-rBR/strings.xml | 2 -- Tethering/res/values-pt-rPT/strings.xml | 2 -- Tethering/res/values-pt/strings.xml | 2 -- Tethering/res/values-ro/strings.xml | 2 -- Tethering/res/values-ru/strings.xml | 2 -- Tethering/res/values-si/strings.xml | 2 -- Tethering/res/values-sk/strings.xml | 2 -- Tethering/res/values-sl/strings.xml | 2 -- Tethering/res/values-sq/strings.xml | 2 -- Tethering/res/values-sr/strings.xml | 2 -- Tethering/res/values-sv/strings.xml | 2 -- Tethering/res/values-sw/strings.xml | 2 -- Tethering/res/values-ta/strings.xml | 2 -- Tethering/res/values-te/strings.xml | 2 -- Tethering/res/values-th/strings.xml | 2 -- Tethering/res/values-tl/strings.xml | 2 -- Tethering/res/values-tr/strings.xml | 2 -- Tethering/res/values-uk/strings.xml | 2 -- Tethering/res/values-ur/strings.xml | 2 -- Tethering/res/values-uz/strings.xml | 2 -- Tethering/res/values-vi/strings.xml | 2 -- Tethering/res/values-zh-rCN/strings.xml | 2 -- Tethering/res/values-zh-rHK/strings.xml | 2 -- Tethering/res/values-zh-rTW/strings.xml | 2 -- Tethering/res/values-zu/strings.xml | 2 -- 255 files changed, 698 insertions(+), 1022 deletions(-) diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index f4c43b16a2..056168b12e 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Verbinding of warmkol is aktief" "Tik om op te stel." - "Verbinding is gedeaktiveer" "Kontak jou administrateur vir besonderhede" "Warmkol- en verbindingstatus" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 3a8de1200e..ac468dd144 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 355f59f096..7d5bad34da 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "النطاق نشط أو نقطة الاتصال نشطة" "انقر للإعداد." - "التوصيل متوقف." "تواصَل مع المشرف للحصول على التفاصيل." "حالة نقطة الاتصال والتوصيل" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index f44cec0be8..091350455b 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" "ছেট আপ কৰিবলৈ টিপক।" - "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index afd29dffbd..dce70da178 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Birləşmə və ya hotspot aktivdir" "Ayarlamaq üçün toxunun." - "Birləşmə deaktivdir" "Detallar üçün adminlə əlaqə saxlayın" "Hotspot & birləşmə statusu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 3ec6b75b34..b0774ec9a8 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Privezivanje ili hotspot je aktivan" "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" "Potražite detalje od administratora" "Status hotspota i privezivanja" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 577c1d7bdd..a8acebe2e9 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Мадэм або хот-спот актыўныя" "Дакраніцеся, каб наладзіць." - "Рэжым мадэма выключаны" "Звярніцеся да адміністратара па падрабязную інфармацыю" "Стан \"Хот-спот і мадэм\"" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index 9956a6191b..94fb2d8f17 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Има активна споделена връзка или точка за достъп" "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" "Свържете се с администратора си за подробности" "Състояние на функцията за точка за достъп и тетъринг" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 44d8dc6191..aea02b9ddf 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "টিথারিং বা হটস্পট চালু আছে" "সেট-আপ করতে ট্যাপ করুন।" - "টিথারিং বন্ধ করা আছে" "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" "হটস্পট ও টিথারিং স্ট্যাটাস" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index bf0395b7ea..de232724c5 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktivno je povezivanje putem mobitela ili pristupna tačka" "Dodirnite da postavite." - "Povezivanje putem mobitela je onemogućeno" "Kontaktirajte svog administratora za detalje" "Status pristupne tačke i povezivanja putem mobitela" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index cbc161a4e9..88b795c1f8 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Compartició de xarxa o punt d\'accés Wi‑Fi actius" "Toca per configurar." - "La compartició de xarxa està desactivada" "Contacta amb el teu administrador per obtenir més informació" "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5c21603987..8c1b83bf3e 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering nebo hotspot je aktivní" "Klepnutím zahájíte nastavení." - "Tethering je zakázán" "O podrobnosti požádejte administrátora" "Stav hotspotu a tetheringu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 741c7e2d79..f413e70548 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Netdeling eller hotspot er aktivt" "Tryk for at konfigurere." - "Netdeling er deaktiveret" "Kontakt din administrator for at få oplysninger" "Status for hotspot og netdeling" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 980a062674..f057d7824e 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering oder Hotspot aktiv" "Zum Einrichten tippen." - "Tethering ist deaktiviert" "Bitte wende dich für weitere Informationen an den Administrator" "Hotspot- und Tethering-Status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3d8ad1efef..b3c986bdaf 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 18db440b3e..769e01208a 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering or hotspot active" "Tap to set up." - "Tethering is disabled" "Contact your admin for details" "Hotspot and tethering status" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 23866e0db1..f1674bed4e 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index 0bf6c4ed09..63689f4399 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión a red o hotspot conectados" "Presiona para configurar esta opción." - "Se inhabilitó la conexión mediante dispositivo portátil" "Para obtener más información, comunícate con el administrador" "Estado del hotspot y la conexión mediante dispositivo portátil" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 195868b5d0..9a34ed5e38 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión compartida o punto de acceso activos" "Toca para configurar." - "La conexión compartida está inhabilitada" "Solicita más información a tu administrador" "Estado del punto de acceso y de la conexión compartida" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index c4700a9638..0970341ab0 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Jagamine või kuumkoht on aktiivne" "Puudutage seadistamiseks." - "Jagamine on keelatud" "Lisateabe saamiseks võtke ühendust oma administraatoriga" "Kuumkoha ja jagamise olek" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index bcb92d96be..632019e2ef 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -16,16 +16,14 @@ - "Konexioa partekatzea edo sare publikoa aktibo" + "Konexioa partekatzea edo wifi-gunea aktibo dago" "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" - "Sare publikoaren eta konexioa partekatzeko eginbidearen egoera" + "Wifi-gunearen eta konexioa partekatzeko eginbidearen egoera" - diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index 51c3d731c0..2e21c85fa1 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" "برای جزئیات، با سرپرستتان تماس بگیرید" "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index 7a54e16157..413db3f0f8 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Yhteyden jakaminen tai hotspot käytössä" "Ota käyttöön napauttamalla." - "Yhteyden jakaminen on poistettu käytöstä" "Pyydä lisätietoja järjestelmänvalvojalta" "Hotspotin ja yhteyden jakamisen tila" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 556748f5f7..eb2e4ba540 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Partage de connexion ou point d\'accès sans fil activé" "Touchez pour configurer." - "Le partage de connexion est désactivé" "Communiquez avec votre administrateur pour obtenir plus de détails" "Point d\'accès et partage de connexion" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index 9fe55a2394..22259c52ab 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Partage de connexion ou point d\'accès activé" "Appuyez pour effectuer la configuration." - "Le partage de connexion est désactivé" "Pour en savoir plus, contactez votre administrateur" "État du point d\'accès et du partage de connexion" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 474371a128..ded82fcd54 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Conexión compartida ou zona wifi activada" "Toca para configurar." - "A conexión compartida está desactivada" "Contacta co administrador para obter información" "Estado da zona wifi e da conexión compartida" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index cdb830a79a..7cbbc2de3d 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" "સેટઅપ કરવા માટે ટૅપ કરો." - "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index f9e157c9f5..08af81b826 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिंग या हॉटस्पॉट चालू है" "सेट अप करने के लिए टैप करें." - "टेदरिंग बंद है" "जानकारी के लिए अपने एडमिन से संपर्क करें" "हॉटस्पॉट और टेदरिंग की स्थिति" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index 9a99c6457c..827c135f20 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Modemsko povezivanje ili žarišna točka aktivni" "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" "Obratite se administratoru da biste saznali pojedinosti" "Status žarišne točke i modemskog povezivanja" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index f27c1c3e63..eb68d6babf 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Megosztás vagy aktív hotspot" "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" "A részletekért forduljon rendszergazdájához" "Hotspot és internetmegosztás állapota" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index b8b95ea5f9..912941e538 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Մոդեմի ռեժիմը միացված է" "Հպեք՝ կարգավորելու համար։" - "Մոդեմի ռեժիմն անջատված է" "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 24ead4eb3c..a4e175a439 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering atau hotspot aktif" "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" "Hubungi admin untuk mengetahui detailnya" "Status hotspot & tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index 839b0b96fc..e9f6670bcd 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kveikt á tjóðrun eða aðgangsstað" "Ýttu til að setja upp." - "Slökkt er á tjóðrun" "Hafðu samband við kerfisstjórann til að fá upplýsingar" "Staða heits reits og tjóðrunar" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index 31e2b73cf6..ffb9196f5e 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Hotspot o tethering attivo" "Tocca per impostare." - "Tethering disattivato" "Contatta il tuo amministratore per avere informazioni dettagliate" "Stato hotspot e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c97064b8d2..7adcb47350 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" "יש להקיש כדי להגדיר." - "שיתוף האינטרנט בין מכשירים מושבת" "לפרטים, יש לפנות למנהל המערכת" "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index c65f6e2f71..f68a73010b 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "テザリングまたはアクセス ポイントが有効です" "タップしてセットアップします。" - "テザリングは無効に設定されています" "詳しくは、管理者にお問い合わせください" "アクセス ポイントとテザリングのステータス" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 0dca3763f6..7c22e82bd3 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ტეტერინგი ან უსადენო ქსელი აქტიურია" "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" "უსადენო ქსელის და ტეტერინგის სტატუსი" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 9b4423536b..0857d06de2 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Тетеринг немесе хотспот қосулы" "Реттеу үшін түртіңіз." - "Тетеринг өшірілді." "Мәліметтерді әкімшіден алыңыз." "Хотспот және тетеринг күйі" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 7a6ab98d88..536e3d1703 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" "ចុច​ដើម្បី​រៀបចំ។" - "ការភ្ជាប់​ត្រូវបានបិទ" "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index 7c744b83e4..32f54926f4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index ecbddf5fdc..156b24786d 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "테더링 또는 핫스팟 사용" "설정하려면 탭하세요." - "테더링이 사용 중지됨" "자세한 정보는 관리자에게 문의하세요." "핫스팟 및 테더링 상태" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 7b9c0f5714..18ee5fd357 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем режими күйүп турат" "Жөндөө үчүн таптап коюңуз." - "Телефонду модем катары колдонууга болбойт" "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" "Байланыш түйүнүнүн жана модем режиминин статусу" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index d85b1bd096..b12767018c 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index 9a875932ff..8427baf39f 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" "Jei reikia išsamios informacijos, susisiekite su administratoriumi" "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index bb32ab41b1..aa2d6990e0 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Piesaiste vai tīklājs ir aktīvs." "Pieskarieties, lai to iestatītu." - "Piesaiste ir atspējota" "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." "Tīklāja un piesaistes statuss" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml index 8f16cd19ac..19d659c6ce 100644 --- a/Tethering/res/values-mcc310-mnc004-af/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -16,10 +16,9 @@ - "Warmkol het nie internet nie" - "Toestelle kan nie aan internet koppel nie" - "Skakel warmkol af" - "Warmkol is aan" + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" "Bykomende heffings kan geld terwyl jy swerf" - "Gaan voort" diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml index d064fd81d5..8995430b4f 100644 --- a/Tethering/res/values-mcc310-mnc004-am/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -16,10 +16,9 @@ - "መገናኛ ነጥቡ በይነመረብ የለውም" - "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" - "መገናኛ ነጥብ ያጥፉ" - "የመገናኛ ነጥብ በርቷል" + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" - "ቀጥል" diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml index f4b4c176e7..54f3b5389a 100644 --- a/Tethering/res/values-mcc310-mnc004-ar/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -16,10 +16,9 @@ - "نقطة الاتصال غير متصلة بالإنترنت." - "لا يمكن للأجهزة الاتصال بالإنترنت." - "إيقاف نقطة الاتصال" - "نقطة الاتصال مفعّلة" + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" "قد يتم تطبيق رسوم إضافية أثناء التجوال." - "متابعة" diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml index 5bcadfd7fc..e215141c9e 100644 --- a/Tethering/res/values-mcc310-mnc004-as/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" - "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" - "হটস্পট অফ কৰক" - "হটস্পট অন হৈ আছে" + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" - "অব্যাহত ৰাখক" diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml index 41c018eec1..1fd8e4c963 100644 --- a/Tethering/res/values-mcc310-mnc004-az/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -16,10 +16,9 @@ - "Hotspotun internetə girişi yoxdur" - "Cihazlar internetə qoşula bilmir" - "Hotspot\'u deaktiv edin" - "Hotspot aktivdir" + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" - "Davam edin" diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml index 8acc587975..1abe4f3aa3 100644 --- a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nema pristup internetu" - "Uređaji ne mogu da se povežu na internet" - "Isključi hotspot" - "Hotspot je uključen" + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" "Možda važe dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml index b03379a899..38dbd1e391 100644 --- a/Tethering/res/values-mcc310-mnc004-be/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -16,10 +16,9 @@ - "Хот-спот не падключаны да інтэрнэту" - "Прылады не могуць падключацца да інтэрнэту" - "Выключыць хот-спот" - "Хот-спот уключаны" + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" - "Працягнуць" diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml index 122bdb69c6..04b44db5c1 100644 --- a/Tethering/res/values-mcc310-mnc004-bg/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -16,10 +16,9 @@ - "Точката за достъп няма връзка с интернет" - "Устройствата не могат да се свържат с интернет" - "Изключване на точката за достъп" - "Точката за достъп е включена" + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" "Възможно е да ви бъдат начислени допълнителни такси при роуминг" - "Напред" diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml index 7a8d1e173e..579d1be1c1 100644 --- a/Tethering/res/values-mcc310-mnc004-bn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" - "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" - "হটস্পট বন্ধ করুন" - "হটস্পট চালু আছে" + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" - "চালিয়ে যান" diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml index a4ec581fe9..9ce3efe6c3 100644 --- a/Tethering/res/values-mcc310-mnc004-bs/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -16,10 +16,9 @@ - "Pristupna tačka nema internet" - "Uređaji se ne mogu povezati na internet" - "Isključi pristupnu tačku" - "Pristupna tačka je uključena" + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" "Mogu nastati dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml index 9c46426601..46d4c35b9b 100644 --- a/Tethering/res/values-mcc310-mnc004-ca/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -16,10 +16,9 @@ - "El punt d\'accés Wi‑Fi no té accés a Internet" - "Els dispositius no es poden connectar a Internet" - "Desactiva el punt d\'accés Wi‑Fi" - "El punt d\'accés Wi‑Fi està activat" + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" "És possible que s\'apliquin costos addicionals en itinerància" - "Continua" diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml index 66e4dfb3da..cc13860b3d 100644 --- a/Tethering/res/values-mcc310-mnc004-cs/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá připojení k internetu" - "Zařízení se nemohou připojit k internetu" - "Vypnout hotspot" - "Hotspot je aktivní" + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" "Při roamingu mohou být účtovány dodatečné poplatky" - "Pokračovat" diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml index 04a48a77c4..92c3ae1156 100644 --- a/Tethering/res/values-mcc310-mnc004-da/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -16,10 +16,9 @@ - "Hotspottet har intet internet" - "Enheder kan ikke oprette forbindelse til internettet" - "Deaktiver hotspot" - "Hotspottet er aktiveret" + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" "Der opkræves muligvis yderligere gebyrer ved roaming" - "Fortsæt" diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml index a9136784e9..967eb4db2e 100644 --- a/Tethering/res/values-mcc310-mnc004-de/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -16,10 +16,9 @@ - "Hotspot ist nicht mit dem Internet verbunden" - "Geräte können nicht mit dem Internet verbunden werden" - "Hotspot deaktivieren" - "Hotspot aktiviert" + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" "Für das Roaming können zusätzliche Gebühren anfallen" - "Weiter" diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml index 19be3c7077..5fb497451f 100644 --- a/Tethering/res/values-mcc310-mnc004-el/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -16,10 +16,9 @@ - "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." - "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." - "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" - "Σημείο πρόσβασης Wi-Fi ενεργό" + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." - "Συνέχεια" diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml index b844c09c62..45647f93f2 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml index 6384e89ce0..7877074afc 100644 --- a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -16,10 +16,9 @@ - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎Turn off hotspot‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎Continue‎‏‎‎‏‎" diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml index 91368bf011..08edd81a6b 100644 --- a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -16,10 +16,9 @@ - "El hotspot no tiene conexión a Internet" - "Los dispositivos no pueden conectarse a Internet" - "Desactiva el hotspot" - "El hotspot está activado" + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" "Es posible que se apliquen cargos adicionales por roaming" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml index c717033145..79f51d00e2 100644 --- a/Tethering/res/values-mcc310-mnc004-es/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -16,10 +16,9 @@ - "El punto de acceso no tiene conexión a Internet" - "Los dispositivos no se pueden conectar a Internet" - "Desactivar punto de acceso" - "Punto de acceso activado" + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" "Puede que se apliquen cargos adicionales en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml index 271f82ad6a..2da5f8a6d6 100644 --- a/Tethering/res/values-mcc310-mnc004-et/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -16,10 +16,9 @@ - "Kuumkohal puudub Interneti-ühendus" - "Seadmed ei saa Internetiga ühendust luua" - "Lülita kuumkoht välja" - "Kuumkoht on sees" + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" "Rändluse kasutamisega võivad kaasneda lisatasud" - "Jätka" diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml index 09de71f8bc..2073f2806c 100644 --- a/Tethering/res/values-mcc310-mnc004-eu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -16,10 +16,9 @@ - "Sare publikoak ez du Interneteko konexiorik" - "Gailuak ezin dira konektatu Internetera" - "Desaktibatu sare publikoa" - "Sare publikoa aktibatuta dago" + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" - "Egin aurrera" diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml index b370e0fd81..e21b2a0852 100644 --- a/Tethering/res/values-mcc310-mnc004-fa/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -16,10 +16,9 @@ - "نقطه اتصال به اینترنت دسترسی ندارد" - "دستگاه‌ها به اینترنت متصل نشدند" - "نقطه اتصال را خاموش کنید" - "نقطه اتصال روشن است" + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" - "ادامه" diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml index da86391ee9..88b0b13eb4 100644 --- a/Tethering/res/values-mcc310-mnc004-fi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -16,10 +16,9 @@ - "Hotspotilla ei ole internetyhteyttä" - "Laitteet eivät voi yhdistää internetiin" - "Laita hotspot pois päältä" - "Hotspot on päällä" + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" "Roaming voi aiheuttaa lisämaksuja" - "Jatka" diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml index 6ffd8116e8..3b781bc8db 100644 --- a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml index 6ffd8116e8..51d7203c36 100644 --- a/Tethering/res/values-mcc310-mnc004-fr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml index 9e7f00cbe0..008ccb475d 100644 --- a/Tethering/res/values-mcc310-mnc004-gl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -16,10 +16,9 @@ - "A zona wifi non ten acceso a Internet" - "Os dispositivos non se poden conectar a Internet" - "Desactivar zona wifi" - "A zona wifi está activada" + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" "Pódense aplicar cargos adicionais en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml index 580f3c5cbf..f2e3b4df78 100644 --- a/Tethering/res/values-mcc310-mnc004-gu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -16,10 +16,9 @@ - "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" - "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" - "હૉટસ્પૉટ બંધ કરો" - "હૉટસ્પૉટ ચાલુ છે" + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" - "આગળ વધો" diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml index b6faa3a0f7..b11839d760 100644 --- a/Tethering/res/values-mcc310-mnc004-hi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉट से इंटरनेट नहीं चल रहा" - "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" - "हॉटस्पॉट बंद करें" - "हॉटस्पॉट चालू है" + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" - "जारी रखें" diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml index 86b58ded22..0a5aca25b1 100644 --- a/Tethering/res/values-mcc310-mnc004-hr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -16,10 +16,9 @@ - "Žarišna točka nema pristup internetu" - "Uređaji se ne mogu povezati s internetom" - "Isključi žarišnu točku" - "Žarišna je točka uključena" + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" "U roamingu su mogući dodatni troškovi" - "Nastavi" diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml index 27ddabf29d..21c689a44e 100644 --- a/Tethering/res/values-mcc310-mnc004-hu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -16,10 +16,9 @@ - "A hotspot nem csatlakozik az internethez" - "Az eszközök nem tudnak csatlakozni az internethez" - "Hotspot kikapcsolása" - "A hotspot be van kapcsolva" + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" "Roaming során további díjak léphetnek fel" - "Tovább" diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml index abdb207626..689d92870e 100644 --- a/Tethering/res/values-mcc310-mnc004-hy/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -16,10 +16,9 @@ - "Թեժ կետը միացված չէ ինտերնետին" - "Սարքերը չեն կարողանում միանալ ինտերնետին" - "Անջատել թեժ կետը" - "Թեժ կետը միացված է" + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" - "Շարունակել" diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml index bef3fc59d3..a5f4d19abf 100644 --- a/Tethering/res/values-mcc310-mnc004-in/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -16,10 +16,9 @@ - "Hotspot tidak memiliki koneksi internet" - "Perangkat tidak dapat tersambung ke internet" - "Nonaktifkan hotspot" - "Hotspot aktif" + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" "Biaya tambahan mungkin berlaku saat roaming" - "Lanjutkan" diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml index f4e5dd4ad3..fc7e8aaf4e 100644 --- a/Tethering/res/values-mcc310-mnc004-is/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -16,10 +16,9 @@ - "Heitur reitur er ekki nettengdur" - "Tæki geta ekki tengst við internetið" - "Slökkva á heitum reit" - "Kveikt er á heitum reit" + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" "Viðbótargjöld kunna að eiga við í reiki" - "Halda áfram" diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml index cc5a6a5cda..6456dd1b80 100644 --- a/Tethering/res/values-mcc310-mnc004-it/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -16,10 +16,9 @@ - "L\'hotspot non ha accesso a Internet" - "I dispositivi non possono connettersi a Internet" - "Disattiva l\'hotspot" - "Hotspot attivo" + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" "Potrebbero essere applicati costi aggiuntivi durante il roaming" - "Continua" diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml index 0922ee9e4d..46b24bd3c5 100644 --- a/Tethering/res/values-mcc310-mnc004-iw/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -16,10 +16,9 @@ - "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" - "המכשירים לא יכולים להתחבר לאינטרנט" - "כיבוי הנקודה לשיתוף אינטרנט" - "הנקודה לשיתוף אינטרנט פועלת" + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" "ייתכנו חיובים נוספים בעת נדידה" - "המשך" diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml index 63ddc476e6..e6eb277b90 100644 --- a/Tethering/res/values-mcc310-mnc004-ja/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -16,10 +16,9 @@ - "アクセス ポイントがインターネットに接続されていません" - "デバイスをインターネットに接続できません" - "アクセス ポイントを OFF にする" - "アクセス ポイント: ON" + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" "ローミング時に追加料金が発生することがあります" - "続行" diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml index 4f20c76a12..aeddd7101d 100644 --- a/Tethering/res/values-mcc310-mnc004-ka/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -16,10 +16,9 @@ - "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" - "მოწყობილობები ვერ უკავშირდება ინტერნეტს" - "გამორთეთ უსადენო ქსელი" - "უსადენო ქსელი ჩართულია" + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" - "გაგრძელება" diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml index 11e293416b..255f0a276f 100644 --- a/Tethering/res/values-mcc310-mnc004-kk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -16,10 +16,9 @@ - "Хотспотта интернет жоқ" - "Құрылғылар интернетке қосылмайды" - "Хотспотты өшіру" - "Хотспот қосулы" + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" "Роуминг кезінде қосымша ақы алынуы мүмкін." - "Жалғастыру" diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml index b8d94d40a3..2bceb1cf77 100644 --- a/Tethering/res/values-mcc310-mnc004-km/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -16,10 +16,9 @@ - "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" - "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" - "បិទ​ហតស្ប៉ត" - "ហតស្ប៉ត​ត្រូវបានបើក" + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" - "បន្ត" diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml index 8044c9f5f6..ed769305a6 100644 --- a/Tethering/res/values-mcc310-mnc004-kn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -16,10 +16,9 @@ - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" - "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" - "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml index 59de04c55d..6e504941eb 100644 --- a/Tethering/res/values-mcc310-mnc004-ko/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -16,10 +16,9 @@ - "핫스팟이 인터넷에 연결되지 않음" - "기기를 인터넷에 연결할 수 없음" - "핫스팟 사용 중지" - "핫스팟 사용 중" + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" "로밍 중에는 추가 요금이 발생할 수 있습니다." - "계속" diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml index 860c3e41f1..d68128b9a5 100644 --- a/Tethering/res/values-mcc310-mnc004-ky/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -16,10 +16,9 @@ - "Байланыш түйүнүндө Интернет жок" - "Түзмөктөр Интернетке туташпай жатат" - "Туташуу түйүнүн өчүрүү" - "Кошулуу түйүнү күйүк" + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" "Роумингде кошумча акы алынышы мүмкүн" - "Улантуу" diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml index b6b8252164..03e134a0fc 100644 --- a/Tethering/res/values-mcc310-mnc004-lo/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -16,10 +16,9 @@ - "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" - "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" - "ປິດຮັອດສະປອດ" - "ຮັອດສະປອດເປີດຢູ່" + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" - "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml index aa15bfe1f5..652cedc6e6 100644 --- a/Tethering/res/values-mcc310-mnc004-lt/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -16,10 +16,9 @@ - "Nėra viešosios interneto prieigos taško interneto ryšio" - "Įrenginiams nepavyksta prisijungti prie interneto" - "Išjungti viešosios interneto prieigos tašką" - "Viešosios interneto prieigos taškas įjungtas" + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" - "Tęsti" diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml index 1e0d2f1c6f..221972298c 100644 --- a/Tethering/res/values-mcc310-mnc004-lv/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -16,10 +16,9 @@ - "Tīklājam nav interneta savienojuma" - "Ierīces nevar izveidot savienojumu ar internetu" - "Izslēgt tīklāju" - "Tīklājs ir ieslēgts" + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" "Viesabonēšanas laikā var tikt piemērota papildu samaksa" - "Tālāk" diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml index 5fe2a49af6..227f9e3466 100644 --- a/Tethering/res/values-mcc310-mnc004-mk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -16,10 +16,9 @@ - "Точката на пристап нема интернет" - "Уредите не може да се поврзат на интернет" - "Исклучи ја точката на пристап" - "Точката на пристап е вклучена" + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" "При роаминг може да се наплатат дополнителни трошоци" - "Продолжи" diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml index b8fdda0991..ec43885126 100644 --- a/Tethering/res/values-mcc310-mnc004-ml/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -16,10 +16,9 @@ - "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" - "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" - "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" - "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" - "തുടരുക" diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml index 462e73f7a4..e263573799 100644 --- a/Tethering/res/values-mcc310-mnc004-mn/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -16,10 +16,9 @@ - "Сүлжээний цэг дээр интернэт алга байна" - "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" - "Сүлжээний цэгийг унтраах" - "Сүлжээний цэг асаалттай байна" + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" - "Үргэлжлүүлэх" diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml index b1d9b8505b..adf845d078 100644 --- a/Tethering/res/values-mcc310-mnc004-mr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉटला इंटरनेट नाही" - "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" - "हॉटस्पॉट बंद करा" - "हॉटस्पॉट सुरू आहे" + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" - "सुरू ठेवा" diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml index 936629ca14..f65c451e4c 100644 --- a/Tethering/res/values-mcc310-mnc004-ms/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -16,10 +16,9 @@ - "Tempat liputan tiada Internet" - "Peranti tidak dapat menyambung kepada Internet" - "Matikan tempat liputan" - "Tempat liputan dihidupkan" + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" "Caj tambahan mungkin digunakan semasa perayauan" - "Teruskan" diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml index 052df883eb..4118e775cd 100644 --- a/Tethering/res/values-mcc310-mnc004-my/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -16,10 +16,9 @@ - "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" - "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" - "ဟော့စပေါ့ ပိတ်ရန်" - "ဟော့စပေါ့ ဖွင့်ထားသည်" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" - "ရှေ့ဆက်ရန်" diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml index 09012cbfec..36853583ce 100644 --- a/Tethering/res/values-mcc310-mnc004-nb/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -16,10 +16,9 @@ - "Wi-Fi-sonen har ikke internettilgang" - "Enheter kan ikke koble til internett" - "Slå av Wi-Fi-sonen" - "Wi-Fi-sonen er på" + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" "Ytterligere kostnader kan påløpe under roaming" - "Fortsett" diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index 86c070500f..2a7330098f 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,10 +16,13 @@ - "हटस्पटमा इन्टरनेट छैन" - "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" - "हटस्पट निष्क्रिय पार्नुहोस्" - "हटस्पट सक्रिय छ" + + + + + + + + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" - "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml index 912290cb67..1d888942f4 100644 --- a/Tethering/res/values-mcc310-mnc004-nl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot heeft geen internet" - "Apparaten kunnen geen verbinding maken met internet" - "Hotspot uitschakelen" - "Hotspot is ingeschakeld" + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" "Er kunnen extra kosten voor roaming in rekening worden gebracht." - "Doorgaan" diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml index 5509a54b2f..8038815fe8 100644 --- a/Tethering/res/values-mcc310-mnc004-or/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -16,10 +16,9 @@ - "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" - "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" - "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" - "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" - "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml index 790fced58e..819833eab0 100644 --- a/Tethering/res/values-mcc310-mnc004-pa/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -16,10 +16,9 @@ - "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" - "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" - "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" - "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" - "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml index 51d5c3fd7e..65e4380e39 100644 --- a/Tethering/res/values-mcc310-mnc004-pl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nie ma internetu" - "Urządzenia nie mogą połączyć się z internetem" - "Wyłącz hotspot" - "Hotspot jest włączony" + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" - "Dalej" diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml index 6e605797d0..d8866170c1 100644 --- a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml index 79957977dc..bfd45ca0a3 100644 --- a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -16,10 +16,9 @@ - "A zona Wi-Fi não tem Internet" - "Não é possível ligar os dispositivos à Internet" - "Desativar zona Wi-Fi" - "A zona Wi-Fi está ativada" + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" "Podem aplicar-se custos adicionais em roaming." - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml index 6e605797d0..d8866170c1 100644 --- a/Tethering/res/values-mcc310-mnc004-pt/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml index 7be2f72195..8d87a9e516 100644 --- a/Tethering/res/values-mcc310-mnc004-ro/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -16,10 +16,9 @@ - "Hotspotul nu are internet" - "Dispozitivele nu se pot conecta la internet" - "Dezactivați hotspotul" - "Hotspotul este activ" + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" "Se pot aplica taxe suplimentare pentru roaming" - "Continuați" diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml index 1ff63cf967..dbdb9ebe49 100644 --- a/Tethering/res/values-mcc310-mnc004-ru/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -16,10 +16,9 @@ - "Точка доступа не подключена к Интернету" - "Устройства не могут подключаться к Интернету" - "Отключить точку доступа" - "Точка доступа включена" + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" "За использование услуг связи в роуминге может взиматься дополнительная плата." - "Продолжить" diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml index 357dd904ac..d8301e41c2 100644 --- a/Tethering/res/values-mcc310-mnc004-si/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -16,10 +16,9 @@ - "හොට්ස්පොට් හට අන්තර්ජාලය නැත" - "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" - "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" - "හොට්ස්පොට් ක්‍රියාත්මකයි" + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" - "ඉදිරියට යන්න" diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml index 276e5797ee..bef71363f4 100644 --- a/Tethering/res/values-mcc310-mnc004-sk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá internetové pripojenie" - "Zariadenia sa nedajú pripojiť k internetu" - "Vypnúť hotspot" - "Hotspot je zapnutý" + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" "Počas roamingu vám môžu byť účtované ďalšie poplatky" - "Pokračovať" diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml index 884bddd292..3202c62e8a 100644 --- a/Tethering/res/values-mcc310-mnc004-sl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -16,10 +16,9 @@ - "Dostopna točka nima internetne povezave" - "Naprave ne morejo vzpostaviti internetne povezave" - "Izklopi dostopno točko" - "Dostopna točka je vklopljena" + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" "Med gostovanjem lahko nastanejo dodatni stroški" - "Naprej" diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml index a2caddf667..37f6ad2868 100644 --- a/Tethering/res/values-mcc310-mnc004-sq/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -16,10 +16,9 @@ - "Zona e qasjes për internet nuk ka internet" - "Pajisjet nuk mund të lidhen me internetin" - "Çaktivizo zonën e qasjes për internet" - "Zona e qasjes për internet është aktive" + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" "Mund të zbatohen tarifime shtesë kur je në roaming" - "Vazhdo" diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml index 7745923331..5566d03ed1 100644 --- a/Tethering/res/values-mcc310-mnc004-sr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -16,10 +16,9 @@ - "Хотспот нема приступ интернету" - "Уређаји не могу да се повежу на интернет" - "Искључи хотспот" - "Хотспот је укључен" + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" "Можда важе додатни трошкови у ромингу" - "Настави" diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml index 906862aa17..9765acd0cf 100644 --- a/Tethering/res/values-mcc310-mnc004-sv/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -16,10 +16,9 @@ - "Surfzonen har ingen internetanslutning" - "Enheterna har ingen internetanslutning" - "Inaktivera surfzon" - "Surfzonen är aktiverad" + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" "Ytterligare avgifter kan tillkomma vid roaming" - "Fortsätt" diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml index 00e99bdf5f..cf850c9cd2 100644 --- a/Tethering/res/values-mcc310-mnc004-sw/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -16,10 +16,9 @@ - "Mtandao pepe hauna intaneti" - "Vifaa vimeshindwa kuunganisha kwenye intaneti" - "Zima mtandao pepe" - "Mtandao pepe umewashwa" + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" - "Endelea" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index 416d73f2d7..ea04821e33 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,10 +16,13 @@ - "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" - "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" - "ஹாட்ஸ்பாட்டை ஆஃப் செய்" - "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + + + + + + + + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" - "தொடர்க" diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml index 864f726b94..937d34d520 100644 --- a/Tethering/res/values-mcc310-mnc004-te/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -16,10 +16,9 @@ - "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" - "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" - "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" - "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" - "కొనసాగించు" diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml index 44114e5891..f781fae525 100644 --- a/Tethering/res/values-mcc310-mnc004-th/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -16,10 +16,9 @@ - "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" - "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" - "ปิดฮอตสปอต" - "ฮอตสปอตเปิดอยู่" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" - "ต่อไป" diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml index 440999014c..8d5d465373 100644 --- a/Tethering/res/values-mcc310-mnc004-tl/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -16,10 +16,9 @@ - "Walang internet ang hotspot" - "Hindi makakonekta sa internet ang mga device" - "I-off ang hotspot" - "Naka-on ang hotspot" + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" - "Ituloy" diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml index d21ad95181..80cab33ac0 100644 --- a/Tethering/res/values-mcc310-mnc004-tr/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -16,10 +16,9 @@ - "Hotspot\'un internet bağlantısı yok" - "Cihazlar internete bağlanamıyor" - "Hotspot\'u kapat" - "Hotspot açık" + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" "Dolaşım sırasında ek ücretler uygulanabilir" - "Devam" diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml index e7b8c68eb1..c05932a5ae 100644 --- a/Tethering/res/values-mcc310-mnc004-uk/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -16,10 +16,9 @@ - "Точка доступу не підключена до Інтернету" - "Не вдається підключити пристрої до Інтернету" - "Вимкнути точку доступу" - "Точку доступу ввімкнено" + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" "У роумінгу може стягуватися додаткова плата" - "Продовжити" diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml index 08edfcffeb..d820eee8ba 100644 --- a/Tethering/res/values-mcc310-mnc004-ur/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -16,10 +16,9 @@ - "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" - "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" - "ہاٹ اسپاٹ آف کریں" - "ہاٹ اسپاٹ آن ہے" + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" - "جاری رکھیں" diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml index 167b41a7ed..726148aaee 100644 --- a/Tethering/res/values-mcc310-mnc004-uz/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -16,10 +16,9 @@ - "Hotspot internetga ulanmagan" - "Qurilmalar internetga ulana olmayapti" - "Hotspotni faolsizlantirish" - "Hotspot yoniq" + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" "Rouming vaqtida qoʻshimcha haq olinishi mumkin" - "Davom etish" diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml index e4f818bf42..b7cb0456b6 100644 --- a/Tethering/res/values-mcc310-mnc004-vi/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -16,10 +16,9 @@ - "Điểm phát sóng không có kết nối Internet" - "Các thiết bị không thể kết nối Internet" - "Tắt điểm phát sóng" - "Điểm phát sóng đang bật" + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" - "Tiếp tục" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml index 570d793c44..af91afff9a 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -16,10 +16,9 @@ - "热点没有网络连接" - "设备无法连接到互联网" - "关闭热点" - "热点已开启" + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" "漫游时可能会产生额外的费用" - "继续" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml index 05321db9f2..28e6b80c01 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -16,10 +16,9 @@ - "熱點沒有互聯網連線" - "裝置無法連線至互聯網" - "關閉熱點" - "已開啟熱點" + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" "漫遊時可能需要支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml index 57b9e0de3b..05b90692ea 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -16,10 +16,9 @@ - "無線基地台沒有網際網路連線" - "裝置無法連上網際網路" - "關閉無線基地台" - "無線基地台已開啟" + "無法透過數據連線連上網際網路" + "裝置無法連線" + "關閉數據連線" + "無線基地台或數據連線已開啟" "使用漫遊服務可能須支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml index 7e899705af..11eb666219 100644 --- a/Tethering/res/values-mcc310-mnc004-zu/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -16,10 +16,9 @@ - "I-Hotspot ayina-inthanethi" - "Amadivayisi awakwazi ukuxhuma ku-inthanethi" - "Vala i-hotspot" - "I-Hotspot ivuliwe" + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" "Kungaba nezinkokhelo ezengeziwe uma uzula" - "Qhubeka" diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml index 6fc432256a..9bfa5317a9 100644 --- a/Tethering/res/values-mcc311-mnc480-af/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -16,10 +16,9 @@ - "Warmkol het nie internet nie" - "Toestelle kan nie aan internet koppel nie" - "Skakel warmkol af" - "Warmkol is aan" + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" "Bykomende heffings kan geld terwyl jy swerf" - "Gaan voort" diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml index 749cb54022..5949dfa776 100644 --- a/Tethering/res/values-mcc311-mnc480-am/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -16,10 +16,9 @@ - "መገናኛ ነጥቡ በይነመረብ የለውም" - "መሣሪያዎች ከበይነመረብ ጋር መገናኘት አይችሉም" - "መገናኛ ነጥብ ያጥፉ" - "የመገናኛ ነጥብ በርቷል" + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" - "ቀጥል" diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml index 15e5605d13..8467f9b1f5 100644 --- a/Tethering/res/values-mcc311-mnc480-ar/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -16,10 +16,9 @@ - "نقطة الاتصال غير متصلة بالإنترنت." - "لا يمكن للأجهزة الاتصال بالإنترنت." - "إيقاف نقطة الاتصال" - "نقطة الاتصال مفعّلة" + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" "قد يتم تطبيق رسوم إضافية أثناء التجوال." - "متابعة" diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml index e18e4ec67d..9776bd89da 100644 --- a/Tethering/res/values-mcc311-mnc480-as/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটৰ কোনো ইণ্টাৰনেট নাই" - "ডিভাইচসমূহ ইণ্টাৰনেটৰ সৈতে সংযোগ কৰিব নোৱাৰি" - "হটস্পট অফ কৰক" - "হটস্পট অন হৈ আছে" + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" - "অব্যাহত ৰাখক" diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml index 77740cb6c6..e6d3eaf9f0 100644 --- a/Tethering/res/values-mcc311-mnc480-az/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -16,10 +16,9 @@ - "Hotspotun internetə girişi yoxdur" - "Cihazlar internetə qoşula bilmir" - "Hotspot\'u deaktiv edin" - "Hotspot aktivdir" + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" - "Davam edin" diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml index 7170c06662..4c8a1df8ee 100644 --- a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nema pristup internetu" - "Uređaji ne mogu da se povežu na internet" - "Isključi hotspot" - "Hotspot je uključen" + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" "Možda važe dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml index 7388d218fd..edfa41e1ff 100644 --- a/Tethering/res/values-mcc311-mnc480-be/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -16,10 +16,9 @@ - "Хот-спот не падключаны да інтэрнэту" - "Прылады не могуць падключацца да інтэрнэту" - "Выключыць хот-спот" - "Хот-спот уключаны" + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" - "Працягнуць" diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml index aa7a40bfa1..f56398196f 100644 --- a/Tethering/res/values-mcc311-mnc480-bg/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -16,10 +16,9 @@ - "Точката за достъп няма връзка с интернет" - "Устройствата не могат да се свържат с интернет" - "Изключване на точката за достъп" - "Точката за достъп е включена" + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" "Възможно е да ви бъдат начислени допълнителни такси при роуминг" - "Напред" diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml index 4058f719c9..d8ecd2e988 100644 --- a/Tethering/res/values-mcc311-mnc480-bn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -16,10 +16,9 @@ - "হটস্পটের সাথে ইন্টারনেট কানেক্ট করা নেই" - "ডিভাইস ইন্টারনেটের সাথে কানেক্ট করতে পারছে না" - "হটস্পট বন্ধ করুন" - "হটস্পট চালু আছে" + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" - "চালিয়ে যান" diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml index ccfb199cee..b85fd5e285 100644 --- a/Tethering/res/values-mcc311-mnc480-bs/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -16,10 +16,9 @@ - "Pristupna tačka nema internet" - "Uređaji se ne mogu povezati na internet" - "Isključi pristupnu tačku" - "Pristupna tačka je uključena" + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" "Mogu nastati dodatni troškovi u romingu" - "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml index 43c9e137bb..a3572151be 100644 --- a/Tethering/res/values-mcc311-mnc480-ca/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -16,10 +16,9 @@ - "El punt d\'accés Wi‑Fi no té accés a Internet" - "Els dispositius no es poden connectar a Internet" - "Desactiva el punt d\'accés Wi‑Fi" - "El punt d\'accés Wi‑Fi està activat" + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" "És possible que s\'apliquin costos addicionals en itinerància" - "Continua" diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml index c9210f7f40..91196be9e5 100644 --- a/Tethering/res/values-mcc311-mnc480-cs/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá připojení k internetu" - "Zařízení se nemohou připojit k internetu" - "Vypnout hotspot" - "Hotspot je aktivní" + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" "Při roamingu mohou být účtovány dodatečné poplatky" - "Pokračovat" diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml index 3615ff49ff..196890011d 100644 --- a/Tethering/res/values-mcc311-mnc480-da/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -16,10 +16,9 @@ - "Hotspottet har intet internet" - "Enheder kan ikke oprette forbindelse til internettet" - "Deaktiver hotspot" - "Hotspottet er aktiveret" + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" "Der opkræves muligvis yderligere gebyrer ved roaming" - "Fortsæt" diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml index ee8809d80b..eb3f8c52c0 100644 --- a/Tethering/res/values-mcc311-mnc480-de/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -16,10 +16,9 @@ - "Hotspot ist nicht mit dem Internet verbunden" - "Geräte können nicht mit dem Internet verbunden werden" - "Hotspot deaktivieren" - "Hotspot aktiviert" + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" "Für das Roaming können zusätzliche Gebühren anfallen" - "Weiter" diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml index 3a79be8735..56c3d81b63 100644 --- a/Tethering/res/values-mcc311-mnc480-el/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -16,10 +16,9 @@ - "Το σημείο πρόσβασης Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο." - "Δεν είναι η δυνατή η σύνδεση των συσκευών στο διαδίκτυο." - "Απενεργοποίηση σημείου πρόσβασης Wi-Fi" - "Σημείο πρόσβασης Wi-Fi ενεργό" + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." - "Συνέχεια" diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml index 4c7de17998..dd1a1971cd 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -16,10 +16,9 @@ - "Hotspot has no Internet" - "Devices can’t connect to Internet" - "Turn off hotspot" - "Hotspot is on" + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" "Additional charges may apply while roaming" - "Continue" diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml index 2daad6ad1c..d3347aae20 100644 --- a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -16,10 +16,9 @@ - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎Hotspot has no internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎Devices can’t connect to internet‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎Turn off hotspot‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎Hotspot is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎Continue‎‏‎‎‏‎" diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml index 522fb5fc72..2f0504f07d 100644 --- a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -16,10 +16,9 @@ - "El hotspot no tiene conexión a Internet" - "Los dispositivos no pueden conectarse a Internet" - "Desactiva el hotspot" - "El hotspot está activado" + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" "Es posible que se apliquen cargos adicionales por roaming" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml index e2e30ee934..2d8f882425 100644 --- a/Tethering/res/values-mcc311-mnc480-es/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -16,10 +16,9 @@ - "El punto de acceso no tiene conexión a Internet" - "Los dispositivos no se pueden conectar a Internet" - "Desactivar punto de acceso" - "Punto de acceso activado" + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" "Puede que se apliquen cargos adicionales en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml index e59e12e71d..8493c47071 100644 --- a/Tethering/res/values-mcc311-mnc480-et/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -16,10 +16,9 @@ - "Kuumkohal puudub Interneti-ühendus" - "Seadmed ei saa Internetiga ühendust luua" - "Lülita kuumkoht välja" - "Kuumkoht on sees" + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" "Rändluse kasutamisega võivad kaasneda lisatasud" - "Jätka" diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml index 34c36bb056..33bccab3e8 100644 --- a/Tethering/res/values-mcc311-mnc480-eu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -16,10 +16,9 @@ - "Sare publikoak ez du Interneteko konexiorik" - "Gailuak ezin dira konektatu Internetera" - "Desaktibatu sare publikoa" - "Sare publikoa aktibatuta dago" + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" - "Egin aurrera" diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml index a2324d84f0..cf8a0cc277 100644 --- a/Tethering/res/values-mcc311-mnc480-fa/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -16,10 +16,9 @@ - "نقطه اتصال به اینترنت دسترسی ندارد" - "دستگاه‌ها به اینترنت متصل نشدند" - "نقطه اتصال را خاموش کنید" - "نقطه اتصال روشن است" + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" - "ادامه" diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml index ec6ac929fb..6a3ab806db 100644 --- a/Tethering/res/values-mcc311-mnc480-fi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -16,10 +16,9 @@ - "Hotspotilla ei ole internetyhteyttä" - "Laitteet eivät voi yhdistää internetiin" - "Laita hotspot pois päältä" - "Hotspot on päällä" + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" "Roaming voi aiheuttaa lisämaksuja" - "Jatka" diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml index eeaf8f3ad4..ffb9bf6047 100644 --- a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml index eeaf8f3ad4..768bce3f0a 100644 --- a/Tethering/res/values-mcc311-mnc480-fr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -16,10 +16,9 @@ - "Le point d\'accès n\'est pas connecté à Internet" - "Appareils non connectés à Internet" - "Désactiver le point d\'accès" - "Le point d\'accès est activé" + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" "En itinérance, des frais supplémentaires peuvent s\'appliquer" - "Continuer" diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml index 56b3a9b79d..0c4195a7ca 100644 --- a/Tethering/res/values-mcc311-mnc480-gl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -16,10 +16,9 @@ - "A zona wifi non ten acceso a Internet" - "Os dispositivos non se poden conectar a Internet" - "Desactivar zona wifi" - "A zona wifi está activada" + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" "Pódense aplicar cargos adicionais en itinerancia" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml index 13f74ac93d..e9d33a7db2 100644 --- a/Tethering/res/values-mcc311-mnc480-gu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -16,10 +16,9 @@ - "હૉટસ્પૉટથી ઇન્ટરનેટ ચાલી રહ્યું નથી" - "ડિવાઇસ, ઇન્ટરનેટ સાથે કનેક્ટ થઈ શકતા નથી" - "હૉટસ્પૉટ બંધ કરો" - "હૉટસ્પૉટ ચાલુ છે" + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" - "આગળ વધો" diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml index 8bb5fb29ae..aa418ac5d3 100644 --- a/Tethering/res/values-mcc311-mnc480-hi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉट से इंटरनेट नहीं चल रहा" - "डिवाइस इंटरनेट से कनेक्ट नहीं हो पा रहे" - "हॉटस्पॉट बंद करें" - "हॉटस्पॉट चालू है" + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" - "जारी रखें" diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml index 551b1b36fe..51c524afbc 100644 --- a/Tethering/res/values-mcc311-mnc480-hr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -16,10 +16,9 @@ - "Žarišna točka nema pristup internetu" - "Uređaji se ne mogu povezati s internetom" - "Isključi žarišnu točku" - "Žarišna je točka uključena" + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" "U roamingu su mogući dodatni troškovi" - "Nastavi" diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml index 4113195c19..164e45edd1 100644 --- a/Tethering/res/values-mcc311-mnc480-hu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -16,10 +16,9 @@ - "A hotspot nem csatlakozik az internethez" - "Az eszközök nem tudnak csatlakozni az internethez" - "Hotspot kikapcsolása" - "A hotspot be van kapcsolva" + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" "Roaming során további díjak léphetnek fel" - "Tovább" diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml index 393eac056c..e76c0a4c80 100644 --- a/Tethering/res/values-mcc311-mnc480-hy/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -16,10 +16,9 @@ - "Թեժ կետը միացված չէ ինտերնետին" - "Սարքերը չեն կարողանում միանալ ինտերնետին" - "Անջատել թեժ կետը" - "Թեժ կետը միացված է" + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" - "Շարունակել" diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml index 16efe936ef..2b817f8abd 100644 --- a/Tethering/res/values-mcc311-mnc480-in/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -16,10 +16,9 @@ - "Hotspot tidak memiliki koneksi internet" - "Perangkat tidak dapat tersambung ke internet" - "Nonaktifkan hotspot" - "Hotspot aktif" + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" "Biaya tambahan mungkin berlaku saat roaming" - "Lanjutkan" diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml index d28383f51b..a338d9c7ca 100644 --- a/Tethering/res/values-mcc311-mnc480-is/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -16,10 +16,9 @@ - "Heitur reitur er ekki nettengdur" - "Tæki geta ekki tengst við internetið" - "Slökkva á heitum reit" - "Kveikt er á heitum reit" + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" "Viðbótargjöld kunna að eiga við í reiki" - "Halda áfram" diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml index 6ffa05bf93..77769c2ac5 100644 --- a/Tethering/res/values-mcc311-mnc480-it/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -16,10 +16,9 @@ - "L\'hotspot non ha accesso a Internet" - "I dispositivi non possono connettersi a Internet" - "Disattiva l\'hotspot" - "Hotspot attivo" + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" "Potrebbero essere applicati costi aggiuntivi durante il roaming" - "Continua" diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml index bbc379501c..5267b51264 100644 --- a/Tethering/res/values-mcc311-mnc480-iw/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -16,10 +16,9 @@ - "לנקודה לשיתוף אינטרנט אין חיבור לאינטרנט" - "המכשירים לא יכולים להתחבר לאינטרנט" - "כיבוי הנקודה לשיתוף אינטרנט" - "הנקודה לשיתוף אינטרנט פועלת" + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" "ייתכנו חיובים נוספים בעת נדידה" - "המשך" diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml index d7cb66b1dd..66a9a6dd35 100644 --- a/Tethering/res/values-mcc311-mnc480-ja/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -16,10 +16,9 @@ - "アクセス ポイントがインターネットに接続されていません" - "デバイスをインターネットに接続できません" - "アクセス ポイントを OFF にする" - "アクセス ポイント: ON" + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" "ローミング時に追加料金が発生することがあります" - "続行" diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml index 9651a563bd..d8ad880849 100644 --- a/Tethering/res/values-mcc311-mnc480-ka/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -16,10 +16,9 @@ - "უსადენო ქსელს არ აქვს ინტერნეტზე წვდომა" - "მოწყობილობები ვერ უკავშირდება ინტერნეტს" - "გამორთეთ უსადენო ქსელი" - "უსადენო ქსელი ჩართულია" + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" - "გაგრძელება" diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml index f2db66b11e..1ddd6b419b 100644 --- a/Tethering/res/values-mcc311-mnc480-kk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -16,10 +16,9 @@ - "Хотспотта интернет жоқ" - "Құрылғылар интернетке қосылмайды" - "Хотспотты өшіру" - "Хотспот қосулы" + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" "Роуминг кезінде қосымша ақы алынуы мүмкін." - "Жалғастыру" diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml index 16699c5a0a..cf5a1379cc 100644 --- a/Tethering/res/values-mcc311-mnc480-km/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -16,10 +16,9 @@ - "ហតស្ប៉ត​មិនមាន​អ៊ីនធឺណិត​ទេ" - "ឧបករណ៍​មិនអាច​ភ្ជាប់​អ៊ីនធឺណិត​បានទេ" - "បិទ​ហតស្ប៉ត" - "ហតស្ប៉ត​ត្រូវបានបើក" + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" - "បន្ត" diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml index cc401b1775..68ae68bc19 100644 --- a/Tethering/res/values-mcc311-mnc480-kn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -16,10 +16,9 @@ - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ" - "ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲು ಸಾಧನಗಳಿಗೆ ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ" - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್‌ ಮಾಡಿ" - "ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ" + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" - "ಮುಂದುವರಿಸಿ" diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml index 3892bc36a9..17185ba2d0 100644 --- a/Tethering/res/values-mcc311-mnc480-ko/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -16,10 +16,9 @@ - "핫스팟이 인터넷에 연결되지 않음" - "기기를 인터넷에 연결할 수 없음" - "핫스팟 사용 중지" - "핫스팟 사용 중" + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" "로밍 중에는 추가 요금이 발생할 수 있습니다." - "계속" diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml index cbae0056fe..6a9fb9810c 100644 --- a/Tethering/res/values-mcc311-mnc480-ky/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -16,10 +16,9 @@ - "Байланыш түйүнүндө Интернет жок" - "Түзмөктөр Интернетке туташпай жатат" - "Туташуу түйүнүн өчүрүү" - "Кошулуу түйүнү күйүк" + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" "Роумингде кошумча акы алынышы мүмкүн" - "Улантуу" diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml index 33b03f8690..bcc4b57626 100644 --- a/Tethering/res/values-mcc311-mnc480-lo/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -16,10 +16,9 @@ - "ຮັອດສະປອດບໍ່ມີອິນເຕີເນັດ" - "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ອິນເຕີເນັດໄດ້" - "ປິດຮັອດສະປອດ" - "ຮັອດສະປອດເປີດຢູ່" + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" - "ສືບຕໍ່" diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml index 83aabd176f..011c2c11fb 100644 --- a/Tethering/res/values-mcc311-mnc480-lt/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -16,10 +16,9 @@ - "Nėra viešosios interneto prieigos taško interneto ryšio" - "Įrenginiams nepavyksta prisijungti prie interneto" - "Išjungti viešosios interneto prieigos tašką" - "Viešosios interneto prieigos taškas įjungtas" + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" - "Tęsti" diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml index 83feb11f8a..5cb2f3b7aa 100644 --- a/Tethering/res/values-mcc311-mnc480-lv/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -16,10 +16,9 @@ - "Tīklājam nav interneta savienojuma" - "Ierīces nevar izveidot savienojumu ar internetu" - "Izslēgt tīklāju" - "Tīklājs ir ieslēgts" + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" "Viesabonēšanas laikā var tikt piemērota papildu samaksa" - "Tālāk" diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml index 040e2a5d8e..4cbfd887c5 100644 --- a/Tethering/res/values-mcc311-mnc480-mk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -16,10 +16,9 @@ - "Точката на пристап нема интернет" - "Уредите не може да се поврзат на интернет" - "Исклучи ја точката на пристап" - "Точката на пристап е вклучена" + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" "При роаминг може да се наплатат дополнителни трошоци" - "Продолжи" diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml index 9e5336e46d..9cf4eaf34a 100644 --- a/Tethering/res/values-mcc311-mnc480-ml/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -16,10 +16,9 @@ - "ഹോട്ട്സ്പോട്ടിൽ ഇന്റർനെറ്റ് ലഭ്യമല്ല" - "ഉപകരണങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്യാനാവില്ല" - "ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കുക" - "ഹോട്ട്സ്പോട്ട് ഓണാണ്" + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" - "തുടരുക" diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml index e5a845051d..47c82c14d9 100644 --- a/Tethering/res/values-mcc311-mnc480-mn/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -16,10 +16,9 @@ - "Сүлжээний цэг дээр интернэт алга байна" - "Төхөөрөмжүүд нь интернэтэд холбогдох боломжгүй байна" - "Сүлжээний цэгийг унтраах" - "Сүлжээний цэг асаалттай байна" + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" - "Үргэлжлүүлэх" diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml index c7f1cc6c66..ad9e809ab2 100644 --- a/Tethering/res/values-mcc311-mnc480-mr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -16,10 +16,9 @@ - "हॉटस्पॉटला इंटरनेट नाही" - "डिव्हाइस इंटरनेटला कनेक्ट करू शकत नाहीत" - "हॉटस्पॉट बंद करा" - "हॉटस्पॉट सुरू आहे" + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" - "सुरू ठेवा" diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml index 35d36f69f1..e708cb8717 100644 --- a/Tethering/res/values-mcc311-mnc480-ms/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -16,10 +16,9 @@ - "Tempat liputan tiada Internet" - "Peranti tidak dapat menyambung kepada Internet" - "Matikan tempat liputan" - "Tempat liputan dihidupkan" + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" "Caj tambahan mungkin digunakan semasa perayauan" - "Teruskan" diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml index bc374725ae..ba5462250b 100644 --- a/Tethering/res/values-mcc311-mnc480-my/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -16,10 +16,9 @@ - "ဟော့စပေါ့တွင် အင်တာနက်မရှိပါ" - "စက်များက အင်တာနက်ချိတ်ဆက်၍ မရပါ" - "ဟော့စပေါ့ ပိတ်ရန်" - "ဟော့စပေါ့ ဖွင့်ထားသည်" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" - "ရှေ့ဆက်ရန်" diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml index 413e165c0f..57db484a25 100644 --- a/Tethering/res/values-mcc311-mnc480-nb/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -16,10 +16,9 @@ - "Wi-Fi-sonen har ikke internettilgang" - "Enheter kan ikke koble til internett" - "Slå av Wi-Fi-sonen" - "Wi-Fi-sonen er på" + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" "Ytterligere kostnader kan påløpe under roaming" - "Fortsett" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 2d7cf4d316..617c50dd0c 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,10 +16,13 @@ - "हटस्पटमा इन्टरनेट छैन" - "यन्त्रहरू इन्टरनेटमा कनेक्ट गर्न सकिएन" - "हटस्पट निष्क्रिय पार्नुहोस्" - "हटस्पट सक्रिय छ" + + + + + + + + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" - "जारी राख्नुहोस्" diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml index 7f7f39187f..b08133f4e5 100644 --- a/Tethering/res/values-mcc311-mnc480-nl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot heeft geen internet" - "Apparaten kunnen geen verbinding maken met internet" - "Hotspot uitschakelen" - "Hotspot is ingeschakeld" + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" "Er kunnen extra kosten voor roaming in rekening worden gebracht." - "Doorgaan" diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml index e4c2458f44..1ad4ca354a 100644 --- a/Tethering/res/values-mcc311-mnc480-or/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -16,10 +16,9 @@ - "ହଟସ୍ପଟରେ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" - "ଡିଭାଇସଗୁଡ଼ିକ ଇଣ୍ଟର୍ନେଟ୍ ସହ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" - "ହଟସ୍ପଟ ବନ୍ଦ କରନ୍ତୁ" - "ହଟସ୍ପଟ ଚାଲୁ ଅଛି" + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" - "ଜାରି ରଖନ୍ତୁ" diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml index 642befbd64..88def563d8 100644 --- a/Tethering/res/values-mcc311-mnc480-pa/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -16,10 +16,9 @@ - "ਹੌਟਸਪੌਟ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" - "ਡੀਵਾਈਸ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਦੇ" - "ਹੌਟਸਪੌਟ ਬੰਦ ਕਰੋ" - "ਹੌਟਸਪੌਟ ਚਾਲੂ ਹੈ" + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" - "ਜਾਰੀ ਰੱਖੋ" diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml index c578b278d9..f9890abdc2 100644 --- a/Tethering/res/values-mcc311-mnc480-pl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nie ma internetu" - "Urządzenia nie mogą połączyć się z internetem" - "Wyłącz hotspot" - "Hotspot jest włączony" + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" - "Dalej" diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml index 502b5ddb7d..ce3b88479f 100644 --- a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml index a477516145..7e883ea576 100644 --- a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -16,10 +16,9 @@ - "A zona Wi-Fi não tem Internet" - "Não é possível ligar os dispositivos à Internet" - "Desativar zona Wi-Fi" - "A zona Wi-Fi está ativada" + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" "Podem aplicar-se custos adicionais em roaming." - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml index 502b5ddb7d..ce3b88479f 100644 --- a/Tethering/res/values-mcc311-mnc480-pt/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -16,10 +16,9 @@ - "O ponto de acesso não tem conexão com a Internet" - "Não foi possível conectar os dispositivos à Internet" - "Desativar ponto de acesso" - "O ponto de acesso está ativado" + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" "Pode haver cobranças extras durante o roaming" - "Continuar" diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml index d6808b04e6..1009417316 100644 --- a/Tethering/res/values-mcc311-mnc480-ro/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -16,10 +16,9 @@ - "Hotspotul nu are internet" - "Dispozitivele nu se pot conecta la internet" - "Dezactivați hotspotul" - "Hotspotul este activ" + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" "Se pot aplica taxe suplimentare pentru roaming" - "Continuați" diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml index fb2caa9428..88683bed95 100644 --- a/Tethering/res/values-mcc311-mnc480-ru/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -16,10 +16,9 @@ - "Точка доступа не подключена к Интернету" - "Устройства не могут подключаться к Интернету" - "Отключить точку доступа" - "Точка доступа включена" + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" "За использование услуг связи в роуминге может взиматься дополнительная плата." - "Продолжить" diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml index 5008b7326c..176bcdb797 100644 --- a/Tethering/res/values-mcc311-mnc480-si/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -16,10 +16,9 @@ - "හොට්ස්පොට් හට අන්තර්ජාලය නැත" - "උපාංගවලට අන්තර්ජාලයට සම්බන්ධ විය නොහැකිය" - "හොට්ස්පොට් ක්‍රියාවිරහිත කරන්න" - "හොට්ස්පොට් ක්‍රියාත්මකයි" + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" - "ඉදිරියට යන්න" diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml index 010677d1d6..b9e2127fa8 100644 --- a/Tethering/res/values-mcc311-mnc480-sk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -16,10 +16,9 @@ - "Hotspot nemá internetové pripojenie" - "Zariadenia sa nedajú pripojiť k internetu" - "Vypnúť hotspot" - "Hotspot je zapnutý" + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" "Počas roamingu vám môžu byť účtované ďalšie poplatky" - "Pokračovať" diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml index 3662ca9e2a..e8140e686a 100644 --- a/Tethering/res/values-mcc311-mnc480-sl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -16,10 +16,9 @@ - "Dostopna točka nima internetne povezave" - "Naprave ne morejo vzpostaviti internetne povezave" - "Izklopi dostopno točko" - "Dostopna točka je vklopljena" + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" "Med gostovanjem lahko nastanejo dodatni stroški" - "Naprej" diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml index 5453d54fd9..61e698d6e8 100644 --- a/Tethering/res/values-mcc311-mnc480-sq/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -16,10 +16,9 @@ - "Zona e qasjes për internet nuk ka internet" - "Pajisjet nuk mund të lidhen me internetin" - "Çaktivizo zonën e qasjes për internet" - "Zona e qasjes për internet është aktive" + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" "Mund të zbatohen tarifime shtesë kur je në roaming" - "Vazhdo" diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml index f52cbf387e..b4c411c354 100644 --- a/Tethering/res/values-mcc311-mnc480-sr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -16,10 +16,9 @@ - "Хотспот нема приступ интернету" - "Уређаји не могу да се повежу на интернет" - "Искључи хотспот" - "Хотспот је укључен" + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" "Можда важе додатни трошкови у ромингу" - "Настави" diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml index 8474342f26..4f543e47b9 100644 --- a/Tethering/res/values-mcc311-mnc480-sv/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -16,10 +16,9 @@ - "Surfzonen har ingen internetanslutning" - "Enheterna har ingen internetanslutning" - "Inaktivera surfzon" - "Surfzonen är aktiverad" + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" "Ytterligare avgifter kan tillkomma vid roaming" - "Fortsätt" diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml index e3bb799a6b..ac347ab485 100644 --- a/Tethering/res/values-mcc311-mnc480-sw/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -16,10 +16,9 @@ - "Mtandao pepe hauna intaneti" - "Vifaa vimeshindwa kuunganisha kwenye intaneti" - "Zima mtandao pepe" - "Mtandao pepe umewashwa" + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" - "Endelea" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 4fa3f03e82..0e437593ee 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,10 +16,13 @@ - "ஹாட்ஸ்பாட்டில் இணையம் இல்லை" - "சாதனங்களால் இணையத்தில் இணைய இயலவில்லை" - "ஹாட்ஸ்பாட்டை ஆஃப் செய்" - "ஹாட்ஸ்பாட் ஆன் செய்யப்பட்டுள்ளது" + + + + + + + + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" - "தொடர்க" diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml index 49d7687178..9360297dd8 100644 --- a/Tethering/res/values-mcc311-mnc480-te/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -16,10 +16,9 @@ - "హాట్‌స్పాట్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు" - "పరికరాలను ఇంటర్నెట్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు" - "హాట్‌స్పాట్‌ని ఆఫ్ చేయండి" - "హాట్‌స్పాట్ ఆన్‌లో ఉంది" + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" - "కొనసాగించు" diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml index a26ac0403b..9c4d7e08f2 100644 --- a/Tethering/res/values-mcc311-mnc480-th/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -16,10 +16,9 @@ - "ฮอตสปอตไม่ได้เชื่อมต่ออินเทอร์เน็ต" - "อุปกรณ์เชื่อมต่ออินเทอร์เน็ตไม่ได้" - "ปิดฮอตสปอต" - "ฮอตสปอตเปิดอยู่" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" - "ต่อไป" diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml index 6e98146cd5..a7c78a5932 100644 --- a/Tethering/res/values-mcc311-mnc480-tl/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -16,10 +16,9 @@ - "Walang internet ang hotspot" - "Hindi makakonekta sa internet ang mga device" - "I-off ang hotspot" - "Naka-on ang hotspot" + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" - "Ituloy" diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml index 423bd76689..93da2c3f79 100644 --- a/Tethering/res/values-mcc311-mnc480-tr/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -16,10 +16,9 @@ - "Hotspot\'un internet bağlantısı yok" - "Cihazlar internete bağlanamıyor" - "Hotspot\'u kapat" - "Hotspot açık" + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" "Dolaşım sırasında ek ücretler uygulanabilir" - "Devam" diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml index 193b3c348b..ee0dcd2c4b 100644 --- a/Tethering/res/values-mcc311-mnc480-uk/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -16,10 +16,9 @@ - "Точка доступу не підключена до Інтернету" - "Не вдається підключити пристрої до Інтернету" - "Вимкнути точку доступу" - "Точку доступу ввімкнено" + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" "У роумінгу може стягуватися додаткова плата" - "Продовжити" diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml index 3564ead361..41cd28eef9 100644 --- a/Tethering/res/values-mcc311-mnc480-ur/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -16,10 +16,9 @@ - "ہاٹ اسپاٹ میں انٹرنیٹ نہیں ہے" - "آلات انٹرنیٹ سے منسلک نہیں ہو سکتے" - "ہاٹ اسپاٹ آف کریں" - "ہاٹ اسپاٹ آن ہے" + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" - "جاری رکھیں" diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml index c6bd803e3f..c847bc943b 100644 --- a/Tethering/res/values-mcc311-mnc480-uz/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -16,10 +16,9 @@ - "Hotspot internetga ulanmagan" - "Qurilmalar internetga ulana olmayapti" - "Hotspotni faolsizlantirish" - "Hotspot yoniq" + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" "Rouming vaqtida qoʻshimcha haq olinishi mumkin" - "Davom etish" diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml index 998ebe4d7b..a74326f09e 100644 --- a/Tethering/res/values-mcc311-mnc480-vi/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -16,10 +16,9 @@ - "Điểm phát sóng không có kết nối Internet" - "Các thiết bị không thể kết nối Internet" - "Tắt điểm phát sóng" - "Điểm phát sóng đang bật" + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" - "Tiếp tục" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml index eae5865b0c..d7370036e3 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -16,10 +16,9 @@ - "热点没有网络连接" - "设备无法连接到互联网" - "关闭热点" - "热点已开启" + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" "漫游时可能会产生额外的费用" - "继续" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml index 7f7453c306..f378a9dc2c 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -16,10 +16,9 @@ - "熱點沒有互聯網連線" - "裝置無法連線至互聯網" - "關閉熱點" - "已開啟熱點" + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" "漫遊時可能需要支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml index 4b4afc017e..ea01b943fb 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -16,10 +16,9 @@ - "無線基地台沒有網際網路連線" - "裝置無法連上網際網路" - "關閉無線基地台" - "無線基地台已開啟" + "無法透過數據連線連上網際網路" + "裝置無法連線" + "關閉數據連線" + "無線基地台或數據連線已開啟" "使用漫遊服務可能須支付額外費用" - "繼續" diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml index 48ac295ebc..32f6df56f1 100644 --- a/Tethering/res/values-mcc311-mnc480-zu/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -16,10 +16,9 @@ - "I-Hotspot ayina-inthanethi" - "Amadivayisi awakwazi ukuxhuma ku-inthanethi" - "Vala i-hotspot" - "I-Hotspot ivuliwe" + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" "Kungaba nezinkokhelo ezengeziwe uma uzula" - "Qhubeka" diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 04f0fa8c71..9ad9b9a589 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Активно е врзување или точка на пристап" "Допрете за поставување." - "Врзувањето е оневозможено" "Контактирајте со администраторот за детали" "Статус на точката на пристап и врзувањето" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index 2d14f8e0f5..9db79ce220 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4f3334c8e3..42d1edbace 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" "Тохируулахын тулд товшино уу." - "Модем болгохыг идэвхгүй болгосон" "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" "Сүлжээний цэг болон модем болгох төлөв" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index ba9f324982..13995b6b8a 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद केले आहे" "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" "हॉटस्पॉट आणि टेदरिंगची स्थिती" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index c343e311f4..d6a67f37b1 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Penambatan atau tempat liputan aktif" "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" "Status tempat liputan & penambatan" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 84bcdb4c07..49f6b88a75 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 877c128c2d..9594e0a70a 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Internettdeling eller Wi-Fi-sone er aktiv" "Trykk for å konfigurere." - "Internettdeling er slått av" "Ta kontakt med administratoren din for å få mer informasjon" "Status for Wi-Fi-sone og internettdeling" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index d50fe240c4..72ae3a80a9 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "टेदरिङ वा हटस्पट सक्रिय छ" "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङ सुविधा असक्षम पारिएको छ" "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" "हटस्पट तथा टेदरिङको स्थिति" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 6950c239ab..18b2bbfc76 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering of hotspot actief" "Tik om in te stellen." - "Tethering is uitgeschakeld" "Neem contact op met je beheerder voor meer informatie" "Status van hotspot en tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 2500a6f66b..a15a6db42a 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" - "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index 1fd496f968..a8235e423e 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index df1d5aeffa..ccb017d43f 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktywny tethering lub punkt dostępu" "Kliknij, by skonfigurować" - "Tethering został wyłączony" "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" "Hotspot i tethering – stan" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 2c3757d6de..a0a4745f93 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ponto de acesso ou tethering ativo" "Toque para configurar." - "Tethering desativado" "Fale com seu administrador para saber detalhes" "Status de ponto de acesso e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 5af2d22a57..e3f03fcc69 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." "Contacte o administrador para obter detalhes." "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 2c3757d6de..a0a4745f93 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ponto de acesso ou tethering ativo" "Toque para configurar." - "Tethering desativado" "Fale com seu administrador para saber detalhes" "Status de ponto de acesso e tethering" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index 1dad542d4f..5706a4a69c 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering sau hotspot activ" "Atingeți ca să configurați." - "Tetheringul este dezactivat" "Contactați administratorul pentru detalii" "Starea hotspotului și a tetheringului" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 4d31484229..7cb6f7db3f 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Включен режим модема или точка доступа" "Нажмите, чтобы настроить." - "Использование телефона в качестве модема запрещено" "Чтобы узнать подробности, обратитесь к администратору." "Статус хот-спота и режима модема" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index d21f2b5388..ec34c22de7 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index f2242b93b3..43e787c84f 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering alebo prístupový bod je aktívny" "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" "O podrobnosti požiadajte svojho správcu" "Stav hotspotu a tetheringu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index c01cace360..59433626a1 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" "Za podrobnosti se obrnite na skrbnika" "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index f7e2a7be74..21e11558bb 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ndarja e internetit ose zona e qasjes së internetit është aktive" "Trokit për ta konfiguruar." - "Ndarja e internetit është çaktivizuar" "Kontakto me administratorin për detaje" "Statusi i zonës së qasjes dhe ndarjes së internetit" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index c5f84eb45d..e2e4dc6361 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Привезивање или хотспот је активан" "Додирните да бисте подесили." - "Привезивање је онемогућено" "Потражите детаље од администратора" "Статус хотспота и привезивања" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index d745dad2ff..72702c2858 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Internetdelning eller surfzon har aktiverats" "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" "Kontakta administratören om du vill veta mer" "Trådlös surfzon och internetdelning har inaktiverats" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index beaa306374..65e4aa8ceb 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kusambaza mtandao au mtandaopepe umewashwa" "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" "Wasiliana na msimamizi wako ili upate maelezo zaidi" "Mtandaopepe na hali ya kusambaza mtandao" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index bc8957e096..4aba62d4ab 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" "அமைக்க, தட்டவும்." - "டெதெரிங் முடக்கப்பட்டுள்ளது" "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index b7afdb4cad..1f91791341 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" "సెటప్ చేయడానికి ట్యాప్ చేయండి." - "టెథరింగ్ డిజేబుల్ చేయబడింది" "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index e60d43496e..44171c0db8 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 79523bb0f4..7347dd3e62 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Aktibo ang pag-tether o hotspot" "I-tap para i-set up." - "Naka-disable ang pag-tether" "Makipag-ugnayan sa iyong admin para sa mga detalye" "Status ng hotspot at pag-tether" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index cf100a42e2..32030f1765 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tethering veya hotspot etkin" "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" "Ayrıntılı bilgi için yöneticinize başvurun" "Hotspot ve tethering durumu" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 0a8ceddad7..1ca89b3f78 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Модем чи точка доступу активні" "Натисніть, щоб налаштувати." - "Використання телефона як модема вимкнено" "Щоб дізнатися більше, зв\'яжіться з адміністратором" "Статус точки доступу та модема" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 043dba3161..d72c7d4195 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ٹیدرنگ یا ہاٹ اسپاٹ فعال" "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 5b9d62afd9..af3b2ebb35 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Modem rejimi yoki hotspot yoniq" "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" "Tafsilotlari uchun administratoringizga murojaat qiling" "Hotspot va modem rejimi holati" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 156ab2d383..21a0735922 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" "Hãy nhấn để thiết lập." - "Đã tắt tính năng chia sẻ Internet" "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" "Trạng thái điểm phát sóng và chia sẻ Internet" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index d137df5f33..98e3b4b46f 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "网络共享或热点已启用" "点按即可设置。" - "网络共享已停用" "如需了解详情,请与您的管理员联系" "热点和网络共享状态" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 12c071091b..9cafd42dd4 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "網絡共享或熱點已啟用" "輕按即可設定。" - "網絡共享已停用" "請聯絡您的管理員以瞭解詳情" "熱點和網絡共享狀態" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 24fb76e824..9d738a76eb 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "數據連線或無線基地台已啟用" "輕觸即可進行設定。" - "數據連線已停用" "詳情請洽你的管理員" "無線基地台與數據連線狀態" @@ -27,5 +26,4 @@ - diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index f4859aa195..f210f8726e 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -18,7 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" "Xhumana nomphathi wakho ukuze uthole imininingwane" "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" @@ -27,5 +26,4 @@ - From 39cc315273a2216e5947a1dd856b04dd8b67beb4 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 22 Apr 2020 13:50:15 -0700 Subject: [PATCH 1004/1415] Fix Error Prone errors Soong wasn't including android_app or android_test sources in the javac-check target used for the Error Prone build, which allowed some Error Prone errors to get in. Fix them so Error Prone can be re-enabled for these targets. Fixes: cts/hostsidetests/net/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java:61: error: [CollectionIncompatibleType] Argument '~requiredProperty.getValue()' should not be passed to this method; its type int is not compatible with its collection's type argument Property Bug: 146455923 Test: m RUN_ERROR_PRONE=true javac-check Change-Id: I7c5bf823bf371902285ce3ee3929796fa40c653b Merged-In: I48b1ccb61c807d0b41a165298ef5981258d6656e --- .../android/cts/net/hostside/RequiredPropertiesRule.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java index 1e333200db..98c97c5687 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java @@ -58,8 +58,12 @@ public class RequiredPropertiesRule extends BeforeAfterRule { continue; } for (Property requiredProperty : requiredProperties.value()) { - if (!allRequiredProperties.contains(~requiredProperty.getValue())) { - allRequiredProperties.add(requiredProperty); + for (Property p : Property.values()) { + if (p.getValue() == ~requiredProperty.getValue()) { + if (!allRequiredProperties.contains(p)) { + allRequiredProperties.add(requiredProperty); + } + } } } } From a6a1ad183ed2158ec3e11fa3177db79805e6f0fa Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 5 Feb 2020 17:54:01 -0800 Subject: [PATCH 1005/1415] Fix a regression in how required properties are collected. + Enable app standby mode before running the tests. Fixes: 147459100 Fixes: 117169751 Test: atest hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Test: cts-tradefed run singleCommand cts-on-gsi --skip-device-info \ --skip-preconditions -m CtsHostsideNetworkTests \ -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: I782f8a06922622d28f9a9d5c9f2afa2b12f8aa80 Merged-In: I782f8a06922622d28f9a9d5c9f2afa2b12f8aa80 --- tests/cts/hostside/AndroidTest.xml | 1 + .../net/hostside/RequiredPropertiesRule.java | 8 +-- .../cts/net/NetworkPolicyTestsPreparer.java | 59 +++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 5479c51a4c..d4f30e0cf3 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -21,6 +21,7 @@

    TODO(b/148689509): Statically include the PacketUtils source file instead of copying it. + */ +public class PacketUtils { + private static final String TAG = PacketUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + + static final int IP4_HDRLEN = 20; + static final int IP6_HDRLEN = 40; + static final int UDP_HDRLEN = 8; + static final int TCP_HDRLEN = 20; + static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12; + + // Not defined in OsConstants + static final int IPPROTO_IPV4 = 4; + static final int IPPROTO_ESP = 50; + + // Encryption parameters + static final int AES_GCM_IV_LEN = 8; + static final int AES_CBC_IV_LEN = 16; + static final int AES_GCM_BLK_SIZE = 4; + static final int AES_CBC_BLK_SIZE = 16; + + // Encryption algorithms + static final String AES = "AES"; + static final String AES_CBC = "AES/CBC/NoPadding"; + static final String HMAC_SHA_256 = "HmacSHA256"; + + public interface Payload { + byte[] getPacketBytes(IpHeader header) throws Exception; + + void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception; + + short length(); + + int getProtocolId(); + } + + public abstract static class IpHeader { + + public final byte proto; + public final InetAddress srcAddr; + public final InetAddress dstAddr; + public final Payload payload; + + public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) { + this.proto = (byte) proto; + this.srcAddr = src; + this.dstAddr = dst; + this.payload = payload; + } + + public abstract byte[] getPacketBytes() throws Exception; + + public abstract int getProtocolId(); + } + + public static class Ip4Header extends IpHeader { + private short checksum; + + public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) { + super(proto, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer resultBuffer = buildHeader(); + payload.addPacketBytes(this, resultBuffer); + + return getByteArrayFromBuffer(resultBuffer); + } + + public ByteBuffer buildHeader() { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version, IHL + bb.put((byte) (0x45)); + + // DCSP, ECN + bb.put((byte) 0); + + // Total Length + bb.putShort((short) (IP4_HDRLEN + payload.length())); + + // Empty for Identification, Flags and Fragment Offset + bb.putShort((short) 0); + bb.put((byte) 0x40); + bb.put((byte) 0x00); + + // TTL + bb.put((byte) 64); + + // Protocol + bb.put(proto); + + // Header Checksum + final int ipChecksumOffset = bb.position(); + bb.putShort((short) 0); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + bb.putShort(ipChecksumOffset, calculateChecksum(bb)); + + return bb; + } + + private short calculateChecksum(ByteBuffer bb) { + int checksum = 0; + + // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit + // aligned, so no special cases needed for unaligned values. + ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer(); + while (shortBuffer.hasRemaining()) { + short val = shortBuffer.get(); + + // Wrap as needed + checksum = addAndWrapForChecksum(checksum, val); + } + + return onesComplement(checksum); + } + + public int getProtocolId() { + return IPPROTO_IPV4; + } + } + + public static class Ip6Header extends IpHeader { + public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) { + super(nextHeader, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version | Traffic Class (First 4 bits) + bb.put((byte) 0x60); + + // Traffic class (Last 4 bits), Flow Label + bb.put((byte) 0); + bb.put((byte) 0); + bb.put((byte) 0); + + // Payload Length + bb.putShort((short) payload.length()); + + // Next Header + bb.put(proto); + + // Hop Limit + bb.put((byte) 64); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + // Payload + payload.addPacketBytes(this, bb); + + return getByteArrayFromBuffer(bb); + } + + public int getProtocolId() { + return IPPROTO_IPV6; + } + } + + public static class BytePayload implements Payload { + public final byte[] payload; + + public BytePayload(byte[] payload) { + this.payload = payload; + } + + public int getProtocolId() { + return -1; + } + + public byte[] getPacketBytes(IpHeader header) { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) { + resultBuffer.put(payload); + } + + public short length() { + return (short) payload.length; + } + } + + public static class UdpHeader implements Payload { + + public final short srcPort; + public final short dstPort; + public final Payload payload; + + public UdpHeader(int srcPort, int dstPort, Payload payload) { + this.srcPort = (short) srcPort; + this.dstPort = (short) dstPort; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_UDP; + } + + public short length() { + return (short) (payload.length() + 8); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + // Source, Destination port + resultBuffer.putShort(srcPort); + resultBuffer.putShort(dstPort); + + // Payload Length + resultBuffer.putShort(length()); + + // Get payload bytes for checksum + payload + ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + payload.addPacketBytes(header, payloadBuffer); + byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer); + + // Checksum + resultBuffer.putShort(calculateChecksum(header, payloadBytes)); + + // Payload + resultBuffer.put(payloadBytes); + } + + private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception { + int newChecksum = 0; + ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer(); + ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer(); + + while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) { + short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get(); + + // Wrap as needed + newChecksum = addAndWrapForChecksum(newChecksum, val); + } + + // Add pseudo-header values. Proto is 0-padded, so just use the byte. + newChecksum = addAndWrapForChecksum(newChecksum, header.proto); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + newChecksum = addAndWrapForChecksum(newChecksum, srcPort); + newChecksum = addAndWrapForChecksum(newChecksum, dstPort); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + + ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer(); + while (payloadShortBuffer.hasRemaining()) { + newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get()); + } + if (payload.length() % 2 != 0) { + newChecksum = + addAndWrapForChecksum( + newChecksum, (payloadBytes[payloadBytes.length - 1] << 8)); + } + + return onesComplement(newChecksum); + } + } + + public static class EspHeader implements Payload { + public final int nextHeader; + public final int spi; + public final int seqNum; + public final byte[] key; + public final byte[] payload; + + /** + * Generic constructor for ESP headers. + * + *

    For Tunnel mode, payload will be a full IP header + attached payloads + * + *

    For Transport mode, payload will be only the attached payloads, but with the checksum + * calculated using the pre-encryption IP header + */ + public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) { + this.nextHeader = nextHeader; + this.spi = spi; + this.seqNum = seqNum; + this.key = key; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_ESP; + } + + public short length() { + // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len) + return (short) + calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + espPayloadBuffer.putInt(spi); + espPayloadBuffer.putInt(seqNum); + espPayloadBuffer.put(getCiphertext(key)); + + espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16); + resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer)); + } + + private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException { + Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256); + SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256); + sha256HMAC.init(authKey); + + return sha256HMAC.doFinal(authenticatedSection); + } + + /** + * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks + * + *

    The ciphertext does NOT include the SPI/Sequence numbers, or the ICV. + */ + private byte[] getCiphertext(byte[] key) throws GeneralSecurityException { + int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE); + ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen); + paddedPayload.put(payload); + + // Add padding - consecutive integers from 0x01 + int pad = 1; + while (paddedPayload.position() < paddedPayload.limit()) { + paddedPayload.put((byte) pad++); + } + + paddedPayload.position(paddedPayload.limit() - 2); + paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length + paddedPayload.put((byte) nextHeader); + + // Generate Initialization Vector + byte[] iv = new byte[AES_CBC_IV_LEN]; + new SecureRandom().nextBytes(iv); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); + + // Encrypt payload + Cipher cipher = Cipher.getInstance(AES_CBC); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload)); + + // Build ciphertext + ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length); + cipherText.put(iv); + cipherText.put(encrypted); + + return getByteArrayFromBuffer(cipherText); + } + } + + private static int addAndWrapForChecksum(int currentChecksum, int value) { + currentChecksum += value & 0x0000ffff; + + // Wrap anything beyond the first 16 bits, and add to lower order bits + return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff); + } + + private static short onesComplement(int val) { + val = (val >>> 16) + (val & 0xffff); + + if (val == 0) return 0; + return (short) ((~val) & 0xffff); + } + + public static int calculateEspPacketSize( + int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { + final int ESP_HDRLEN = 4 + 4; // SPI + Seq# + final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length + payloadLen += cryptIvLength; // Initialization Vector + + // Align to block size of encryption algorithm + payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize); + return payloadLen + ESP_HDRLEN + ICV_LEN; + } + + private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) { + payloadLen += 2; // ESP trailer + + // Align to block size of encryption algorithm + return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize); + } + + private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) { + return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; + } + + private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) { + return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); + } + + /* + * Debug printing + */ + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(hexArray[b >>> 4]); + sb.append(hexArray[b & 0x0F]); + sb.append(' '); + } + return sb.toString(); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java new file mode 100644 index 0000000000..71450ea9c0 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java @@ -0,0 +1,264 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.IPPROTO_ESP; +import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; +import static android.system.OsConstants.IPPROTO_UDP; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import android.os.ParcelFileDescriptor; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +/** + * This code is a exact copy of {@link TunUtils} in + * cts/tests/tests/net/src/android/net/cts/TunUtils.java, except the import path of PacketUtils is + * the path to the copy of PacktUtils. + * + *

    TODO(b/148689509): Statically include the TunUtils source file instead of copying it. + */ +public class TunUtils { + private static final String TAG = TunUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + private static final int TIMEOUT = 100; + + private static final int IP4_PROTO_OFFSET = 9; + private static final int IP6_PROTO_OFFSET = 6; + + private static final int IP4_ADDR_OFFSET = 12; + private static final int IP4_ADDR_LEN = 4; + private static final int IP6_ADDR_OFFSET = 8; + private static final int IP6_ADDR_LEN = 16; + + private final ParcelFileDescriptor mTunFd; + private final List mPackets = new ArrayList<>(); + private final Thread mReaderThread; + + public TunUtils(ParcelFileDescriptor tunFd) { + mTunFd = tunFd; + + // Start background reader thread + mReaderThread = + new Thread( + () -> { + try { + // Loop will exit and thread will quit when tunFd is closed. + // Receiving either EOF or an exception will exit this reader loop. + // FileInputStream in uninterruptable, so there's no good way to + // ensure that this thread shuts down except upon FD closure. + while (true) { + byte[] intercepted = receiveFromTun(); + if (intercepted == null) { + // Exit once we've hit EOF + return; + } else if (intercepted.length > 0) { + // Only save packet if we've received any bytes. + synchronized (mPackets) { + mPackets.add(intercepted); + mPackets.notifyAll(); + } + } + } + } catch (IOException ignored) { + // Simply exit this reader thread + return; + } + }); + mReaderThread.start(); + } + + private byte[] receiveFromTun() throws IOException { + FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor()); + byte[] inBytes = new byte[DATA_BUFFER_LEN]; + int bytesRead = in.read(inBytes); + + if (bytesRead < 0) { + return null; // return null for EOF + } else if (bytesRead >= DATA_BUFFER_LEN) { + throw new IllegalStateException("Too big packet. Fragmentation unsupported"); + } + return Arrays.copyOf(inBytes, bytesRead); + } + + private byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { + synchronized (mPackets) { + for (int i = startIndex; i < mPackets.size(); i++) { + byte[] pkt = mPackets.get(i); + if (verifier.test(pkt)) { + return pkt; + } + } + } + return null; + } + + /** + * Checks if the specified bytes were ever sent in plaintext. + * + *

    Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like + * + * @param plaintext the plaintext bytes to check for + * @param startIndex the index in the list to check for + */ + public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { + Predicate verifier = + (pkt) -> { + return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) + != -1; + }; + return getFirstMatchingPacket(verifier, startIndex) != null; + } + + public byte[] getEspPacket(int spi, boolean encap, int startIndex) { + return getFirstMatchingPacket( + (pkt) -> { + return isEsp(pkt, spi, encap); + }, + startIndex); + } + + public byte[] awaitEspPacketNoPlaintext( + int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + long endTime = System.currentTimeMillis() + TIMEOUT; + int startIndex = 0; + + synchronized (mPackets) { + while (System.currentTimeMillis() < endTime) { + byte[] espPkt = getEspPacket(spi, useEncap, startIndex); + if (espPkt != null) { + // Validate packet size + assertEquals(expectedPacketSize, espPkt.length); + + // Always check plaintext from start + assertFalse(hasPlaintextPacket(plaintext, 0)); + return espPkt; // We've found the packet we're looking for. + } + + startIndex = mPackets.size(); + + // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout + long waitTimeout = endTime - System.currentTimeMillis(); + if (waitTimeout > 0) { + mPackets.wait(waitTimeout); + } + } + + fail("No such ESP packet found with SPI " + spi); + } + return null; + } + + private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { + // Check SPI byte by byte. + return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) + && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) + && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) + && pkt[espOffset + 3] == (byte) (spi & 0xff); + } + + private static boolean isEsp(byte[] pkt, int spi, boolean encap) { + if (isIpv6(pkt)) { + // IPv6 UDP encap not supported by kernels; assume non-encap. + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); + } else { + // Use default IPv4 header length (assuming no options) + if (encap) { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP + && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi); + } else { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi); + } + } + } + + private static boolean isIpv6(byte[] pkt) { + // First nibble shows IP version. 0x60 for IPv6 + return (pkt[0] & (byte) 0xF0) == (byte) 0x60; + } + + private static byte[] getReflectedPacket(byte[] pkt) { + byte[] reflected = Arrays.copyOf(pkt, pkt.length); + + if (isIpv6(pkt)) { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset + reflected, // dst + IP6_ADDR_OFFSET, // dst offset + IP6_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET, // src offset + reflected, // dst + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset + IP6_ADDR_LEN); // len + } else { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset + reflected, // dst + IP4_ADDR_OFFSET, // dst offset + IP4_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET, // src offset + reflected, // dst + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset + IP4_ADDR_LEN); // len + } + return reflected; + } + + /** Takes all captured packets, flips the src/dst, and re-injects them. */ + public void reflectPackets() throws IOException { + synchronized (mPackets) { + for (byte[] pkt : mPackets) { + injectPacket(getReflectedPacket(pkt)); + } + } + } + + public void injectPacket(byte[] pkt) throws IOException { + FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor()); + out.write(pkt); + out.flush(); + } + + /** Resets the intercepted packets. */ + public void reset() throws IOException { + synchronized (mPackets) { + mPackets.clear(); + } + } +} From 3fe17e291b7ccb86a9ebe928214739dfd033d7e7 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 23 Apr 2020 02:17:41 -0700 Subject: [PATCH 1011/1415] Import translations. DO NOT MERGE Change-Id: Ib2f7fbbb8ebd73b517aa44a4708a7040d2394823 Auto-generated-cl: translation import --- Tethering/res/values-af/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-am/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ar/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-as/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-az/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-b+sr+Latn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-be/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bg/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bs/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ca/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-cs/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-da/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-de/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-el/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rAU/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rCA/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rGB/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rIN/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rXC/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-es-rUS/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-es/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-et/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-eu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fa/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fr-rCA/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-gl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-gu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hy/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-in/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-is/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-it/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-iw/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ja/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ka/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-kk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-km/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-kn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ko/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ky/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lo/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lt/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lv/strings.xml | 29 ++++++++++++++++--- .../res/values-mcc310-mnc004-af/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-am/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ar/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-as/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-az/strings.xml | 24 +++++++++++++++ .../strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-be/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bg/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bs/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ca/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-cs/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-da/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-de/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-el/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rAU/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rCA/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rGB/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rIN/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rXC/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-es-rUS/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-es/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-et/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-eu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fa/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fi/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-fr-rCA/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-gl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-gu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hi/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hy/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-in/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-is/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-it/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-iw/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ja/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ka/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-kk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-km/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-kn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ko/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ky/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lo/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lt/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lv/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ml/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ms/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-my/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-nb/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ne/strings.xml | 28 ++++++++++++++++++ .../res/values-mcc310-mnc004-nl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-or/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pa/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pl/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-pt-rBR/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-pt-rPT/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pt/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ro/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ru/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-si/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sq/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sv/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sw/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ta/strings.xml | 28 ++++++++++++++++++ .../res/values-mcc310-mnc004-te/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-th/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-tl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-tr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-uk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ur/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-uz/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-vi/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rCN/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rHK/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rTW/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-zu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-af/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-am/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ar/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-as/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-az/strings.xml | 24 +++++++++++++++ .../strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-be/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bg/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bs/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ca/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-cs/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-da/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-de/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-el/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rAU/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rCA/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rGB/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rIN/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rXC/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-es-rUS/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-es/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-et/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-eu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fa/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fi/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-fr-rCA/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-gl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-gu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hi/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hy/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-in/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-is/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-it/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-iw/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ja/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ka/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-kk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-km/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-kn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ko/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ky/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lo/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lt/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lv/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ml/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ms/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-my/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-nb/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ne/strings.xml | 28 ++++++++++++++++++ .../res/values-mcc311-mnc480-nl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-or/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pa/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pl/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-pt-rBR/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-pt-rPT/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pt/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ro/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ru/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-si/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sq/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sv/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sw/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ta/strings.xml | 28 ++++++++++++++++++ .../res/values-mcc311-mnc480-te/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-th/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-tl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-tr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-uk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ur/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-uz/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-vi/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rCN/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rHK/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rTW/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-zu/strings.xml | 24 +++++++++++++++ Tethering/res/values-mk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ml/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-mn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-mr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ms/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-my/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-nb/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ne/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-nl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-or/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pa/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt-rBR/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt-rPT/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ro/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ru/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-si/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sq/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sv/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sw/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ta/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-te/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-th/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-tl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-tr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-uk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ur/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-uz/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-vi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rCN/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rHK/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rTW/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zu/strings.xml | 29 ++++++++++++++++--- 255 files changed, 6221 insertions(+), 340 deletions(-) create mode 100644 Tethering/res/values-mcc310-mnc004-af/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-am/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ar/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-as/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-az/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-be/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bg/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ca/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-cs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-da/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-de/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-el/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-et/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-eu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hy/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-in/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-is/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-it/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-iw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ja/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ka/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-km/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ko/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ky/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lo/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ml/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ms/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-my/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nb/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ne/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-or/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ro/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ru/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-si/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sq/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ta/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-te/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-th/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ur/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uz/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-vi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-af/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-am/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ar/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-as/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-az/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-be/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bg/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ca/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-cs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-da/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-de/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-el/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-et/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-eu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hy/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-in/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-is/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-it/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-iw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ja/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ka/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-km/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ko/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ky/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lo/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ml/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ms/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-my/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nb/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ne/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-or/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ro/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ru/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-si/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sq/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ta/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-te/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-th/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ur/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uz/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-vi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zu/strings.xml diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index 1258805378..056168b12e 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -1,8 +1,29 @@ + + - "Verbinding of Wi-Fi-warmkol aktief" - "Tik om op te stel." - "Verbinding is gedeaktiveer" - "Kontak jou administrateur vir besonderhede" + "Verbinding of warmkol is aktief" + "Tik om op te stel." + "Verbinding is gedeaktiveer" + "Kontak jou administrateur vir besonderhede" + "Warmkol- en verbindingstatus" + + + + + diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 9c36192257..ac468dd144 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -1,8 +1,29 @@ + + - "መሰካት ወይም ገባሪ ድረስ ነጥብ" - "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" - "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" + "ለማዋቀር መታ ያድርጉ።" + "እንደ ሞደም መሰካት ተሰናክሏል" + "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" + + + + + diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 9f84ce4090..7d5bad34da 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -1,8 +1,29 @@ + + - "النطاق أو نقطة الاتصال نشطة" - "انقر للإعداد." - "تم إيقاف التوصيل" - "اتصل بالمشرف للحصول على التفاصيل" + "النطاق نشط أو نقطة الاتصال نشطة" + "انقر للإعداد." + "التوصيل متوقف." + "تواصَل مع المشرف للحصول على التفاصيل." + "حالة نقطة الاتصال والتوصيل" + + + + + diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index 8855822e7c..091350455b 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -1,8 +1,29 @@ + + - "টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে" - "ছেট আপ কৰিবলৈ টিপক।" - "টেডাৰিং অক্ষম কৰি থোৱা হৈছে" - "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" + "ছেট আপ কৰিবলৈ টিপক।" + "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" + "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" + + + + + diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index eba50eb636..dce70da178 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -1,8 +1,29 @@ + + - "Tezerinq və ya hotspot aktivdir" - "Quraşdırmaq üçün tıklayın." - "Birləşmə deaktivdir" - "Məlumat üçün adminlə əlaqə saxlayın" + "Birləşmə və ya hotspot aktivdir" + "Ayarlamaq üçün toxunun." + "Birləşmə deaktivdir" + "Detallar üçün adminlə əlaqə saxlayın" + "Hotspot & birləşmə statusu" + + + + + diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 5b0e488ba5..b0774ec9a8 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -1,8 +1,29 @@ + + - "Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot" - "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" - "Potražite detalje od administratora" + "Privezivanje ili hotspot je aktivan" + "Dodirnite da biste podesili." + "Privezivanje je onemogućeno" + "Potražite detalje od administratora" + "Status hotspota i privezivanja" + + + + + diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 5966c7155e..a8acebe2e9 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -1,8 +1,29 @@ + + - "USB-мадэм або хот-спот Wi-Fi актыўныя" - "Дакраніцеся, каб наладзіць." - "Рэжым мадэма адключаны" - "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Мадэм або хот-спот актыўныя" + "Дакраніцеся, каб наладзіць." + "Рэжым мадэма выключаны" + "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Стан \"Хот-спот і мадэм\"" + + + + + diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index ed58d7311a..94fb2d8f17 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -1,8 +1,29 @@ + + - "Има активна споделена връзка или безжична точка за достъп" - "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" - "Свържете се с администратора си за подробности" + "Има активна споделена връзка или точка за достъп" + "Докоснете, за да настроите." + "Функцията за тетъринг е деактивирана" + "Свържете се с администратора си за подробности" + "Състояние на функцията за точка за достъп и тетъринг" + + + + + diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 8d9880aa9a..aea02b9ddf 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -1,8 +1,29 @@ + + - "টিথারিং বা হটস্পট সক্রিয় আছে" - "সেট-আপ করার জন্য আলতো চাপুন৷" - "টিথারিং অক্ষম করা আছে" - "বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন" + "টিথারিং বা হটস্পট চালু আছে" + "সেট-আপ করতে ট্যাপ করুন।" + "টিথারিং বন্ধ করা আছে" + "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" + "হটস্পট ও টিথারিং স্ট্যাটাস" + + + + + diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index 2361b9dd38..de232724c5 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -1,8 +1,29 @@ + + - "Uređaj dijeli vezu ili djeluje kao pristupna tačka" - "Dodirnite za postavke" - "Povezivanje putem mobitela je onemogućeno" - "Kontaktirajte svog administratora za dodatne detalje" + "Aktivno je povezivanje putem mobitela ili pristupna tačka" + "Dodirnite da postavite." + "Povezivanje putem mobitela je onemogućeno" + "Kontaktirajte svog administratora za detalje" + "Status pristupne tačke i povezivanja putem mobitela" + + + + + diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index 6752b519e2..88b795c1f8 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -1,8 +1,29 @@ + + - "Compartició de xarxa o punt d\'accés Wi-Fi activat" - "Toca per configurar." - "La compartició de xarxa està desactivada" - "Contacta amb el teu administrador per obtenir més informació" + "Compartició de xarxa o punt d\'accés Wi‑Fi actius" + "Toca per configurar." + "La compartició de xarxa està desactivada" + "Contacta amb el teu administrador per obtenir més informació" + "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" + + + + + diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5fdd53adf1..8c1b83bf3e 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -1,8 +1,29 @@ + + - "Sdílené připojení nebo hotspot je aktivní." - "Klepnutím zahájíte nastavení." - "Tethering je zakázán" - "O podrobnosti požádejte administrátora" + "Tethering nebo hotspot je aktivní" + "Klepnutím zahájíte nastavení." + "Tethering je zakázán" + "O podrobnosti požádejte administrátora" + "Stav hotspotu a tetheringu" + + + + + diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 2775dfa551..f413e70548 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -1,8 +1,29 @@ + + - "Netdeling eller hotspot er aktivt" - "Tryk for at konfigurere" - "Netdeling er deaktiveret" - "Kontakt din administrator for at få oplysninger" + "Netdeling eller hotspot er aktivt" + "Tryk for at konfigurere." + "Netdeling er deaktiveret" + "Kontakt din administrator for at få oplysninger" + "Status for hotspot og netdeling" + + + + + diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 9046cd5e11..f057d7824e 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering oder Hotspot aktiv" - "Zum Einrichten tippen." - "Tethering ist deaktiviert" - "Bitte wende dich für weitere Informationen an den Administrator" + "Tethering oder Hotspot aktiv" + "Zum Einrichten tippen." + "Tethering ist deaktiviert" + "Bitte wende dich für weitere Informationen an den Administrator" + "Hotspot- und Tethering-Status" + + + + + diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3b9f53733b..b3c986bdaf 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -1,8 +1,29 @@ + + - "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" - "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" - "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" + "Πατήστε για ρύθμιση." + "Η σύνδεση είναι απενεργοποιημένη" + "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" + + + + + diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 7f47fc89d2..f1674bed4e 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -1,8 +1,29 @@ + + - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎Tethering is disabled‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" + + + + + diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index e4618b8cec..63689f4399 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -1,8 +1,29 @@ + + - "Anclaje a red o zona activa conectados" - "Presiona para configurar." - "Se inhabilitó la conexión mediante dispositivo portátil" - "Para obtener más información, comunícate con el administrador" + "Conexión a red o hotspot conectados" + "Presiona para configurar esta opción." + "Se inhabilitó la conexión mediante dispositivo portátil" + "Para obtener más información, comunícate con el administrador" + "Estado del hotspot y la conexión mediante dispositivo portátil" + + + + + diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 8dc1575ce8..9a34ed5e38 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -1,8 +1,29 @@ + + - "Compartir conexión/Zona Wi-Fi activada" - "Toca para configurar." - "La conexión compartida está inhabilitada" - "Ponte en contacto con el administrador para obtener más información" + "Conexión compartida o punto de acceso activos" + "Toca para configurar." + "La conexión compartida está inhabilitada" + "Solicita más información a tu administrador" + "Estado del punto de acceso y de la conexión compartida" + + + + + diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index 872c8a74cc..0970341ab0 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -1,8 +1,29 @@ + + - "Jagamine või kuumkoht on aktiivne" - "Puudutage seadistamiseks." - "Jagamine on keelatud" - "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Jagamine või kuumkoht on aktiivne" + "Puudutage seadistamiseks." + "Jagamine on keelatud" + "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Kuumkoha ja jagamise olek" + + + + + diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index 6c4605e616..632019e2ef 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -1,8 +1,29 @@ + + - "Konexioa partekatzea edo sare publikoa aktibo" - "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" - "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Konexioa partekatzea edo wifi-gunea aktibo dago" + "Sakatu konfiguratzeko." + "Desgaituta dago konexioa partekatzeko aukera" + "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Wifi-gunearen eta konexioa partekatzeko eginbidearen egoera" + + + + + diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index bc2ee23609..2e21c85fa1 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -1,8 +1,29 @@ + + - "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" - "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" - "برای جزئیات، با سرپرستتان تماس بگیرید" + "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" + "برای راه‌اندازی ضربه بزنید." + "اشتراک‌گذاری اینترنت غیرفعال است" + "برای جزئیات، با سرپرستتان تماس بگیرید" + "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" + + + + + diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index ff0fca6502..413db3f0f8 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -1,8 +1,29 @@ + + - "Internetin jakaminen tai yhteyspiste käytössä" - "Määritä napauttamalla." - "Yhteyden jakaminen poistettu käytöstä" - "Kysy lisätietoja järjestelmänvalvojalta." + "Yhteyden jakaminen tai hotspot käytössä" + "Ota käyttöön napauttamalla." + "Yhteyden jakaminen on poistettu käytöstä" + "Pyydä lisätietoja järjestelmänvalvojalta" + "Hotspotin ja yhteyden jakamisen tila" + + + + + diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 1f5df0ee0c..eb2e4ba540 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -1,8 +1,29 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Touchez pour configurer." - "Le partage de connexion est désactivé" - "Communiquez avec votre administrateur pour obtenir plus de détails" + "Partage de connexion ou point d\'accès sans fil activé" + "Touchez pour configurer." + "Le partage de connexion est désactivé" + "Communiquez avec votre administrateur pour obtenir plus de détails" + "Point d\'accès et partage de connexion" + + + + + diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index daf7c9d830..22259c52ab 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -1,8 +1,29 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Appuyez ici pour configurer." - "Le partage de connexion est désactivé" - "Pour en savoir plus, contactez votre administrateur" + "Partage de connexion ou point d\'accès activé" + "Appuyez pour effectuer la configuration." + "Le partage de connexion est désactivé" + "Pour en savoir plus, contactez votre administrateur" + "État du point d\'accès et du partage de connexion" + + + + + diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 0d16a1de09..ded82fcd54 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -1,8 +1,29 @@ + + - "Conexión compartida ou zona wifi activada" - "Tocar para configurar." - "A conexión compartida está desactivada" - "Contacta co administrador para obter información" + "Conexión compartida ou zona wifi activada" + "Toca para configurar." + "A conexión compartida está desactivada" + "Contacta co administrador para obter información" + "Estado da zona wifi e da conexión compartida" + + + + + diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index 9d6b02f85f..7cbbc2de3d 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -1,8 +1,29 @@ + + - "ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય" - "સેટ કરવા માટે ટૅપ કરો." - "ટિથરિંગ અક્ષમ કરેલ છે" - "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" + "સેટઅપ કરવા માટે ટૅપ કરો." + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" + "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" + + + + + diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index 9c29d9a8f9..08af81b826 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -1,8 +1,29 @@ + + - "टेदरिंग या हॉटस्‍पॉट सक्रिय" - "सेट करने के लिए टैप करें." - "टेदरिंग अक्षम है" - "जानकारी के लिए अपने एडमिन से संपर्क करें" + "टेदरिंग या हॉटस्पॉट चालू है" + "सेट अप करने के लिए टैप करें." + "टेदरिंग बंद है" + "जानकारी के लिए अपने एडमिन से संपर्क करें" + "हॉटस्पॉट और टेदरिंग की स्थिति" + + + + + diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index d0d25bb755..827c135f20 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -1,8 +1,29 @@ + + - "Ograničenje ili aktivan hotspot" - "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" - "Obratite se administratoru da biste saznali pojedinosti" + "Modemsko povezivanje ili žarišna točka aktivni" + "Dodirnite da biste postavili." + "Modemsko je povezivanje onemogućeno" + "Obratite se administratoru da biste saznali pojedinosti" + "Status žarišne točke i modemskog povezivanja" + + + + + diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index 3129659923..eb68d6babf 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -1,8 +1,29 @@ + + - "Megosztás vagy aktív hotspot" - "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" - "A részletekért forduljon rendszergazdájához" + "Megosztás vagy aktív hotspot" + "Koppintson a beállításhoz." + "Az internetmegosztás le van tiltva" + "A részletekért forduljon rendszergazdájához" + "Hotspot és internetmegosztás állapota" + + + + + diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index 8ba6435fd5..912941e538 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -1,8 +1,29 @@ + + - "Մոդեմի ռեժիմը միացված է" - "Հպեք՝ կարգավորելու համար:" - "Մոդեմի ռեժիմն անջատված է" - "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Մոդեմի ռեժիմը միացված է" + "Հպեք՝ կարգավորելու համար։" + "Մոդեմի ռեժիմն անջատված է" + "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" + + + + + diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 1e093ab237..a4e175a439 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering (Penambatan) atau hotspot aktif" - "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" - "Hubungi admin untuk mengetahui detailnya" + "Tethering atau hotspot aktif" + "Ketuk untuk menyiapkan." + "Tethering dinonaktifkan" + "Hubungi admin untuk mengetahui detailnya" + "Status hotspot & tethering" + + + + + diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index f5769d5344..e9f6670bcd 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -1,8 +1,29 @@ + + - "Kveikt á tjóðrun eða aðgangsstað" - "Ýttu til að setja upp." - "Slökkt er á tjóðrun" - "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Kveikt á tjóðrun eða aðgangsstað" + "Ýttu til að setja upp." + "Slökkt er á tjóðrun" + "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Staða heits reits og tjóðrunar" + + + + + diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index e0b3724325..ffb9196f5e 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering oppure hotspot attivo" - "Tocca per impostare." - "Tethering disattivato" - "Contatta il tuo amministratore per avere informazioni dettagliate" + "Hotspot o tethering attivo" + "Tocca per impostare." + "Tethering disattivato" + "Contatta il tuo amministratore per avere informazioni dettagliate" + "Stato hotspot e tethering" + + + + + diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c002c44b23..7adcb47350 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -1,8 +1,29 @@ + + - "שיתוף אינטרנט פעיל" - "הקש כדי להגדיר." - "שיתוף האינטרנט בין ניידים מושבת" - "לפרטים, יש לפנות למנהל המערכת" + "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" + "יש להקיש כדי להגדיר." + "שיתוף האינטרנט בין מכשירים מושבת" + "לפרטים, יש לפנות למנהל המערכת" + "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" + + + + + diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index 314bde00df..f68a73010b 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -1,8 +1,29 @@ + + - "テザリングまたはアクセスポイントが有効です" - "タップしてセットアップします。" - "テザリングは無効に設定されています" - "詳しくは、管理者にお問い合わせください" + "テザリングまたはアクセス ポイントが有効です" + "タップしてセットアップします。" + "テザリングは無効に設定されています" + "詳しくは、管理者にお問い合わせください" + "アクセス ポイントとテザリングのステータス" + + + + + diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 7bbd81d343..7c22e82bd3 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -1,8 +1,29 @@ + + - "ტეტერინგი ან უსადენო ქსელი აქტიურია" - "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" - "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "ტეტერინგი ან უსადენო ქსელი აქტიურია" + "შეეხეთ დასაყენებლად." + "ტეტერინგი გათიშულია" + "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "უსადენო ქსელის და ტეტერინგის სტატუსი" + + + + + diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 7fd87a1596..0857d06de2 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -1,8 +1,29 @@ + + - "Тетеринг немесе хотспот қосулы" - "Реттеу үшін түртіңіз." - "Тетеринг өшірілді" - "Мәліметтерді әкімшіден алыңыз" + "Тетеринг немесе хотспот қосулы" + "Реттеу үшін түртіңіз." + "Тетеринг өшірілді." + "Мәліметтерді әкімшіден алыңыз." + "Хотспот және тетеринг күйі" + + + + + diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 2f85224679..536e3d1703 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -1,8 +1,29 @@ + + - "ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម" - "ប៉ះដើម្បីកំណត់" - "ការភ្ជាប់​ត្រូវបានបិទ" - "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត" + "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" + "ចុច​ដើម្បី​រៀបចំ។" + "ការភ្ជាប់​ត្រូវបានបិទ" + "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" + "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" + + + + + diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index f11a83ea40..32f54926f4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -1,8 +1,29 @@ + + - "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" - "ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" - "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" + "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." + "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" + "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" + + + + + diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index 57f24f5b1a..156b24786d 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -1,8 +1,29 @@ + + - "테더링 또는 핫스팟 사용" - "설정하려면 탭하세요." - "테더링이 사용 중지됨" - "자세한 정보는 관리자에게 문의하세요." + "테더링 또는 핫스팟 사용" + "설정하려면 탭하세요." + "테더링이 사용 중지됨" + "자세한 정보는 관리자에게 문의하세요." + "핫스팟 및 테더링 상태" + + + + + diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 79854859d4..18ee5fd357 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -1,8 +1,29 @@ + + - "Жалгаштыруу же хотспот жандырылган" - "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" - "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Модем режими күйүп турат" + "Жөндөө үчүн таптап коюңуз." + "Телефонду модем катары колдонууга болбойт" + "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Байланыш түйүнүнүн жана модем режиминин статусу" + + + + + diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index 78f1585f60..b12767018c 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -1,8 +1,29 @@ + + - "ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ" - "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" - "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" + "ແຕະເພື່ອຕັ້ງຄ່າ." + "ການປ່ອຍສັນຍານຖືກປິດໄວ້" + "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" + + + + + diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index ebff8ac9d1..8427baf39f 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -1,8 +1,29 @@ + + - "Susietas ar aktyvus" - "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" - "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" + "Palieskite, kad nustatytumėte." + "Įrenginio kaip modemo naudojimas išjungtas" + "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" + + + + + diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index 54d0048b52..aa2d6990e0 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -1,8 +1,29 @@ + + - "Piesaiste vai tīklājs ir aktīvs." - "Pieskarieties, lai iestatītu." - "Piesaiste ir atspējota" - "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Piesaiste vai tīklājs ir aktīvs." + "Pieskarieties, lai to iestatītu." + "Piesaiste ir atspējota" + "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Tīklāja un piesaistes statuss" + + + + + diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml new file mode 100644 index 0000000000..19d659c6ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -0,0 +1,24 @@ + + + + + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" + "Bykomende heffings kan geld terwyl jy swerf" + diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml new file mode 100644 index 0000000000..8995430b4f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -0,0 +1,24 @@ + + + + + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml new file mode 100644 index 0000000000..54f3b5389a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -0,0 +1,24 @@ + + + + + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." + diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml new file mode 100644 index 0000000000..e215141c9e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -0,0 +1,24 @@ + + + + + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml new file mode 100644 index 0000000000..1fd8e4c963 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..1abe4f3aa3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" + "Možda važe dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml new file mode 100644 index 0000000000..38dbd1e391 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -0,0 +1,24 @@ + + + + + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml new file mode 100644 index 0000000000..04b44db5c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml new file mode 100644 index 0000000000..579d1be1c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -0,0 +1,24 @@ + + + + + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" + diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml new file mode 100644 index 0000000000..9ce3efe6c3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml new file mode 100644 index 0000000000..46d4c35b9b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -0,0 +1,24 @@ + + + + + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" + "És possible que s\'apliquin costos addicionals en itinerància" + diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml new file mode 100644 index 0000000000..cc13860b3d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" + "Při roamingu mohou být účtovány dodatečné poplatky" + diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml new file mode 100644 index 0000000000..92c3ae1156 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -0,0 +1,24 @@ + + + + + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml new file mode 100644 index 0000000000..967eb4db2e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml new file mode 100644 index 0000000000..5fb497451f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -0,0 +1,24 @@ + + + + + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml new file mode 100644 index 0000000000..7877074afc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -0,0 +1,24 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml new file mode 100644 index 0000000000..08edd81a6b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml new file mode 100644 index 0000000000..79f51d00e2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" + "Puede que se apliquen cargos adicionales en itinerancia" + diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml new file mode 100644 index 0000000000..2da5f8a6d6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -0,0 +1,24 @@ + + + + + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" + "Rändluse kasutamisega võivad kaasneda lisatasud" + diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml new file mode 100644 index 0000000000..2073f2806c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" + diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml new file mode 100644 index 0000000000..e21b2a0852 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -0,0 +1,24 @@ + + + + + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml new file mode 100644 index 0000000000..88b0b13eb4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" + "Roaming voi aiheuttaa lisämaksuja" + diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml new file mode 100644 index 0000000000..3b781bc8db --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml new file mode 100644 index 0000000000..51d7203c36 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml new file mode 100644 index 0000000000..008ccb475d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -0,0 +1,24 @@ + + + + + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" + "Pódense aplicar cargos adicionais en itinerancia" + diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml new file mode 100644 index 0000000000..f2e3b4df78 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -0,0 +1,24 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" + diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml new file mode 100644 index 0000000000..b11839d760 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml new file mode 100644 index 0000000000..0a5aca25b1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" + "U roamingu su mogući dodatni troškovi" + diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml new file mode 100644 index 0000000000..21c689a44e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" + "Roaming során további díjak léphetnek fel" + diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml new file mode 100644 index 0000000000..689d92870e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -0,0 +1,24 @@ + + + + + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml new file mode 100644 index 0000000000..a5f4d19abf --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" + "Biaya tambahan mungkin berlaku saat roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml new file mode 100644 index 0000000000..fc7e8aaf4e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" + "Viðbótargjöld kunna að eiga við í reiki" + diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml new file mode 100644 index 0000000000..6456dd1b80 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml new file mode 100644 index 0000000000..46b24bd3c5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -0,0 +1,24 @@ + + + + + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml new file mode 100644 index 0000000000..e6eb277b90 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -0,0 +1,24 @@ + + + + + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" + "ローミング時に追加料金が発生することがあります" + diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml new file mode 100644 index 0000000000..aeddd7101d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -0,0 +1,24 @@ + + + + + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml new file mode 100644 index 0000000000..255f0a276f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml new file mode 100644 index 0000000000..2bceb1cf77 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -0,0 +1,24 @@ + + + + + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml new file mode 100644 index 0000000000..ed769305a6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -0,0 +1,24 @@ + + + + + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" + diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml new file mode 100644 index 0000000000..6e504941eb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -0,0 +1,24 @@ + + + + + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml new file mode 100644 index 0000000000..d68128b9a5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml new file mode 100644 index 0000000000..03e134a0fc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -0,0 +1,24 @@ + + + + + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" + diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml new file mode 100644 index 0000000000..652cedc6e6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml new file mode 100644 index 0000000000..221972298c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml new file mode 100644 index 0000000000..227f9e3466 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" + "При роаминг може да се наплатат дополнителни трошоци" + diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml new file mode 100644 index 0000000000..ec43885126 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -0,0 +1,24 @@ + + + + + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" + diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml new file mode 100644 index 0000000000..e263573799 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml new file mode 100644 index 0000000000..adf845d078 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml new file mode 100644 index 0000000000..f65c451e4c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -0,0 +1,24 @@ + + + + + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml new file mode 100644 index 0000000000..4118e775cd --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -0,0 +1,24 @@ + + + + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml new file mode 100644 index 0000000000..36853583ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" + "Ytterligere kostnader kan påløpe under roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml new file mode 100644 index 0000000000..2a7330098f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" + diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml new file mode 100644 index 0000000000..1d888942f4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml new file mode 100644 index 0000000000..8038815fe8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -0,0 +1,24 @@ + + + + + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" + diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml new file mode 100644 index 0000000000..819833eab0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -0,0 +1,24 @@ + + + + + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" + diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml new file mode 100644 index 0000000000..65e4380e39 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml new file mode 100644 index 0000000000..d8866170c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml new file mode 100644 index 0000000000..bfd45ca0a3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -0,0 +1,24 @@ + + + + + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" + "Podem aplicar-se custos adicionais em roaming." + diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml new file mode 100644 index 0000000000..d8866170c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml new file mode 100644 index 0000000000..8d87a9e516 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -0,0 +1,24 @@ + + + + + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" + "Se pot aplica taxe suplimentare pentru roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml new file mode 100644 index 0000000000..dbdb9ebe49 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -0,0 +1,24 @@ + + + + + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml new file mode 100644 index 0000000000..d8301e41c2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -0,0 +1,24 @@ + + + + + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml new file mode 100644 index 0000000000..bef71363f4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml new file mode 100644 index 0000000000..3202c62e8a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml new file mode 100644 index 0000000000..37f6ad2868 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml new file mode 100644 index 0000000000..5566d03ed1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" + "Можда важе додатни трошкови у ромингу" + diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml new file mode 100644 index 0000000000..9765acd0cf --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" + "Ytterligare avgifter kan tillkomma vid roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml new file mode 100644 index 0000000000..cf850c9cd2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -0,0 +1,24 @@ + + + + + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml new file mode 100644 index 0000000000..ea04821e33 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" + diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml new file mode 100644 index 0000000000..937d34d520 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -0,0 +1,24 @@ + + + + + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" + diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml new file mode 100644 index 0000000000..f781fae525 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -0,0 +1,24 @@ + + + + + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml new file mode 100644 index 0000000000..8d5d465373 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml new file mode 100644 index 0000000000..80cab33ac0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml new file mode 100644 index 0000000000..c05932a5ae --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" + "У роумінгу може стягуватися додаткова плата" + diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml new file mode 100644 index 0000000000..d820eee8ba --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -0,0 +1,24 @@ + + + + + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml new file mode 100644 index 0000000000..726148aaee --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" + diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml new file mode 100644 index 0000000000..b7cb0456b6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml new file mode 100644 index 0000000000..af91afff9a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + + + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" + "漫游时可能会产生额外的费用" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml new file mode 100644 index 0000000000..28e6b80c01 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" + "漫遊時可能需要支付額外費用" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml new file mode 100644 index 0000000000..05b90692ea --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過數據連線連上網際網路" + "裝置無法連線" + "關閉數據連線" + "無線基地台或數據連線已開啟" + "使用漫遊服務可能須支付額外費用" + diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml new file mode 100644 index 0000000000..11eb666219 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml new file mode 100644 index 0000000000..9bfa5317a9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -0,0 +1,24 @@ + + + + + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" + "Bykomende heffings kan geld terwyl jy swerf" + diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml new file mode 100644 index 0000000000..5949dfa776 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -0,0 +1,24 @@ + + + + + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml new file mode 100644 index 0000000000..8467f9b1f5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -0,0 +1,24 @@ + + + + + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." + diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml new file mode 100644 index 0000000000..9776bd89da --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -0,0 +1,24 @@ + + + + + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml new file mode 100644 index 0000000000..e6d3eaf9f0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..4c8a1df8ee --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" + "Možda važe dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml new file mode 100644 index 0000000000..edfa41e1ff --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -0,0 +1,24 @@ + + + + + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml new file mode 100644 index 0000000000..f56398196f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml new file mode 100644 index 0000000000..d8ecd2e988 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -0,0 +1,24 @@ + + + + + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" + diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml new file mode 100644 index 0000000000..b85fd5e285 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml new file mode 100644 index 0000000000..a3572151be --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -0,0 +1,24 @@ + + + + + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" + "És possible que s\'apliquin costos addicionals en itinerància" + diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml new file mode 100644 index 0000000000..91196be9e5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" + "Při roamingu mohou být účtovány dodatečné poplatky" + diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml new file mode 100644 index 0000000000..196890011d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -0,0 +1,24 @@ + + + + + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml new file mode 100644 index 0000000000..eb3f8c52c0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml new file mode 100644 index 0000000000..56c3d81b63 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -0,0 +1,24 @@ + + + + + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml new file mode 100644 index 0000000000..d3347aae20 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -0,0 +1,24 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml new file mode 100644 index 0000000000..2f0504f07d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml new file mode 100644 index 0000000000..2d8f882425 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" + "Puede que se apliquen cargos adicionales en itinerancia" + diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml new file mode 100644 index 0000000000..8493c47071 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -0,0 +1,24 @@ + + + + + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" + "Rändluse kasutamisega võivad kaasneda lisatasud" + diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml new file mode 100644 index 0000000000..33bccab3e8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" + diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml new file mode 100644 index 0000000000..cf8a0cc277 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -0,0 +1,24 @@ + + + + + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml new file mode 100644 index 0000000000..6a3ab806db --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" + "Roaming voi aiheuttaa lisämaksuja" + diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml new file mode 100644 index 0000000000..ffb9bf6047 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml new file mode 100644 index 0000000000..768bce3f0a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml new file mode 100644 index 0000000000..0c4195a7ca --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -0,0 +1,24 @@ + + + + + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" + "Pódense aplicar cargos adicionais en itinerancia" + diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml new file mode 100644 index 0000000000..e9d33a7db2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -0,0 +1,24 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" + diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml new file mode 100644 index 0000000000..aa418ac5d3 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml new file mode 100644 index 0000000000..51c524afbc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" + "U roamingu su mogući dodatni troškovi" + diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml new file mode 100644 index 0000000000..164e45edd1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" + "Roaming során további díjak léphetnek fel" + diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml new file mode 100644 index 0000000000..e76c0a4c80 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -0,0 +1,24 @@ + + + + + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml new file mode 100644 index 0000000000..2b817f8abd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" + "Biaya tambahan mungkin berlaku saat roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml new file mode 100644 index 0000000000..a338d9c7ca --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" + "Viðbótargjöld kunna að eiga við í reiki" + diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml new file mode 100644 index 0000000000..77769c2ac5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml new file mode 100644 index 0000000000..5267b51264 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -0,0 +1,24 @@ + + + + + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml new file mode 100644 index 0000000000..66a9a6dd35 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -0,0 +1,24 @@ + + + + + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" + "ローミング時に追加料金が発生することがあります" + diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml new file mode 100644 index 0000000000..d8ad880849 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -0,0 +1,24 @@ + + + + + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml new file mode 100644 index 0000000000..1ddd6b419b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml new file mode 100644 index 0000000000..cf5a1379cc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -0,0 +1,24 @@ + + + + + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml new file mode 100644 index 0000000000..68ae68bc19 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -0,0 +1,24 @@ + + + + + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" + diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml new file mode 100644 index 0000000000..17185ba2d0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -0,0 +1,24 @@ + + + + + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml new file mode 100644 index 0000000000..6a9fb9810c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml new file mode 100644 index 0000000000..bcc4b57626 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -0,0 +1,24 @@ + + + + + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" + diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml new file mode 100644 index 0000000000..011c2c11fb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml new file mode 100644 index 0000000000..5cb2f3b7aa --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml new file mode 100644 index 0000000000..4cbfd887c5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" + "При роаминг може да се наплатат дополнителни трошоци" + diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml new file mode 100644 index 0000000000..9cf4eaf34a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -0,0 +1,24 @@ + + + + + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" + diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml new file mode 100644 index 0000000000..47c82c14d9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml new file mode 100644 index 0000000000..ad9e809ab2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml new file mode 100644 index 0000000000..e708cb8717 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -0,0 +1,24 @@ + + + + + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml new file mode 100644 index 0000000000..ba5462250b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -0,0 +1,24 @@ + + + + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml new file mode 100644 index 0000000000..57db484a25 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" + "Ytterligere kostnader kan påløpe under roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml new file mode 100644 index 0000000000..617c50dd0c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" + diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml new file mode 100644 index 0000000000..b08133f4e5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml new file mode 100644 index 0000000000..1ad4ca354a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -0,0 +1,24 @@ + + + + + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" + diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml new file mode 100644 index 0000000000..88def563d8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -0,0 +1,24 @@ + + + + + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" + diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml new file mode 100644 index 0000000000..f9890abdc2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml new file mode 100644 index 0000000000..ce3b88479f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml new file mode 100644 index 0000000000..7e883ea576 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -0,0 +1,24 @@ + + + + + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" + "Podem aplicar-se custos adicionais em roaming." + diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml new file mode 100644 index 0000000000..ce3b88479f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml new file mode 100644 index 0000000000..1009417316 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -0,0 +1,24 @@ + + + + + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" + "Se pot aplica taxe suplimentare pentru roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml new file mode 100644 index 0000000000..88683bed95 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -0,0 +1,24 @@ + + + + + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml new file mode 100644 index 0000000000..176bcdb797 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -0,0 +1,24 @@ + + + + + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml new file mode 100644 index 0000000000..b9e2127fa8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml new file mode 100644 index 0000000000..e8140e686a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml new file mode 100644 index 0000000000..61e698d6e8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml new file mode 100644 index 0000000000..b4c411c354 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" + "Можда важе додатни трошкови у ромингу" + diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml new file mode 100644 index 0000000000..4f543e47b9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" + "Ytterligare avgifter kan tillkomma vid roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml new file mode 100644 index 0000000000..ac347ab485 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -0,0 +1,24 @@ + + + + + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml new file mode 100644 index 0000000000..0e437593ee --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" + diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml new file mode 100644 index 0000000000..9360297dd8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -0,0 +1,24 @@ + + + + + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" + diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml new file mode 100644 index 0000000000..9c4d7e08f2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -0,0 +1,24 @@ + + + + + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml new file mode 100644 index 0000000000..a7c78a5932 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml new file mode 100644 index 0000000000..93da2c3f79 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml new file mode 100644 index 0000000000..ee0dcd2c4b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" + "У роумінгу може стягуватися додаткова плата" + diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml new file mode 100644 index 0000000000..41cd28eef9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -0,0 +1,24 @@ + + + + + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml new file mode 100644 index 0000000000..c847bc943b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" + diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml new file mode 100644 index 0000000000..a74326f09e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml new file mode 100644 index 0000000000..d7370036e3 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + + + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" + "漫游时可能会产生额外的费用" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml new file mode 100644 index 0000000000..f378a9dc2c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" + "漫遊時可能需要支付額外費用" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml new file mode 100644 index 0000000000..ea01b943fb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過數據連線連上網際網路" + "裝置無法連線" + "關閉數據連線" + "無線基地台或數據連線已開啟" + "使用漫遊服務可能須支付額外費用" + diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml new file mode 100644 index 0000000000..32f6df56f1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 0fab8aa476..9ad9b9a589 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -1,8 +1,29 @@ + + - "Поврзувањето или точката на пристап се активни" - "Допрете за поставување." - "Врзувањето е оневозможено" - "Контактирајте со администраторот за детали" + "Активно е врзување или точка на пристап" + "Допрете за поставување." + "Врзувањето е оневозможено" + "Контактирајте со администраторот за детали" + "Статус на точката на пристап и врзувањето" + + + + + diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index fd7e556e38..9db79ce220 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -1,8 +1,29 @@ + + - "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" - "സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" - "വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" + "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." + "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" + "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" + + + + + diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4596577c5d..42d1edbace 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -1,8 +1,29 @@ + + - "Модем болгох эсвэл идэвхтэй цэг болгох" - "Тохируулахын тулд товшино уу." - "Модем болгох боломжгүй байна" - "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" + "Тохируулахын тулд товшино уу." + "Модем болгохыг идэвхгүй болгосон" + "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Сүлжээний цэг болон модем болгох төлөв" + + + + + diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index 85c9ade4fe..13995b6b8a 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -1,8 +1,29 @@ + + - "टेदरिंग किंवा हॉटस्पॉट सक्रिय" - "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद आहे" - "तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा" + "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" + "सेट करण्यासाठी टॅप करा." + "टेदरिंग बंद केले आहे" + "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" + "हॉटस्पॉट आणि टेदरिंगची स्थिती" + + + + + diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index ec6bdbda08..d6a67f37b1 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -1,8 +1,29 @@ + + - "Penambatan atau titik panas aktif" - "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" - "Hubungi pentadbir anda untuk maklumat lanjut" + "Penambatan atau tempat liputan aktif" + "Ketik untuk membuat persediaan." + "Penambatan dilumpuhkan" + "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" + "Status tempat liputan & penambatan" + + + + + diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 83978b67d4..49f6b88a75 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -1,8 +1,29 @@ + + - "တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" - "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်" - "အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" + "စနစ်ထည့်သွင်းရန် တို့ပါ။" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" + "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" + + + + + diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 9abf32dd7b..9594e0a70a 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -1,8 +1,29 @@ + + - "Internettdeling eller trådløs sone er aktiv" - "Trykk for å konfigurere." - "Internettdeling er slått av" - "Ta kontakt med administratoren din for å få mer informasjon" + "Internettdeling eller Wi-Fi-sone er aktiv" + "Trykk for å konfigurere." + "Internettdeling er slått av" + "Ta kontakt med administratoren din for å få mer informasjon" + "Status for Wi-Fi-sone og internettdeling" + + + + + diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index c8869298a5..72ae3a80a9 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -1,8 +1,29 @@ + + - "टेथर गर्ने वा हटस्पट सक्रिय" - "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङलाई असक्षम पारिएको छ" - "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "टेदरिङ वा हटस्पट सक्रिय छ" + "सेटअप गर्न ट्याप गर्नुहोस्।" + "टेदरिङ सुविधा असक्षम पारिएको छ" + "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "हटस्पट तथा टेदरिङको स्थिति" + + + + + diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 0ec4bff621..18b2bbfc76 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering of hotspot actief" - "Tik om in te stellen." - "Tethering is uitgeschakeld" - "Neem contact op met je beheerder voor meer informatie" + "Tethering of hotspot actief" + "Tik om in te stellen." + "Tethering is uitgeschakeld" + "Neem contact op met je beheerder voor meer informatie" + "Status van hotspot en tethering" + + + + + diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 457685795a..a15a6db42a 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -1,8 +1,29 @@ + + - "ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି" - "ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।" - "ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି" - "ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" + "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" + "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" + "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" + + + + + diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index deddf2ea27..a8235e423e 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -1,8 +1,29 @@ + + - "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" - "ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ" - "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ" + "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" + "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" + "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" + "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" + + + + + diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index 48d8468935..ccb017d43f 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -1,8 +1,29 @@ + + - "Aktywny tethering lub punkt dostępu" - "Kliknij, by skonfigurować." - "Tethering został wyłączony" - "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Aktywny tethering lub punkt dostępu" + "Kliknij, by skonfigurować" + "Tethering został wyłączony" + "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Hotspot i tethering – stan" + + + + + diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 32c22b8713..a0a4745f93 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -1,8 +1,29 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 641e22f44f..e3f03fcc69 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -1,8 +1,29 @@ + + - "Ligação ponto a ponto ou hotspot activos" - "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." - "Contacte o gestor para obter detalhes." + "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" + "Toque para configurar." + "A ligação (à Internet) via telemóvel está desativada." + "Contacte o administrador para obter detalhes." + "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" + + + + + diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 32c22b8713..a0a4745f93 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -1,8 +1,29 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index f861f733b4..5706a4a69c 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering sau hotspot activ" - "Atingeți ca să configurați." - "Tetheringul este dezactivat" - "Contactați administratorul pentru detalii" + "Tethering sau hotspot activ" + "Atingeți ca să configurați." + "Tetheringul este dezactivat" + "Contactați administratorul pentru detalii" + "Starea hotspotului și a tetheringului" + + + + + diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 027cb410c5..7cb6f7db3f 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -1,8 +1,29 @@ + + - "Включен режим модема" - "Нажмите, чтобы настроить." - "Включить режим модема нельзя" - "Обратитесь к администратору, чтобы узнать подробности." + "Включен режим модема или точка доступа" + "Нажмите, чтобы настроить." + "Использование телефона в качестве модема запрещено" + "Чтобы узнать подробности, обратитесь к администратору." + "Статус хот-спота и режима модема" + + + + + diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index 7d8599f2c2..ec34c22de7 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -1,8 +1,29 @@ + + - "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" - "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" - "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" + "පිහිටුවීමට තට්ටු කරන්න." + "ටෙදරින් අබල කර ඇත" + "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" + + + + + diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index a8fe297c00..43e787c84f 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering alebo prístupový bod je aktívny" - "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" - "O podrobnosti požiadajte svojho správcu" + "Tethering alebo prístupový bod je aktívny" + "Klepnutím prejdete na nastavenie." + "Tethering je deaktivovaný" + "O podrobnosti požiadajte svojho správcu" + "Stav hotspotu a tetheringu" + + + + + diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index b5e5e3856f..59433626a1 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -1,8 +1,29 @@ + + - "Aktivna povezava z internetom ali dostopna točka sta aktivni" - "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" - "Za podrobnosti se obrnite na skrbnika" + "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" + "Dotaknite se, če želite nastaviti." + "Povezava z internetom prek mobilnega telefona je onemogočena" + "Za podrobnosti se obrnite na skrbnika" + "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" + + + + + diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index fdd4906cc5..21e11558bb 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -1,8 +1,29 @@ + + - "Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive" - "Trokit për ta konfiguruar." - "Lidhja e çiftimit është çaktivizuar" - "Kontakto me administratorin për detaje" + "Ndarja e internetit ose zona e qasjes së internetit është aktive" + "Trokit për ta konfiguruar." + "Ndarja e internetit është çaktivizuar" + "Kontakto me administratorin për detaje" + "Statusi i zonës së qasjes dhe ndarjes së internetit" + + + + + diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index 9fab345897..e2e4dc6361 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -1,8 +1,29 @@ + + - "Активно повезивање са интернетом преко мобилног уређаја или хотспот" - "Додирните да бисте подесили." - "Привезивање је онемогућено" - "Потражите детаље од администратора" + "Привезивање или хотспот је активан" + "Додирните да бисте подесили." + "Привезивање је онемогућено" + "Потражите детаље од администратора" + "Статус хотспота и привезивања" + + + + + diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index 10eeb0fe12..72702c2858 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -1,8 +1,29 @@ + + - "Internetdelning eller surfzon aktiverad" - "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" - "Kontakta administratören om du vill veta mer" + "Internetdelning eller surfzon har aktiverats" + "Tryck om du vill konfigurera." + "Internetdelning har inaktiverats" + "Kontakta administratören om du vill veta mer" + "Trådlös surfzon och internetdelning har inaktiverats" + + + + + diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index 3353963077..65e4aa8ceb 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -1,8 +1,29 @@ + + - "Kushiriki au kusambaza intaneti kumewashwa" - "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" - "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Kusambaza mtandao au mtandaopepe umewashwa" + "Gusa ili uweke mipangilio." + "Umezima kipengele cha kusambaza mtandao" + "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Mtandaopepe na hali ya kusambaza mtandao" + + + + + diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index b1e5cc2413..4aba62d4ab 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -1,8 +1,29 @@ + + - "டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது" - "அமைக்க, தட்டவும்." - "இணைப்பு முறை முடக்கப்பட்டுள்ளது" - "விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" + "அமைக்க, தட்டவும்." + "டெதெரிங் முடக்கப்பட்டுள்ளது" + "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" + + + + + diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index aae40dee40..1f91791341 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -1,8 +1,29 @@ + + - "టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది" - "సెటప్ చేయడానికి నొక్కండి." - "టెథెరింగ్ నిలిపివేయబడింది" - "వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి" + "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" + "సెటప్ చేయడానికి ట్యాప్ చేయండి." + "టెథరింగ్ డిజేబుల్ చేయబడింది" + "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" + "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" + + + + + diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index 1b800565ad..44171c0db8 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -1,8 +1,29 @@ + + - "การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่" - "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" - "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" + "แตะเพื่อตั้งค่า" + "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" + "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + + + + + diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 12863f90e1..7347dd3e62 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -1,8 +1,29 @@ + + - "Pagsasama o aktibong hotspot" - "I-tap upang i-set up." - "Naka-disable ang pag-tether" - "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Aktibo ang pag-tether o hotspot" + "I-tap para i-set up." + "Naka-disable ang pag-tether" + "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Status ng hotspot at pag-tether" + + + + + diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index bfcf1ace2c..32030f1765 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering veya hotspot etkin" - "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" - "Ayrıntılı bilgi için yöneticinize başvurun" + "Tethering veya hotspot etkin" + "Ayarlamak için dokunun." + "Tethering devre dışı bırakıldı" + "Ayrıntılı bilgi için yöneticinize başvurun" + "Hotspot ve tethering durumu" + + + + + diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 8e159c0723..1ca89b3f78 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -1,8 +1,29 @@ + + - "Прив\'язка чи точка дост. активна" - "Торкніться, щоб налаштувати." - "Використання телефона в режимі модема вимкнено" - "Щоб дізнатися більше, зв’яжіться з адміністратором" + "Модем чи точка доступу активні" + "Натисніть, щоб налаштувати." + "Використання телефона як модема вимкнено" + "Щоб дізнатися більше, зв\'яжіться з адміністратором" + "Статус точки доступу та модема" + + + + + diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 89195d4aae..d72c7d4195 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -1,8 +1,29 @@ + + - "ٹیدرنگ یا ہاٹ اسپاٹ فعال" - "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" - "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ٹیدرنگ یا ہاٹ اسپاٹ فعال" + "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" + "ٹیدرنگ غیر فعال ہے" + "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" + + + + + diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 0ac4d4a741..af3b2ebb35 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -1,8 +1,29 @@ + + - "Modem rejimi yoniq" - "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" - "Tafsilotlari uchun administratoringizga murojaat qiling" + "Modem rejimi yoki hotspot yoniq" + "Sozlash uchun bosing." + "Modem rejimi faolsizlantirildi" + "Tafsilotlari uchun administratoringizga murojaat qiling" + "Hotspot va modem rejimi holati" + + + + + diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 85a4db8aa5..21a0735922 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -1,8 +1,29 @@ + + - "Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động" - "Nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" - "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" + "Hãy nhấn để thiết lập." + "Đã tắt tính năng chia sẻ Internet" + "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Trạng thái điểm phát sóng và chia sẻ Internet" + + + + + diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index ff1fe03953..98e3b4b46f 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -1,8 +1,29 @@ + + - "网络共享或热点已启用" - "点按即可进行设置。" - "网络共享已停用" - "请与您的管理员联系以了解详情" + "网络共享或热点已启用" + "点按即可设置。" + "网络共享已停用" + "如需了解详情,请与您的管理员联系" + "热点和网络共享状态" + + + + + diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 0de39fac97..9cafd42dd4 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -1,8 +1,29 @@ + + - "已啟用網絡共享或熱點" - "輕按即可設定。" - "網絡共享已停用" - "請聯絡您的管理員以瞭解詳情" + "網絡共享或熱點已啟用" + "輕按即可設定。" + "網絡共享已停用" + "請聯絡您的管理員以瞭解詳情" + "熱點和網絡共享狀態" + + + + + diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9a117bbca4..9d738a76eb 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -1,8 +1,29 @@ + + - "網路共用或無線基地台已啟用" - "輕觸即可進行設定。" - "數據連線已停用" - "詳情請洽你的管理員" + "數據連線或無線基地台已啟用" + "輕觸即可進行設定。" + "數據連線已停用" + "詳情請洽你的管理員" + "無線基地台與數據連線狀態" + + + + + diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index 8fe10d86cb..f210f8726e 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -1,8 +1,29 @@ + + - "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" - "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" - "Xhumana nomphathi wakho ukuze uthole imininingwane" + "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" + "Thepha ukuze usethe." + "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" + "Xhumana nomphathi wakho ukuze uthole imininingwane" + "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" + + + + + From f46d6a1e8d1d059d2b6597ab100786f179e5dafd Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Thu, 23 Apr 2020 13:28:22 +0000 Subject: [PATCH 1012/1415] Test enable tethering permission and stopAllTethering 1. Test whether start tethering is gated by suitable permission. 2. Test stopAllTethering Bug: 153613718 Test: atest CtsTetheringTest Merged-In: I38702886ea355e1aec8eb8ac404fdd46a44582e3 Change-Id: I38702886ea355e1aec8eb8ac404fdd46a44582e3 --- tests/cts/tethering/Android.bp | 1 + .../tethering/cts/TetheringManagerTest.java | 274 ++++++++++++------ 2 files changed, 189 insertions(+), 86 deletions(-) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 37894ec4dc..9f32403c98 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -28,6 +28,7 @@ android_test { "TetheringCommonTests", "TetheringIntegrationTestsLib", "compatibility-device-util-axt", + "net-tests-utils", "ctstestrunner-axt", "junit", "junit-params", diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index ccad14cdd2..60f9400363 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,20 +15,24 @@ */ package android.tethering.test; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; +import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.app.UiAutomation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -48,6 +52,8 @@ import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.testutils.ArrayTrackRecord; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -77,11 +83,21 @@ public class TetheringManagerTest { private static final int DEFAULT_TIMEOUT_MS = 60_000; + private void adoptShellPermissionIdentity() { + final UiAutomation uiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uiAutomation.adoptShellPermissionIdentity(); + } + + private void dropShellPermissionIdentity() { + final UiAutomation uiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uiAutomation.dropShellPermissionIdentity(); + } + @Before public void setUp() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(); + adoptShellPermissionIdentity(); mContext = InstrumentationRegistry.getContext(); mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); mTetherChangeReceiver = new TetherChangeReceiver(); @@ -93,10 +109,9 @@ public class TetheringManagerTest { @After public void tearDown() throws Exception { + mTM.stopAllTethering(); mContext.unregisterReceiver(mTetherChangeReceiver); - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .dropShellPermissionIdentity(); + dropShellPermissionIdentity(); } private class TetherChangeReceiver extends BroadcastReceiver { @@ -202,15 +217,54 @@ public class TetheringManagerTest { } } - private class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static int TIMEOUT_MS = 30_000; + public static class CallbackValue { + public final int error; + + private CallbackValue(final int e) { + error = e; + } + + public static class OnTetheringStarted extends CallbackValue { + OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); } + } + + public static class OnTetheringFailed extends CallbackValue { + OnTetheringFailed(final int error) { super(error); } + } + + @Override + public String toString() { + return String.format("%s(%d)", getClass().getSimpleName(), error); + } + } + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + @Override public void onTetheringStarted() { - // Do nothing, TetherChangeReceiver will wait until it receives the broadcast. + mHistory.add(new CallbackValue.OnTetheringStarted()); } @Override public void onTetheringFailed(final int error) { - fail("startTethering fail: " + error); + mHistory.add(new CallbackValue.OnTetheringFailed(error)); + } + + public void verifyTetheringStarted() { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv); + assertTrue("Fail start tethering:" + cv, + cv instanceof CallbackValue.OnTetheringStarted); + } + + public void expectTetheringFailed(final int expected) throws InterruptedException { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv); + assertTrue("Expect fail with error code " + expected + ", but received: " + cv, + (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected)); } } @@ -244,8 +298,10 @@ public class TetheringManagerTest { mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(), - startTetheringCallback); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); + mTetherChangeReceiver.expectActiveTethering(wifiRegexs); mTM.stopTethering(TETHERING_WIFI); @@ -277,6 +333,7 @@ public class TetheringManagerTest { // Must poll the callback before looking at the member. private static class TestTetheringEventCallback implements TetheringEventCallback { + private static final int TIMEOUT_MS = 30_000; public enum CallbackType { ON_SUPPORTED, ON_UPSTREAM, @@ -299,7 +356,10 @@ public class TetheringManagerTest { this.callbackParam2 = param2; } } - private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + private TetheringInterfaceRegexps mTetherableRegex; private List mTetherableIfaces; @@ -307,108 +367,96 @@ public class TetheringManagerTest { @Override public void onTetheringSupported(boolean supported) { - mCallbacks.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); } @Override public void onUpstreamChanged(Network network) { - mCallbacks.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); } @Override public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { mTetherableRegex = reg; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); } @Override public void onTetherableInterfacesChanged(List interfaces) { mTetherableIfaces = interfaces; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); } @Override public void onTetheredInterfacesChanged(List interfaces) { mTetheredIfaces = interfaces; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); } @Override public void onError(String ifName, int error) { - mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); + mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); } @Override public void onClientsChanged(Collection clients) { - mCallbacks.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); } @Override public void onOffloadStatusChanged(int status) { - mCallbacks.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); - } - - public CallbackValue pollCallback() { - try { - return mCallbacks.poll(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - fail("Callback not seen"); - } - return null; + mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); } public void expectTetherableInterfacesChanged(@NonNull List regexs) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected tetherable ifaces callback"); - if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) continue; - - final List interfaces = (List) cv.callbackParam; - if (isIfaceMatch(regexs, interfaces)) break; - } + assertNotNull("No expected tetherable ifaces callback", mHistory.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; + final List interfaces = (List) cv.callbackParam; + return isIfaceMatch(regexs, interfaces); + })); } public void expectTetheredInterfacesChanged(@NonNull List regexs) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected tethered ifaces callback"); - if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) continue; + assertNotNull("No expected tethered ifaces callback", mHistory.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; - final List interfaces = (List) cv.callbackParam; + final List interfaces = (List) cv.callbackParam; - // Null regexs means no active tethering. - if (regexs == null) { - if (interfaces.size() == 0) break; - } else if (isIfaceMatch(regexs, interfaces)) { - break; - } - } + // Null regexs means no active tethering. + if (regexs == null) return interfaces.isEmpty(); + + return isIfaceMatch(regexs, interfaces); + })); } public void expectCallbackStarted() { + int receivedBitMap = 0; // The each bit represent a type from CallbackType.ON_*. // Expect all of callbacks except for ON_ERROR. - final int expectedBitMap = 0x7f ^ (1 << CallbackType.ON_ERROR.ordinal()); - int receivedBitMap = 0; - while (receivedBitMap != expectedBitMap) { - final CallbackValue cv = pollCallback(); + final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal()); + // Receive ON_ERROR on started callback is not matter. It just means tethering is + // failed last time, should able to continue the test this time. + while ((receivedBitMap & expectedBitMap) != expectedBitMap) { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); if (cv == null) { fail("No expected callbacks, " + "expected bitmap: " + expectedBitMap + ", actual: " + receivedBitMap); } - receivedBitMap = receivedBitMap | (1 << cv.callbackType.ordinal()); + receivedBitMap |= (1 << cv.callbackType.ordinal()); } } public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected offload status change callback"); - if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) continue; + assertNotNull("No offload status changed", mHistory.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; final int status = (int) cv.callbackParam; - for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return; - } + for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return true; + + return false; + })); } public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { @@ -424,52 +472,78 @@ public class TetheringManagerTest { } } - @Test - public void testRegisterTetheringEventCallback() throws Exception { - if (!mTM.isTetheringSupported()) return; - + private TestTetheringEventCallback registerTetheringEventCallback() { final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); - mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); + mTM.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); tetherEventCallback.expectCallbackStarted(); - tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - final TetheringInterfaceRegexps tetherableRegexs = - tetherEventCallback.getTetheringInterfaceRegexps(); - final List wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); - if (wifiRegexs.size() == 0) return; + return tetherEventCallback; + } + private void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) { + mTM.unregisterTetheringEventCallback(callback); + } + + private List getWifiTetherableInterfaceRegexps( + final TestTetheringEventCallback callback) { + return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); + } + + private boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) { + return !getWifiTetherableInterfaceRegexps(callback).isEmpty(); + } + + private void startWifiTethering(final TestTetheringEventCallback callback) + throws InterruptedException { + final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); final boolean isIfaceAvailWhenNoTethering = - isIfaceMatch(wifiRegexs, tetherEventCallback.getTetherableInterfaces()); + isIfaceMatch(wifiRegexs, callback.getTetherableInterfaces()); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(), - new StartTetheringCallback()); + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); // If interface is already available before starting tethering, the available callback may // not be sent after tethering enabled. if (!isIfaceAvailWhenNoTethering) { - tetherEventCallback.expectTetherableInterfacesChanged(wifiRegexs); + callback.expectTetherableInterfacesChanged(wifiRegexs); } - tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); - tetherEventCallback.expectOneOfOffloadStatusChanged( + callback.expectTetheredInterfacesChanged(wifiRegexs); + + callback.expectOneOfOffloadStatusChanged( TETHER_HARDWARE_OFFLOAD_STARTED, TETHER_HARDWARE_OFFLOAD_FAILED); + } + private void stopWifiTethering(final TestTetheringEventCallback callback) { mTM.stopTethering(TETHERING_WIFI); + callback.expectTetheredInterfacesChanged(null); + callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + } - tetherEventCallback.expectTetheredInterfacesChanged(null); - tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - mTM.unregisterTetheringEventCallback(tetherEventCallback); + @Test + public void testRegisterTetheringEventCallback() throws Exception { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + + if (!isWifiTetheringSupported(tetherEventCallback)) return; + + startWifiTethering(tetherEventCallback); + + stopWifiTethering(tetherEventCallback); + + unregisterTetheringEventCallback(tetherEventCallback); } @Test public void testGetTetherableInterfaceRegexps() { if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); - mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); - tetherEventCallback.expectCallbackStarted(); + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); final TetheringInterfaceRegexps tetherableRegexs = tetherEventCallback.getTetheringInterfaceRegexps(); @@ -486,7 +560,35 @@ public class TetheringManagerTest { wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); - mTM.unregisterTetheringEventCallback(tetherEventCallback); + unregisterTetheringEventCallback(tetherEventCallback); + } + + @Test + public void testStopAllTethering() throws Exception { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + + if (!isWifiTetheringSupported(tetherEventCallback)) return; + + // TODO: start ethernet tethering here when TetheringManagerTest is moved to + // TetheringIntegrationTest. + + startWifiTethering(tetherEventCallback); + + mTM.stopAllTethering(); + tetherEventCallback.expectTetheredInterfacesChanged(null); + + unregisterTetheringEventCallback(tetherEventCallback); + } + + @Test + public void testEnableTetheringPermission() throws Exception { + dropShellPermissionIdentity(); + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); } private class EntitlementResultListener implements OnTetheringEntitlementResultListener { From b9c19778f4354ceda99930a9030bfe0e6783d8a5 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 1 Apr 2020 12:21:24 +0800 Subject: [PATCH 1013/1415] Remove Preconditions usage to stop dependecy with non-updatble class Stop depending on Preconditions that is not released on the same cadence as the module, and is maintained as part of the framework. Bug: 148636687 Test: atest TetheringTests NetworkStackNextTests Change-Id: Id0dcec44f362f79bc8c046d722635687a7388aa2 --- Tethering/jarjar-rules.txt | 1 - .../networkstack/tethering/UpstreamNetworkMonitor.java | 5 +++-- Tethering/tests/unit/jarjar-rules.txt | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt index c6efa41e58..e90a2ccaa2 100644 --- a/Tethering/jarjar-rules.txt +++ b/Tethering/jarjar-rules.txt @@ -8,7 +8,6 @@ rule com.android.internal.util.BitUtils* com.android.networkstack.tethering.util rule com.android.internal.util.IndentingPrintWriter.java* com.android.networkstack.tethering.util.IndentingPrintWriter.java@1 rule com.android.internal.util.IState.java* com.android.networkstack.tethering.util.IState.java@1 rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.util.MessageUtils@1 -rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1 rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 diff --git a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java index 25ddce4404..320427c393 100644 --- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java +++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java @@ -43,7 +43,6 @@ import android.util.Log; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import com.android.internal.util.StateMachine; import java.util.HashMap; @@ -591,7 +590,9 @@ public class UpstreamNetworkMonitor { // Map from type to transports. final int notFound = -1; final int transport = sLegacyTypeToTransport.get(type, notFound); - Preconditions.checkArgument(transport != notFound, "unknown legacy type: " + type); + if (transport == notFound) { + throw new IllegalArgumentException("unknown legacy type: " + type); + } builder.addTransportType(transport); if (type == TYPE_MOBILE_DUN) { diff --git a/Tethering/tests/unit/jarjar-rules.txt b/Tethering/tests/unit/jarjar-rules.txt index 921fbed373..1ea56cdf1a 100644 --- a/Tethering/tests/unit/jarjar-rules.txt +++ b/Tethering/tests/unit/jarjar-rules.txt @@ -4,7 +4,6 @@ rule com.android.internal.util.BitUtils* com.android.networkstack.tethering.util rule com.android.internal.util.IndentingPrintWriter.java* com.android.networkstack.tethering.util.IndentingPrintWriter.java@1 rule com.android.internal.util.IState.java* com.android.networkstack.tethering.util.IState.java@1 rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.util.MessageUtils@1 -rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1 rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 From 8cfc634bbc75fc9f3f91a725ba60e5118a5bb54f Mon Sep 17 00:00:00 2001 From: evitayan Date: Thu, 16 Apr 2020 23:03:47 -0700 Subject: [PATCH 1014/1415] Create base class that sets up test network This class will be extended by both IkeSessionParamsTest and IkeSessionTestBase Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I98979758a7a684219e35c02ded93224ea172d44f --- .../ike/cts/IkeSessionParamsTestBase.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java new file mode 100644 index 0000000000..c3e3ba353c --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java @@ -0,0 +1,85 @@ +/* + * 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.ipsec.ike.cts; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.LinkAddress; +import android.net.Network; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; +import android.os.Binder; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.AppModeFull; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +abstract class IkeSessionParamsTestBase extends IkeTestBase { + // Static state to reduce setup/teardown + static ConnectivityManager sCM; + static TestNetworkManager sTNM; + static ParcelFileDescriptor sTunFd; + static TestNetworkCallback sTunNetworkCallback; + static Network sTunNetwork; + + static Context sContext = InstrumentationRegistry.getContext(); + static IBinder sBinder = new Binder(); + + // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass + // methods. + @BeforeClass + public static void setUpTestNetworkBeforeClass() throws Exception { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + + TestNetworkInterface testIface = + sTNM.createTunInterface( + new LinkAddress[] {new LinkAddress(IPV4_ADDRESS_LOCAL, IP4_PREFIX_LEN)}); + + sTunFd = testIface.getFileDescriptor(); + sTunNetworkCallback = + TestNetworkUtils.setupAndGetTestNetwork( + sCM, sTNM, testIface.getInterfaceName(), sBinder); + sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); + } + + // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass + // methods. + @AfterClass + public static void tearDownTestNetworkAfterClass() throws Exception { + sCM.unregisterNetworkCallback(sTunNetworkCallback); + + sTNM.teardownTestNetwork(sTunNetwork); + sTunFd.close(); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } +} From 3cd28c2a39a24599a7ee767ec2244590050939ba Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 22 Apr 2020 12:25:23 -0700 Subject: [PATCH 1015/1415] Reland "Pull service dumps to help debug test failures." + Convert tests to use Junit4 + Add annotations to specify required conditions for the test to run. This reverts commit 89099548f8ea46046095ccac1e82c2c88d1d0bee. Bug: 137859686 Change-Id: I7bb2a7e4b2dca3696761e7c030f3380b9226b676 Merged-In: I93317c201a0ea06732e29154ab7e140735381f59 --- tests/cts/hostside/AndroidTest.xml | 5 + tests/cts/hostside/app/Android.bp | 2 + tests/cts/hostside/app/AndroidManifest.xml | 3 +- .../net/hostside/AbstractAppIdleTestCase.java | 76 ++-- .../AbstractBatterySaverModeTestCase.java | 68 +--- .../hostside/AbstractDozeModeTestCase.java | 66 +--- ...ractRestrictBackgroundNetworkTestCase.java | 361 ++---------------- .../cts/net/hostside/AppIdleMeteredTest.java | 13 +- .../net/hostside/AppIdleNonMeteredTest.java | 7 +- .../hostside/BatterySaverModeMeteredTest.java | 13 +- .../BatterySaverModeNonMeteredTest.java | 9 +- .../cts/net/hostside/DataSaverModeTest.java | 66 ++-- .../cts/net/hostside/DozeModeMeteredTest.java | 13 +- .../net/hostside/DozeModeNonMeteredTest.java | 8 +- .../cts/net/hostside/DumpOnFailureRule.java | 91 +++++ .../MeterednessConfigurationRule.java | 60 +++ .../cts/net/hostside/MixedModesTest.java | 230 +++++------ .../cts/net/hostside/NetworkCallbackTest.java | 173 +++++---- .../net/hostside/NetworkPolicyTestUtils.java | 255 +++++++++++++ .../android/cts/net/hostside/Property.java | 70 ++++ .../cts/net/hostside/RequiredProperties.java | 31 ++ .../net/hostside/RequiredPropertiesRule.java | 90 +++++ .../cts/net/HostsideNetworkCallbackTests.java | 8 +- .../cts/net/HostsideNetworkTestCase.java | 3 +- 24 files changed, 939 insertions(+), 782 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index dbff1794e9..5479c51a4c 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -31,4 +31,9 @@

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - - /** - * Resets the (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void tearDownMeteredNetwork() throws Exception { + setBatterySaverMode(false); } + @Test public void testBackgroundNetworkAccess_enabled() throws Exception { - if (!isSupported()) return; - setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -118,9 +80,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { - if (!isSupported()) return; - setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -140,9 +101,8 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_disabled() throws Exception { - if (!isSupported()) return; - assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index f20f1d1c4d..6f32c563c1 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -16,20 +16,25 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE; + import android.os.SystemClock; -import android.util.Log; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Base class for metered and non-metered Doze Mode tests. */ +@RequiredProperties({DOZE_MODE}) abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { - @Override - protected final void setUp() throws Exception { + @Before + public final void setUp() throws Exception { super.setUp(); - if (!isSupported()) return; - // Set initial state. removePowerSaveModeWhitelist(TEST_APP2_PKG); removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); @@ -38,48 +43,15 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor registerBroadcastReceiver(); } - @Override - protected final void tearDown() throws Exception { + @After + public final void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - - try { - tearDownMeteredNetwork(); - } finally { - setDozeMode(false); - } - } - - @Override - protected boolean isSupported() throws Exception { - boolean supported = isDozeModeEnabled(); - if (!supported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); - } - return supported; - } - - /** - * Sets the initial (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void setUpMeteredNetwork() throws Exception { - } - - /** - * Resets the (non) metered network state. - * - *

    By default is empty - it's up to subclasses to override. - */ - protected void tearDownMeteredNetwork() throws Exception { + setDozeMode(false); } + @Test public void testBackgroundNetworkAccess_enabled() throws Exception { - if (!isSupported()) return; - setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -96,9 +68,8 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { - if (!isSupported()) return; - setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -118,19 +89,18 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } + @Test public void testBackgroundNetworkAccess_disabled() throws Exception { - if (!isSupported()) return; - assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(true); } + @RequiredProperties({NOT_LOW_RAM_DEVICE}) + @Test public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() throws Exception { - if (!isSupported() || isLowRamDevice()) return; - setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); try { registerNotificationListenerService(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 40d7e34fcc..57b7bb4f8d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -17,14 +17,22 @@ package com.android.cts.net.hostside; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; -import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static android.os.BatteryManager.BATTERY_PLUGGED_AC; import static android.os.BatteryManager.BATTERY_PLUGGED_USB; import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; -import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.app.ActivityManager; import android.app.Instrumentation; @@ -34,9 +42,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; @@ -44,24 +50,27 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; -import android.os.SystemProperties; import android.provider.Settings; import android.service.notification.NotificationListenerService; -import android.test.InstrumentationTestCase; -import android.text.TextUtils; import android.util.Log; -import com.android.compatibility.common.util.BatteryUtils; +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.runner.RunWith; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + /** * Superclass for tests related to background network restrictions. */ -abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase { - protected static final String TAG = "RestrictBackgroundNetworkTests"; +@RunWith(AndroidJUnit4.class) +public abstract class AbstractRestrictBackgroundNetworkTestCase { + public static final String TAG = "RestrictBackgroundNetworkTests"; protected static final String TEST_PKG = "com.android.cts.net.hostside"; protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; @@ -98,8 +107,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static int PROCESS_STATE_FOREGROUND_SERVICE; - private static final int PROCESS_STATE_TOP = 2; - private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; protected static final int TYPE_COMPONENT_ACTIVTIY = 0; @@ -126,22 +133,23 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected WifiManager mWfm; protected int mUid; private int mMyUid; - private String mMeteredWifi; private MyServiceClient mServiceClient; private String mDeviceIdleConstantsSetting; - private boolean mSupported; private boolean mIsLocationOn; - @Override + @Rule + public final RuleChain mRuleChain = RuleChain.outerRule(new DumpOnFailureRule()) + .around(new RequiredPropertiesRule()) + .around(new MeterednessConfigurationRule()); + protected void setUp() throws Exception { - super.setUp(); PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null); mInstrumentation = getInstrumentation(); - mContext = mInstrumentation.getContext(); - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mContext = getContext(); + mCm = getConnectivityManager(); + mWfm = getWifiManager(); mUid = getUid(TEST_APP2_PKG); mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); @@ -151,10 +159,9 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation if (!mIsLocationOn) { enableLocation(); } - mSupported = setUpActiveNetworkMeteringState(); setAppIdle(false); - Log.i(TAG, "Apps status on " + getName() + ":\n" + Log.i(TAG, "Apps status:\n" + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -165,16 +172,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation final String currentConstants = executeShellCommand("settings get global app_idle_constants"); assertEquals(appIdleConstants, currentConstants); - } + } - @Override protected void tearDown() throws Exception { if (!mIsLocationOn) { disableLocation(); } mServiceClient.unbind(); - - super.tearDown(); } private void enableLocation() throws Exception { @@ -259,23 +263,8 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { final String status = mServiceClient.getRestrictBackgroundStatus(); assertNotNull("didn't get API status from app2", status); - final String actualStatus = toString(Integer.parseInt(status)); - assertEquals("wrong status", toString(expectedStatus), actualStatus); - } - - protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { - final int actualStatus = mCm.getRestrictBackgroundStatus(); - assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); - } - - protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { - final int actualStatus = mCm.getRestrictBackgroundStatus(); - if (expectedStatus != actualStatus) { - Log.d(TAG, "Expected: " + toString(expectedStatus) - + " but actual: " + toString(actualStatus)); - return false; - } - return true; + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(Integer.parseInt(status))); } protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { @@ -297,28 +286,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */); } - /** - * Whether this device suport this type of test. - * - *

    Should be overridden when necessary (but always calling - * {@code super.isSupported()} first), and explicitly used before each test - * Example: - * - *

    
    -     * public void testSomething() {
    -     *    if (!isSupported()) return;
    -     * 
    - * - * @return {@code true} by default. - */ - protected boolean isSupported() throws Exception { - return mSupported; - } - - protected boolean isBatterySaverSupported() { - return BatteryUtils.isBatterySaverSupported(); - } - /** * Asserts that an app always have access while on foreground or running a foreground service. * @@ -387,23 +354,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state ); } - /** - * As per CDD requirements, if the device doesn't support data saver mode then - * ConnectivityManager.getRestrictBackgroundStatus() will always return - * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if - * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns - * RESTRICT_BACKGROUND_STATUS_DISABLED or not. - */ - protected boolean isDataSaverSupported() throws Exception { - assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - try { - setRestrictBackground(true); - return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - } finally { - setRestrictBackground(false); - } - } - /** * Returns whether an app state should be considered "background" for restriction purposes. */ @@ -443,40 +393,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // Exponential back-off. timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS); } - dumpOnFailure(); fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries + " attempts.\nLast error: " + error); } - private void dumpOnFailure() throws Exception { - dumpAllNetworkRules(); - Log.d(TAG, "Usagestats dump: " + getUsageStatsDump()); - executeShellCommand("settings get global app_idle_constants"); - } - - private void dumpAllNetworkRules() throws Exception { - final String networkManagementDump = runShellCommand(mInstrumentation, - "dumpsys network_management").trim(); - final String networkPolicyDump = runShellCommand(mInstrumentation, - "dumpsys netpolicy").trim(); - TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); - splitter.setString(networkManagementDump); - String next; - Log.d(TAG, ">>> Begin network_management dump"); - while (splitter.hasNext()) { - next = splitter.next(); - Log.d(TAG, next); - } - Log.d(TAG, "<<< End network_management dump"); - splitter.setString(networkPolicyDump); - Log.d(TAG, ">>> Begin netpolicy dump"); - while (splitter.hasNext()) { - next = splitter.next(); - Log.d(TAG, next); - } - Log.d(TAG, "<<< End netpolicy dump"); - } - /** * Checks whether the network is available as expected. * @@ -528,22 +448,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return errors.toString(); } - protected boolean isLowRamDevice() { - final ActivityManager am = (ActivityManager) mContext.getSystemService( - Context.ACTIVITY_SERVICE); - return am.isLowRamDevice(); - } - - protected String executeShellCommand(String command) throws Exception { - final String result = runShellCommand(mInstrumentation, command).trim(); - if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'"); - return result; - } - /** * Runs a Shell command which is not expected to generate output. */ - protected void executeSilentShellCommand(String command) throws Exception { + protected void executeSilentShellCommand(String command) { final String result = executeShellCommand(command); assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty()); } @@ -572,10 +480,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation }); } - protected void assertDelayedShellCommand(String command, ExpectResultChecker checker) - throws Exception { - assertDelayedShellCommand(command, 5, 1, checker); - } protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, ExpectResultChecker checker) throws Exception { String result = ""; @@ -592,159 +496,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation + " attempts. Last result: '" + result + "'"); } - /** - * Sets the initial metering state for the active network. - * - *

    It's called on setup and by default does nothing - it's up to the - * subclasses to override. - * - * @return whether the tests in the subclass are supported on this device. - */ - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return true; - } - - /** - * Makes sure the active network is not metered. - * - *

    If the device does not supoprt un-metered networks (for example if it - * only has cellular data but not wi-fi), it should return {@code false}; - * otherwise, it should return {@code true} (or fail if the un-metered - * network could not be set). - * - * @return {@code true} if the network is now unmetered. - */ - protected boolean setUnmeteredNetwork() throws Exception { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - assertNotNull("Could not get active network", info); - if (!mCm.isActiveNetworkMetered()) { - Log.d(TAG, "Active network is not metered: " + info); - } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { - Log.i(TAG, "Setting active WI-FI network as not metered: " + info ); - setWifiMeteredStatus(false); - } else { - Log.d(TAG, "Active network cannot be set to un-metered: " + info); - return false; - } - assertActiveNetworkMetered(false); // Sanity check. - return true; - } - - /** - * Enables metering on the active network if supported. - * - *

    If the device does not support metered networks it should return - * {@code false}; otherwise, it should return {@code true} (or fail if the - * metered network could not be set). - * - * @return {@code true} if the network is now metered. - */ - protected boolean setMeteredNetwork() throws Exception { - final NetworkInfo info = mCm.getActiveNetworkInfo(); - final boolean metered = mCm.isActiveNetworkMetered(); - if (metered) { - Log.d(TAG, "Active network already metered: " + info); - return true; - } else if (info.getType() != ConnectivityManager.TYPE_WIFI) { - Log.w(TAG, "Active network does not support metering: " + info); - return false; - } else { - Log.w(TAG, "Active network not metered: " + info); - } - final String netId = setWifiMeteredStatus(true); - - // Set flag so status is reverted on resetMeteredNetwork(); - mMeteredWifi = netId; - // Sanity check. - assertWifiMeteredStatus(netId, true); - assertActiveNetworkMetered(true); - return true; - } - - /** - * Resets the device metering state to what it was before the test started. - * - *

    This reverts any metering changes made by {@code setMeteredNetwork}. - */ - protected void resetMeteredNetwork() throws Exception { - if (mMeteredWifi != null) { - Log.i(TAG, "resetMeteredNetwork(): SID '" + mMeteredWifi - + "' was set as metered by test case; resetting it"); - setWifiMeteredStatus(mMeteredWifi, false); - assertActiveNetworkMetered(false); // Sanity check. - } - } - - private void assertActiveNetworkMetered(boolean expected) throws Exception { - final int maxTries = 5; - NetworkInfo info = null; - for (int i = 1; i <= maxTries; i++) { - info = mCm.getActiveNetworkInfo(); - if (info == null) { - Log.v(TAG, "No active network info on attempt #" + i - + "; sleeping 1s before polling again"); - } else if (mCm.isActiveNetworkMetered() != expected) { - Log.v(TAG, "Wrong metered status for active network " + info + "; expected=" - + expected + "; sleeping 1s before polling again"); - } else { - break; - } - Thread.sleep(SECOND_IN_MS); - } - assertNotNull("No active network after " + maxTries + " attempts", info); - assertEquals("Wrong metered status for active network " + info, expected, - mCm.isActiveNetworkMetered()); - } - - private String setWifiMeteredStatus(boolean metered) throws Exception { - // We could call setWifiEnabled() here, but it might take sometime to be in a consistent - // state (for example, if one of the saved network is not properly authenticated), so it's - // better to let the hostside test take care of that. - assertTrue("wi-fi is disabled", mWfm.isWifiEnabled()); - // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests - // to make the actual verification of restrictions optional. - final String ssid = mWfm.getConnectionInfo().getSSID(); - return setWifiMeteredStatus(ssid, metered); - } - - private String setWifiMeteredStatus(String ssid, boolean metered) throws Exception { - assertNotNull("null SSID", ssid); - final String netId = ssid.trim().replaceAll("\"", ""); // remove quotes, if any. - assertFalse("empty SSID", ssid.isEmpty()); - - Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered); - final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered; - assertDelayedShellCommand(setCommand, ""); - - return netId; - } - - private void assertWifiMeteredStatus(String netId, boolean status) throws Exception { - final String command = "cmd netpolicy list wifi-networks"; - final String expectedLine = netId + ";" + status; - assertDelayedShellCommand(command, new ExpectResultChecker() { - - @Override - public boolean isExpected(String result) { - return result.contains(expectedLine); - } - - @Override - public String getExpected() { - return "line containing " + expectedLine; - } - }); - } - - protected void setRestrictBackground(boolean enabled) throws Exception { - executeShellCommand("cmd netpolicy set restrict-background " + enabled); - final String output = executeShellCommand("cmd netpolicy get restrict-background "); - final String expectedSuffix = enabled ? "enabled" : "disabled"; - // TODO: use MoreAsserts? - assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", - output.endsWith(expectedSuffix)); - } - protected void addRestrictBackgroundWhitelist(int uid) throws Exception { executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); assertRestrictBackgroundWhitelist(uid, true); @@ -924,7 +675,7 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation protected void setDozeMode(boolean enabled) throws Exception { // Sanity check, since tests should check beforehand.... - assertTrue("Device does not support Doze Mode", isDozeModeEnabled()); + assertTrue("Device does not support Doze Mode", isDozeModeSupported()); Log.i(TAG, "Setting Doze Mode to " + enabled); if (enabled) { @@ -944,43 +695,16 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE"); } - protected boolean isDozeModeEnabled() throws Exception { - final String result = executeShellCommand("cmd deviceidle enabled deep").trim(); - return result.equals("1"); - } - protected void setAppIdle(boolean enabled) throws Exception { Log.i(TAG, "Setting app idle to " + enabled); executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); assertAppIdle(enabled); // Sanity check } - private String getUsageStatsDump() throws Exception { - final String output = runShellCommand(mInstrumentation, "dumpsys usagestats").trim(); - final StringBuilder sb = new StringBuilder(); - final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n'); - splitter.setString(output); - String str; - while (splitter.hasNext()) { - str = splitter.next(); - if (str.contains("package=") - && !str.contains(TEST_PKG) && !str.contains(TEST_APP2_PKG)) { - continue; - } - if (str.trim().startsWith("config=") || str.trim().startsWith("time=")) { - continue; - } - sb.append(str).append('\n'); - } - return sb.toString(); - } - protected void assertAppIdle(boolean enabled) throws Exception { try { assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled); } catch (Throwable e) { - Log.d(TAG, "UsageStats dump:\n" + getUsageStatsDump()); - executeShellCommand("settings get global app_idle_constants"); throw e; } } @@ -1061,12 +785,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation // App didn't come to foreground when the activity is started, so try again. assertForegroundNetworkAccess(); } else { - dumpOnFailure(); fail("Network is not available for app2 (" + mUid + "): " + errors[0]); } } } else { - dumpOnFailure(); fail("Timed out waiting for network availability status from app2 (" + mUid + ")"); } } else { @@ -1150,19 +872,6 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } } - private String toString(int status) { - switch (status) { - case RESTRICT_BACKGROUND_STATUS_DISABLED: - return "DISABLED"; - case RESTRICT_BACKGROUND_STATUS_WHITELISTED: - return "WHITELISTED"; - case RESTRICT_BACKGROUND_STATUS_ENABLED: - return "ENABLED"; - default: - return "UNKNOWN_STATUS_" + status; - } - } - private ProcessState getProcessStateByUid(int uid) throws Exception { return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid)); } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java index 622d99361f..f1858d65a5 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class AppIdleMeteredTest extends AbstractAppIdleTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java index bde71f9100..e737a6dabe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java @@ -16,9 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase { - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java index 3071cfe3f1..c78ca2ec77 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java index 6d3076fe0e..fb52a540d8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -16,10 +16,9 @@ package com.android.cts.net.hostside; -public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) +public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java index cfe6a73a0f..aa2c914e02 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -20,24 +20,33 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; -import android.util.Log; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE; + +import static org.junit.Assert.fail; import com.android.compatibility.common.util.CddTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import androidx.test.filters.LargeTest; + +@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK}) +@LargeTest public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String[] REQUIRED_WHITELISTED_PACKAGES = { "com.android.providers.downloads" }; - private boolean mIsDataSaverSupported; - - @Override + @Before public void setUp() throws Exception { super.setUp(); - mIsDataSaverSupported = isDataSaverSupported(); - // Set initial state. setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); @@ -47,36 +56,15 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertRestrictBackgroundChangedReceived(0); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - - try { - resetMeteredNetwork(); - } finally { - setRestrictBackground(false); - } - } - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected boolean isSupported() throws Exception { - if (!mIsDataSaverSupported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Data Saver Mode"); - } - return mIsDataSaverSupported && super.isSupported(); + setRestrictBackground(false); } + @Test public void testGetRestrictBackgroundStatus_disabled() throws Exception { - if (!isSupported()) return; - assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); // Sanity check: make sure status is always disabled, never whitelisted @@ -88,9 +76,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); } + @Test public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { - if (!isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -107,9 +94,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); } + @Test public void testGetRestrictBackgroundStatus_enabled() throws Exception { - if (!isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -142,9 +128,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertBackgroundNetworkAccess(false); } + @Test public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { - if (!isSupported()) return; - addRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(1); assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); @@ -180,9 +165,8 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase assertsForegroundAlwaysHasNetworkAccess(); } + @Test public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { - if (!isSupported()) return; - final StringBuilder error = new StringBuilder(); for (String packageName : REQUIRED_WHITELISTED_PACKAGES) { int uid = -1; @@ -202,10 +186,10 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase } } + @RequiredProperties({NO_DATA_SAVER_MODE}) @CddTest(requirement="7.4.7/C-2-2") + @Test public void testBroadcastNotSentOnUnsupportedDevices() throws Exception { - if (isSupported()) return; - setRestrictBackground(true); assertRestrictBackgroundChangedReceived(0); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java index e4189af587..4306c991c2 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java @@ -16,15 +16,8 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) public class DozeModeMeteredTest extends AbstractDozeModeTestCase { - - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setMeteredNetwork(); - } - - @Override - protected void tearDownMeteredNetwork() throws Exception { - resetMeteredNetwork(); - } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java index edbbb9e1ce..1e89f158a3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java @@ -16,10 +16,8 @@ package com.android.cts.net.hostside; -public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; - @Override - protected boolean setUpActiveNetworkMeteringState() throws Exception { - return setUnmeteredNetwork(); - } +@RequiredProperties({NON_METERED_NETWORK}) +public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java new file mode 100644 index 0000000000..cedd62a0bc --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG; + +import android.os.Environment; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import com.android.compatibility.common.util.OnFailureRule; + +import org.junit.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class DumpOnFailureRule extends OnFailureRule { + private File mDumpDir = new File(Environment.getExternalStorageDirectory(), + "CtsHostsideNetworkTests"); + + @Override + public void onTestFailure(Statement base, Description description, Throwable throwable) { + final String testName = description.getClassName() + "_" + description.getMethodName(); + + if (throwable instanceof AssumptionViolatedException) { + Log.d(TAG, "Skipping test " + testName + ": " + throwable); + return; + } + + prepareDumpRootDir(); + final File dumpFile = new File(mDumpDir, "dump-" + testName); + Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath()); + try (FileOutputStream out = new FileOutputStream(dumpFile)) { + for (String cmd : new String[] { + "dumpsys netpolicy", + "dumpsys network_management", + "dumpsys usagestats " + TEST_PKG, + "dumpsys usagestats appstandby", + }) { + dumpCommandOutput(out, cmd); + } + } catch (FileNotFoundException e) { + Log.e(TAG, "Error opening file: " + dumpFile, e); + } catch (IOException e) { + Log.e(TAG, "Error closing file: " + dumpFile, e); + } + } + + void dumpCommandOutput(FileOutputStream out, String cmd) { + final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation() + .getUiAutomation().executeShellCommand(cmd); + try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8)); + FileUtils.copy(in, out); + out.write("\n\n=================================================================\n\n" + .getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + Log.e(TAG, "Error dumping '" + cmd + "'", e); + } + } + + void prepareDumpRootDir() { + if (!mDumpDir.exists() && !mDumpDir.mkdir()) { + Log.e(TAG, "Error creating " + mDumpDir); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java new file mode 100644 index 0000000000..8fadf9e295 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.resetMeteredNetwork; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupMeteredNetwork; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +import android.util.ArraySet; +import android.util.Pair; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class MeterednessConfigurationRule extends BeforeAfterRule { + private Pair mSsidAndInitialMeteredness; + + @Override + public void onBefore(Statement base, Description description) throws Throwable { + final ArraySet requiredProperties + = RequiredPropertiesRule.getRequiredProperties(); + if (requiredProperties.contains(METERED_NETWORK)) { + configureNetworkMeteredness(true); + } else if (requiredProperties.contains(NON_METERED_NETWORK)) { + configureNetworkMeteredness(false); + } + } + + @Override + public void onAfter(Statement base, Description description) throws Throwable { + resetNetworkMeteredness(); + } + + public void configureNetworkMeteredness(boolean metered) throws Exception { + mSsidAndInitialMeteredness = setupMeteredNetwork(metered); + } + + public void resetNetworkMeteredness() throws Exception { + if (mSsidAndInitialMeteredness != null) { + resetMeteredNetwork(mSsidAndInitialMeteredness.first, + mSsidAndInitialMeteredness.second); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index b1a21867b3..c9edda6e0b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -15,9 +15,21 @@ */ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + import android.os.SystemClock; import android.util.Log; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + /** * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode * and Data Saver Mode) are applied simultaneously. @@ -29,12 +41,10 @@ import android.util.Log; public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { private static final String TAG = "MixedModesTest"; - @Override + @Before public void setUp() throws Exception { super.setUp(); - if (!isSupported()) return; - // Set initial state. removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); @@ -44,12 +54,10 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { registerBroadcastReceiver(); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!isSupported()) return; - try { setRestrictBackground(false); } finally { @@ -57,34 +65,15 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } - @Override - public boolean isSupported() throws Exception { - if (!isDozeModeEnabled()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); - return false; - } - return true; - } - /** * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, METERED_NETWORK}) + @Test public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) return; - - Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); - if (!setMeteredNetwork()) { - Log.w(TAG, "testDataAndBatterySaverModes_meteredNetwork() skipped because " - + "device cannot use a metered network"); - return; - } - + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); try { setRestrictBackground(true); setBatterySaverMode(true); @@ -137,7 +126,7 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { removeRestrictBackgroundBlacklist(mUid); removePowerSaveModeWhitelist(TEST_APP2_PKG); } finally { - resetMeteredNetwork(); + meterednessConfiguration.resetNetworkMeteredness(); } } @@ -145,86 +134,75 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered * networks. */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, NON_METERED_NETWORK}) + @Test public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + setRestrictBackground(true); + setBatterySaverMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); } - if (!isSupported()) return; - - if (!setUnmeteredNetwork()) { - Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network" - + " is metered"); - return; - } - Log.i(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() tests"); - setRestrictBackground(true); - setBatterySaverMode(true); - - Log.v(TAG, "Not whitelisted for any."); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - - Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); - addRestrictBackgroundWhitelist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - - Log.v(TAG, "Whitelisted for both."); - addRestrictBackgroundWhitelist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundWhitelist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(false); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(false); - removeRestrictBackgroundBlacklist(mUid); - - Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); - addRestrictBackgroundBlacklist(mUid); - addPowerSaveModeWhitelist(TEST_APP2_PKG); - assertBackgroundNetworkAccess(true); - assertsForegroundAlwaysHasNetworkAccess(); - assertBackgroundNetworkAccess(true); - removeRestrictBackgroundBlacklist(mUid); - removePowerSaveModeWhitelist(TEST_APP2_PKG); } /** * Tests that powersave whitelists works as expected when doze and battery saver modes * are enabled. */ + @RequiredProperties({DOZE_MODE, BATTERY_SAVER_MODE}) + @Test public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setDozeMode(true); @@ -250,11 +228,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests that powersave whitelists works as expected when doze and appIdle modes * are enabled. */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -276,11 +252,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -299,16 +273,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setAppIdle(true); @@ -330,11 +297,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { /** * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled. */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -353,11 +318,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { - if (!isSupported()) { - return; - } - setDozeMode(true); setAppIdle(true); @@ -380,16 +343,9 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } } + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { - if (!isBatterySaverSupported()) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Battery saver mode"); - return; - } - if (!isSupported()) { - return; - } - setBatterySaverMode(true); setAppIdle(true); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index 24dde9d356..ed397b91fc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -16,15 +16,26 @@ package com.android.cts.net.hostside; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import android.net.Network; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.Objects; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase { - private boolean mIsDataSaverSupported; private Network mNetwork; private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback(); @@ -132,108 +143,122 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } } - @Override + @Before public void setUp() throws Exception { super.setUp(); - mIsDataSaverSupported = isDataSaverSupported(); - mNetwork = mCm.getActiveNetwork(); - // Set initial state. - setBatterySaverMode(false); registerBroadcastReceiver(); - if (!mIsDataSaverSupported) return; - setRestrictBackground(false); removeRestrictBackgroundWhitelist(mUid); removeRestrictBackgroundBlacklist(mUid); assertRestrictBackgroundChangedReceived(0); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { super.tearDown(); - if (!mIsDataSaverSupported) return; + setRestrictBackground(false); + setBatterySaverMode(false); + } + @RequiredProperties({DATA_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_dataSaver() throws Exception { + // Initial state + setBatterySaverMode(false); + setRestrictBackground(false); + + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); try { - resetMeteredNetwork(); + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable restrict background + setRestrictBackground(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Add to whitelist + addRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Remove from whitelist + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } + + // Set to non-metered network + meterednessConfiguration.configureNetworkMeteredness(false); + try { + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Disable restrict background, should not trigger callback setRestrictBackground(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.assertNoCallback(); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); } } - public void testOnBlockedStatusChanged_data_saver() throws Exception { - if (!mIsDataSaverSupported) return; - - // Prepare metered wifi - if (!setMeteredNetwork()) return; - - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable restrict background - setRestrictBackground(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Add to whitelist - addRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Remove from whitelist - removeRestrictBackgroundWhitelist(mUid); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Set to non-metered network - setUnmeteredNetwork(); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Disable restrict background, should not trigger callback + @RequiredProperties({BATTERY_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_powerSaver() throws Exception { + // Set initial state. + setBatterySaverMode(false); setRestrictBackground(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.assertNoCallback(); - } + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); + try { + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - public void testOnBlockedStatusChanged_power_saver() throws Exception { - // Prepare metered wifi - if (!setMeteredNetwork()) return; + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - // Register callback - registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); - mTestNetworkCallback.expectAvailableCallback(mNetwork); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); - - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } // Set to non-metered network - setUnmeteredNetwork(); - mTestNetworkCallback.assertNoCallback(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + mTestNetworkCallback.assertNoCallback(); - // Enable Power Saver - setBatterySaverMode(true); - assertBackgroundNetworkAccess(false); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); - // Disable Power Saver - setBatterySaverMode(false); - assertBackgroundNetworkAccess(true); - mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } } // TODO: 1. test against VPN lockdown. diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java new file mode 100644 index 0000000000..ca2864c0b8 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.ActivityManager; +import android.app.Instrumentation; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.wifi.WifiManager; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; + +import com.android.compatibility.common.util.AppStandbyUtils; +import com.android.compatibility.common.util.BatteryUtils; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class NetworkPolicyTestUtils { + + private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 5000; + + private static ConnectivityManager mCm; + private static WifiManager mWm; + + private static Boolean mBatterySaverSupported; + private static Boolean mDataSaverSupported; + private static Boolean mDozeModeSupported; + private static Boolean mAppStandbySupported; + + private NetworkPolicyTestUtils() {} + + public static boolean isBatterySaverSupported() { + if (mBatterySaverSupported == null) { + mBatterySaverSupported = BatteryUtils.isBatterySaverSupported(); + } + return mBatterySaverSupported; + } + + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + public static boolean isDataSaverSupported() { + if (mDataSaverSupported == null) { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + mDataSaverSupported = !isMyRestrictBackgroundStatus( + RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + return mDataSaverSupported; + } + + public static boolean isDozeModeSupported() { + if (mDozeModeSupported == null) { + final String result = executeShellCommand("cmd deviceidle enabled deep"); + mDozeModeSupported = result.equals("1"); + } + return mDozeModeSupported; + } + + public static boolean isAppStandbySupported() { + if (mAppStandbySupported == null) { + mAppStandbySupported = AppStandbyUtils.isAppStandbyEnabled(); + } + return mAppStandbySupported; + } + + public static boolean isLowRamDevice() { + final ActivityManager am = (ActivityManager) getContext().getSystemService( + Context.ACTIVITY_SERVICE); + return am.isLowRamDevice(); + } + + public static boolean isActiveNetworkMetered(boolean metered) { + return getConnectivityManager().isActiveNetworkMetered() == metered; + } + + public static boolean canChangeActiveNetworkMeteredness() { + final Network activeNetwork = getConnectivityManager().getActiveNetwork(); + final NetworkCapabilities networkCapabilities + = getConnectivityManager().getNetworkCapabilities(activeNetwork); + return networkCapabilities.hasTransport(TRANSPORT_WIFI); + } + + public static Pair setupMeteredNetwork(boolean metered) throws Exception { + if (isActiveNetworkMetered(metered)) { + return null; + } + final String ssid = unquoteSSID(getWifiManager().getConnectionInfo().getSSID()); + setWifiMeteredStatus(ssid, metered); + return Pair.create(ssid, !metered); + } + + public static void resetMeteredNetwork(String ssid, boolean metered) throws Exception { + setWifiMeteredStatus(ssid, metered); + } + + public static void setWifiMeteredStatus(String ssid, boolean metered) throws Exception { + assertFalse("SSID should not be empty", TextUtils.isEmpty(ssid)); + final String cmd = "cmd netpolicy set metered-network " + ssid + " " + metered; + executeShellCommand(cmd); + assertWifiMeteredStatus(ssid, metered); + assertActiveNetworkMetered(metered); + } + + public static void assertWifiMeteredStatus(String ssid, boolean expectedMeteredStatus) { + final String result = executeShellCommand("cmd netpolicy list wifi-networks"); + final String expectedLine = ssid + ";" + expectedMeteredStatus; + assertTrue("Expected line: " + expectedLine + "; Actual result: " + result, + result.contains(expectedLine)); + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + public static void assertActiveNetworkMetered(boolean expectedMeteredStatus) throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final NetworkCallback networkCallback = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); + if (metered == expectedMeteredStatus) { + latch.countDown(); + } + } + }; + // Registering a callback here guarantees onCapabilitiesChanged is called immediately + // with the current setting. Therefore, if the setting has already been changed, + // this method will return right away, and if not it will wait for the setting to change. + getConnectivityManager().registerDefaultNetworkCallback(networkCallback); + if (!latch.await(TIMEOUT_CHANGE_METEREDNESS_MS, TimeUnit.MILLISECONDS)) { + fail("Timed out waiting for active network metered status to change to " + + expectedMeteredStatus + " ; network = " + + getConnectivityManager().getActiveNetwork()); + } + getConnectivityManager().unregisterNetworkCallback(networkCallback); + } + + public static void setRestrictBackground(boolean enabled) { + executeShellCommand("cmd netpolicy set restrict-background " + enabled); + final String output = executeShellCommand("cmd netpolicy get restrict-background"); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + + public static boolean isMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "MyRestrictBackgroundStatus: " + + "Expected: " + restrictBackgroundValueToString(expectedStatus) + + "; Actual: " + restrictBackgroundValueToString(actualStatus)); + return false; + } + return true; + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + private static String unquoteSSID(String ssid) { + // SSID is returned surrounded by quotes if it can be decoded as UTF-8. + // Otherwise it's guaranteed not to start with a quote. + if (ssid.charAt(0) == '"') { + return ssid.substring(1, ssid.length() - 1); + } else { + return ssid; + } + } + + public static String restrictBackgroundValueToString(int status) { + switch (status) { + case RESTRICT_BACKGROUND_STATUS_DISABLED: + return "DISABLED"; + case RESTRICT_BACKGROUND_STATUS_WHITELISTED: + return "WHITELISTED"; + case RESTRICT_BACKGROUND_STATUS_ENABLED: + return "ENABLED"; + default: + return "UNKNOWN_STATUS_" + status; + } + } + + public static String executeShellCommand(String command) { + final String result = runShellCommand(command).trim(); + Log.d(TAG, "Output of '" + command + "': '" + result + "'"); + return result; + } + + public static void assertMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(actualStatus)); + } + + public static ConnectivityManager getConnectivityManager() { + if (mCm == null) { + mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + } + return mCm; + } + + public static WifiManager getWifiManager() { + if (mWm == null) { + mWm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + } + return mWm; + } + + public static Context getContext() { + return getInstrumentation().getContext(); + } + + public static Instrumentation getInstrumentation() { + return InstrumentationRegistry.getInstrumentation(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java new file mode 100644 index 0000000000..18805f9613 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDataSaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isLowRamDevice; + +public enum Property { + BATTERY_SAVER_MODE(1 << 0) { + public boolean isSupported() { return isBatterySaverSupported(); } + }, + + DATA_SAVER_MODE(1 << 1) { + public boolean isSupported() { return isDataSaverSupported(); } + }, + + NO_DATA_SAVER_MODE(~DATA_SAVER_MODE.getValue()) { + public boolean isSupported() { return !isDataSaverSupported(); } + }, + + DOZE_MODE(1 << 2) { + public boolean isSupported() { return isDozeModeSupported(); } + }, + + APP_STANDBY_MODE(1 << 3) { + public boolean isSupported() { return isAppStandbySupported(); } + }, + + NOT_LOW_RAM_DEVICE(1 << 4) { + public boolean isSupported() { return !isLowRamDevice(); } + }, + + METERED_NETWORK(1 << 5) { + public boolean isSupported() { + return isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness(); + } + }, + + NON_METERED_NETWORK(~METERED_NETWORK.getValue()) { + public boolean isSupported() { + return isActiveNetworkMetered(false) || canChangeActiveNetworkMeteredness(); + } + }; + + private int mValue; + + Property(int value) { mValue = value; } + + public int getValue() { return mValue; } + + abstract boolean isSupported(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java new file mode 100644 index 0000000000..96838bba0a --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({METHOD, TYPE}) +@Inherited +public @interface RequiredProperties { + Property[] value(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java new file mode 100644 index 0000000000..1e333200db --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.Log; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.Assume; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.util.ArrayList; +import java.util.Collections; + +public class RequiredPropertiesRule extends BeforeAfterRule { + + private static ArraySet mRequiredProperties; + + @Override + public void onBefore(Statement base, Description description) { + mRequiredProperties = getAllRequiredProperties(description); + + final String testName = description.getClassName() + "#" + description.getMethodName(); + assertTestIsValid(testName, mRequiredProperties); + Log.i(TAG, "Running test " + testName + " with required properties: " + + propertiesToString(mRequiredProperties)); + } + + private ArraySet getAllRequiredProperties(Description description) { + final ArraySet allRequiredProperties = new ArraySet<>(); + RequiredProperties requiredProperties = description.getAnnotation(RequiredProperties.class); + if (requiredProperties != null) { + Collections.addAll(allRequiredProperties, requiredProperties.value()); + } + + for (Class clazz = description.getTestClass(); + clazz != null; clazz = clazz.getSuperclass()) { + requiredProperties = clazz.getDeclaredAnnotation(RequiredProperties.class); + if (requiredProperties == null) { + continue; + } + for (Property requiredProperty : requiredProperties.value()) { + if (!allRequiredProperties.contains(~requiredProperty.getValue())) { + allRequiredProperties.add(requiredProperty); + } + } + } + return allRequiredProperties; + } + + private void assertTestIsValid(String testName, ArraySet requiredProperies) { + if (requiredProperies == null) { + return; + } + final ArrayList unsupportedProperties = new ArrayList<>(); + for (Property property : requiredProperies) { + if (!property.isSupported()) { + unsupportedProperties.add(property); + } + } + Assume.assumeTrue("Unsupported properties: " + + propertiesToString(unsupportedProperties), unsupportedProperties.isEmpty()); + } + + public static ArraySet getRequiredProperties() { + return mRequiredProperties; + } + + private static String propertiesToString(Iterable properties) { + return "[" + TextUtils.join(",", properties) + "]"; + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java index 8d6c4acd7d..1312085478 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java @@ -29,14 +29,14 @@ public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase { uninstallPackage(TEST_APP2_PKG, true); } - public void testOnBlockedStatusChanged_data_saver() throws Exception { + public void testOnBlockedStatusChanged_dataSaver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_data_saver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_dataSaver"); } - public void testOnBlockedStatusChanged_power_saver() throws Exception { + public void testOnBlockedStatusChanged_powerSaver() throws Exception { runDeviceTests(TEST_PKG, - TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_power_saver"); + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_powerSaver"); } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index a2443b391a..ce203795f9 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -79,7 +79,8 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void installPackage(String apk) throws FileNotFoundException, DeviceNotAvailableException { CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); - assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false)); + assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), + false /* reinstall */, true /* grantPermissions */)); } protected void uninstallPackage(String packageName, boolean shouldSucceed) From a0e71e89eaef5491aa8363c6287712bf261c8491 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 22 Apr 2020 13:50:15 -0700 Subject: [PATCH 1016/1415] Fix Error Prone errors Soong wasn't including android_app or android_test sources in the javac-check target used for the Error Prone build, which allowed some Error Prone errors to get in. Fix them so Error Prone can be re-enabled for these targets. Fixes: cts/hostsidetests/net/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java:61: error: [CollectionIncompatibleType] Argument '~requiredProperty.getValue()' should not be passed to this method; its type int is not compatible with its collection's type argument Property Bug: 146455923 Test: m RUN_ERROR_PRONE=true javac-check Change-Id: I7c5bf823bf371902285ce3ee3929796fa40c653b Merged-In: I48b1ccb61c807d0b41a165298ef5981258d6656e --- .../android/cts/net/hostside/RequiredPropertiesRule.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java index 1e333200db..98c97c5687 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java @@ -58,8 +58,12 @@ public class RequiredPropertiesRule extends BeforeAfterRule { continue; } for (Property requiredProperty : requiredProperties.value()) { - if (!allRequiredProperties.contains(~requiredProperty.getValue())) { - allRequiredProperties.add(requiredProperty); + for (Property p : Property.values()) { + if (p.getValue() == ~requiredProperty.getValue()) { + if (!allRequiredProperties.contains(p)) { + allRequiredProperties.add(requiredProperty); + } + } } } } From 004c442de90543dd2ba3b8d152f7a2b90e0b2c91 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 5 Feb 2020 17:54:01 -0800 Subject: [PATCH 1017/1415] Fix a regression in how required properties are collected. + Enable app standby mode before running the tests. Fixes: 147459100 Fixes: 117169751 Test: atest hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Test: cts-tradefed run singleCommand cts-on-gsi --skip-device-info \ --skip-preconditions -m CtsHostsideNetworkTests \ -t com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: I782f8a06922622d28f9a9d5c9f2afa2b12f8aa80 Merged-In: I782f8a06922622d28f9a9d5c9f2afa2b12f8aa80 --- tests/cts/hostside/AndroidTest.xml | 1 + .../net/hostside/RequiredPropertiesRule.java | 8 +-- .../cts/net/NetworkPolicyTestsPreparer.java | 59 +++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 5479c51a4c..d4f30e0cf3 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -21,6 +21,7 @@

    If not set, the default value is null. */ public DhcpServingParamsParcelExt setSingleClientAddr(@Nullable Inet4Address clientAddr) { - this.clientAddr = clientAddr == null ? 0 : inet4AddressToIntHTH(clientAddr); + this.singleClientAddr = clientAddr == null ? 0 : inet4AddressToIntHTH(clientAddr); return this; } diff --git a/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java index f8eb1476ba..a8857b2e5c 100644 --- a/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java +++ b/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java @@ -110,7 +110,7 @@ public class DhcpServingParamsParcelExtTest { @Test public void testSetClientAddr() { mParcel.setSingleClientAddr(TEST_CLIENT_ADDRESS); - assertEquals(TEST_CLIENT_ADDRESS_PARCELED, mParcel.clientAddr); + assertEquals(TEST_CLIENT_ADDRESS_PARCELED, mParcel.singleClientAddr); } private static Inet4Address inet4Addr(String addr) { diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 28bfae0ced..c798cf403c 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -1689,7 +1689,7 @@ public class TetheringTest { final DhcpServingParamsParcel params = dhcpParamsCaptor.getValue(); assertEquals(serverAddr, intToInet4AddressHTH(params.serverAddr).getHostAddress()); assertEquals(24, params.serverAddrPrefixLength); - assertEquals(clientAddrParceled, params.clientAddr); + assertEquals(clientAddrParceled, params.singleClientAddr); } @Test From 1a54afc5b194161deac341eaebed1553b6c5448b Mon Sep 17 00:00:00 2001 From: markchien Date: Sun, 19 Apr 2020 22:50:35 +0800 Subject: [PATCH 1020/1415] Test legacy tether/untether API and onError callback Test legacy tether/untether API behavior. tether() rely on downstream setup ready for tethering. Currently the only user is bluetooth tethering. For other tetherings, there is no guaranteed that calling tether() can always switch given interface to tethered. Tethering may callback with onError depend on the interface status. Caller should use startTethering/stopTethering API instead of these legacy APIs. This change also change the precondition verification of startTethering. If tethering interface got error last time, such interface would not be reported as tetherable. Bug: 150632712 Test: atest CtsTetheringTest Change-Id: Ifb3a0618208ffd0ff224c60f377036bc22ba0565 --- .../tethering/cts/TetheringManagerTest.java | 116 ++++++++---------- 1 file changed, 54 insertions(+), 62 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 60f9400363..11ffe2c456 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -21,6 +21,7 @@ import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; @@ -31,6 +32,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.app.UiAutomation; import android.content.BroadcastReceiver; @@ -64,10 +66,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) @@ -140,28 +140,24 @@ public class TetheringManagerTest { public final LinkedBlockingQueue mResult = new LinkedBlockingQueue<>(); - // This method expects either an event where one of the interfaces is active, or events - // where the interfaces are available followed by one event where one of the interfaces is - // active. Here is a typical example for wifi tethering: - // AVAILABLE(wlan0) -> AVAILABLE(wlan1) -> ACTIVATE(wlan1). - public void expectActiveTethering(String[] ifaceRegexs) { - TetherState state = null; + // Expects that tethering reaches the desired state. + // - If active is true, expects that tethering is enabled on at least one interface + // matching ifaceRegexs. + // - If active is false, expects that tethering is disabled on all the interfaces matching + // ifaceRegexs. + // Fails if any interface matching ifaceRegexs becomes errored. + public void expectTethering(final boolean active, final String[] ifaceRegexs) { while (true) { - state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS); - if (state == null) fail("Do not receive active state change broadcast"); + final TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS, ifaceRegexs); + assertNotNull("Did not receive expected state change, active: " + active, state); - if (isIfaceActive(ifaceRegexs, state)) return; - - if (!isIfaceAvailable(ifaceRegexs, state)) break; + if (isIfaceActive(ifaceRegexs, state) == active) return; } - - fail("Tethering is not actived, available ifaces: " + state.mAvailable.toString() - + ", active ifaces: " + state.mActive.toString()); } - private TetherState pollAndAssertNoError(final int timeout) { + private TetherState pollAndAssertNoError(final int timeout, final String[] ifaceRegexs) { final TetherState state = pollTetherState(timeout); - assertNoErroredIfaces(state); + assertNoErroredIfaces(state, ifaceRegexs); return state; } @@ -178,43 +174,13 @@ public class TetheringManagerTest { return isIfaceMatch(ifaceRegexs, state.mActive); } - private boolean isIfaceAvailable(final String[] ifaceRegexs, final TetherState state) { - return isIfaceMatch(ifaceRegexs, state.mAvailable); - } - - // This method requires a broadcast to have been recorded iff the timeout is non-zero. - public void expectNoActiveTethering(final int timeout) { - final TetherState state = pollAndAssertNoError(timeout); - - if (state == null) { - if (timeout != 0) { - fail("Do not receive tethering state change broadcast"); - } - return; - } - - assertNoActiveIfaces(state); - - for (final TetherState ts : mResult) { - assertNoErroredIfaces(ts); - - assertNoActiveIfaces(ts); - } - } - - private void assertNoErroredIfaces(final TetherState state) { + private void assertNoErroredIfaces(final TetherState state, final String[] ifaceRegexs) { if (state == null || state.mErrored == null) return; - if (state.mErrored.size() > 0) { + if (isIfaceMatch(ifaceRegexs, state.mErrored)) { fail("Found failed tethering interfaces: " + Arrays.toString(state.mErrored.toArray())); } } - - private void assertNoActiveIfaces(final TetherState state) { - if (state.mActive != null && state.mActive.size() > 0) { - fail("Found active tethering interface: " + Arrays.toString(state.mActive.toArray())); - } - } } private static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { @@ -295,17 +261,18 @@ public class TetheringManagerTest { final String[] wifiRegexs = mTM.getTetherableWifiRegexs(); if (wifiRegexs.length == 0) return; - mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */); + final String[] tetheredIfaces = mTM.getTetheredIfaces(); + assertTrue(tetheredIfaces.length == 0); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.verifyTetheringStarted(); - mTetherChangeReceiver.expectActiveTethering(wifiRegexs); + mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); mTM.stopTethering(TETHERING_WIFI); - mTetherChangeReceiver.expectNoActiveTethering(DEFAULT_TIMEOUT_MS); + mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); } @Test @@ -459,6 +426,21 @@ public class TetheringManagerTest { })); } + public void expectErrorOrTethered(final String iface) { + assertNotNull("No expected callback", mHistory.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType == CallbackType.ON_ERROR + && iface.equals((String) cv.callbackParam)) { + return true; + } + if (cv.callbackType == CallbackType.ON_TETHERED_IFACES + && ((List) cv.callbackParam).contains(iface)) { + return true; + } + + return false; + })); + } + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { return mTetherableRegex; } @@ -497,20 +479,13 @@ public class TetheringManagerTest { private void startWifiTethering(final TestTetheringEventCallback callback) throws InterruptedException { final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); - final boolean isIfaceAvailWhenNoTethering = - isIfaceMatch(wifiRegexs, callback.getTetherableInterfaces()); + assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.verifyTetheringStarted(); - // If interface is already available before starting tethering, the available callback may - // not be sent after tethering enabled. - if (!isIfaceAvailWhenNoTethering) { - callback.expectTetherableInterfacesChanged(wifiRegexs); - } - callback.expectTetheredInterfacesChanged(wifiRegexs); callback.expectOneOfOffloadStatusChanged( @@ -534,9 +509,26 @@ public class TetheringManagerTest { startWifiTethering(tetherEventCallback); + final List tetheredIfaces = tetherEventCallback.getTetheredInterfaces(); + assertEquals(1, tetheredIfaces.size()); + final String wifiTetheringIface = tetheredIfaces.get(0); + stopWifiTethering(tetherEventCallback); - unregisterTetheringEventCallback(tetherEventCallback); + try { + final int ret = mTM.tether(wifiTetheringIface); + + // There is no guarantee that the wifi interface will be available after disabling + // the hotspot, so don't fail the test if the call to tether() fails. + assumeTrue(ret == TETHER_ERROR_NO_ERROR); + + // If calling #tether successful, there is a callback to tell the result of tethering + // setup. + tetherEventCallback.expectErrorOrTethered(wifiTetheringIface); + } finally { + mTM.untether(wifiTetheringIface); + unregisterTetheringEventCallback(tetherEventCallback); + } } @Test From a6b3b70278fbb9eb76a154d77088e1e51fea1fc6 Mon Sep 17 00:00:00 2001 From: markchien Date: Sun, 19 Apr 2020 22:50:35 +0800 Subject: [PATCH 1021/1415] Test legacy tether/untether API and onError callback Test legacy tether/untether API behavior. tether() rely on downstream setup ready for tethering. Currently the only user is bluetooth tethering. For other tetherings, there is no guaranteed that calling tether() can always switch given interface to tethered. Tethering may callback with onError depend on the interface status. Caller should use startTethering/stopTethering API instead of these legacy APIs. This change also change the precondition verification of startTethering. If tethering interface got error last time, such interface would not be reported as tetherable. Bug: 150632712 Test: atest CtsTetheringTest Change-Id: Ifb3a0618208ffd0ff224c60f377036bc22ba0565 Merged-In: Ifb3a0618208ffd0ff224c60f377036bc22ba0565 --- .../tethering/cts/TetheringManagerTest.java | 116 ++++++++---------- 1 file changed, 54 insertions(+), 62 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 60f9400363..11ffe2c456 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -21,6 +21,7 @@ import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; @@ -31,6 +32,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.app.UiAutomation; import android.content.BroadcastReceiver; @@ -64,10 +66,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) @@ -140,28 +140,24 @@ public class TetheringManagerTest { public final LinkedBlockingQueue mResult = new LinkedBlockingQueue<>(); - // This method expects either an event where one of the interfaces is active, or events - // where the interfaces are available followed by one event where one of the interfaces is - // active. Here is a typical example for wifi tethering: - // AVAILABLE(wlan0) -> AVAILABLE(wlan1) -> ACTIVATE(wlan1). - public void expectActiveTethering(String[] ifaceRegexs) { - TetherState state = null; + // Expects that tethering reaches the desired state. + // - If active is true, expects that tethering is enabled on at least one interface + // matching ifaceRegexs. + // - If active is false, expects that tethering is disabled on all the interfaces matching + // ifaceRegexs. + // Fails if any interface matching ifaceRegexs becomes errored. + public void expectTethering(final boolean active, final String[] ifaceRegexs) { while (true) { - state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS); - if (state == null) fail("Do not receive active state change broadcast"); + final TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS, ifaceRegexs); + assertNotNull("Did not receive expected state change, active: " + active, state); - if (isIfaceActive(ifaceRegexs, state)) return; - - if (!isIfaceAvailable(ifaceRegexs, state)) break; + if (isIfaceActive(ifaceRegexs, state) == active) return; } - - fail("Tethering is not actived, available ifaces: " + state.mAvailable.toString() - + ", active ifaces: " + state.mActive.toString()); } - private TetherState pollAndAssertNoError(final int timeout) { + private TetherState pollAndAssertNoError(final int timeout, final String[] ifaceRegexs) { final TetherState state = pollTetherState(timeout); - assertNoErroredIfaces(state); + assertNoErroredIfaces(state, ifaceRegexs); return state; } @@ -178,43 +174,13 @@ public class TetheringManagerTest { return isIfaceMatch(ifaceRegexs, state.mActive); } - private boolean isIfaceAvailable(final String[] ifaceRegexs, final TetherState state) { - return isIfaceMatch(ifaceRegexs, state.mAvailable); - } - - // This method requires a broadcast to have been recorded iff the timeout is non-zero. - public void expectNoActiveTethering(final int timeout) { - final TetherState state = pollAndAssertNoError(timeout); - - if (state == null) { - if (timeout != 0) { - fail("Do not receive tethering state change broadcast"); - } - return; - } - - assertNoActiveIfaces(state); - - for (final TetherState ts : mResult) { - assertNoErroredIfaces(ts); - - assertNoActiveIfaces(ts); - } - } - - private void assertNoErroredIfaces(final TetherState state) { + private void assertNoErroredIfaces(final TetherState state, final String[] ifaceRegexs) { if (state == null || state.mErrored == null) return; - if (state.mErrored.size() > 0) { + if (isIfaceMatch(ifaceRegexs, state.mErrored)) { fail("Found failed tethering interfaces: " + Arrays.toString(state.mErrored.toArray())); } } - - private void assertNoActiveIfaces(final TetherState state) { - if (state.mActive != null && state.mActive.size() > 0) { - fail("Found active tethering interface: " + Arrays.toString(state.mActive.toArray())); - } - } } private static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { @@ -295,17 +261,18 @@ public class TetheringManagerTest { final String[] wifiRegexs = mTM.getTetherableWifiRegexs(); if (wifiRegexs.length == 0) return; - mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */); + final String[] tetheredIfaces = mTM.getTetheredIfaces(); + assertTrue(tetheredIfaces.length == 0); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.verifyTetheringStarted(); - mTetherChangeReceiver.expectActiveTethering(wifiRegexs); + mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); mTM.stopTethering(TETHERING_WIFI); - mTetherChangeReceiver.expectNoActiveTethering(DEFAULT_TIMEOUT_MS); + mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); } @Test @@ -459,6 +426,21 @@ public class TetheringManagerTest { })); } + public void expectErrorOrTethered(final String iface) { + assertNotNull("No expected callback", mHistory.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType == CallbackType.ON_ERROR + && iface.equals((String) cv.callbackParam)) { + return true; + } + if (cv.callbackType == CallbackType.ON_TETHERED_IFACES + && ((List) cv.callbackParam).contains(iface)) { + return true; + } + + return false; + })); + } + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { return mTetherableRegex; } @@ -497,20 +479,13 @@ public class TetheringManagerTest { private void startWifiTethering(final TestTetheringEventCallback callback) throws InterruptedException { final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); - final boolean isIfaceAvailWhenNoTethering = - isIfaceMatch(wifiRegexs, callback.getTetherableInterfaces()); + assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.verifyTetheringStarted(); - // If interface is already available before starting tethering, the available callback may - // not be sent after tethering enabled. - if (!isIfaceAvailWhenNoTethering) { - callback.expectTetherableInterfacesChanged(wifiRegexs); - } - callback.expectTetheredInterfacesChanged(wifiRegexs); callback.expectOneOfOffloadStatusChanged( @@ -534,9 +509,26 @@ public class TetheringManagerTest { startWifiTethering(tetherEventCallback); + final List tetheredIfaces = tetherEventCallback.getTetheredInterfaces(); + assertEquals(1, tetheredIfaces.size()); + final String wifiTetheringIface = tetheredIfaces.get(0); + stopWifiTethering(tetherEventCallback); - unregisterTetheringEventCallback(tetherEventCallback); + try { + final int ret = mTM.tether(wifiTetheringIface); + + // There is no guarantee that the wifi interface will be available after disabling + // the hotspot, so don't fail the test if the call to tether() fails. + assumeTrue(ret == TETHER_ERROR_NO_ERROR); + + // If calling #tether successful, there is a callback to tell the result of tethering + // setup. + tetherEventCallback.expectErrorOrTethered(wifiTetheringIface); + } finally { + mTM.untether(wifiTetheringIface); + unregisterTetheringEventCallback(tetherEventCallback); + } } @Test From 0420e692a7d9f18b2304c7c3c1d07ff9a8fa84b0 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 13 Apr 2020 16:22:12 +0800 Subject: [PATCH 1022/1415] Add testTetheringUpstream cts test If cellular is the mobile network, tethering should select it as upstream. If DUN is required, tethering should use DUN as its upstream. Bug: 153614366 Bug: 150644305 Test: atest CtsTetheringTest Change-Id: Ief9c745322e8705c0e50185e749a81c5a9d20743 --- tests/cts/tethering/Android.bp | 1 + .../tethering/cts/TetheringManagerTest.java | 142 ++++++++++++++---- 2 files changed, 117 insertions(+), 26 deletions(-) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 9f32403c98..85bb0e03f1 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -28,6 +28,7 @@ android_test { "TetheringCommonTests", "TetheringIntegrationTestsLib", "compatibility-device-util-axt", + "cts-net-utils", "net-tests-utils", "ctstestrunner-axt", "junit", diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 11ffe2c456..bbb9403334 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,6 +15,11 @@ */ package android.tethering.test; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; @@ -32,6 +37,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import android.app.UiAutomation; @@ -39,16 +45,22 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.TetheredClient; import android.net.TetheringManager; import android.net.TetheringManager.OnTetheringEntitlementResultListener; import android.net.TetheringManager.TetheringEventCallback; import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; +import android.net.cts.util.CtsNetUtils; +import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.ResultReceiver; +import android.telephony.TelephonyManager; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; @@ -75,11 +87,13 @@ public class TetheringManagerTest { private Context mContext; + private ConnectivityManager mCm; private TetheringManager mTM; + private WifiManager mWm; + private PackageManager mPm; private TetherChangeReceiver mTetherChangeReceiver; - - private String[] mTetheredList; + private CtsNetUtils mCtsNetUtils; private static final int DEFAULT_TIMEOUT_MS = 60_000; @@ -99,7 +113,11 @@ public class TetheringManagerTest { public void setUp() throws Exception { adoptShellPermissionIdentity(); mContext = InstrumentationRegistry.getContext(); + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); + mWm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mPm = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); mTetherChangeReceiver = new TetherChangeReceiver(); final IntentFilter filter = new IntentFilter( TetheringManager.ACTION_TETHER_STATE_CHANGED); @@ -301,6 +319,7 @@ public class TetheringManagerTest { // Must poll the callback before looking at the member. private static class TestTetheringEventCallback implements TetheringEventCallback { private static final int TIMEOUT_MS = 30_000; + public enum CallbackType { ON_SUPPORTED, ON_UPSTREAM, @@ -324,9 +343,11 @@ public class TetheringManagerTest { } } - private final ArrayTrackRecord.ReadHead mHistory = - new ArrayTrackRecord().newReadHead(); + private final ArrayTrackRecord mHistory = + new ArrayTrackRecord(); + private final ArrayTrackRecord.ReadHead mCurrent = + mHistory.newReadHead(); private TetheringInterfaceRegexps mTetherableRegex; private List mTetherableIfaces; @@ -334,7 +355,7 @@ public class TetheringManagerTest { @Override public void onTetheringSupported(boolean supported) { - mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, (supported ? 1 : 0))); } @Override @@ -376,7 +397,7 @@ public class TetheringManagerTest { } public void expectTetherableInterfacesChanged(@NonNull List regexs) { - assertNotNull("No expected tetherable ifaces callback", mHistory.poll(TIMEOUT_MS, + assertNotNull("No expected tetherable ifaces callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; final List interfaces = (List) cv.callbackParam; @@ -385,7 +406,7 @@ public class TetheringManagerTest { } public void expectTetheredInterfacesChanged(@NonNull List regexs) { - assertNotNull("No expected tethered ifaces callback", mHistory.poll(TIMEOUT_MS, + assertNotNull("No expected tethered ifaces callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; @@ -406,17 +427,18 @@ public class TetheringManagerTest { // Receive ON_ERROR on started callback is not matter. It just means tethering is // failed last time, should able to continue the test this time. while ((receivedBitMap & expectedBitMap) != expectedBitMap) { - final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + final CallbackValue cv = mCurrent.poll(TIMEOUT_MS, c -> true); if (cv == null) { fail("No expected callbacks, " + "expected bitmap: " + expectedBitMap + ", actual: " + receivedBitMap); } + receivedBitMap |= (1 << cv.callbackType.ordinal()); } } public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { - assertNotNull("No offload status changed", mHistory.poll(TIMEOUT_MS, (cv) -> { + assertNotNull("No offload status changed", mCurrent.poll(TIMEOUT_MS, (cv) -> { if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; final int status = (int) cv.callbackParam; @@ -427,7 +449,7 @@ public class TetheringManagerTest { } public void expectErrorOrTethered(final String iface) { - assertNotNull("No expected callback", mHistory.poll(TIMEOUT_MS, (cv) -> { + assertNotNull("No expected callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { if (cv.callbackType == CallbackType.ON_ERROR && iface.equals((String) cv.callbackParam)) { return true; @@ -441,6 +463,27 @@ public class TetheringManagerTest { })); } + public Network getCurrentValidUpstream() { + final CallbackValue result = mCurrent.poll(TIMEOUT_MS, (cv) -> { + return (cv.callbackType == CallbackType.ON_UPSTREAM) + && cv.callbackParam != null; + }); + + assertNotNull("No valid upstream", result); + return (Network) result.callbackParam; + } + + public void assumeTetheringSupported() { + final ArrayTrackRecord.ReadHead history = + mHistory.newReadHead(); + assertNotNull("No onSupported callback", history.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_SUPPORTED) return false; + + assumeTrue(cv.callbackParam2 == 1 /* supported */); + return true; + })); + } + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { return mTetherableRegex; } @@ -455,7 +498,8 @@ public class TetheringManagerTest { } private TestTetheringEventCallback registerTetheringEventCallback() { - final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + new TestTetheringEventCallback(); mTM.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); tetherEventCallback.expectCallbackStarted(); @@ -501,11 +545,13 @@ public class TetheringManagerTest { @Test public void testRegisterTetheringEventCallback() throws Exception { - if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); - if (!isWifiTetheringSupported(tetherEventCallback)) return; + if (!isWifiTetheringSupported(tetherEventCallback)) { + unregisterTetheringEventCallback(tetherEventCallback); + return; + } startWifiTethering(tetherEventCallback); @@ -533,9 +579,8 @@ public class TetheringManagerTest { @Test public void testGetTetherableInterfaceRegexps() { - if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); final TetheringInterfaceRegexps tetherableRegexs = tetherEventCallback.getTetheringInterfaceRegexps(); @@ -557,21 +602,22 @@ public class TetheringManagerTest { @Test public void testStopAllTethering() throws Exception { - if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); - if (!isWifiTetheringSupported(tetherEventCallback)) return; + try { + if (!isWifiTetheringSupported(tetherEventCallback)) return; - // TODO: start ethernet tethering here when TetheringManagerTest is moved to - // TetheringIntegrationTest. + // TODO: start ethernet tethering here when TetheringManagerTest is moved to + // TetheringIntegrationTest. - startWifiTethering(tetherEventCallback); + startWifiTethering(tetherEventCallback); - mTM.stopAllTethering(); - tetherEventCallback.expectTetheredInterfacesChanged(null); - - unregisterTetheringEventCallback(tetherEventCallback); + mTM.stopAllTethering(); + tetherEventCallback.expectTetheredInterfacesChanged(null); + } finally { + unregisterTetheringEventCallback(tetherEventCallback); + } } @Test @@ -631,4 +677,48 @@ public class TetheringManagerTest { TETHERING_WIFI, false, c -> c.run(), null); } catch (IllegalArgumentException expect) { } } + + @Test + public void testTetheringUpstream() throws Exception { + assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY)); + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); + final boolean previousWifiEnabledState = mWm.isWifiEnabled(); + + try { + if (!isWifiTetheringSupported(tetherEventCallback)) return; + + if (previousWifiEnabledState) { + mCtsNetUtils.disconnectFromWifi(null); + } + + final Network activeNetwork = mCm.getActiveNetwork(); + assertNotNull("No active network. Please ensure the device has working mobile data.", + activeNetwork); + final NetworkCapabilities activeNetCap = mCm.getNetworkCapabilities(activeNetwork); + + // If active nework is ETHERNET, tethering may not use cell network as upstream. + assumeFalse(activeNetCap.hasTransport(TRANSPORT_ETHERNET)); + + assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR)); + + startWifiTethering(tetherEventCallback); + + final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + final boolean dunRequired = telephonyManager.isTetheringApnRequired(); + final int expectedCap = dunRequired ? NET_CAPABILITY_DUN : NET_CAPABILITY_INTERNET; + final Network network = tetherEventCallback.getCurrentValidUpstream(); + final NetworkCapabilities netCap = mCm.getNetworkCapabilities(network); + assertTrue(netCap.hasTransport(TRANSPORT_CELLULAR)); + assertTrue(netCap.hasCapability(expectedCap)); + + stopWifiTethering(tetherEventCallback); + } finally { + unregisterTetheringEventCallback(tetherEventCallback); + if (previousWifiEnabledState) { + mCtsNetUtils.connectToWifi(); + } + } + } } From 668dfa59987ef0a5b17770d77d9569f4d49cfff2 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 13 Apr 2020 16:22:12 +0800 Subject: [PATCH 1023/1415] Add testTetheringUpstream cts test If cellular is the mobile network, tethering should select it as upstream. If DUN is required, tethering should use DUN as its upstream. Bug: 153614366 Bug: 150644305 Test: atest CtsTetheringTest Change-Id: Ief9c745322e8705c0e50185e749a81c5a9d20743 Merged-In: Ief9c745322e8705c0e50185e749a81c5a9d20743 --- tests/cts/tethering/Android.bp | 1 + .../tethering/cts/TetheringManagerTest.java | 142 ++++++++++++++---- 2 files changed, 117 insertions(+), 26 deletions(-) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 9f32403c98..85bb0e03f1 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -28,6 +28,7 @@ android_test { "TetheringCommonTests", "TetheringIntegrationTestsLib", "compatibility-device-util-axt", + "cts-net-utils", "net-tests-utils", "ctstestrunner-axt", "junit", diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 11ffe2c456..bbb9403334 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,6 +15,11 @@ */ package android.tethering.test; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; @@ -32,6 +37,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import android.app.UiAutomation; @@ -39,16 +45,22 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.TetheredClient; import android.net.TetheringManager; import android.net.TetheringManager.OnTetheringEntitlementResultListener; import android.net.TetheringManager.TetheringEventCallback; import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; +import android.net.cts.util.CtsNetUtils; +import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.ResultReceiver; +import android.telephony.TelephonyManager; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; @@ -75,11 +87,13 @@ public class TetheringManagerTest { private Context mContext; + private ConnectivityManager mCm; private TetheringManager mTM; + private WifiManager mWm; + private PackageManager mPm; private TetherChangeReceiver mTetherChangeReceiver; - - private String[] mTetheredList; + private CtsNetUtils mCtsNetUtils; private static final int DEFAULT_TIMEOUT_MS = 60_000; @@ -99,7 +113,11 @@ public class TetheringManagerTest { public void setUp() throws Exception { adoptShellPermissionIdentity(); mContext = InstrumentationRegistry.getContext(); + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); + mWm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mPm = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); mTetherChangeReceiver = new TetherChangeReceiver(); final IntentFilter filter = new IntentFilter( TetheringManager.ACTION_TETHER_STATE_CHANGED); @@ -301,6 +319,7 @@ public class TetheringManagerTest { // Must poll the callback before looking at the member. private static class TestTetheringEventCallback implements TetheringEventCallback { private static final int TIMEOUT_MS = 30_000; + public enum CallbackType { ON_SUPPORTED, ON_UPSTREAM, @@ -324,9 +343,11 @@ public class TetheringManagerTest { } } - private final ArrayTrackRecord.ReadHead mHistory = - new ArrayTrackRecord().newReadHead(); + private final ArrayTrackRecord mHistory = + new ArrayTrackRecord(); + private final ArrayTrackRecord.ReadHead mCurrent = + mHistory.newReadHead(); private TetheringInterfaceRegexps mTetherableRegex; private List mTetherableIfaces; @@ -334,7 +355,7 @@ public class TetheringManagerTest { @Override public void onTetheringSupported(boolean supported) { - mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, (supported ? 1 : 0))); } @Override @@ -376,7 +397,7 @@ public class TetheringManagerTest { } public void expectTetherableInterfacesChanged(@NonNull List regexs) { - assertNotNull("No expected tetherable ifaces callback", mHistory.poll(TIMEOUT_MS, + assertNotNull("No expected tetherable ifaces callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; final List interfaces = (List) cv.callbackParam; @@ -385,7 +406,7 @@ public class TetheringManagerTest { } public void expectTetheredInterfacesChanged(@NonNull List regexs) { - assertNotNull("No expected tethered ifaces callback", mHistory.poll(TIMEOUT_MS, + assertNotNull("No expected tethered ifaces callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; @@ -406,17 +427,18 @@ public class TetheringManagerTest { // Receive ON_ERROR on started callback is not matter. It just means tethering is // failed last time, should able to continue the test this time. while ((receivedBitMap & expectedBitMap) != expectedBitMap) { - final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + final CallbackValue cv = mCurrent.poll(TIMEOUT_MS, c -> true); if (cv == null) { fail("No expected callbacks, " + "expected bitmap: " + expectedBitMap + ", actual: " + receivedBitMap); } + receivedBitMap |= (1 << cv.callbackType.ordinal()); } } public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { - assertNotNull("No offload status changed", mHistory.poll(TIMEOUT_MS, (cv) -> { + assertNotNull("No offload status changed", mCurrent.poll(TIMEOUT_MS, (cv) -> { if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; final int status = (int) cv.callbackParam; @@ -427,7 +449,7 @@ public class TetheringManagerTest { } public void expectErrorOrTethered(final String iface) { - assertNotNull("No expected callback", mHistory.poll(TIMEOUT_MS, (cv) -> { + assertNotNull("No expected callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { if (cv.callbackType == CallbackType.ON_ERROR && iface.equals((String) cv.callbackParam)) { return true; @@ -441,6 +463,27 @@ public class TetheringManagerTest { })); } + public Network getCurrentValidUpstream() { + final CallbackValue result = mCurrent.poll(TIMEOUT_MS, (cv) -> { + return (cv.callbackType == CallbackType.ON_UPSTREAM) + && cv.callbackParam != null; + }); + + assertNotNull("No valid upstream", result); + return (Network) result.callbackParam; + } + + public void assumeTetheringSupported() { + final ArrayTrackRecord.ReadHead history = + mHistory.newReadHead(); + assertNotNull("No onSupported callback", history.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_SUPPORTED) return false; + + assumeTrue(cv.callbackParam2 == 1 /* supported */); + return true; + })); + } + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { return mTetherableRegex; } @@ -455,7 +498,8 @@ public class TetheringManagerTest { } private TestTetheringEventCallback registerTetheringEventCallback() { - final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + new TestTetheringEventCallback(); mTM.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); tetherEventCallback.expectCallbackStarted(); @@ -501,11 +545,13 @@ public class TetheringManagerTest { @Test public void testRegisterTetheringEventCallback() throws Exception { - if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); - if (!isWifiTetheringSupported(tetherEventCallback)) return; + if (!isWifiTetheringSupported(tetherEventCallback)) { + unregisterTetheringEventCallback(tetherEventCallback); + return; + } startWifiTethering(tetherEventCallback); @@ -533,9 +579,8 @@ public class TetheringManagerTest { @Test public void testGetTetherableInterfaceRegexps() { - if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); final TetheringInterfaceRegexps tetherableRegexs = tetherEventCallback.getTetheringInterfaceRegexps(); @@ -557,21 +602,22 @@ public class TetheringManagerTest { @Test public void testStopAllTethering() throws Exception { - if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); - if (!isWifiTetheringSupported(tetherEventCallback)) return; + try { + if (!isWifiTetheringSupported(tetherEventCallback)) return; - // TODO: start ethernet tethering here when TetheringManagerTest is moved to - // TetheringIntegrationTest. + // TODO: start ethernet tethering here when TetheringManagerTest is moved to + // TetheringIntegrationTest. - startWifiTethering(tetherEventCallback); + startWifiTethering(tetherEventCallback); - mTM.stopAllTethering(); - tetherEventCallback.expectTetheredInterfacesChanged(null); - - unregisterTetheringEventCallback(tetherEventCallback); + mTM.stopAllTethering(); + tetherEventCallback.expectTetheredInterfacesChanged(null); + } finally { + unregisterTetheringEventCallback(tetherEventCallback); + } } @Test @@ -631,4 +677,48 @@ public class TetheringManagerTest { TETHERING_WIFI, false, c -> c.run(), null); } catch (IllegalArgumentException expect) { } } + + @Test + public void testTetheringUpstream() throws Exception { + assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY)); + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); + final boolean previousWifiEnabledState = mWm.isWifiEnabled(); + + try { + if (!isWifiTetheringSupported(tetherEventCallback)) return; + + if (previousWifiEnabledState) { + mCtsNetUtils.disconnectFromWifi(null); + } + + final Network activeNetwork = mCm.getActiveNetwork(); + assertNotNull("No active network. Please ensure the device has working mobile data.", + activeNetwork); + final NetworkCapabilities activeNetCap = mCm.getNetworkCapabilities(activeNetwork); + + // If active nework is ETHERNET, tethering may not use cell network as upstream. + assumeFalse(activeNetCap.hasTransport(TRANSPORT_ETHERNET)); + + assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR)); + + startWifiTethering(tetherEventCallback); + + final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + final boolean dunRequired = telephonyManager.isTetheringApnRequired(); + final int expectedCap = dunRequired ? NET_CAPABILITY_DUN : NET_CAPABILITY_INTERNET; + final Network network = tetherEventCallback.getCurrentValidUpstream(); + final NetworkCapabilities netCap = mCm.getNetworkCapabilities(network); + assertTrue(netCap.hasTransport(TRANSPORT_CELLULAR)); + assertTrue(netCap.hasCapability(expectedCap)); + + stopWifiTethering(tetherEventCallback); + } finally { + unregisterTetheringEventCallback(tetherEventCallback); + if (previousWifiEnabledState) { + mCtsNetUtils.connectToWifi(); + } + } + } } From b9438336c793b2a2eb17892d20d30772e7ea1c35 Mon Sep 17 00:00:00 2001 From: evitayan Date: Sun, 12 Apr 2020 19:37:22 -0700 Subject: [PATCH 1024/1415] Add initial CTS test for IkeSessionParams This commit adds tests for building IkeSessionParams with PSK. It also tests configuring SA lifetimes, retransmissions and PCSCF server requests Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I16fdc1ff9a22acb82b376211e0f187c4ead4cae5 --- .../ipsec/ike/cts/IkeSessionParamsTest.java | 262 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 13 + 2 files changed, 275 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java new file mode 100644 index 0000000000..91ef7789e3 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java @@ -0,0 +1,262 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeIdentification; +import android.net.ipsec.ike.IkeSaProposal; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer; +import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer; +import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { + private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(20L); + private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(10L); + private static final int DPD_DELAY_SECONDS = (int) TimeUnit.MINUTES.toSeconds(10L); + private static final int[] RETRANS_TIMEOUT_MS_LIST = new int[] {500, 500, 500, 500, 500, 500}; + + private static final Map, Integer> EXPECTED_REQ_COUNT = + new HashMap<>(); + private static final HashSet EXPECTED_PCSCF_SERVERS = new HashSet<>(); + + static { + EXPECTED_REQ_COUNT.put(ConfigRequestIpv4PcscfServer.class, 3); + EXPECTED_REQ_COUNT.put(ConfigRequestIpv6PcscfServer.class, 3); + + EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_1); + EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_2); + EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_1); + EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_2); + } + + // Arbitrary proposal and remote ID. Local ID is chosen to match the client end cert in the + // following CL + private static final IkeSaProposal SA_PROPOSAL = + SaProposalTest.buildIkeSaProposalWithNormalModeCipher(); + private static final IkeIdentification LOCAL_ID = new IkeFqdnIdentification(LOCAL_HOSTNAME); + private static final IkeIdentification REMOTE_ID = new IkeFqdnIdentification(REMOTE_HOSTNAME); + + /** + * Create a Builder that has minimum configurations to build an IkeSessionParams. + * + *

    Authentication method is arbitrarily selected. Using other method (e.g. setAuthEap) also + * works. + */ + private IkeSessionParams.Builder createIkeParamsBuilderMinimum() { + return new IkeSessionParams.Builder(sContext) + .setNetwork(sTunNetwork) + .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) + .addSaProposal(SA_PROPOSAL) + .setLocalIdentification(LOCAL_ID) + .setRemoteIdentification(REMOTE_ID) + .setAuthPsk(IKE_PSK); + } + + /** + * Verify the minimum configurations to build an IkeSessionParams. + * + * @see #createIkeParamsBuilderMinimum + */ + private void verifyIkeParamsMinimum(IkeSessionParams sessionParams) { + assertEquals(sTunNetwork, sessionParams.getNetwork()); + assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); + assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); + assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); + assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthPskConfig); + assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk()); + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthPskConfig); + assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); + } + + private void verifySpecificPcscfConfigReqs( + HashSet expectedAddresses, IkeSessionParams sessionParams) { + Set resultAddresses = new HashSet<>(); + + for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) { + if (req instanceof ConfigRequestIpv4PcscfServer + && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) { + resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress()); + } else if (req instanceof ConfigRequestIpv6PcscfServer + && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) { + resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress()); + } + } + + assertEquals(expectedAddresses, resultAddresses); + } + + @Test + public void testBuildWithMinimumSet() throws Exception { + IkeSessionParams sessionParams = createIkeParamsBuilderMinimum().build(); + + verifyIkeParamsMinimum(sessionParams); + + // Verify default values that do not need explicit configuration. Do not do assertEquals + // to be avoid being a change-detector test + assertTrue(sessionParams.getHardLifetimeSeconds() > sessionParams.getSoftLifetimeSeconds()); + assertTrue(sessionParams.getSoftLifetimeSeconds() > 0); + assertTrue(sessionParams.getDpdDelaySeconds() > 0); + assertTrue(sessionParams.getRetransmissionTimeoutsMillis().length > 0); + for (int timeout : sessionParams.getRetransmissionTimeoutsMillis()) { + assertTrue(timeout > 0); + } + assertTrue(sessionParams.getConfigurationRequests().isEmpty()); + assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); + } + + @Test + public void testSetLifetimes() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) + .build(); + + verifyIkeParamsMinimum(sessionParams); + assertEquals(HARD_LIFETIME_SECONDS, sessionParams.getHardLifetimeSeconds()); + assertEquals(SOFT_LIFETIME_SECONDS, sessionParams.getSoftLifetimeSeconds()); + } + + @Test + public void testSetDpdDelay() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum().setDpdDelaySeconds(DPD_DELAY_SECONDS).build(); + + verifyIkeParamsMinimum(sessionParams); + assertEquals(DPD_DELAY_SECONDS, sessionParams.getDpdDelaySeconds()); + } + + @Test + public void testSetRetransmissionTimeouts() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST) + .build(); + + verifyIkeParamsMinimum(sessionParams); + assertArrayEquals(RETRANS_TIMEOUT_MS_LIST, sessionParams.getRetransmissionTimeoutsMillis()); + } + + @Test + public void testSetPcscfConfigRequests() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST) + .addPcscfServerRequest(AF_INET) + .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_1) + .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_1) + .addPcscfServerRequest(AF_INET6) + .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_2) + .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_2) + .build(); + + verifyIkeParamsMinimum(sessionParams); + verifyConfigRequestTypes(EXPECTED_REQ_COUNT, sessionParams.getConfigurationRequests()); + + Set resultAddresses = new HashSet<>(); + for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) { + if (req instanceof ConfigRequestIpv4PcscfServer + && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) { + resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress()); + } else if (req instanceof ConfigRequestIpv6PcscfServer + && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) { + resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress()); + } + } + assertEquals(EXPECTED_PCSCF_SERVERS, resultAddresses); + } + + @Test + public void testAddIkeOption() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .build(); + + verifyIkeParamsMinimum(sessionParams); + assertTrue(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); + } + + @Test + public void testRemoveIkeOption() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .removeIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .build(); + + verifyIkeParamsMinimum(sessionParams); + assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); + } + + @Test + public void testBuildWithPsk() throws Exception { + IkeSessionParams sessionParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(sTunNetwork) + .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) + .addSaProposal(SA_PROPOSAL) + .setLocalIdentification(LOCAL_ID) + .setRemoteIdentification(REMOTE_ID) + .setAuthPsk(IKE_PSK) + .build(); + assertEquals(sTunNetwork, sessionParams.getNetwork()); + assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); + assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); + assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); + assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthPskConfig); + assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk()); + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthPskConfig); + assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); + } + + // TODO(b/148689509): Add tests for building IkeSessionParams using EAP and + // digital-signature-based authentication +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index d3aa8d03d5..5f608df137 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -24,6 +24,7 @@ import android.net.ipsec.ike.IkeTrafficSelector; import java.net.Inet4Address; import java.net.Inet6Address; +import java.net.InetAddress; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,6 +41,11 @@ abstract class IkeTestBase { static final int IP4_PREFIX_LEN = 32; static final int IP6_PREFIX_LEN = 64; + static final byte[] IKE_PSK = "ikeAndroidPsk".getBytes(); + + static final String LOCAL_HOSTNAME = "client.test.ike.android.net"; + static final String REMOTE_HOSTNAME = "server.test.ike.android.net"; + static final Inet4Address IPV4_ADDRESS_LOCAL = (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); static final Inet4Address IPV4_ADDRESS_REMOTE = @@ -49,6 +55,13 @@ abstract class IkeTestBase { static final Inet6Address IPV6_ADDRESS_REMOTE = (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8:255::100")); + static final InetAddress PCSCF_IPV4_ADDRESS_1 = InetAddresses.parseNumericAddress("192.0.2.1"); + static final InetAddress PCSCF_IPV4_ADDRESS_2 = InetAddresses.parseNumericAddress("192.0.2.2"); + static final InetAddress PCSCF_IPV6_ADDRESS_1 = + InetAddresses.parseNumericAddress("2001:DB8::1"); + static final InetAddress PCSCF_IPV6_ADDRESS_2 = + InetAddresses.parseNumericAddress("2001:DB8::2"); + static final IkeTrafficSelector DEFAULT_V4_TS = new IkeTrafficSelector( MIN_PORT, From 9dcef4002333d2ee50ce1f772eb0c29a2c1948fb Mon Sep 17 00:00:00 2001 From: evitayan Date: Mon, 20 Apr 2020 15:15:24 -0700 Subject: [PATCH 1025/1415] Add test for IkeIdentification Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ieda584446c37d121fc16a212e2c6c60b934b0f53 --- .../ipsec/ike/cts/IkeIdentificationTest.java | 75 +++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 3 + 2 files changed, 78 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java new file mode 100644 index 0000000000..0317def92e --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java @@ -0,0 +1,75 @@ +/* + * 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.ipsec.ike.cts; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import android.net.ipsec.ike.IkeDerAsn1DnIdentification; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeIpv4AddrIdentification; +import android.net.ipsec.ike.IkeIpv6AddrIdentification; +import android.net.ipsec.ike.IkeKeyIdIdentification; +import android.net.ipsec.ike.IkeRfc822AddrIdentification; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.security.auth.x500.X500Principal; + +@RunWith(AndroidJUnit4.class) +public final class IkeIdentificationTest extends IkeTestBase { + @Test + public void testIkeDerAsn1DnIdentification() throws Exception { + X500Principal asn1Dn = new X500Principal(LOCAL_ASN1_DN_STRING); + + IkeDerAsn1DnIdentification ikeId = new IkeDerAsn1DnIdentification(asn1Dn); + assertEquals(asn1Dn, ikeId.derAsn1Dn); + } + + @Test + public void testIkeFqdnIdentification() throws Exception { + IkeFqdnIdentification ikeId = new IkeFqdnIdentification(LOCAL_HOSTNAME); + assertEquals(LOCAL_HOSTNAME, ikeId.fqdn); + } + + @Test + public void testIkeIpv4AddrIdentification() throws Exception { + IkeIpv4AddrIdentification ikeId = new IkeIpv4AddrIdentification(IPV4_ADDRESS_LOCAL); + assertEquals(IPV4_ADDRESS_LOCAL, ikeId.ipv4Address); + } + + @Test + public void testIkeIpv6AddrIdentification() throws Exception { + IkeIpv6AddrIdentification ikeId = new IkeIpv6AddrIdentification(IPV6_ADDRESS_LOCAL); + assertEquals(IPV6_ADDRESS_LOCAL, ikeId.ipv6Address); + } + + @Test + public void testIkeKeyIdIdentification() throws Exception { + IkeKeyIdIdentification ikeId = new IkeKeyIdIdentification(LOCAL_KEY_ID); + assertArrayEquals(LOCAL_KEY_ID, ikeId.keyId); + } + + @Test + public void testIkeRfc822AddrIdentification() throws Exception { + IkeRfc822AddrIdentification ikeId = new IkeRfc822AddrIdentification(LOCAL_RFC822_NAME); + assertEquals(LOCAL_RFC822_NAME, ikeId.rfc822Name); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index 5f608df137..08477446d2 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -45,6 +45,9 @@ abstract class IkeTestBase { static final String LOCAL_HOSTNAME = "client.test.ike.android.net"; static final String REMOTE_HOSTNAME = "server.test.ike.android.net"; + static final String LOCAL_ASN1_DN_STRING = "CN=client.test.ike.android.net, O=Android, C=US"; + static final String LOCAL_RFC822_NAME = "client.test.ike@example.com"; + static final byte[] LOCAL_KEY_ID = "Local Key ID".getBytes(); static final Inet4Address IPV4_ADDRESS_LOCAL = (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); From de7f511bd1866d17c8c5e259a6363bba5340571c Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 23 Apr 2020 23:20:51 +0000 Subject: [PATCH 1026/1415] Create base class that sets up test network This class will be extended by both IkeSessionParamsTest and IkeSessionTestBase Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I98979758a7a684219e35c02ded93224ea172d44f Merged-In: I98979758a7a684219e35c02ded93224ea172d44f (cherry picked from commit 50908b926635355f0753b7388f96b684f6be351d) --- .../ike/cts/IkeSessionParamsTestBase.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java new file mode 100644 index 0000000000..c3e3ba353c --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java @@ -0,0 +1,85 @@ +/* + * 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.ipsec.ike.cts; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.LinkAddress; +import android.net.Network; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; +import android.os.Binder; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.AppModeFull; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +abstract class IkeSessionParamsTestBase extends IkeTestBase { + // Static state to reduce setup/teardown + static ConnectivityManager sCM; + static TestNetworkManager sTNM; + static ParcelFileDescriptor sTunFd; + static TestNetworkCallback sTunNetworkCallback; + static Network sTunNetwork; + + static Context sContext = InstrumentationRegistry.getContext(); + static IBinder sBinder = new Binder(); + + // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass + // methods. + @BeforeClass + public static void setUpTestNetworkBeforeClass() throws Exception { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + + TestNetworkInterface testIface = + sTNM.createTunInterface( + new LinkAddress[] {new LinkAddress(IPV4_ADDRESS_LOCAL, IP4_PREFIX_LEN)}); + + sTunFd = testIface.getFileDescriptor(); + sTunNetworkCallback = + TestNetworkUtils.setupAndGetTestNetwork( + sCM, sTNM, testIface.getInterfaceName(), sBinder); + sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); + } + + // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass + // methods. + @AfterClass + public static void tearDownTestNetworkAfterClass() throws Exception { + sCM.unregisterNetworkCallback(sTunNetworkCallback); + + sTNM.teardownTestNetwork(sTunNetwork); + sTunFd.close(); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } +} From 7db1b713ba761dd9d61164e4f691167f77572f6d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 24 Apr 2020 01:15:02 +0000 Subject: [PATCH 1027/1415] Add CTS for EapSessionConfig Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I54dedff0555bdfcaae390ddde7b05d24dfabe9b0 Merged-In: I54dedff0555bdfcaae390ddde7b05d24dfabe9b0 (cherry picked from commit b6dff211348df9b4b8d7ce0631512cba65195e47) --- .../net/eap/cts/EapSessionConfigTest.java | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java diff --git a/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java b/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java new file mode 100644 index 0000000000..c24379dae0 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java @@ -0,0 +1,98 @@ +/* + * 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.eap.cts; + +import static android.telephony.TelephonyManager.APPTYPE_USIM; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.net.eap.EapSessionConfig; +import android.net.eap.EapSessionConfig.EapAkaConfig; +import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; +import android.net.eap.EapSessionConfig.EapMsChapV2Config; +import android.net.eap.EapSessionConfig.EapSimConfig; +import android.net.eap.EapSessionConfig.EapUiccConfig; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class EapSessionConfigTest { + // These constants are IANA-defined values and are copies of hidden constants in + // frameworks/opt/net/ike/src/java/com/android/internal/net/eap/message/EapData.java. + private static final int EAP_TYPE_SIM = 18; + private static final int EAP_TYPE_AKA = 23; + private static final int EAP_TYPE_MSCHAP_V2 = 26; + private static final int EAP_TYPE_AKA_PRIME = 50; + + private static final int SUB_ID = 1; + private static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); + private static final String NETWORK_NAME = "android.net"; + private static final String EAP_MSCHAPV2_USERNAME = "username"; + private static final String EAP_MSCHAPV2_PASSWORD = "password"; + + @Test + public void testBuildWithAllEapMethods() { + EapSessionConfig result = + new EapSessionConfig.Builder() + .setEapIdentity(EAP_IDENTITY) + .setEapSimConfig(SUB_ID, APPTYPE_USIM) + .setEapAkaConfig(SUB_ID, APPTYPE_USIM) + .setEapAkaPrimeConfig( + SUB_ID, + APPTYPE_USIM, + NETWORK_NAME, + true /* allowMismatchedNetworkNames */) + .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) + .build(); + + assertArrayEquals(EAP_IDENTITY, result.getEapIdentity()); + + EapSimConfig eapSimConfig = result.getEapSimConfig(); + assertNotNull(eapSimConfig); + assertEquals(EAP_TYPE_SIM, eapSimConfig.getMethodType()); + verifyEapUiccConfigCommon(eapSimConfig); + + EapAkaConfig eapAkaConfig = result.getEapAkaConfig(); + assertNotNull(eapAkaConfig); + assertEquals(EAP_TYPE_AKA, eapAkaConfig.getMethodType()); + verifyEapUiccConfigCommon(eapAkaConfig); + + EapAkaPrimeConfig eapAkaPrimeConfig = result.getEapAkaPrimeConfig(); + assertNotNull(eapAkaPrimeConfig); + assertEquals(EAP_TYPE_AKA_PRIME, eapAkaPrimeConfig.getMethodType()); + assertEquals(NETWORK_NAME, eapAkaPrimeConfig.getNetworkName()); + assertTrue(NETWORK_NAME, eapAkaPrimeConfig.allowsMismatchedNetworkNames()); + verifyEapUiccConfigCommon(eapAkaPrimeConfig); + + EapMsChapV2Config eapMsChapV2Config = result.getEapMsChapV2onfig(); + assertNotNull(eapMsChapV2Config); + assertEquals(EAP_TYPE_MSCHAP_V2, eapMsChapV2Config.getMethodType()); + assertEquals(EAP_MSCHAPV2_USERNAME, eapMsChapV2Config.getUsername()); + assertEquals(EAP_MSCHAPV2_PASSWORD, eapMsChapV2Config.getPassword()); + } + + private void verifyEapUiccConfigCommon(EapUiccConfig config) { + assertEquals(SUB_ID, config.getSubId()); + assertEquals(APPTYPE_USIM, config.getAppType()); + } +} From e800e9503770368869d1b0e095d09a8906193795 Mon Sep 17 00:00:00 2001 From: evitayan Date: Tue, 14 Apr 2020 18:26:53 -0700 Subject: [PATCH 1028/1415] Test building IkeSessionParams with EAP Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Iea7f4d14502f4b204c7a0d7357e1aaec99954e1f --- tests/cts/net/ipsec/Android.bp | 1 + .../assets/pem/server-a-self-signed-ca.pem | 20 +++ .../ipsec/ike/cts/IkeSessionParamsTest.java | 144 ++++++++++++++---- .../net/ipsec/ike/cts/IkeTestBase.java | 6 + 4 files changed, 141 insertions(+), 30 deletions(-) create mode 100644 tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp index 8c073c9602..f1f120b32b 100644 --- a/tests/cts/net/ipsec/Android.bp +++ b/tests/cts/net/ipsec/Android.bp @@ -26,6 +26,7 @@ android_test { srcs: [ "src/**/*.java", + ":ike-test-utils", ], static_libs: [ diff --git a/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem b/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem new file mode 100644 index 0000000000..972fd55372 --- /dev/null +++ b/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSDCCAjCgAwIBAgIITJQJ6HC1rjwwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h +bmRyb2lkLm5ldDAeFw0xOTA5MzAxNzU1NTJaFw0yOTA5MjcxNzU1NTJaMEIxCzAJ +BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSEwHwYDVQQDExhyb290LmNhLnRl +c3QuYW5kcm9pZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCT +q3hGF+JvLaB1xW7KGKmaxiQ7BxX2Sn7cbp7ggoVYXsFlBUuPPv3+Vg5PfPCPhsJ8 +/7w4HyKo3uc/vHs5HpQ7rSd9blhAkfmJci2ULLq73FB8Mix4CzPwMx29RrN1X9bU +z4G0vJMczIBGxbZ0uw7n8bKcXBV7AIeax+J8lseEZ3k8iSuBkUJqGIpPFKTqByFZ +A1Lvt47xkON5SZh6c/Oe+o6291wXaCOJUSAKv6PAWZkq9HeD2fqKA/ck9dBaz1M3 +YvzQ9V/7so3/dECjAfKia388h1I6XSGNUM+d5hpxMXpAFgG42eUXHpJ10OjDvSwd +7ZSC91/kRQewUomEKBK1AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBRJn6hHhdeDY/dXpCKUfrFYQhKAGjANBgkqhkiG +9w0BAQsFAAOCAQEAig/94aGfHBhZuvbbhwAK4rUNpizmR567u0ZJ+QUEKyAlo9lT +ZWYHSm7qTAZYvPEjzTQIptnAlxCHePXh3Cfwgo+r82lhG2rcdI03iRyvHWjM8gyk +BXCJTi0Q08JHHpTP6GnAqpz58qEIFkk8P766zNXdhYrGPOydF+p7MFcb1Zv1gum3 +zmRLt0XUAMfjPUv1Bl8kTKFxH5lkMBLR1E0jnoJoTTfgRPrf9CuFSoh48n7YhoBT +KV75xZY8b8+SuB0v6BvQmkpKZGoxBjuVsShyG7q1+4JTAtwhiP7BlkDvVkaBEi7t +WIMFp2r2ZDisHgastNaeYFyzHYz9g1FCCrHQ4w== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java index 91ef7789e3..532be675aa 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java @@ -17,16 +17,22 @@ package android.net.ipsec.ike.cts; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; +import static android.telephony.TelephonyManager.APPTYPE_USIM; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import android.net.eap.EapSessionConfig; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeIdentification; import android.net.ipsec.ike.IkeSaProposal; @@ -37,10 +43,14 @@ import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.internal.net.ipsec.ike.testutils.CertUtils; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -76,6 +86,29 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { private static final IkeIdentification LOCAL_ID = new IkeFqdnIdentification(LOCAL_HOSTNAME); private static final IkeIdentification REMOTE_ID = new IkeFqdnIdentification(REMOTE_HOSTNAME); + private static final EapSessionConfig EAP_ALL_METHODS_CONFIG = + createEapOnlySafeMethodsBuilder() + .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) + .build(); + private static final EapSessionConfig EAP_ONLY_SAFE_METHODS_CONFIG = + createEapOnlySafeMethodsBuilder().build(); + + private X509Certificate mServerCaCert; + + @Before + public void setUp() throws Exception { + mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); + } + + private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() { + return new EapSessionConfig.Builder() + .setEapIdentity(EAP_IDENTITY) + .setEapSimConfig(SUB_ID, APPTYPE_USIM) + .setEapAkaConfig(SUB_ID, APPTYPE_USIM) + .setEapAkaPrimeConfig( + SUB_ID, APPTYPE_USIM, NETWORK_NAME, true /* allowMismatchedNetworkNames */); + } + /** * Create a Builder that has minimum configurations to build an IkeSessionParams. * @@ -112,23 +145,6 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); } - private void verifySpecificPcscfConfigReqs( - HashSet expectedAddresses, IkeSessionParams sessionParams) { - Set resultAddresses = new HashSet<>(); - - for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) { - if (req instanceof ConfigRequestIpv4PcscfServer - && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) { - resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress()); - } else if (req instanceof ConfigRequestIpv6PcscfServer - && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) { - resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress()); - } - } - - assertEquals(expectedAddresses, resultAddresses); - } - @Test public void testBuildWithMinimumSet() throws Exception { IkeSessionParams sessionParams = createIkeParamsBuilderMinimum().build(); @@ -232,22 +248,39 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); } - @Test - public void testBuildWithPsk() throws Exception { - IkeSessionParams sessionParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(sTunNetwork) - .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) - .addSaProposal(SA_PROPOSAL) - .setLocalIdentification(LOCAL_ID) - .setRemoteIdentification(REMOTE_ID) - .setAuthPsk(IKE_PSK) - .build(); + /** + * Create a Builder that has minimum configurations to build an IkeSessionParams, except for + * authentication method. + */ + private IkeSessionParams.Builder createIkeParamsBuilderMinimumWithoutAuth() { + return new IkeSessionParams.Builder(sContext) + .setNetwork(sTunNetwork) + .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) + .addSaProposal(SA_PROPOSAL) + .setLocalIdentification(LOCAL_ID) + .setRemoteIdentification(REMOTE_ID); + } + + /** + * Verify the minimum configurations to build an IkeSessionParams, except for authentication + * method. + * + * @see #createIkeParamsBuilderMinimumWithoutAuth + */ + private void verifyIkeParamsMinimumWithoutAuth(IkeSessionParams sessionParams) { assertEquals(sTunNetwork, sessionParams.getNetwork()); assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); + } + + @Test + public void testBuildWithPsk() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth().setAuthPsk(IKE_PSK).build(); + + verifyIkeParamsMinimumWithoutAuth(sessionParams); IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); assertTrue(localConfig instanceof IkeAuthPskConfig); @@ -257,6 +290,57 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); } - // TODO(b/148689509): Add tests for building IkeSessionParams using EAP and - // digital-signature-based authentication + @Test + public void testBuildWithEap() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG) + .build(); + + verifyIkeParamsMinimumWithoutAuth(sessionParams); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthEapConfig); + assertEquals(EAP_ALL_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig()); + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals( + mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); + } + + @Test + public void testBuildWithEapOnlyAuth() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthEap(mServerCaCert, EAP_ONLY_SAFE_METHODS_CONFIG) + .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH) + .build(); + + assertTrue(sessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH)); + verifyIkeParamsMinimumWithoutAuth(sessionParams); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthEapConfig); + assertEquals(EAP_ONLY_SAFE_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig()); + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals( + mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); + } + + @Test + public void testThrowBuildEapOnlyAuthWithUnsafeMethod() throws Exception { + try { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG) + .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH) + .build(); + fail("Expected to fail because EAP only unsafe method is proposed"); + } catch (IllegalArgumentException expected) { + } + } + + // TODO(b/148689509): Add tests for building IkeSessionParams using digital-signature-based + // authentication } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index 5f608df137..54c28e3a92 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -46,6 +46,12 @@ abstract class IkeTestBase { static final String LOCAL_HOSTNAME = "client.test.ike.android.net"; static final String REMOTE_HOSTNAME = "server.test.ike.android.net"; + static final int SUB_ID = 1; + static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); + static final String NETWORK_NAME = "android.net"; + static final String EAP_MSCHAPV2_USERNAME = "username"; + static final String EAP_MSCHAPV2_PASSWORD = "password"; + static final Inet4Address IPV4_ADDRESS_LOCAL = (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); static final Inet4Address IPV4_ADDRESS_REMOTE = From bba019dc40e57bf53ac07dc59f1d45f22e4cbfd0 Mon Sep 17 00:00:00 2001 From: evitayan Date: Sun, 12 Apr 2020 19:37:22 -0700 Subject: [PATCH 1029/1415] Test configuring digital-signature-based auth Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ieaceaadf116cb2885cbf22ae48579cec88268416 --- .../ipsec/assets/key/client-a-private-key.key | 28 +++++++++ .../ipsec/assets/pem/client-a-end-cert.pem | 21 +++++++ .../pem/client-a-intermediate-ca-one.pem | 21 +++++++ .../pem/client-a-intermediate-ca-two.pem | 21 +++++++ .../ipsec/ike/cts/IkeSessionParamsTest.java | 63 ++++++++++++++++++- 5 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/ipsec/assets/key/client-a-private-key.key create mode 100644 tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem create mode 100644 tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem create mode 100644 tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem diff --git a/tests/cts/net/ipsec/assets/key/client-a-private-key.key b/tests/cts/net/ipsec/assets/key/client-a-private-key.key new file mode 100644 index 0000000000..22736e98e0 --- /dev/null +++ b/tests/cts/net/ipsec/assets/key/client-a-private-key.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL +8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu +7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K +Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i +pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS +jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK +a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub +G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n +zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo +zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL +gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc +9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf +spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL +ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms +TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy +GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK +QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ ++K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE +i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh +fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU +ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+ +NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN +mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR +wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G +xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf +idNFcaIrC52PtZIH7QCzdDY= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem b/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem new file mode 100644 index 0000000000..e82da85c50 --- /dev/null +++ b/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu +ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG +A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0 +LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE +CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc +6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw +D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC +25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG +R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL +bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu +bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK +I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio +4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP +ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab +SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7 +T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy +rmkYV2MAWguFeckh +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem new file mode 100644 index 0000000000..707e575bc3 --- /dev/null +++ b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIIIbjMyRn2770wDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h +bmRyb2lkLm5ldDAeFw0xOTA5MzAxODQzMThaFw0yNDA5MjgxODQzMThaMEExCzAJ +BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSAwHgYDVQQDExdvbmUuY2EudGVz +dC5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNN +sRr5Z30rAEw2jrAh/BIekbEy/MvOucAr1w0lxH71p+ybRBx5Bj7G07UGXbL659gm +meMV6nabY4HjQXNMq22POiJBZj+U+rw34br6waljBttxCmmJac1VvgqNsSspXjRy +NbiVQdFjyKSX0NOPcEkwANk15mZbOgJBaYYc8jQCY2G/p8eARVBTLJCy8LEwEU6j +XRv/4eYST79qpBFc7gQQj2FLmh9oppDIvcIVBHwtd1tBoVuehRSud1o8vQRkl/HJ +Mrwp24nO5YYhmVNSFRtBpmWMSu1KknFUwkOebINUNsKXXHebVa7cP4XIQUL8mRT3 +5X9rFJFSQJE01S3NjNMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAQYwHQYDVR0OBBYEFHK3FIm7g8dxEIwK9zMAO8EWhRYxMB8GA1UdIwQY +MBaAFEmfqEeF14Nj91ekIpR+sVhCEoAaMA0GCSqGSIb3DQEBCwUAA4IBAQAeMlXT +TnxZo8oz0204gKZ63RzlgDpJ7SqA3qFG+pV+TiqGfSuVkXuIdOskjxJnA9VxUzrr +LdMTCn5e0FK6wCYjZ2GT/CD7oD3vSMkzGbLGNcNJhhDHUq8BOLPkPzz/rwQFPBSb +zr6hsiVXphEt/psGoN7Eu9blPeQaIwMfWnaufAwF664S/3dmCRbNMWSam1qzzz8q +jr0cDOIMa//ZIAcM16cvoBK6pFGnUmuoJYYRtfpY5MmfCWz0sCJxENIX/lxyhd7N +FdRALA1ZP3E//Tn2vQoeFjbKaAba527RE26HgHJ9zZDo1nn8J8J/YwYRJdBWM/3S +LYebNiMtcyB5nIkj +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem new file mode 100644 index 0000000000..39808f885e --- /dev/null +++ b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIIKWCREnNCs+wwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF29uZS5jYS50ZXN0LmFu +ZHJvaWQubmV0MB4XDTE5MDkzMDE4NDQwMloXDTI0MDkyODE4NDQwMlowQTELMAkG +A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0 +LmFuZHJvaWQubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLUa +RqkYl2m7lUmMnkooqO0DNNY1aN9r7mJc3ndYn5gjkpb3yLgOYPDNLcQerV6uWk/u +qKudNHed2dInGonl3oxwwv7++6oUvvtrSWLDZlRg16GsdIE1Y98DSMQWkSxevYy9 +Nh6FGTdlBFQVMpiMa8qHEkrOyKsy85yCW1sgzlpGTIBwbDAqYtwe3rgbwyHwUtfy +0EU++DBcR4ll/pDqB0OQtW5E3AOq2GH1iaGeFLKSUQ5KAbdI8y4/b8IkSDffvxcc +kXig7S54aLrNlL/ZjQ+H4Chgjj2A5wMucd81+Fb60Udej73ICL9PpMPnXQ1+BVYd +MJ/txjLNmrOJG9yEHQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQUcqSu1uRYT/DLbLoDNUz38nGvCKQwHwYDVR0jBBgw +FoAUcrcUibuDx3EQjAr3MwA7wRaFFjEwDQYJKoZIhvcNAQELBQADggEBADY461GT +Rw0dGnD07xaGJcI0i0pV+WnGSrl1s1PAIdMYihJAqYnh10fXbFXLm2WMWVmv/pxs +FI/xDJno+pd4mCa/sIhm63ar/Nv+lFQmcpIlvSlKnhhV4SLNBeqbVhPBGTCHfrG4 +aIyCwm1KJsnkWbf03crhSskR/2CXIjX6lcAy7K3fE2u1ELpAdH0kMJR7VXkLFLUm +gqe9YCluR0weMpe2sCaOGzdVzQSmMMCzGP5cxeFR5U6K40kMOpiW11JNmQ06xI/m +YVkMNwoiV/ITT0/C/g9FxJmkO0mVSLEqxaLS/hNiQNDlroVM0rbxhzviXLI3R3AO +50VvlOQYGxWed/I= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java index 532be675aa..6fc7cb3634 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java @@ -19,6 +19,7 @@ package android.net.ipsec.ike.cts; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; @@ -51,9 +52,12 @@ import org.junit.runner.RunWith; import java.net.InetAddress; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -94,10 +98,20 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { createEapOnlySafeMethodsBuilder().build(); private X509Certificate mServerCaCert; + private X509Certificate mClientEndCert; + private X509Certificate mClientIntermediateCaCertOne; + private X509Certificate mClientIntermediateCaCertTwo; + private RSAPrivateKey mClientPrivateKey; @Before public void setUp() throws Exception { mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); + mClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); + mClientIntermediateCaCertOne = + CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem"); + mClientIntermediateCaCertTwo = + CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem"); + mClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); } private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() { @@ -341,6 +355,51 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { } } - // TODO(b/148689509): Add tests for building IkeSessionParams using digital-signature-based - // authentication + @Test + public void testBuildWithDigitalSignature() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthDigitalSignature(mServerCaCert, mClientEndCert, mClientPrivateKey) + .build(); + + verifyIkeParamsMinimumWithoutAuth(sessionParams); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); + IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig; + assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate()); + assertEquals(Collections.EMPTY_LIST, localSignConfig.getIntermediateCertificates()); + assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey()); + + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals( + mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); + } + + @Test + public void testBuildWithDigitalSignatureAndIntermediateCerts() throws Exception { + List intermediateCerts = + Arrays.asList(mClientIntermediateCaCertOne, mClientIntermediateCaCertTwo); + + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthDigitalSignature( + mServerCaCert, mClientEndCert, intermediateCerts, mClientPrivateKey) + .build(); + + verifyIkeParamsMinimumWithoutAuth(sessionParams); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); + IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig; + assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate()); + assertEquals(intermediateCerts, localSignConfig.getIntermediateCertificates()); + assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey()); + + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals( + mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); + } } From 2b2db7a57f6fbcb548ce762e5303f3100fbf556b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 23 Apr 2020 23:20:28 +0000 Subject: [PATCH 1030/1415] Make a copy of TunUtils and PacketUtils Temporarily make copies. Eventually will statically include the source files in CtsIkeTestCases Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I7dd5c8b849f0d987fa6d76bc5a0bc1a7eed49b0d Merged-In: I7dd5c8b849f0d987fa6d76bc5a0bc1a7eed49b0d (cherry picked from commit 52716ec0e6807e7c7c78d9789788a0de2bab8b06) --- .../net/ipsec/ike/cts/PacketUtils.java | 467 ++++++++++++++++++ .../android/net/ipsec/ike/cts/TunUtils.java | 264 ++++++++++ 2 files changed, 731 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java new file mode 100644 index 0000000000..35e6719fb7 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java @@ -0,0 +1,467 @@ +/* + * 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.ipsec.ike.cts; + +import static android.system.OsConstants.IPPROTO_IPV6; +import static android.system.OsConstants.IPPROTO_UDP; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Arrays; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * This code is a exact copy of {@link PacketUtils} in + * cts/tests/tests/net/src/android/net/cts/PacketUtils.java. + * + *

    TODO(b/148689509): Statically include the PacketUtils source file instead of copying it. + */ +public class PacketUtils { + private static final String TAG = PacketUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + + static final int IP4_HDRLEN = 20; + static final int IP6_HDRLEN = 40; + static final int UDP_HDRLEN = 8; + static final int TCP_HDRLEN = 20; + static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12; + + // Not defined in OsConstants + static final int IPPROTO_IPV4 = 4; + static final int IPPROTO_ESP = 50; + + // Encryption parameters + static final int AES_GCM_IV_LEN = 8; + static final int AES_CBC_IV_LEN = 16; + static final int AES_GCM_BLK_SIZE = 4; + static final int AES_CBC_BLK_SIZE = 16; + + // Encryption algorithms + static final String AES = "AES"; + static final String AES_CBC = "AES/CBC/NoPadding"; + static final String HMAC_SHA_256 = "HmacSHA256"; + + public interface Payload { + byte[] getPacketBytes(IpHeader header) throws Exception; + + void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception; + + short length(); + + int getProtocolId(); + } + + public abstract static class IpHeader { + + public final byte proto; + public final InetAddress srcAddr; + public final InetAddress dstAddr; + public final Payload payload; + + public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) { + this.proto = (byte) proto; + this.srcAddr = src; + this.dstAddr = dst; + this.payload = payload; + } + + public abstract byte[] getPacketBytes() throws Exception; + + public abstract int getProtocolId(); + } + + public static class Ip4Header extends IpHeader { + private short checksum; + + public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) { + super(proto, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer resultBuffer = buildHeader(); + payload.addPacketBytes(this, resultBuffer); + + return getByteArrayFromBuffer(resultBuffer); + } + + public ByteBuffer buildHeader() { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version, IHL + bb.put((byte) (0x45)); + + // DCSP, ECN + bb.put((byte) 0); + + // Total Length + bb.putShort((short) (IP4_HDRLEN + payload.length())); + + // Empty for Identification, Flags and Fragment Offset + bb.putShort((short) 0); + bb.put((byte) 0x40); + bb.put((byte) 0x00); + + // TTL + bb.put((byte) 64); + + // Protocol + bb.put(proto); + + // Header Checksum + final int ipChecksumOffset = bb.position(); + bb.putShort((short) 0); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + bb.putShort(ipChecksumOffset, calculateChecksum(bb)); + + return bb; + } + + private short calculateChecksum(ByteBuffer bb) { + int checksum = 0; + + // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit + // aligned, so no special cases needed for unaligned values. + ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer(); + while (shortBuffer.hasRemaining()) { + short val = shortBuffer.get(); + + // Wrap as needed + checksum = addAndWrapForChecksum(checksum, val); + } + + return onesComplement(checksum); + } + + public int getProtocolId() { + return IPPROTO_IPV4; + } + } + + public static class Ip6Header extends IpHeader { + public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) { + super(nextHeader, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version | Traffic Class (First 4 bits) + bb.put((byte) 0x60); + + // Traffic class (Last 4 bits), Flow Label + bb.put((byte) 0); + bb.put((byte) 0); + bb.put((byte) 0); + + // Payload Length + bb.putShort((short) payload.length()); + + // Next Header + bb.put(proto); + + // Hop Limit + bb.put((byte) 64); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + // Payload + payload.addPacketBytes(this, bb); + + return getByteArrayFromBuffer(bb); + } + + public int getProtocolId() { + return IPPROTO_IPV6; + } + } + + public static class BytePayload implements Payload { + public final byte[] payload; + + public BytePayload(byte[] payload) { + this.payload = payload; + } + + public int getProtocolId() { + return -1; + } + + public byte[] getPacketBytes(IpHeader header) { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) { + resultBuffer.put(payload); + } + + public short length() { + return (short) payload.length; + } + } + + public static class UdpHeader implements Payload { + + public final short srcPort; + public final short dstPort; + public final Payload payload; + + public UdpHeader(int srcPort, int dstPort, Payload payload) { + this.srcPort = (short) srcPort; + this.dstPort = (short) dstPort; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_UDP; + } + + public short length() { + return (short) (payload.length() + 8); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + // Source, Destination port + resultBuffer.putShort(srcPort); + resultBuffer.putShort(dstPort); + + // Payload Length + resultBuffer.putShort(length()); + + // Get payload bytes for checksum + payload + ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + payload.addPacketBytes(header, payloadBuffer); + byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer); + + // Checksum + resultBuffer.putShort(calculateChecksum(header, payloadBytes)); + + // Payload + resultBuffer.put(payloadBytes); + } + + private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception { + int newChecksum = 0; + ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer(); + ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer(); + + while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) { + short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get(); + + // Wrap as needed + newChecksum = addAndWrapForChecksum(newChecksum, val); + } + + // Add pseudo-header values. Proto is 0-padded, so just use the byte. + newChecksum = addAndWrapForChecksum(newChecksum, header.proto); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + newChecksum = addAndWrapForChecksum(newChecksum, srcPort); + newChecksum = addAndWrapForChecksum(newChecksum, dstPort); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + + ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer(); + while (payloadShortBuffer.hasRemaining()) { + newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get()); + } + if (payload.length() % 2 != 0) { + newChecksum = + addAndWrapForChecksum( + newChecksum, (payloadBytes[payloadBytes.length - 1] << 8)); + } + + return onesComplement(newChecksum); + } + } + + public static class EspHeader implements Payload { + public final int nextHeader; + public final int spi; + public final int seqNum; + public final byte[] key; + public final byte[] payload; + + /** + * Generic constructor for ESP headers. + * + *

    For Tunnel mode, payload will be a full IP header + attached payloads + * + *

    For Transport mode, payload will be only the attached payloads, but with the checksum + * calculated using the pre-encryption IP header + */ + public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) { + this.nextHeader = nextHeader; + this.spi = spi; + this.seqNum = seqNum; + this.key = key; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_ESP; + } + + public short length() { + // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len) + return (short) + calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + espPayloadBuffer.putInt(spi); + espPayloadBuffer.putInt(seqNum); + espPayloadBuffer.put(getCiphertext(key)); + + espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16); + resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer)); + } + + private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException { + Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256); + SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256); + sha256HMAC.init(authKey); + + return sha256HMAC.doFinal(authenticatedSection); + } + + /** + * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks + * + *

    The ciphertext does NOT include the SPI/Sequence numbers, or the ICV. + */ + private byte[] getCiphertext(byte[] key) throws GeneralSecurityException { + int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE); + ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen); + paddedPayload.put(payload); + + // Add padding - consecutive integers from 0x01 + int pad = 1; + while (paddedPayload.position() < paddedPayload.limit()) { + paddedPayload.put((byte) pad++); + } + + paddedPayload.position(paddedPayload.limit() - 2); + paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length + paddedPayload.put((byte) nextHeader); + + // Generate Initialization Vector + byte[] iv = new byte[AES_CBC_IV_LEN]; + new SecureRandom().nextBytes(iv); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); + + // Encrypt payload + Cipher cipher = Cipher.getInstance(AES_CBC); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload)); + + // Build ciphertext + ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length); + cipherText.put(iv); + cipherText.put(encrypted); + + return getByteArrayFromBuffer(cipherText); + } + } + + private static int addAndWrapForChecksum(int currentChecksum, int value) { + currentChecksum += value & 0x0000ffff; + + // Wrap anything beyond the first 16 bits, and add to lower order bits + return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff); + } + + private static short onesComplement(int val) { + val = (val >>> 16) + (val & 0xffff); + + if (val == 0) return 0; + return (short) ((~val) & 0xffff); + } + + public static int calculateEspPacketSize( + int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { + final int ESP_HDRLEN = 4 + 4; // SPI + Seq# + final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length + payloadLen += cryptIvLength; // Initialization Vector + + // Align to block size of encryption algorithm + payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize); + return payloadLen + ESP_HDRLEN + ICV_LEN; + } + + private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) { + payloadLen += 2; // ESP trailer + + // Align to block size of encryption algorithm + return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize); + } + + private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) { + return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; + } + + private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) { + return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); + } + + /* + * Debug printing + */ + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(hexArray[b >>> 4]); + sb.append(hexArray[b & 0x0F]); + sb.append(' '); + } + return sb.toString(); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java new file mode 100644 index 0000000000..71450ea9c0 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java @@ -0,0 +1,264 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.IPPROTO_ESP; +import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; +import static android.system.OsConstants.IPPROTO_UDP; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import android.os.ParcelFileDescriptor; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +/** + * This code is a exact copy of {@link TunUtils} in + * cts/tests/tests/net/src/android/net/cts/TunUtils.java, except the import path of PacketUtils is + * the path to the copy of PacktUtils. + * + *

    TODO(b/148689509): Statically include the TunUtils source file instead of copying it. + */ +public class TunUtils { + private static final String TAG = TunUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + private static final int TIMEOUT = 100; + + private static final int IP4_PROTO_OFFSET = 9; + private static final int IP6_PROTO_OFFSET = 6; + + private static final int IP4_ADDR_OFFSET = 12; + private static final int IP4_ADDR_LEN = 4; + private static final int IP6_ADDR_OFFSET = 8; + private static final int IP6_ADDR_LEN = 16; + + private final ParcelFileDescriptor mTunFd; + private final List mPackets = new ArrayList<>(); + private final Thread mReaderThread; + + public TunUtils(ParcelFileDescriptor tunFd) { + mTunFd = tunFd; + + // Start background reader thread + mReaderThread = + new Thread( + () -> { + try { + // Loop will exit and thread will quit when tunFd is closed. + // Receiving either EOF or an exception will exit this reader loop. + // FileInputStream in uninterruptable, so there's no good way to + // ensure that this thread shuts down except upon FD closure. + while (true) { + byte[] intercepted = receiveFromTun(); + if (intercepted == null) { + // Exit once we've hit EOF + return; + } else if (intercepted.length > 0) { + // Only save packet if we've received any bytes. + synchronized (mPackets) { + mPackets.add(intercepted); + mPackets.notifyAll(); + } + } + } + } catch (IOException ignored) { + // Simply exit this reader thread + return; + } + }); + mReaderThread.start(); + } + + private byte[] receiveFromTun() throws IOException { + FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor()); + byte[] inBytes = new byte[DATA_BUFFER_LEN]; + int bytesRead = in.read(inBytes); + + if (bytesRead < 0) { + return null; // return null for EOF + } else if (bytesRead >= DATA_BUFFER_LEN) { + throw new IllegalStateException("Too big packet. Fragmentation unsupported"); + } + return Arrays.copyOf(inBytes, bytesRead); + } + + private byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { + synchronized (mPackets) { + for (int i = startIndex; i < mPackets.size(); i++) { + byte[] pkt = mPackets.get(i); + if (verifier.test(pkt)) { + return pkt; + } + } + } + return null; + } + + /** + * Checks if the specified bytes were ever sent in plaintext. + * + *

    Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like + * + * @param plaintext the plaintext bytes to check for + * @param startIndex the index in the list to check for + */ + public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { + Predicate verifier = + (pkt) -> { + return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) + != -1; + }; + return getFirstMatchingPacket(verifier, startIndex) != null; + } + + public byte[] getEspPacket(int spi, boolean encap, int startIndex) { + return getFirstMatchingPacket( + (pkt) -> { + return isEsp(pkt, spi, encap); + }, + startIndex); + } + + public byte[] awaitEspPacketNoPlaintext( + int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + long endTime = System.currentTimeMillis() + TIMEOUT; + int startIndex = 0; + + synchronized (mPackets) { + while (System.currentTimeMillis() < endTime) { + byte[] espPkt = getEspPacket(spi, useEncap, startIndex); + if (espPkt != null) { + // Validate packet size + assertEquals(expectedPacketSize, espPkt.length); + + // Always check plaintext from start + assertFalse(hasPlaintextPacket(plaintext, 0)); + return espPkt; // We've found the packet we're looking for. + } + + startIndex = mPackets.size(); + + // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout + long waitTimeout = endTime - System.currentTimeMillis(); + if (waitTimeout > 0) { + mPackets.wait(waitTimeout); + } + } + + fail("No such ESP packet found with SPI " + spi); + } + return null; + } + + private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { + // Check SPI byte by byte. + return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) + && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) + && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) + && pkt[espOffset + 3] == (byte) (spi & 0xff); + } + + private static boolean isEsp(byte[] pkt, int spi, boolean encap) { + if (isIpv6(pkt)) { + // IPv6 UDP encap not supported by kernels; assume non-encap. + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); + } else { + // Use default IPv4 header length (assuming no options) + if (encap) { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP + && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi); + } else { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi); + } + } + } + + private static boolean isIpv6(byte[] pkt) { + // First nibble shows IP version. 0x60 for IPv6 + return (pkt[0] & (byte) 0xF0) == (byte) 0x60; + } + + private static byte[] getReflectedPacket(byte[] pkt) { + byte[] reflected = Arrays.copyOf(pkt, pkt.length); + + if (isIpv6(pkt)) { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset + reflected, // dst + IP6_ADDR_OFFSET, // dst offset + IP6_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET, // src offset + reflected, // dst + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset + IP6_ADDR_LEN); // len + } else { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset + reflected, // dst + IP4_ADDR_OFFSET, // dst offset + IP4_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET, // src offset + reflected, // dst + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset + IP4_ADDR_LEN); // len + } + return reflected; + } + + /** Takes all captured packets, flips the src/dst, and re-injects them. */ + public void reflectPackets() throws IOException { + synchronized (mPackets) { + for (byte[] pkt : mPackets) { + injectPacket(getReflectedPacket(pkt)); + } + } + } + + public void injectPacket(byte[] pkt) throws IOException { + FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor()); + out.write(pkt); + out.flush(); + } + + /** Resets the intercepted packets. */ + public void reset() throws IOException { + synchronized (mPackets) { + mPackets.clear(); + } + } +} From 5d8b8a1f7128dce20e724e8568462b182ea11433 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sat, 25 Apr 2020 03:08:19 +0000 Subject: [PATCH 1031/1415] Add initial CTS test for IkeSessionParams This commit adds tests for building IkeSessionParams with PSK. It also tests configuring SA lifetimes, retransmissions and PCSCF server requests Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: I16fdc1ff9a22acb82b376211e0f187c4ead4cae5 Merged-In: I16fdc1ff9a22acb82b376211e0f187c4ead4cae5 (cherry picked from commit c98c75308fae272eb4c9f539bed22c1a91aab2a4) --- .../ipsec/ike/cts/IkeSessionParamsTest.java | 262 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 13 + 2 files changed, 275 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java new file mode 100644 index 0000000000..91ef7789e3 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java @@ -0,0 +1,262 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeIdentification; +import android.net.ipsec.ike.IkeSaProposal; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer; +import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer; +import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { + private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(20L); + private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(10L); + private static final int DPD_DELAY_SECONDS = (int) TimeUnit.MINUTES.toSeconds(10L); + private static final int[] RETRANS_TIMEOUT_MS_LIST = new int[] {500, 500, 500, 500, 500, 500}; + + private static final Map, Integer> EXPECTED_REQ_COUNT = + new HashMap<>(); + private static final HashSet EXPECTED_PCSCF_SERVERS = new HashSet<>(); + + static { + EXPECTED_REQ_COUNT.put(ConfigRequestIpv4PcscfServer.class, 3); + EXPECTED_REQ_COUNT.put(ConfigRequestIpv6PcscfServer.class, 3); + + EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_1); + EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_2); + EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_1); + EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_2); + } + + // Arbitrary proposal and remote ID. Local ID is chosen to match the client end cert in the + // following CL + private static final IkeSaProposal SA_PROPOSAL = + SaProposalTest.buildIkeSaProposalWithNormalModeCipher(); + private static final IkeIdentification LOCAL_ID = new IkeFqdnIdentification(LOCAL_HOSTNAME); + private static final IkeIdentification REMOTE_ID = new IkeFqdnIdentification(REMOTE_HOSTNAME); + + /** + * Create a Builder that has minimum configurations to build an IkeSessionParams. + * + *

    Authentication method is arbitrarily selected. Using other method (e.g. setAuthEap) also + * works. + */ + private IkeSessionParams.Builder createIkeParamsBuilderMinimum() { + return new IkeSessionParams.Builder(sContext) + .setNetwork(sTunNetwork) + .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) + .addSaProposal(SA_PROPOSAL) + .setLocalIdentification(LOCAL_ID) + .setRemoteIdentification(REMOTE_ID) + .setAuthPsk(IKE_PSK); + } + + /** + * Verify the minimum configurations to build an IkeSessionParams. + * + * @see #createIkeParamsBuilderMinimum + */ + private void verifyIkeParamsMinimum(IkeSessionParams sessionParams) { + assertEquals(sTunNetwork, sessionParams.getNetwork()); + assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); + assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); + assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); + assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthPskConfig); + assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk()); + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthPskConfig); + assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); + } + + private void verifySpecificPcscfConfigReqs( + HashSet expectedAddresses, IkeSessionParams sessionParams) { + Set resultAddresses = new HashSet<>(); + + for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) { + if (req instanceof ConfigRequestIpv4PcscfServer + && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) { + resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress()); + } else if (req instanceof ConfigRequestIpv6PcscfServer + && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) { + resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress()); + } + } + + assertEquals(expectedAddresses, resultAddresses); + } + + @Test + public void testBuildWithMinimumSet() throws Exception { + IkeSessionParams sessionParams = createIkeParamsBuilderMinimum().build(); + + verifyIkeParamsMinimum(sessionParams); + + // Verify default values that do not need explicit configuration. Do not do assertEquals + // to be avoid being a change-detector test + assertTrue(sessionParams.getHardLifetimeSeconds() > sessionParams.getSoftLifetimeSeconds()); + assertTrue(sessionParams.getSoftLifetimeSeconds() > 0); + assertTrue(sessionParams.getDpdDelaySeconds() > 0); + assertTrue(sessionParams.getRetransmissionTimeoutsMillis().length > 0); + for (int timeout : sessionParams.getRetransmissionTimeoutsMillis()) { + assertTrue(timeout > 0); + } + assertTrue(sessionParams.getConfigurationRequests().isEmpty()); + assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); + } + + @Test + public void testSetLifetimes() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) + .build(); + + verifyIkeParamsMinimum(sessionParams); + assertEquals(HARD_LIFETIME_SECONDS, sessionParams.getHardLifetimeSeconds()); + assertEquals(SOFT_LIFETIME_SECONDS, sessionParams.getSoftLifetimeSeconds()); + } + + @Test + public void testSetDpdDelay() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum().setDpdDelaySeconds(DPD_DELAY_SECONDS).build(); + + verifyIkeParamsMinimum(sessionParams); + assertEquals(DPD_DELAY_SECONDS, sessionParams.getDpdDelaySeconds()); + } + + @Test + public void testSetRetransmissionTimeouts() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST) + .build(); + + verifyIkeParamsMinimum(sessionParams); + assertArrayEquals(RETRANS_TIMEOUT_MS_LIST, sessionParams.getRetransmissionTimeoutsMillis()); + } + + @Test + public void testSetPcscfConfigRequests() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST) + .addPcscfServerRequest(AF_INET) + .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_1) + .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_1) + .addPcscfServerRequest(AF_INET6) + .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_2) + .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_2) + .build(); + + verifyIkeParamsMinimum(sessionParams); + verifyConfigRequestTypes(EXPECTED_REQ_COUNT, sessionParams.getConfigurationRequests()); + + Set resultAddresses = new HashSet<>(); + for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) { + if (req instanceof ConfigRequestIpv4PcscfServer + && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) { + resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress()); + } else if (req instanceof ConfigRequestIpv6PcscfServer + && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) { + resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress()); + } + } + assertEquals(EXPECTED_PCSCF_SERVERS, resultAddresses); + } + + @Test + public void testAddIkeOption() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .build(); + + verifyIkeParamsMinimum(sessionParams); + assertTrue(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); + } + + @Test + public void testRemoveIkeOption() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimum() + .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .removeIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .build(); + + verifyIkeParamsMinimum(sessionParams); + assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); + } + + @Test + public void testBuildWithPsk() throws Exception { + IkeSessionParams sessionParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(sTunNetwork) + .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) + .addSaProposal(SA_PROPOSAL) + .setLocalIdentification(LOCAL_ID) + .setRemoteIdentification(REMOTE_ID) + .setAuthPsk(IKE_PSK) + .build(); + assertEquals(sTunNetwork, sessionParams.getNetwork()); + assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); + assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); + assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); + assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthPskConfig); + assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk()); + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthPskConfig); + assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); + } + + // TODO(b/148689509): Add tests for building IkeSessionParams using EAP and + // digital-signature-based authentication +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index d3aa8d03d5..5f608df137 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -24,6 +24,7 @@ import android.net.ipsec.ike.IkeTrafficSelector; import java.net.Inet4Address; import java.net.Inet6Address; +import java.net.InetAddress; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,6 +41,11 @@ abstract class IkeTestBase { static final int IP4_PREFIX_LEN = 32; static final int IP6_PREFIX_LEN = 64; + static final byte[] IKE_PSK = "ikeAndroidPsk".getBytes(); + + static final String LOCAL_HOSTNAME = "client.test.ike.android.net"; + static final String REMOTE_HOSTNAME = "server.test.ike.android.net"; + static final Inet4Address IPV4_ADDRESS_LOCAL = (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); static final Inet4Address IPV4_ADDRESS_REMOTE = @@ -49,6 +55,13 @@ abstract class IkeTestBase { static final Inet6Address IPV6_ADDRESS_REMOTE = (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8:255::100")); + static final InetAddress PCSCF_IPV4_ADDRESS_1 = InetAddresses.parseNumericAddress("192.0.2.1"); + static final InetAddress PCSCF_IPV4_ADDRESS_2 = InetAddresses.parseNumericAddress("192.0.2.2"); + static final InetAddress PCSCF_IPV6_ADDRESS_1 = + InetAddresses.parseNumericAddress("2001:DB8::1"); + static final InetAddress PCSCF_IPV6_ADDRESS_2 = + InetAddresses.parseNumericAddress("2001:DB8::2"); + static final IkeTrafficSelector DEFAULT_V4_TS = new IkeTrafficSelector( MIN_PORT, From 913ce19d40b07d49d8b10f35e8f676299ccf7c1a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sun, 26 Apr 2020 22:34:31 +0000 Subject: [PATCH 1032/1415] Test building IkeSessionParams with EAP Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Iea7f4d14502f4b204c7a0d7357e1aaec99954e1f Merged-In: Iea7f4d14502f4b204c7a0d7357e1aaec99954e1f (cherry picked from commit 5ad4adaff63b06c66ce9466387118a077331f0c3) --- tests/cts/net/ipsec/Android.bp | 1 + .../assets/pem/server-a-self-signed-ca.pem | 20 +++ .../ipsec/ike/cts/IkeSessionParamsTest.java | 144 ++++++++++++++---- .../net/ipsec/ike/cts/IkeTestBase.java | 6 + 4 files changed, 141 insertions(+), 30 deletions(-) create mode 100644 tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp index 86969c31ae..1d9128b7fe 100644 --- a/tests/cts/net/ipsec/Android.bp +++ b/tests/cts/net/ipsec/Android.bp @@ -26,6 +26,7 @@ android_test { srcs: [ "src/**/*.java", + ":ike-test-utils", ], static_libs: [ diff --git a/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem b/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem new file mode 100644 index 0000000000..972fd55372 --- /dev/null +++ b/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSDCCAjCgAwIBAgIITJQJ6HC1rjwwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h +bmRyb2lkLm5ldDAeFw0xOTA5MzAxNzU1NTJaFw0yOTA5MjcxNzU1NTJaMEIxCzAJ +BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSEwHwYDVQQDExhyb290LmNhLnRl +c3QuYW5kcm9pZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCT +q3hGF+JvLaB1xW7KGKmaxiQ7BxX2Sn7cbp7ggoVYXsFlBUuPPv3+Vg5PfPCPhsJ8 +/7w4HyKo3uc/vHs5HpQ7rSd9blhAkfmJci2ULLq73FB8Mix4CzPwMx29RrN1X9bU +z4G0vJMczIBGxbZ0uw7n8bKcXBV7AIeax+J8lseEZ3k8iSuBkUJqGIpPFKTqByFZ +A1Lvt47xkON5SZh6c/Oe+o6291wXaCOJUSAKv6PAWZkq9HeD2fqKA/ck9dBaz1M3 +YvzQ9V/7so3/dECjAfKia388h1I6XSGNUM+d5hpxMXpAFgG42eUXHpJ10OjDvSwd +7ZSC91/kRQewUomEKBK1AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBRJn6hHhdeDY/dXpCKUfrFYQhKAGjANBgkqhkiG +9w0BAQsFAAOCAQEAig/94aGfHBhZuvbbhwAK4rUNpizmR567u0ZJ+QUEKyAlo9lT +ZWYHSm7qTAZYvPEjzTQIptnAlxCHePXh3Cfwgo+r82lhG2rcdI03iRyvHWjM8gyk +BXCJTi0Q08JHHpTP6GnAqpz58qEIFkk8P766zNXdhYrGPOydF+p7MFcb1Zv1gum3 +zmRLt0XUAMfjPUv1Bl8kTKFxH5lkMBLR1E0jnoJoTTfgRPrf9CuFSoh48n7YhoBT +KV75xZY8b8+SuB0v6BvQmkpKZGoxBjuVsShyG7q1+4JTAtwhiP7BlkDvVkaBEi7t +WIMFp2r2ZDisHgastNaeYFyzHYz9g1FCCrHQ4w== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java index 91ef7789e3..532be675aa 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java @@ -17,16 +17,22 @@ package android.net.ipsec.ike.cts; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; +import static android.telephony.TelephonyManager.APPTYPE_USIM; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import android.net.eap.EapSessionConfig; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeIdentification; import android.net.ipsec.ike.IkeSaProposal; @@ -37,10 +43,14 @@ import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.internal.net.ipsec.ike.testutils.CertUtils; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -76,6 +86,29 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { private static final IkeIdentification LOCAL_ID = new IkeFqdnIdentification(LOCAL_HOSTNAME); private static final IkeIdentification REMOTE_ID = new IkeFqdnIdentification(REMOTE_HOSTNAME); + private static final EapSessionConfig EAP_ALL_METHODS_CONFIG = + createEapOnlySafeMethodsBuilder() + .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) + .build(); + private static final EapSessionConfig EAP_ONLY_SAFE_METHODS_CONFIG = + createEapOnlySafeMethodsBuilder().build(); + + private X509Certificate mServerCaCert; + + @Before + public void setUp() throws Exception { + mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); + } + + private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() { + return new EapSessionConfig.Builder() + .setEapIdentity(EAP_IDENTITY) + .setEapSimConfig(SUB_ID, APPTYPE_USIM) + .setEapAkaConfig(SUB_ID, APPTYPE_USIM) + .setEapAkaPrimeConfig( + SUB_ID, APPTYPE_USIM, NETWORK_NAME, true /* allowMismatchedNetworkNames */); + } + /** * Create a Builder that has minimum configurations to build an IkeSessionParams. * @@ -112,23 +145,6 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); } - private void verifySpecificPcscfConfigReqs( - HashSet expectedAddresses, IkeSessionParams sessionParams) { - Set resultAddresses = new HashSet<>(); - - for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) { - if (req instanceof ConfigRequestIpv4PcscfServer - && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) { - resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress()); - } else if (req instanceof ConfigRequestIpv6PcscfServer - && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) { - resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress()); - } - } - - assertEquals(expectedAddresses, resultAddresses); - } - @Test public void testBuildWithMinimumSet() throws Exception { IkeSessionParams sessionParams = createIkeParamsBuilderMinimum().build(); @@ -232,22 +248,39 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); } - @Test - public void testBuildWithPsk() throws Exception { - IkeSessionParams sessionParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(sTunNetwork) - .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) - .addSaProposal(SA_PROPOSAL) - .setLocalIdentification(LOCAL_ID) - .setRemoteIdentification(REMOTE_ID) - .setAuthPsk(IKE_PSK) - .build(); + /** + * Create a Builder that has minimum configurations to build an IkeSessionParams, except for + * authentication method. + */ + private IkeSessionParams.Builder createIkeParamsBuilderMinimumWithoutAuth() { + return new IkeSessionParams.Builder(sContext) + .setNetwork(sTunNetwork) + .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) + .addSaProposal(SA_PROPOSAL) + .setLocalIdentification(LOCAL_ID) + .setRemoteIdentification(REMOTE_ID); + } + + /** + * Verify the minimum configurations to build an IkeSessionParams, except for authentication + * method. + * + * @see #createIkeParamsBuilderMinimumWithoutAuth + */ + private void verifyIkeParamsMinimumWithoutAuth(IkeSessionParams sessionParams) { assertEquals(sTunNetwork, sessionParams.getNetwork()); assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); + } + + @Test + public void testBuildWithPsk() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth().setAuthPsk(IKE_PSK).build(); + + verifyIkeParamsMinimumWithoutAuth(sessionParams); IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); assertTrue(localConfig instanceof IkeAuthPskConfig); @@ -257,6 +290,57 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); } - // TODO(b/148689509): Add tests for building IkeSessionParams using EAP and - // digital-signature-based authentication + @Test + public void testBuildWithEap() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG) + .build(); + + verifyIkeParamsMinimumWithoutAuth(sessionParams); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthEapConfig); + assertEquals(EAP_ALL_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig()); + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals( + mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); + } + + @Test + public void testBuildWithEapOnlyAuth() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthEap(mServerCaCert, EAP_ONLY_SAFE_METHODS_CONFIG) + .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH) + .build(); + + assertTrue(sessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH)); + verifyIkeParamsMinimumWithoutAuth(sessionParams); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthEapConfig); + assertEquals(EAP_ONLY_SAFE_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig()); + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals( + mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); + } + + @Test + public void testThrowBuildEapOnlyAuthWithUnsafeMethod() throws Exception { + try { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG) + .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH) + .build(); + fail("Expected to fail because EAP only unsafe method is proposed"); + } catch (IllegalArgumentException expected) { + } + } + + // TODO(b/148689509): Add tests for building IkeSessionParams using digital-signature-based + // authentication } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index 5f608df137..54c28e3a92 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -46,6 +46,12 @@ abstract class IkeTestBase { static final String LOCAL_HOSTNAME = "client.test.ike.android.net"; static final String REMOTE_HOSTNAME = "server.test.ike.android.net"; + static final int SUB_ID = 1; + static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); + static final String NETWORK_NAME = "android.net"; + static final String EAP_MSCHAPV2_USERNAME = "username"; + static final String EAP_MSCHAPV2_PASSWORD = "password"; + static final Inet4Address IPV4_ADDRESS_LOCAL = (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); static final Inet4Address IPV4_ADDRESS_REMOTE = From fe6c2565dac3d81d20294de01c221f7d125f7448 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 27 Apr 2020 03:28:29 +0000 Subject: [PATCH 1033/1415] Test configuring digital-signature-based auth Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ieaceaadf116cb2885cbf22ae48579cec88268416 Merged-In: Ieaceaadf116cb2885cbf22ae48579cec88268416 (cherry picked from commit ca5515626ce03bde9116603485ec0e85f476ecd3) --- .../ipsec/assets/key/client-a-private-key.key | 28 +++++++++ .../ipsec/assets/pem/client-a-end-cert.pem | 21 +++++++ .../pem/client-a-intermediate-ca-one.pem | 21 +++++++ .../pem/client-a-intermediate-ca-two.pem | 21 +++++++ .../ipsec/ike/cts/IkeSessionParamsTest.java | 63 ++++++++++++++++++- 5 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/ipsec/assets/key/client-a-private-key.key create mode 100644 tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem create mode 100644 tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem create mode 100644 tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem diff --git a/tests/cts/net/ipsec/assets/key/client-a-private-key.key b/tests/cts/net/ipsec/assets/key/client-a-private-key.key new file mode 100644 index 0000000000..22736e98e0 --- /dev/null +++ b/tests/cts/net/ipsec/assets/key/client-a-private-key.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL +8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu +7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K +Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i +pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS +jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK +a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub +G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n +zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo +zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL +gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc +9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf +spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL +ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms +TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy +GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK +QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ ++K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE +i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh +fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU +ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+ +NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN +mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR +wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G +xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf +idNFcaIrC52PtZIH7QCzdDY= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem b/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem new file mode 100644 index 0000000000..e82da85c50 --- /dev/null +++ b/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu +ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG +A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0 +LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE +CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc +6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw +D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC +25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG +R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL +bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu +bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK +I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio +4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP +ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab +SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7 +T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy +rmkYV2MAWguFeckh +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem new file mode 100644 index 0000000000..707e575bc3 --- /dev/null +++ b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIIIbjMyRn2770wDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h +bmRyb2lkLm5ldDAeFw0xOTA5MzAxODQzMThaFw0yNDA5MjgxODQzMThaMEExCzAJ +BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSAwHgYDVQQDExdvbmUuY2EudGVz +dC5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNN +sRr5Z30rAEw2jrAh/BIekbEy/MvOucAr1w0lxH71p+ybRBx5Bj7G07UGXbL659gm +meMV6nabY4HjQXNMq22POiJBZj+U+rw34br6waljBttxCmmJac1VvgqNsSspXjRy +NbiVQdFjyKSX0NOPcEkwANk15mZbOgJBaYYc8jQCY2G/p8eARVBTLJCy8LEwEU6j +XRv/4eYST79qpBFc7gQQj2FLmh9oppDIvcIVBHwtd1tBoVuehRSud1o8vQRkl/HJ +Mrwp24nO5YYhmVNSFRtBpmWMSu1KknFUwkOebINUNsKXXHebVa7cP4XIQUL8mRT3 +5X9rFJFSQJE01S3NjNMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAQYwHQYDVR0OBBYEFHK3FIm7g8dxEIwK9zMAO8EWhRYxMB8GA1UdIwQY +MBaAFEmfqEeF14Nj91ekIpR+sVhCEoAaMA0GCSqGSIb3DQEBCwUAA4IBAQAeMlXT +TnxZo8oz0204gKZ63RzlgDpJ7SqA3qFG+pV+TiqGfSuVkXuIdOskjxJnA9VxUzrr +LdMTCn5e0FK6wCYjZ2GT/CD7oD3vSMkzGbLGNcNJhhDHUq8BOLPkPzz/rwQFPBSb +zr6hsiVXphEt/psGoN7Eu9blPeQaIwMfWnaufAwF664S/3dmCRbNMWSam1qzzz8q +jr0cDOIMa//ZIAcM16cvoBK6pFGnUmuoJYYRtfpY5MmfCWz0sCJxENIX/lxyhd7N +FdRALA1ZP3E//Tn2vQoeFjbKaAba527RE26HgHJ9zZDo1nn8J8J/YwYRJdBWM/3S +LYebNiMtcyB5nIkj +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem new file mode 100644 index 0000000000..39808f885e --- /dev/null +++ b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIIKWCREnNCs+wwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF29uZS5jYS50ZXN0LmFu +ZHJvaWQubmV0MB4XDTE5MDkzMDE4NDQwMloXDTI0MDkyODE4NDQwMlowQTELMAkG +A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0 +LmFuZHJvaWQubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLUa +RqkYl2m7lUmMnkooqO0DNNY1aN9r7mJc3ndYn5gjkpb3yLgOYPDNLcQerV6uWk/u +qKudNHed2dInGonl3oxwwv7++6oUvvtrSWLDZlRg16GsdIE1Y98DSMQWkSxevYy9 +Nh6FGTdlBFQVMpiMa8qHEkrOyKsy85yCW1sgzlpGTIBwbDAqYtwe3rgbwyHwUtfy +0EU++DBcR4ll/pDqB0OQtW5E3AOq2GH1iaGeFLKSUQ5KAbdI8y4/b8IkSDffvxcc +kXig7S54aLrNlL/ZjQ+H4Chgjj2A5wMucd81+Fb60Udej73ICL9PpMPnXQ1+BVYd +MJ/txjLNmrOJG9yEHQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQUcqSu1uRYT/DLbLoDNUz38nGvCKQwHwYDVR0jBBgw +FoAUcrcUibuDx3EQjAr3MwA7wRaFFjEwDQYJKoZIhvcNAQELBQADggEBADY461GT +Rw0dGnD07xaGJcI0i0pV+WnGSrl1s1PAIdMYihJAqYnh10fXbFXLm2WMWVmv/pxs +FI/xDJno+pd4mCa/sIhm63ar/Nv+lFQmcpIlvSlKnhhV4SLNBeqbVhPBGTCHfrG4 +aIyCwm1KJsnkWbf03crhSskR/2CXIjX6lcAy7K3fE2u1ELpAdH0kMJR7VXkLFLUm +gqe9YCluR0weMpe2sCaOGzdVzQSmMMCzGP5cxeFR5U6K40kMOpiW11JNmQ06xI/m +YVkMNwoiV/ITT0/C/g9FxJmkO0mVSLEqxaLS/hNiQNDlroVM0rbxhzviXLI3R3AO +50VvlOQYGxWed/I= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java index 532be675aa..6fc7cb3634 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java @@ -19,6 +19,7 @@ package android.net.ipsec.ike.cts; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; +import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; @@ -51,9 +52,12 @@ import org.junit.runner.RunWith; import java.net.InetAddress; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -94,10 +98,20 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { createEapOnlySafeMethodsBuilder().build(); private X509Certificate mServerCaCert; + private X509Certificate mClientEndCert; + private X509Certificate mClientIntermediateCaCertOne; + private X509Certificate mClientIntermediateCaCertTwo; + private RSAPrivateKey mClientPrivateKey; @Before public void setUp() throws Exception { mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); + mClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); + mClientIntermediateCaCertOne = + CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem"); + mClientIntermediateCaCertTwo = + CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem"); + mClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); } private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() { @@ -341,6 +355,51 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { } } - // TODO(b/148689509): Add tests for building IkeSessionParams using digital-signature-based - // authentication + @Test + public void testBuildWithDigitalSignature() throws Exception { + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthDigitalSignature(mServerCaCert, mClientEndCert, mClientPrivateKey) + .build(); + + verifyIkeParamsMinimumWithoutAuth(sessionParams); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); + IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig; + assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate()); + assertEquals(Collections.EMPTY_LIST, localSignConfig.getIntermediateCertificates()); + assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey()); + + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals( + mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); + } + + @Test + public void testBuildWithDigitalSignatureAndIntermediateCerts() throws Exception { + List intermediateCerts = + Arrays.asList(mClientIntermediateCaCertOne, mClientIntermediateCaCertTwo); + + IkeSessionParams sessionParams = + createIkeParamsBuilderMinimumWithoutAuth() + .setAuthDigitalSignature( + mServerCaCert, mClientEndCert, intermediateCerts, mClientPrivateKey) + .build(); + + verifyIkeParamsMinimumWithoutAuth(sessionParams); + + IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); + IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig; + assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate()); + assertEquals(intermediateCerts, localSignConfig.getIntermediateCertificates()); + assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey()); + + IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals( + mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); + } } From 6b3afbe447274043c6d2c2323723c99e77bf27c3 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 27 Apr 2020 11:03:09 +0800 Subject: [PATCH 1034/1415] Unbreak tethering for no offload supported devices Catch NoSuchElementException to unbreak no offload devices. To consistent with fetching offload config service, retry fetcheing offload control service. b/152430668#comment4 assert that the fetch will be retried only if the service is installed on the device. Bug: 155026033 Test: run TetheringCoverageTests in virtual devices(do not support offload) Change-Id: Ie0a32a9062c722327a27c6de13e3bb8d9588bebb --- .../networkstack/tethering/OffloadHardwareInterface.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index 55344fc75d..c4a1078d0b 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.net.SocketAddress; import java.net.SocketException; import java.util.ArrayList; +import java.util.NoSuchElementException; /** @@ -143,7 +144,7 @@ public class OffloadHardwareInterface { IOffloadConfig offloadConfig; try { offloadConfig = IOffloadConfig.getService(true /*retry*/); - } catch (RemoteException e) { + } catch (RemoteException | NoSuchElementException e) { mLog.e("getIOffloadConfig error " + e); return false; } @@ -239,8 +240,8 @@ public class OffloadHardwareInterface { if (mOffloadControl == null) { try { - mOffloadControl = IOffloadControl.getService(); - } catch (RemoteException e) { + mOffloadControl = IOffloadControl.getService(true /*retry*/); + } catch (RemoteException | NoSuchElementException e) { mLog.e("tethering offload control not supported: " + e); return false; } From b85287f5d034cbb9f4a6ab4e389c5dc220f862d1 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Mon, 27 Apr 2020 01:01:45 -0700 Subject: [PATCH 1035/1415] Import translations. DO NOT MERGE Change-Id: I1cdee455c89183fa875ac4916105db6dffd5ee2b Auto-generated-cl: translation import --- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 12 ++++-------- Tethering/res/values-mcc310-mnc004-ta/strings.xml | 12 ++++-------- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 12 ++++-------- Tethering/res/values-mcc311-mnc480-ta/strings.xml | 12 ++++-------- 4 files changed, 16 insertions(+), 32 deletions(-) diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index 2a7330098f..12d6c2cfba 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "Tethering has no internet" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index ea04821e33..f4b15aab19 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 617c50dd0c..0a0aa217c3 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "Tethering has no internet" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 0e437593ee..2ea2467e58 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" From ecb661016ff964d78fc7616ed8c0c546a2cc22fc Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 24 Mar 2020 18:40:42 +0900 Subject: [PATCH 1036/1415] Add test for internet availability on portals Add a test verifying that when the device has detected a captive portal, or when the user is trying to login to a captive portal, the captive portal network does not become the default network if another network can provide internet access. This follows R CDD requirements. Test: atest CtsNetTestCases:android.net.cts.CaptivePortalTest Bug: 152280218 Change-Id: I6a97ed26dba665efdc67abb2371e0fc30ede020c --- tests/cts/net/Android.bp | 1 + .../src/android/net/cts/CaptivePortalTest.kt | 254 ++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/CaptivePortalTest.kt diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 76bb27e448..46fae33b9b 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -47,6 +47,7 @@ java_defaults { "mockwebserver", "junit", "junit-params", + "libnanohttpd", "truth-prebuilt", ], diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt new file mode 100644 index 0000000000..4418e1740e --- /dev/null +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -0,0 +1,254 @@ +/* + * 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 android.Manifest.permission.NETWORK_SETTINGS +import android.Manifest.permission.READ_DEVICE_CONFIG +import android.Manifest.permission.WRITE_DEVICE_CONFIG +import android.content.pm.PackageManager.FEATURE_TELEPHONY +import android.content.pm.PackageManager.FEATURE_WIFI +import android.net.ConnectivityManager +import android.net.ConnectivityManager.NetworkCallback +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import android.net.NetworkRequest +import android.net.Uri +import android.net.cts.util.CtsNetUtils +import android.net.wifi.WifiManager +import android.os.ConditionVariable +import android.platform.test.annotations.AppModeFull +import android.provider.DeviceConfig +import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY +import android.text.TextUtils +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import androidx.test.runner.AndroidJUnit4 +import com.android.compatibility.common.util.SystemUtil +import fi.iki.elonen.NanoHTTPD +import fi.iki.elonen.NanoHTTPD.Response.IStatus +import fi.iki.elonen.NanoHTTPD.Response.Status +import junit.framework.AssertionFailedError +import org.junit.After +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.runner.RunWith +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException +import kotlin.test.Test +import kotlin.test.assertNotEquals +import kotlin.test.assertTrue + +private const val TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING = "test_captive_portal_https_url" +private const val TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING = "test_captive_portal_http_url" +private const val TEST_URL_EXPIRATION_TIME = "test_url_expiration_time" + +private const val TEST_HTTPS_URL_PATH = "https_path" +private const val TEST_HTTP_URL_PATH = "http_path" +private const val TEST_PORTAL_URL_PATH = "portal_path" + +private const val LOCALHOST_HOSTNAME = "localhost" + +// Re-connecting to the AP, obtaining an IP address, revalidating can take a long time +private const val WIFI_CONNECT_TIMEOUT_MS = 120_000L +private const val TEST_TIMEOUT_MS = 10_000L + +private fun CompletableFuture.assertGet(timeoutMs: Long, message: String): T { + try { + return get(timeoutMs, TimeUnit.MILLISECONDS) + } catch (e: TimeoutException) { + throw AssertionFailedError(message) + } +} + +@AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") +@RunWith(AndroidJUnit4::class) +class CaptivePortalTest { + private val context: android.content.Context by lazy { getInstrumentation().context } + private val wm by lazy { context.getSystemService(WifiManager::class.java) } + private val cm by lazy { context.getSystemService(ConnectivityManager::class.java) } + private val pm by lazy { context.packageManager } + private val utils by lazy { CtsNetUtils(context) } + + private val server = HttpServer() + + @Before + fun setUp() { + doAsShell(READ_DEVICE_CONFIG) { + // Verify that the test URLs are not normally set on the device, but do not fail if the + // test URLs are set to what this test uses (URLs on localhost), in case the test was + // interrupted manually and rerun. + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING) + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING) + } + clearTestUrls() + server.start() + } + + @After + fun tearDown() { + clearTestUrls() + server.stop() + } + + private fun assertEmptyOrLocalhostUrl(urlKey: String) { + val url = DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, urlKey) + assertTrue(TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME == Uri.parse(url).host, + "$urlKey must not be set in production scenarios (current value: $url)") + } + + private fun clearTestUrls() { + setHttpsUrl(null) + setHttpUrl(null) + setUrlExpiration(null) + } + + @Test + fun testCaptivePortalIsNotDefaultNetwork() { + assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY)) + assumeTrue(pm.hasSystemFeature(FEATURE_WIFI)) + utils.connectToWifi() + utils.connectToCell() + + // Have network validation use a local server that serves a HTTPS error / HTTP redirect + server.addResponse(TEST_PORTAL_URL_PATH, Status.OK, + content = "Test captive portal content") + server.addResponse(TEST_HTTPS_URL_PATH, Status.INTERNAL_ERROR) + server.addResponse(TEST_HTTP_URL_PATH, Status.REDIRECT, + locationHeader = server.makeUrl(TEST_PORTAL_URL_PATH)) + setHttpsUrl(server.makeUrl(TEST_HTTPS_URL_PATH)) + setHttpUrl(server.makeUrl(TEST_HTTP_URL_PATH)) + // URL expiration needs to be in the next 10 minutes + setUrlExpiration(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)) + + // Expect the portal content to be fetched at some point after detecting the portal. + // Some implementations may fetch the URL before startCaptivePortalApp is called. + val portalContentRequestCv = server.addExpectRequestCv(TEST_PORTAL_URL_PATH) + + // Wait for a captive portal to be detected on the network + val wifiNetworkFuture = CompletableFuture() + val wifiCb = object : NetworkCallback() { + override fun onCapabilitiesChanged( + network: Network, + nc: NetworkCapabilities + ) { + if (nc.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) { + wifiNetworkFuture.complete(network) + } + } + } + cm.requestNetwork(NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(), wifiCb) + + try { + reconnectWifi() + val network = wifiNetworkFuture.assertGet(WIFI_CONNECT_TIMEOUT_MS, + "Captive portal not detected after ${WIFI_CONNECT_TIMEOUT_MS}ms") + + val wifiDefaultMessage = "Wifi should not be the default network when a captive " + + "portal was detected and another network (mobile data) can provide internet " + + "access." + assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) + + doAsShell(NETWORK_SETTINGS) { cm.startCaptivePortalApp(network) } + assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " + + "page was still not fetched ${TEST_TIMEOUT_MS}ms after startCaptivePortalApp.") + + assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) + } finally { + cm.unregisterNetworkCallback(wifiCb) + server.stop() + // disconnectFromCell should be called after connectToCell + utils.disconnectFromCell() + } + + clearTestUrls() + reconnectWifi() + } + + private fun setHttpsUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING, url) + private fun setHttpUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING, url) + private fun setUrlExpiration(timestamp: Long?) = setConfig(TEST_URL_EXPIRATION_TIME, + timestamp?.toString()) + + private fun setConfig(configKey: String, value: String?) { + doAsShell(WRITE_DEVICE_CONFIG) { + DeviceConfig.setProperty( + NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) + } + } + + private fun doAsShell(vararg permissions: String, action: () -> Unit) { + // Wrap the below call to allow for more kotlin-like syntax + SystemUtil.runWithShellPermissionIdentity(action, permissions) + } + + private fun reconnectWifi() { + doAsShell(NETWORK_SETTINGS) { + assertTrue(wm.disconnect()) + assertTrue(wm.reconnect()) + } + } + + /** + * A minimal HTTP server running on localhost (loopback), on a random available port. + */ + private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) { + // Map of URL path -> HTTP response code + private val responses = HashMap() + + // Map of path -> CV to open as soon as a request to the path is received + private val waitForRequestCv = HashMap() + + /** + * Create a URL string that, when fetched, will hit this server with the given URL [path]. + */ + fun makeUrl(path: String): String { + return Uri.Builder() + .scheme("http") + .encodedAuthority("localhost:$listeningPort") + .query(path) + .build() + .toString() + } + + fun addResponse( + path: String, + statusCode: IStatus, + locationHeader: String? = null, + content: String = "" + ) { + val response = newFixedLengthResponse(statusCode, "text/plain", content) + locationHeader?.let { response.addHeader("Location", it) } + responses[path] = response + } + + /** + * Create a [ConditionVariable] that will open when a request to [path] is received. + */ + fun addExpectRequestCv(path: String): ConditionVariable { + return ConditionVariable().apply { waitForRequestCv[path] = this } + } + + override fun serve(session: IHTTPSession): Response { + waitForRequestCv[session.queryParameterString]?.open() + return responses[session.queryParameterString] + // Default response is a 404 + ?: super.serve(session) + } + } +} \ No newline at end of file From 71cfc79527c812fcd334ca688477c0536f1fbee0 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 27 Apr 2020 22:40:11 +0900 Subject: [PATCH 1037/1415] Force reconnect in connectToWifi There is no guarantee that Wifi will automatically reconnect after enabling, especially in cases where no internet access was detected on the access point the last time it was connected. Use WifiManager#reconnect to force wifi to reconnect to the access point. The API is deprecated for general use, but system apps are documented as exempted from the deprecation. Bug: 152280218 Test: atest --rerun-until-failure 200 CtsNetTestCases:CaptivePortalTest Change-Id: Ia7d83337ee0ffad9414031711cf7e937b14f968d --- tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java | 3 +++ 1 file changed, 3 insertions(+) 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 6214f89e98..824146fedf 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 @@ public final class CtsNetUtils { 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); From b921f9ead690959bf0570ca9831cd754fa4f448e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sat, 25 Apr 2020 03:08:38 +0000 Subject: [PATCH 1038/1415] Add test for IkeIdentification Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ieda584446c37d121fc16a212e2c6c60b934b0f53 Merged-In: Ieda584446c37d121fc16a212e2c6c60b934b0f53 (cherry picked from commit 923f59a282367a668f151873860f8f4ff5ba352d) --- .../ipsec/ike/cts/IkeIdentificationTest.java | 75 +++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 3 + 2 files changed, 78 insertions(+) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java new file mode 100644 index 0000000000..0317def92e --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java @@ -0,0 +1,75 @@ +/* + * 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.ipsec.ike.cts; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import android.net.ipsec.ike.IkeDerAsn1DnIdentification; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeIpv4AddrIdentification; +import android.net.ipsec.ike.IkeIpv6AddrIdentification; +import android.net.ipsec.ike.IkeKeyIdIdentification; +import android.net.ipsec.ike.IkeRfc822AddrIdentification; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.security.auth.x500.X500Principal; + +@RunWith(AndroidJUnit4.class) +public final class IkeIdentificationTest extends IkeTestBase { + @Test + public void testIkeDerAsn1DnIdentification() throws Exception { + X500Principal asn1Dn = new X500Principal(LOCAL_ASN1_DN_STRING); + + IkeDerAsn1DnIdentification ikeId = new IkeDerAsn1DnIdentification(asn1Dn); + assertEquals(asn1Dn, ikeId.derAsn1Dn); + } + + @Test + public void testIkeFqdnIdentification() throws Exception { + IkeFqdnIdentification ikeId = new IkeFqdnIdentification(LOCAL_HOSTNAME); + assertEquals(LOCAL_HOSTNAME, ikeId.fqdn); + } + + @Test + public void testIkeIpv4AddrIdentification() throws Exception { + IkeIpv4AddrIdentification ikeId = new IkeIpv4AddrIdentification(IPV4_ADDRESS_LOCAL); + assertEquals(IPV4_ADDRESS_LOCAL, ikeId.ipv4Address); + } + + @Test + public void testIkeIpv6AddrIdentification() throws Exception { + IkeIpv6AddrIdentification ikeId = new IkeIpv6AddrIdentification(IPV6_ADDRESS_LOCAL); + assertEquals(IPV6_ADDRESS_LOCAL, ikeId.ipv6Address); + } + + @Test + public void testIkeKeyIdIdentification() throws Exception { + IkeKeyIdIdentification ikeId = new IkeKeyIdIdentification(LOCAL_KEY_ID); + assertArrayEquals(LOCAL_KEY_ID, ikeId.keyId); + } + + @Test + public void testIkeRfc822AddrIdentification() throws Exception { + IkeRfc822AddrIdentification ikeId = new IkeRfc822AddrIdentification(LOCAL_RFC822_NAME); + assertEquals(LOCAL_RFC822_NAME, ikeId.rfc822Name); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index 5f608df137..08477446d2 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -45,6 +45,9 @@ abstract class IkeTestBase { static final String LOCAL_HOSTNAME = "client.test.ike.android.net"; static final String REMOTE_HOSTNAME = "server.test.ike.android.net"; + static final String LOCAL_ASN1_DN_STRING = "CN=client.test.ike.android.net, O=Android, C=US"; + static final String LOCAL_RFC822_NAME = "client.test.ike@example.com"; + static final byte[] LOCAL_KEY_ID = "Local Key ID".getBytes(); static final Inet4Address IPV4_ADDRESS_LOCAL = (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); From b78e40bd4f47ad40e88c6c7cdf6dfd4e81b05a2e Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Tue, 28 Apr 2020 00:46:32 -0700 Subject: [PATCH 1039/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I5cb9777f596296af4cbe13a0b1fe57ab2a9283b2 --- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 12 ++++-------- Tethering/res/values-mcc310-mnc004-or/strings.xml | 12 ++++-------- Tethering/res/values-mcc310-mnc004-ta/strings.xml | 12 ++++-------- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 12 ++++-------- Tethering/res/values-mcc311-mnc480-or/strings.xml | 12 ++++-------- Tethering/res/values-mcc311-mnc480-ta/strings.xml | 12 ++++-------- 6 files changed, 24 insertions(+), 48 deletions(-) diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index 2a7330098f..12d6c2cfba 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "Tethering has no internet" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml index 919721d91c..8038815fe8 100644 --- a/Tethering/res/values-mcc310-mnc004-or/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index ea04821e33..f4b15aab19 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 617c50dd0c..0a0aa217c3 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "Tethering has no internet" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml index 4ea223cc2e..1ad4ca354a 100644 --- a/Tethering/res/values-mcc311-mnc480-or/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 0e437593ee..2ea2467e58 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" From 388f7240c7e4dfd9830311cfc50a267f685fc2a0 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 28 Apr 2020 06:16:55 +0000 Subject: [PATCH 1040/1415] Add test for internet availability on portals Add a test verifying that when the device has detected a captive portal, or when the user is trying to login to a captive portal, the captive portal network does not become the default network if another network can provide internet access. This follows R CDD requirements. Test: atest CtsNetTestCases:android.net.cts.CaptivePortalTest Bug: 152280218 Merged-In: I6a97ed26dba665efdc67abb2371e0fc30ede020c Change-Id: I6a97ed26dba665efdc67abb2371e0fc30ede020c --- tests/cts/net/Android.bp | 1 + .../src/android/net/cts/CaptivePortalTest.kt | 254 ++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/CaptivePortalTest.kt diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 76bb27e448..46fae33b9b 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -47,6 +47,7 @@ java_defaults { "mockwebserver", "junit", "junit-params", + "libnanohttpd", "truth-prebuilt", ], diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt new file mode 100644 index 0000000000..4418e1740e --- /dev/null +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -0,0 +1,254 @@ +/* + * 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 android.Manifest.permission.NETWORK_SETTINGS +import android.Manifest.permission.READ_DEVICE_CONFIG +import android.Manifest.permission.WRITE_DEVICE_CONFIG +import android.content.pm.PackageManager.FEATURE_TELEPHONY +import android.content.pm.PackageManager.FEATURE_WIFI +import android.net.ConnectivityManager +import android.net.ConnectivityManager.NetworkCallback +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import android.net.NetworkRequest +import android.net.Uri +import android.net.cts.util.CtsNetUtils +import android.net.wifi.WifiManager +import android.os.ConditionVariable +import android.platform.test.annotations.AppModeFull +import android.provider.DeviceConfig +import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY +import android.text.TextUtils +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import androidx.test.runner.AndroidJUnit4 +import com.android.compatibility.common.util.SystemUtil +import fi.iki.elonen.NanoHTTPD +import fi.iki.elonen.NanoHTTPD.Response.IStatus +import fi.iki.elonen.NanoHTTPD.Response.Status +import junit.framework.AssertionFailedError +import org.junit.After +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.runner.RunWith +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException +import kotlin.test.Test +import kotlin.test.assertNotEquals +import kotlin.test.assertTrue + +private const val TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING = "test_captive_portal_https_url" +private const val TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING = "test_captive_portal_http_url" +private const val TEST_URL_EXPIRATION_TIME = "test_url_expiration_time" + +private const val TEST_HTTPS_URL_PATH = "https_path" +private const val TEST_HTTP_URL_PATH = "http_path" +private const val TEST_PORTAL_URL_PATH = "portal_path" + +private const val LOCALHOST_HOSTNAME = "localhost" + +// Re-connecting to the AP, obtaining an IP address, revalidating can take a long time +private const val WIFI_CONNECT_TIMEOUT_MS = 120_000L +private const val TEST_TIMEOUT_MS = 10_000L + +private fun CompletableFuture.assertGet(timeoutMs: Long, message: String): T { + try { + return get(timeoutMs, TimeUnit.MILLISECONDS) + } catch (e: TimeoutException) { + throw AssertionFailedError(message) + } +} + +@AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") +@RunWith(AndroidJUnit4::class) +class CaptivePortalTest { + private val context: android.content.Context by lazy { getInstrumentation().context } + private val wm by lazy { context.getSystemService(WifiManager::class.java) } + private val cm by lazy { context.getSystemService(ConnectivityManager::class.java) } + private val pm by lazy { context.packageManager } + private val utils by lazy { CtsNetUtils(context) } + + private val server = HttpServer() + + @Before + fun setUp() { + doAsShell(READ_DEVICE_CONFIG) { + // Verify that the test URLs are not normally set on the device, but do not fail if the + // test URLs are set to what this test uses (URLs on localhost), in case the test was + // interrupted manually and rerun. + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING) + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING) + } + clearTestUrls() + server.start() + } + + @After + fun tearDown() { + clearTestUrls() + server.stop() + } + + private fun assertEmptyOrLocalhostUrl(urlKey: String) { + val url = DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, urlKey) + assertTrue(TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME == Uri.parse(url).host, + "$urlKey must not be set in production scenarios (current value: $url)") + } + + private fun clearTestUrls() { + setHttpsUrl(null) + setHttpUrl(null) + setUrlExpiration(null) + } + + @Test + fun testCaptivePortalIsNotDefaultNetwork() { + assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY)) + assumeTrue(pm.hasSystemFeature(FEATURE_WIFI)) + utils.connectToWifi() + utils.connectToCell() + + // Have network validation use a local server that serves a HTTPS error / HTTP redirect + server.addResponse(TEST_PORTAL_URL_PATH, Status.OK, + content = "Test captive portal content") + server.addResponse(TEST_HTTPS_URL_PATH, Status.INTERNAL_ERROR) + server.addResponse(TEST_HTTP_URL_PATH, Status.REDIRECT, + locationHeader = server.makeUrl(TEST_PORTAL_URL_PATH)) + setHttpsUrl(server.makeUrl(TEST_HTTPS_URL_PATH)) + setHttpUrl(server.makeUrl(TEST_HTTP_URL_PATH)) + // URL expiration needs to be in the next 10 minutes + setUrlExpiration(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)) + + // Expect the portal content to be fetched at some point after detecting the portal. + // Some implementations may fetch the URL before startCaptivePortalApp is called. + val portalContentRequestCv = server.addExpectRequestCv(TEST_PORTAL_URL_PATH) + + // Wait for a captive portal to be detected on the network + val wifiNetworkFuture = CompletableFuture() + val wifiCb = object : NetworkCallback() { + override fun onCapabilitiesChanged( + network: Network, + nc: NetworkCapabilities + ) { + if (nc.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) { + wifiNetworkFuture.complete(network) + } + } + } + cm.requestNetwork(NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(), wifiCb) + + try { + reconnectWifi() + val network = wifiNetworkFuture.assertGet(WIFI_CONNECT_TIMEOUT_MS, + "Captive portal not detected after ${WIFI_CONNECT_TIMEOUT_MS}ms") + + val wifiDefaultMessage = "Wifi should not be the default network when a captive " + + "portal was detected and another network (mobile data) can provide internet " + + "access." + assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) + + doAsShell(NETWORK_SETTINGS) { cm.startCaptivePortalApp(network) } + assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " + + "page was still not fetched ${TEST_TIMEOUT_MS}ms after startCaptivePortalApp.") + + assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) + } finally { + cm.unregisterNetworkCallback(wifiCb) + server.stop() + // disconnectFromCell should be called after connectToCell + utils.disconnectFromCell() + } + + clearTestUrls() + reconnectWifi() + } + + private fun setHttpsUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING, url) + private fun setHttpUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING, url) + private fun setUrlExpiration(timestamp: Long?) = setConfig(TEST_URL_EXPIRATION_TIME, + timestamp?.toString()) + + private fun setConfig(configKey: String, value: String?) { + doAsShell(WRITE_DEVICE_CONFIG) { + DeviceConfig.setProperty( + NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) + } + } + + private fun doAsShell(vararg permissions: String, action: () -> Unit) { + // Wrap the below call to allow for more kotlin-like syntax + SystemUtil.runWithShellPermissionIdentity(action, permissions) + } + + private fun reconnectWifi() { + doAsShell(NETWORK_SETTINGS) { + assertTrue(wm.disconnect()) + assertTrue(wm.reconnect()) + } + } + + /** + * A minimal HTTP server running on localhost (loopback), on a random available port. + */ + private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) { + // Map of URL path -> HTTP response code + private val responses = HashMap() + + // Map of path -> CV to open as soon as a request to the path is received + private val waitForRequestCv = HashMap() + + /** + * Create a URL string that, when fetched, will hit this server with the given URL [path]. + */ + fun makeUrl(path: String): String { + return Uri.Builder() + .scheme("http") + .encodedAuthority("localhost:$listeningPort") + .query(path) + .build() + .toString() + } + + fun addResponse( + path: String, + statusCode: IStatus, + locationHeader: String? = null, + content: String = "" + ) { + val response = newFixedLengthResponse(statusCode, "text/plain", content) + locationHeader?.let { response.addHeader("Location", it) } + responses[path] = response + } + + /** + * Create a [ConditionVariable] that will open when a request to [path] is received. + */ + fun addExpectRequestCv(path: String): ConditionVariable { + return ConditionVariable().apply { waitForRequestCv[path] = this } + } + + override fun serve(session: IHTTPSession): Response { + waitForRequestCv[session.queryParameterString]?.open() + return responses[session.queryParameterString] + // Default response is a 404 + ?: super.serve(session) + } + } +} \ No newline at end of file From 607fa9efea430b118f00fd867abdda660ee15ff3 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 13 Feb 2020 18:43:41 +0800 Subject: [PATCH 1041/1415] [SP18] Poll network stats in OffloadController to support data warning The OEM implemented tether offload does not support data warning since the HAL only tells the hardware about data limit but not warning. However, to add such interface in HAL needs OEM to comply and implement in hardware. Thus, as a short-term solution, polls network statistics from HAL and notify upper layer when it reaches the alert quota set by NetworkStatsService. Note that when CPU is sleeping, the data warning of tethering offload will not work since the polling is also suspended. Test: manual Test: atest OffloadControllerTest Bug: 149467454 Change-Id: I2467b64779b74cd5fec73b42fb303584f52cb1cb --- .../tethering/OffloadController.java | 74 +++++++++++++++++++ .../tethering/OffloadHardwareInterface.java | 1 - 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java index c007c174fe..445a09d761 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadController.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java @@ -23,6 +23,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStats.UID_TETHERING; +import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; import android.annotation.NonNull; @@ -76,6 +77,7 @@ public class OffloadController { private static final boolean DBG = false; private static final String ANYIP = "0.0.0.0"; private static final ForwardedStats EMPTY_STATS = new ForwardedStats(); + private static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; @VisibleForTesting enum StatsType { @@ -115,6 +117,16 @@ public class OffloadController { // includes upstream interfaces that have a quota set. private HashMap mInterfaceQuotas = new HashMap<>(); + // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert + // quota is interface independent and global for tether offload. Note that this is only + // accessed on the handler thread and in the constructor. + private long mRemainingAlertQuota = QUOTA_UNLIMITED; + // Runnable that used to schedule the next stats poll. + private final Runnable mScheduledPollingTask = () -> { + updateStatsForCurrentUpstream(); + maybeSchedulePollingStats(); + }; + private int mNatUpdateCallbacksReceived; private int mNatUpdateNetlinkErrors; @@ -240,6 +252,7 @@ public class OffloadController { mLog.log("tethering offload started"); mNatUpdateCallbacksReceived = 0; mNatUpdateNetlinkErrors = 0; + maybeSchedulePollingStats(); } return isStarted; } @@ -255,6 +268,9 @@ public class OffloadController { mHwInterface.stopOffloadControl(); mControlInitialized = false; mConfigInitialized = false; + if (mHandler.hasCallbacks(mScheduledPollingTask)) { + mHandler.removeCallbacks(mScheduledPollingTask); + } if (wasStarted) mLog.log("tethering offload stopped"); } @@ -345,6 +361,11 @@ public class OffloadController { @Override public void onSetAlert(long quotaBytes) { // TODO: Ask offload HAL to notify alert without stopping traffic. + // Post it to handler thread since it access remaining quota bytes. + mHandler.post(() -> { + updateAlertQuota(quotaBytes); + maybeSchedulePollingStats(); + }); } } @@ -366,15 +387,66 @@ public class OffloadController { // the stats for each interface, and does not observe partial writes where rxBytes is // updated and txBytes is not. ForwardedStats diff = mHwInterface.getForwardedStats(iface); + final long usedAlertQuota = diff.rxBytes + diff.txBytes; ForwardedStats base = mForwardedStats.get(iface); if (base != null) { diff.add(base); } + + // Update remaining alert quota if it is still positive. + if (mRemainingAlertQuota > 0 && usedAlertQuota > 0) { + // Trim to zero if overshoot. + final long newQuota = Math.max(mRemainingAlertQuota - usedAlertQuota, 0); + updateAlertQuota(newQuota); + } + mForwardedStats.put(iface, diff); // diff is a new object, just created by getForwardedStats(). Therefore, anyone reading from // mForwardedStats (i.e., any caller of getTetherStats) will see the new stats immediately. } + /** + * Update remaining alert quota, fire the {@link NetworkStatsProvider#notifyAlertReached()} + * callback when it reaches zero. This can be invoked either from service setting the alert, or + * {@code maybeUpdateStats} when updating stats. Note that this can be only called on + * handler thread. + * + * @param newQuota non-negative value to indicate the new quota, or + * {@link NetworkStatsProvider#QUOTA_UNLIMITED} to indicate there is no + * quota. + */ + private void updateAlertQuota(long newQuota) { + if (newQuota < QUOTA_UNLIMITED) { + throw new IllegalArgumentException("invalid quota value " + newQuota); + } + if (mRemainingAlertQuota == newQuota) return; + + mRemainingAlertQuota = newQuota; + if (mRemainingAlertQuota == 0) { + mLog.i("notifyAlertReached"); + if (mStatsProvider != null) mStatsProvider.notifyAlertReached(); + } + } + + /** + * Schedule polling if needed, this will be stopped if offload has been + * stopped or remaining quota reaches zero or upstream is empty. + * Note that this can be only called on handler thread. + */ + private void maybeSchedulePollingStats() { + if (!isPollingStatsNeeded()) return; + + if (mHandler.hasCallbacks(mScheduledPollingTask)) { + mHandler.removeCallbacks(mScheduledPollingTask); + } + mHandler.postDelayed(mScheduledPollingTask, DEFAULT_PERFORM_POLL_INTERVAL_MS); + } + + private boolean isPollingStatsNeeded() { + return started() && mRemainingAlertQuota > 0 + && !TextUtils.isEmpty(currentUpstreamInterface()); + } + private boolean maybeUpdateDataLimit(String iface) { // setDataLimit may only be called while offload is occurring on this upstream. if (!started() || !TextUtils.equals(iface, currentUpstreamInterface())) { @@ -414,6 +486,8 @@ public class OffloadController { final String iface = currentUpstreamInterface(); if (!TextUtils.isEmpty(iface)) mForwardedStats.putIfAbsent(iface, EMPTY_STATS); + maybeSchedulePollingStats(); + // TODO: examine return code and decide what to do if programming // upstream parameters fails (probably just wait for a subsequent // onOffloadEvent() callback to tell us offload is available again and diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index 55344fc75d..a29eef2531 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -307,7 +307,6 @@ public class OffloadHardwareInterface { return stats; } - mLog.log(logmsg + YIELDS + stats); return stats; } From 360c88f23835637ef8a779244599ec74d307329a Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 23 Apr 2020 14:03:39 +0800 Subject: [PATCH 1042/1415] [SP18.1] add dependency object to OffloadController In order to mock constant in unit test, a dependency object is introduced with minimum code change to achieve this. Test: atest TetheringTests Bug: 149467454 Change-Id: I38628daddcb7be7c74846e78d36dc88f065b97d9 --- .../tethering/OffloadController.java | 17 +++++++++++++++-- .../networkstack/tethering/Tethering.java | 2 +- .../tethering/OffloadControllerTest.java | 8 +++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java index 445a09d761..1817f35f1d 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadController.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java @@ -130,8 +130,20 @@ public class OffloadController { private int mNatUpdateCallbacksReceived; private int mNatUpdateNetlinkErrors; + @NonNull + private final Dependencies mDeps; + + // TODO: Put more parameters in constructor into dependency object. + static class Dependencies { + int getPerformPollInterval() { + // TODO: Consider make this configurable. + return DEFAULT_PERFORM_POLL_INTERVAL_MS; + } + } + public OffloadController(Handler h, OffloadHardwareInterface hwi, - ContentResolver contentResolver, NetworkStatsManager nsm, SharedLog log) { + ContentResolver contentResolver, NetworkStatsManager nsm, SharedLog log, + @NonNull Dependencies deps) { mHandler = h; mHwInterface = hwi; mContentResolver = contentResolver; @@ -147,6 +159,7 @@ public class OffloadController { provider = null; } mStatsProvider = provider; + mDeps = deps; } /** Start hardware offload. */ @@ -439,7 +452,7 @@ public class OffloadController { if (mHandler.hasCallbacks(mScheduledPollingTask)) { mHandler.removeCallbacks(mScheduledPollingTask); } - mHandler.postDelayed(mScheduledPollingTask, DEFAULT_PERFORM_POLL_INTERVAL_MS); + mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval()); } private boolean isPollingStatsNeeded() { diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 44eacb410d..00b94a8bbf 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -273,7 +273,7 @@ public class Tethering { mHandler = mTetherMasterSM.getHandler(); mOffloadController = new OffloadController(mHandler, mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(), - statsManager, mLog); + statsManager, mLog, new OffloadController.Dependencies()); mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new LinkedHashSet<>(); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index 65797200fa..088a663190 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -116,6 +116,12 @@ public class OffloadControllerTest { private final ArgumentCaptor mControlCallbackCaptor = ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class); private MockContentResolver mContentResolver; + private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() { + @Override + int getPerformPollInterval() { + return 0; + } + }; @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -150,7 +156,7 @@ public class OffloadControllerTest { private OffloadController makeOffloadController() throws Exception { OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()), - mHardware, mContentResolver, mStatsManager, new SharedLog("test")); + mHardware, mContentResolver, mStatsManager, new SharedLog("test"), mDeps); final ArgumentCaptor tetherStatsProviderCaptor = ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); From cae5079d9d070cea3649c9f3e8e29ee30765948d Mon Sep 17 00:00:00 2001 From: Dominic Lemire Date: Wed, 15 Apr 2020 19:20:48 -0700 Subject: [PATCH 1043/1415] Fix error message in RestrictBackgroundNetworkTest Fixed the error message when the expected number of broadcasts is exceeded. Bug: 147139427 Change-Id: I7e69dca81abdb29a9eb7d110266edbe483e17a01 --- .../hostside/AbstractRestrictBackgroundNetworkTestCase.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index c8fe624e5e..638dabd979 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -30,6 +30,7 @@ import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupp import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -188,7 +189,9 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { do { attempts++; count = getNumberBroadcastsReceived(receiverName, ACTION_RESTRICT_BACKGROUND_CHANGED); - if (count >= expectedCount) { + assertFalse("Expected count " + expectedCount + " but actual is " + count, + count > expectedCount); + if (count == expectedCount) { break; } Log.d(TAG, "Expecting count " + expectedCount + " but actual is " + count + " after " From 70285ea6d98dd7f7029f6cb5c68d6a40533dec56 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 21 Jun 2019 14:02:53 -0700 Subject: [PATCH 1044/1415] Add a test to check getUidStats binder call Check the apps cannot get the per uid stats of another uid by directly calling the getUidStats binder interface call provided by networkStatsService. Bug: 129151407 Test: NetworkStatsBinderTest Change-Id: Iabca53a8b37b259cf7e232d603676dbc9887084c --- .../net/cts/NetworkStatsBinderTest.java | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java 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 0000000000..1f3162fdd1 --- /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> 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 predicate) { + PackageManager pm = InstrumentationRegistry.getContext().getPackageManager(); + List 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 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; + } + } + } + } +} From 33d861e6a77cad3c5f75edfe46b08020e82199bb Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 17 Apr 2020 10:02:43 +0800 Subject: [PATCH 1045/1415] Refactor the EntitlementManager 1. Change ArraySet usage to BitSet 2. Change mCellularUpstreamPermitted to mLastCellularUpstreamPermitted. Before this change: a member variable(mCellularUpstreamPermitted) is used to check whether cellular upstream is permitted, the code must ensure to update this variable once entitlement result is changed or the entitlement check is triggered but does not have a result yet. In this change: Instead of storing the information about whether cellular is permitted in a member variable. The information is recalculated every time when user call isCellularUpstreamPermitted(). Now isCellularUpstreamPermitted() is always be used to check whether cellular upstream is permitted no matter inside or outside EntitlementManager. This make the code be easier to maintain that we do not need to care when mCellularUpstreamPermitted need to be updated because the information would be recalculated every time. And the recalculation is lock free because this is only used inside tethering while running in the same thread. Bug: 141256482 Test: atest TetheringTests Change-Id: Ic83f42ff4eec38adf039d55d80fcb9b0f16373cc --- .../tethering/EntitlementManager.java | 113 +++++++++--------- 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java index 049a9f68bb..d9785415c8 100644 --- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java +++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java @@ -45,13 +45,13 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; import android.telephony.CarrierConfigManager; -import android.util.ArraySet; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; import java.io.PrintWriter; +import java.util.BitSet; /** * Re-check tethering provisioning for enabled downstream tether types. @@ -74,11 +74,11 @@ public class EntitlementManager { private final ComponentName mSilentProvisioningService; private static final int MS_PER_HOUR = 60 * 60 * 1000; - // The ArraySet contains enabled downstream types, ex: + // The BitSet is the bit map of each enabled downstream types, ex: // {@link TetheringManager.TETHERING_WIFI} // {@link TetheringManager.TETHERING_USB} // {@link TetheringManager.TETHERING_BLUETOOTH} - private final ArraySet mCurrentTethers; + private final BitSet mCurrentDownstreams; private final Context mContext; private final int mPermissionChangeMessageCode; private final SharedLog mLog; @@ -87,9 +87,9 @@ public class EntitlementManager { private final StateMachine mTetherMasterSM; // Key: TetheringManager.TETHERING_*(downstream). // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). - private final SparseIntArray mCellularPermitted; + private final SparseIntArray mCurrentEntitlementResults; private PendingIntent mProvisioningRecheckAlarm; - private boolean mCellularUpstreamPermitted = true; + private boolean mLastCellularUpstreamPermitted = true; private boolean mUsingCellularAsUpstream = false; private boolean mNeedReRunProvisioningUi = false; private OnUiEntitlementFailedListener mListener; @@ -97,11 +97,10 @@ public class EntitlementManager { public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log, int permissionChangeMessageCode) { - mContext = ctx; mLog = log.forSubComponent(TAG); - mCurrentTethers = new ArraySet(); - mCellularPermitted = new SparseIntArray(); + mCurrentDownstreams = new BitSet(); + mCurrentEntitlementResults = new SparseIntArray(); mEntitlementCacheValue = new SparseIntArray(); mTetherMasterSM = tetherMasterSM; mPermissionChangeMessageCode = permissionChangeMessageCode; @@ -144,13 +143,19 @@ public class EntitlementManager { * Check if cellular upstream is permitted. */ public boolean isCellularUpstreamPermitted() { - // If provisioning is required and EntitlementManager don't know any downstream, - // cellular upstream should not be allowed. final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); - if (mCurrentTethers.size() == 0 && isTetherProvisioningRequired(config)) { - return false; - } - return mCellularUpstreamPermitted; + + return isCellularUpstreamPermitted(config); + } + + private boolean isCellularUpstreamPermitted(final TetheringConfiguration config) { + if (!isTetherProvisioningRequired(config)) return true; + + // If provisioning is required and EntitlementManager doesn't know any downstreams, + // cellular upstream should not be allowed. + if (mCurrentDownstreams.isEmpty()) return false; + + return mCurrentEntitlementResults.indexOfValue(TETHER_ERROR_NO_ERROR) > -1; } /** @@ -164,29 +169,22 @@ public class EntitlementManager { public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) { if (!isValidDownstreamType(downstreamType)) return; - if (!mCurrentTethers.contains(downstreamType)) mCurrentTethers.add(downstreamType); + mCurrentDownstreams.set(downstreamType, true); final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); - if (isTetherProvisioningRequired(config)) { - // If provisioning is required and the result is not available yet, - // cellular upstream should not be allowed. - if (mCellularPermitted.size() == 0) { - mCellularUpstreamPermitted = false; - } - // If upstream is not cellular, provisioning app would not be launched - // till upstream change to cellular. - if (mUsingCellularAsUpstream) { - if (showProvisioningUi) { - runUiTetherProvisioning(downstreamType, config.activeDataSubId); - } else { - runSilentTetherProvisioning(downstreamType, config.activeDataSubId); - } - mNeedReRunProvisioningUi = false; + if (!isTetherProvisioningRequired(config)) return; + + // If upstream is not cellular, provisioning app would not be launched + // till upstream change to cellular. + if (mUsingCellularAsUpstream) { + if (showProvisioningUi) { + runUiTetherProvisioning(downstreamType, config.activeDataSubId); } else { - mNeedReRunProvisioningUi |= showProvisioningUi; + runSilentTetherProvisioning(downstreamType, config.activeDataSubId); } + mNeedReRunProvisioningUi = false; } else { - mCellularUpstreamPermitted = true; + mNeedReRunProvisioningUi |= showProvisioningUi; } } @@ -195,14 +193,14 @@ public class EntitlementManager { * * @param type tethering type from TetheringManager.TETHERING_{@code *} */ - public void stopProvisioningIfNeeded(int type) { - if (!isValidDownstreamType(type)) return; + public void stopProvisioningIfNeeded(int downstreamType) { + if (!isValidDownstreamType(downstreamType)) return; - mCurrentTethers.remove(type); + mCurrentDownstreams.set(downstreamType, false); // There are lurking bugs where the notion of "provisioning required" or // "tethering supported" may change without without tethering being notified properly. // Remove the mapping all the time no matter provisioning is required or not. - removeDownstreamMapping(type); + removeDownstreamMapping(downstreamType); } /** @@ -213,7 +211,7 @@ public class EntitlementManager { public void notifyUpstream(boolean isCellular) { if (DBG) { mLog.i("notifyUpstream: " + isCellular - + ", mCellularUpstreamPermitted: " + mCellularUpstreamPermitted + + ", mLastCellularUpstreamPermitted: " + mLastCellularUpstreamPermitted + ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi); } mUsingCellularAsUpstream = isCellular; @@ -231,7 +229,7 @@ public class EntitlementManager { } private void maybeRunProvisioning(final TetheringConfiguration config) { - if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired(config)) { + if (mCurrentDownstreams.isEmpty() || !isTetherProvisioningRequired(config)) { return; } @@ -239,8 +237,9 @@ public class EntitlementManager { // are allowed. Therefore even if the silent check here ends in a failure and the UI later // yields success, then the downstream that got a failure will re-evaluate as a result of // the change and get the new correct value. - for (Integer downstream : mCurrentTethers) { - if (mCellularPermitted.indexOfKey(downstream) < 0) { + for (int downstream = mCurrentDownstreams.nextSetBit(0); downstream >= 0; + downstream = mCurrentDownstreams.nextSetBit(downstream + 1)) { + if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) { if (mNeedReRunProvisioningUi) { mNeedReRunProvisioningUi = false; runUiTetherProvisioning(downstream, config.activeDataSubId); @@ -286,7 +285,7 @@ public class EntitlementManager { mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread"); } mEntitlementCacheValue.clear(); - mCellularPermitted.clear(); + mCurrentEntitlementResults.clear(); // TODO: refine provisioning check to isTetherProvisioningRequired() ?? if (!config.hasMobileHotspotProvisionApp() @@ -410,22 +409,21 @@ public class EntitlementManager { } private void evaluateCellularPermission(final TetheringConfiguration config) { - final boolean oldPermitted = mCellularUpstreamPermitted; - mCellularUpstreamPermitted = (!isTetherProvisioningRequired(config) - || mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1); + final boolean oldPermitted = mLastCellularUpstreamPermitted; + mLastCellularUpstreamPermitted = isCellularUpstreamPermitted(config); if (DBG) { mLog.i("Cellular permission change from " + oldPermitted - + " to " + mCellularUpstreamPermitted); + + " to " + mLastCellularUpstreamPermitted); } - if (mCellularUpstreamPermitted != oldPermitted) { - mLog.log("Cellular permission change: " + mCellularUpstreamPermitted); + if (mLastCellularUpstreamPermitted != oldPermitted) { + mLog.log("Cellular permission change: " + mLastCellularUpstreamPermitted); mTetherMasterSM.sendMessage(mPermissionChangeMessageCode); } // Only schedule periodic re-check when tether is provisioned // and the result is ok. - if (mCellularUpstreamPermitted && mCellularPermitted.size() > 0) { + if (mLastCellularUpstreamPermitted && mCurrentEntitlementResults.size() > 0) { scheduleProvisioningRechecks(config); } else { cancelTetherProvisioningRechecks(); @@ -441,10 +439,10 @@ public class EntitlementManager { */ protected void addDownstreamMapping(int type, int resultCode) { mLog.i("addDownstreamMapping: " + type + ", result: " + resultCode - + " ,TetherTypeRequested: " + mCurrentTethers.contains(type)); - if (!mCurrentTethers.contains(type)) return; + + " ,TetherTypeRequested: " + mCurrentDownstreams.get(type)); + if (!mCurrentDownstreams.get(type)) return; - mCellularPermitted.put(type, resultCode); + mCurrentEntitlementResults.put(type, resultCode); final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); evaluateCellularPermission(config); } @@ -455,7 +453,7 @@ public class EntitlementManager { */ protected void removeDownstreamMapping(int type) { mLog.i("removeDownstreamMapping: " + type); - mCellularPermitted.delete(type); + mCurrentEntitlementResults.delete(type); final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); evaluateCellularPermission(config); } @@ -488,14 +486,15 @@ public class EntitlementManager { * @param pw {@link PrintWriter} is used to print formatted */ public void dump(PrintWriter pw) { - pw.print("mCellularUpstreamPermitted: "); - pw.println(mCellularUpstreamPermitted); - for (Integer type : mCurrentTethers) { + pw.print("isCellularUpstreamPermitted: "); + pw.println(isCellularUpstreamPermitted()); + for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0; + type = mCurrentDownstreams.nextSetBit(type + 1)) { pw.print("Type: "); pw.print(typeString(type)); - if (mCellularPermitted.indexOfKey(type) > -1) { + if (mCurrentEntitlementResults.indexOfKey(type) > -1) { pw.print(", Value: "); - pw.println(errorString(mCellularPermitted.get(type))); + pw.println(errorString(mCurrentEntitlementResults.get(type))); } else { pw.println(", Value: empty"); } From 33a88fbf5f5260700c835656f19b5fd2806b6f66 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 28 Apr 2020 08:25:34 +0000 Subject: [PATCH 1046/1415] Force reconnect in connectToWifi There is no guarantee that Wifi will automatically reconnect after enabling, especially in cases where no internet access was detected on the access point the last time it was connected. Use WifiManager#reconnect to force wifi to reconnect to the access point. The API is deprecated for general use, but system apps are documented as exempted from the deprecation. Bug: 152280218 Test: atest --rerun-until-failure 200 CtsNetTestCases:CaptivePortalTest Merged-In: Ia7d83337ee0ffad9414031711cf7e937b14f968d Change-Id: Ia7d83337ee0ffad9414031711cf7e937b14f968d --- tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java | 3 +++ 1 file changed, 3 insertions(+) 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 6214f89e98..824146fedf 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 @@ public final class CtsNetUtils { 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); From a8f2e3ead52c6ac577cc6680f853a93ffaa5ffdc Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Thu, 30 Apr 2020 17:02:07 +0100 Subject: [PATCH 1047/1415] Fix tethering module lib stub default It was using the systemapi stub defaults, but should be using the module_lib default. Bug: 144149403 Test: m Change-Id: Iaab154d9d71900284d92d518a086fc1227c00d5c Merged-In: Iaab154d9d71900284d92d518a086fc1227c00d5c (cherry picked from commit dc8e0fc1a11d53e54fa2d318872d1ca85e006960) --- Tethering/common/TetheringLib/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 31c40d2a33..d0c4349c9e 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -133,5 +133,5 @@ java_library { java_library { name: "framework-tethering-stubs-module_libs_api", srcs: [":framework-tethering-stubs-srcs-module_libs_api"], - defaults: ["framework-module-stubs-lib-defaults-systemapi"], + defaults: ["framework-module-stubs-lib-defaults-module_libs_api"], } From bb5231decc5fdeafaa79df1144baef3787fd8854 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Thu, 30 Apr 2020 14:26:22 +0100 Subject: [PATCH 1048/1415] Rename module dist files This makes the filenames of the disted artifacts (api txts and stubs) match the module name of the modules they're from. This matches the naming scheme used by java_sdk_library, which should make the future transition to this build rule easier. Bug: 149293194 Test: lunch sdk_phone_armv7 && m sdk dist && find out/dist/apistubs Change-Id: I076f30931bf2524d57703873cd7de25b3f23b457 Merged-In: I076f30931bf2524d57703873cd7de25b3f23b457 (cherry picked from commit d7f1fabc94776b2b8e043a94618af4a17d33ac6e) --- Tethering/common/TetheringLib/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index d0c4349c9e..3704a04225 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -66,6 +66,7 @@ java_library { stubs_defaults { name: "framework-tethering-stubs-defaults", srcs: [":framework-tethering-srcs"], + dist: { dest: "framework-tethering.txt" }, } filegroup { @@ -122,16 +123,19 @@ java_library { name: "framework-tethering-stubs-publicapi", srcs: [":framework-tethering-stubs-srcs-publicapi"], defaults: ["framework-module-stubs-lib-defaults-publicapi"], + dist: { dest: "framework-tethering.jar" }, } java_library { name: "framework-tethering-stubs-systemapi", srcs: [":framework-tethering-stubs-srcs-systemapi"], defaults: ["framework-module-stubs-lib-defaults-systemapi"], + dist: { dest: "framework-tethering.jar" }, } java_library { name: "framework-tethering-stubs-module_libs_api", srcs: [":framework-tethering-stubs-srcs-module_libs_api"], defaults: ["framework-module-stubs-lib-defaults-module_libs_api"], + dist: { dest: "framework-tethering.jar" }, } From 3b1e3d04f6cd47c1cea152dc78e6ad0358174bbd Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 30 Apr 2020 15:32:29 -0700 Subject: [PATCH 1049/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I3b69996ab87b3c9ddeeb5c6166a1256b77f30c12 --- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 12 ++++-------- Tethering/res/values-mcc310-mnc004-ta/strings.xml | 12 ++++-------- .../res/values-mcc310-mnc004-zh-rTW/strings.xml | 6 +++--- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 12 ++++-------- Tethering/res/values-mcc311-mnc480-ta/strings.xml | 12 ++++-------- .../res/values-mcc311-mnc480-zh-rTW/strings.xml | 6 +++--- Tethering/res/values-zh-rTW/strings.xml | 6 +++--- 7 files changed, 25 insertions(+), 41 deletions(-) diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index 2a7330098f..d074f15699 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index ea04821e33..f4b15aab19 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml index 05b90692ea..528a1e5292 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -16,9 +16,9 @@ - "無法透過數據連線連上網際網路" + "無法透過網路共用連上網際網路" "裝置無法連線" - "關閉數據連線" - "無線基地台或數據連線已開啟" + "關閉網路共用" + "無線基地台或網路共用已開啟" "使用漫遊服務可能須支付額外費用" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 617c50dd0c..1503244f50 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 0e437593ee..2ea2467e58 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml index ea01b943fb..cd653df1da 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -16,9 +16,9 @@ - "無法透過數據連線連上網際網路" + "無法透過網路共用連上網際網路" "裝置無法連線" - "關閉數據連線" - "無線基地台或數據連線已開啟" + "關閉網路共用" + "無線基地台或網路共用已開啟" "使用漫遊服務可能須支付額外費用" diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9d738a76eb..50a50bf7a9 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -16,11 +16,11 @@ - "數據連線或無線基地台已啟用" + "網路共用或無線基地台已啟用" "輕觸即可進行設定。" - "數據連線已停用" + "網路共用已停用" "詳情請洽你的管理員" - "無線基地台與數據連線狀態" + "無線基地台與網路共用狀態" From e54f45286a83b104106494354c9975eb56ac67e8 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 30 Apr 2020 17:16:36 -0700 Subject: [PATCH 1050/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: Ifcec6b94f4da00c387216f50e5e9530cdb8f598d --- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 12 ++++-------- Tethering/res/values-mcc310-mnc004-ta/strings.xml | 12 ++++-------- .../res/values-mcc310-mnc004-zh-rTW/strings.xml | 6 +++--- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 12 ++++-------- Tethering/res/values-mcc311-mnc480-ta/strings.xml | 12 ++++-------- .../res/values-mcc311-mnc480-zh-rTW/strings.xml | 6 +++--- Tethering/res/values-zh-rTW/strings.xml | 6 +++--- 7 files changed, 25 insertions(+), 41 deletions(-) diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index 2a7330098f..d074f15699 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml index ea04821e33..f4b15aab19 100644 --- a/Tethering/res/values-mcc310-mnc004-ta/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml index 05b90692ea..528a1e5292 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -16,9 +16,9 @@ - "無法透過數據連線連上網際網路" + "無法透過網路共用連上網際網路" "裝置無法連線" - "關閉數據連線" - "無線基地台或數據連線已開啟" + "關閉網路共用" + "無線基地台或網路共用已開啟" "使用漫遊服務可能須支付額外費用" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 617c50dd0c..1503244f50 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml index 0e437593ee..2ea2467e58 100644 --- a/Tethering/res/values-mcc311-mnc480-ta/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -16,13 +16,9 @@ - - - - - - - - + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml index ea01b943fb..cd653df1da 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -16,9 +16,9 @@ - "無法透過數據連線連上網際網路" + "無法透過網路共用連上網際網路" "裝置無法連線" - "關閉數據連線" - "無線基地台或數據連線已開啟" + "關閉網路共用" + "無線基地台或網路共用已開啟" "使用漫遊服務可能須支付額外費用" diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9d738a76eb..50a50bf7a9 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -16,11 +16,11 @@ - "數據連線或無線基地台已啟用" + "網路共用或無線基地台已啟用" "輕觸即可進行設定。" - "數據連線已停用" + "網路共用已停用" "詳情請洽你的管理員" - "無線基地台與數據連線狀態" + "無線基地台與網路共用狀態" From 653d7ebb447e00753779634090381ba1fde5077e Mon Sep 17 00:00:00 2001 From: evitayan Date: Tue, 7 Apr 2020 15:16:08 -0700 Subject: [PATCH 1051/1415] Initial CL for testing IkeSession creation This commit: -Extend TunUtils for processing IKE packets -Add IkeSessionBaseTest containing common functionality for all IkeSession tests -Add end-to-end test for IKEv2 PSK verifying creating IKE SA, creating child SAs and closing sessions -Add basic tests for error scenarios Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ie6c18591ffcc883abbf0484d9a59dfda61b33257 --- tests/cts/net/ipsec/Android.bp | 1 + .../ipsec/ike/cts/IkeSessionParamsTest.java | 19 +- .../ike/cts/IkeSessionParamsTestBase.java | 85 ---- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 258 ++++++++++++ .../net/ipsec/ike/cts/IkeSessionTestBase.java | 374 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 6 +- .../net/ipsec/ike/cts/IkeTunUtils.java | 243 ++++++++++++ .../android/net/ipsec/ike/cts/TunUtils.java | 20 +- 8 files changed, 904 insertions(+), 102 deletions(-) delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp index f1f120b32b..16bdb0548a 100644 --- a/tests/cts/net/ipsec/Android.bp +++ b/tests/cts/net/ipsec/Android.bp @@ -33,6 +33,7 @@ android_test { "androidx.test.ext.junit", "compatibility-device-util-axt", "ctstestrunner-axt", + "net-tests-utils", ], platform_apis: true, diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java index 6fc7cb3634..c767b78120 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java @@ -46,6 +46,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.net.ipsec.ike.testutils.CertUtils; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -63,7 +64,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) -public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { +public final class IkeSessionParamsTest extends IkeSessionTestBase { private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(20L); private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(10L); private static final int DPD_DELAY_SECONDS = (int) TimeUnit.MINUTES.toSeconds(10L); @@ -105,6 +106,9 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { @Before public void setUp() throws Exception { + // This address is never used except for setting up the test network + setUpTestNetwork(IPV4_ADDRESS_LOCAL); + mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); mClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); mClientIntermediateCaCertOne = @@ -114,6 +118,11 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { mClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); } + @After + public void tearDown() throws Exception { + tearDownTestNetwork(); + } + private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() { return new EapSessionConfig.Builder() .setEapIdentity(EAP_IDENTITY) @@ -131,7 +140,7 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { */ private IkeSessionParams.Builder createIkeParamsBuilderMinimum() { return new IkeSessionParams.Builder(sContext) - .setNetwork(sTunNetwork) + .setNetwork(mTunNetwork) .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) .addSaProposal(SA_PROPOSAL) .setLocalIdentification(LOCAL_ID) @@ -145,7 +154,7 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { * @see #createIkeParamsBuilderMinimum */ private void verifyIkeParamsMinimum(IkeSessionParams sessionParams) { - assertEquals(sTunNetwork, sessionParams.getNetwork()); + assertEquals(mTunNetwork, sessionParams.getNetwork()); assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); @@ -268,7 +277,7 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { */ private IkeSessionParams.Builder createIkeParamsBuilderMinimumWithoutAuth() { return new IkeSessionParams.Builder(sContext) - .setNetwork(sTunNetwork) + .setNetwork(mTunNetwork) .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) .addSaProposal(SA_PROPOSAL) .setLocalIdentification(LOCAL_ID) @@ -282,7 +291,7 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { * @see #createIkeParamsBuilderMinimumWithoutAuth */ private void verifyIkeParamsMinimumWithoutAuth(IkeSessionParams sessionParams) { - assertEquals(sTunNetwork, sessionParams.getNetwork()); + assertEquals(mTunNetwork, sessionParams.getNetwork()); assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java deleted file mode 100644 index c3e3ba353c..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.LinkAddress; -import android.net.Network; -import android.net.TestNetworkInterface; -import android.net.TestNetworkManager; -import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; -import android.os.Binder; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.platform.test.annotations.AppModeFull; - -import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") -abstract class IkeSessionParamsTestBase extends IkeTestBase { - // Static state to reduce setup/teardown - static ConnectivityManager sCM; - static TestNetworkManager sTNM; - static ParcelFileDescriptor sTunFd; - static TestNetworkCallback sTunNetworkCallback; - static Network sTunNetwork; - - static Context sContext = InstrumentationRegistry.getContext(); - static IBinder sBinder = new Binder(); - - // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass - // methods. - @BeforeClass - public static void setUpTestNetworkBeforeClass() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(); - sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); - sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); - - TestNetworkInterface testIface = - sTNM.createTunInterface( - new LinkAddress[] {new LinkAddress(IPV4_ADDRESS_LOCAL, IP4_PREFIX_LEN)}); - - sTunFd = testIface.getFileDescriptor(); - sTunNetworkCallback = - TestNetworkUtils.setupAndGetTestNetwork( - sCM, sTNM, testIface.getInterfaceName(), sBinder); - sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); - } - - // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass - // methods. - @AfterClass - public static void tearDownTestNetworkAfterClass() throws Exception { - sCM.unregisterNetworkCallback(sTunNetworkCallback); - - sTNM.teardownTestNetwork(sTunNetwork); - sTunFd.close(); - - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .dropShellPermissionIdentity(); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java new file mode 100644 index 0000000000..ed67dd1bd7 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -0,0 +1,258 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static com.android.internal.util.HexDump.hexStringToByteArray; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.net.ipsec.ike.exceptions.IkeException; +import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.platform.test.annotations.AppModeFull; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.Arrays; + +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +public class IkeSessionPskTest extends IkeSessionTestBase { + // Test vectors for success workflow + private static final String SUCCESS_IKE_INIT_RESP = + "46B8ECA1E0D72A18B45427679F9245D421202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0080030000080300000203000008" + + "0200000200000008040000022800008800020000A7AA3435D088EC1A2B7C2A47" + + "1FA1B85F1066C9B2006E7C353FB5B5FDBC2A88347ED2C6F5B7A265D03AE34039" + + "6AAC0145CFCC93F8BDB219DDFF22A603B8856A5DC59B6FAB7F17C5660CF38670" + + "8794FC72F273ADEB7A4F316519794AED6F8AB61F95DFB360FAF18C6C8CABE471" + + "6E18FE215348C2E582171A57FC41146B16C4AFE429000024A634B61C0E5C90C6" + + "8D8818B0955B125A9B1DF47BBD18775710792E651083105C2900001C00004004" + + "406FA3C5685A16B9B72C7F2EEE9993462C619ABE2900001C00004005AF905A87" + + "0A32222AA284A7070585601208A282F0290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + private static final String SUCCESS_IKE_AUTH_RESP = + "46B8ECA1E0D72A18B45427679F9245D42E20232000000001000000EC240000D0" + + "0D06D37198F3F0962DE8170D66F1A9008267F98CDD956D984BDCED2FC7FAF84A" + + "A6664EF25049B46B93C9ED420488E0C172AA6635BF4011C49792EF2B88FE7190" + + "E8859FEEF51724FD20C46E7B9A9C3DC4708EF7005707A18AB747C903ABCEAC5C" + + "6ECF5A5FC13633DCE3844A920ED10EF202F115DBFBB5D6D2D7AB1F34EB08DE7C" + + "A54DCE0A3A582753345CA2D05A0EFDB9DC61E81B2483B7D13EEE0A815D37252C" + + "23D2F29E9C30658227D2BB0C9E1A481EAA80BC6BE9006BEDC13E925A755A0290" + + "AEC4164D29997F52ED7DCC2E"; + private static final String SUCCESS_CREATE_CHILD_RESP = + "46B8ECA1E0D72A18B45427679F9245D42E20242000000002000000CC210000B0" + + "484565D4AF6546274674A8DE339E9C9584EE2326AB9260F41C4D0B6C5B02D1D" + + "2E8394E3CDE3094895F2ACCABCDCA8E82960E5196E9622BD13745FC8D6A2BED" + + "E561FF5D9975421BC463C959A3CBA3478256B6D278159D99B512DDF56AC1658" + + "63C65A986F395FE8B1476124B91F83FD7865304EB95B22CA4DD9601DA7A2533" + + "ABF4B36EB1B8CD09522F6A600032316C74E562E6756D9D49D945854E2ABDC4C" + + "3AF36305353D60D40B58BE44ABF82"; + private static final String SUCCESS_DELETE_CHILD_RESP = + "46B8ECA1E0D72A18B45427679F9245D42E202520000000030000004C2A000030" + + "0C5CEB882DBCA65CE32F4C53909335F1365C91C555316C5E9D9FB553F7AA916" + + "EF3A1D93460B7FABAF0B4B854"; + private static final String SUCCESS_DELETE_IKE_RESP = + "46B8ECA1E0D72A18B45427679F9245D42E202520000000040000004C00000030" + + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" + + "6743A7CEB2BE34AC00095A5B8"; + + private static final long IKE_INIT_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); + + private static final TunnelModeChildSessionParams CHILD_PARAMS = + new TunnelModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .build(); + + private IkeSessionParams createIkeSessionParams(InetAddress mRemoteAddress) { + return new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(mRemoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) + .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) + .setAuthPsk(IKE_PSK) + .build(); + } + + private IkeSession openIkeSession(IkeSessionParams ikeParams) { + return new IkeSession( + sContext, + ikeParams, + CHILD_PARAMS, + mUserCbExecutor, + mIkeSessionCallback, + mFirstChildSessionCallback); + } + + @Test + public void testIkeSessionSetupAndManageChildSas() throws Exception { + // Open IKE Session + IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + int expectedMsgId = 0; + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + false /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); + + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + + // Verify opening IKE Session + IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); + assertNotNull(ikeConfig); + assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); + assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); + assertTrue(ikeConfig.getPcscfServers().isEmpty()); + assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); + + IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); + assertNotNull(ikeConnectInfo); + assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); + assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); + assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); + + // Verify opening first Child Session + ChildSessionConfiguration firstChildConfig = mFirstChildSessionCallback.awaitChildConfig(); + assertNotNull(firstChildConfig); + assertEquals( + Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); + assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); + assertEquals( + Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR), + firstChildConfig.getInternalAddresses()); + assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); + assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); + assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + + // Open additional Child Session + TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); + ikeSession.openChildSession(CHILD_PARAMS, additionalChildCb); + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_CREATE_CHILD_RESP)); + + // Verify opening additional Child Session + ChildSessionConfiguration additionalChildConfig = additionalChildCb.awaitChildConfig(); + assertNotNull(additionalChildConfig); + assertEquals( + Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); + assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); + assertTrue(additionalChildConfig.getInternalAddresses().isEmpty()); + assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); + assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); + assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + + // Close additional Child Session + ikeSession.closeChildSession(additionalChildCb); + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); + + additionalChildCb.awaitOnClosed(); + + // Close IKE Session + ikeSession.close(); + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); + + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + + // TODO: verify IpSecTransform pair is created and deleted + } + + @Test + public void testIkeSessionKill() throws Exception { + // Open IKE Session + IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + int expectedMsgId = 0; + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + false /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); + + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + + ikeSession.kill(); + + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } + + @Test + public void testIkeInitFail() throws Exception { + String ikeInitFailRespHex = + "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; + + // Open IKE Session + IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + int expectedMsgId = 0; + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + false /* expectedUseEncap */, + hexStringToByteArray(ikeInitFailRespHex)); + + IkeException exception = mIkeSessionCallback.awaitOnClosedException(); + assertNotNull(exception); + assertTrue(exception instanceof IkeProtocolException); + IkeProtocolException protocolException = (IkeProtocolException) exception; + assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, protocolException.getErrorType()); + assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); + } + + // TODO(b/148689509): Verify rekey process and handling IKE_AUTH failure +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java new file mode 100644 index 0000000000..deba8fd985 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -0,0 +1,374 @@ +/* + * 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 + * + * 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.ipsec.ike.cts; + +import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; + +import android.annotation.NonNull; +import android.app.AppOpsManager; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.InetAddresses; +import android.net.IpSecTransform; +import android.net.LinkAddress; +import android.net.Network; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.annotations.PolicyDirection; +import android.net.ipsec.ike.ChildSessionCallback; +import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.ipsec.ike.IkeSessionCallback; +import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; +import android.net.ipsec.ike.exceptions.IkeException; +import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.os.Binder; +import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.AppModeFull; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.compatibility.common.util.SystemUtil; +import com.android.testutils.ArrayTrackRecord; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Package private base class for testing IkeSessionParams and IKE exchanges. + * + *

    Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use + * the test network + */ +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +abstract class IkeSessionTestBase extends IkeTestBase { + // Package-wide common expected results that will be shared by all IKE/Child SA creation tests + static final String EXPECTED_REMOTE_APP_VERSION_EMPTY = ""; + static final byte[] EXPECTED_PROTOCOL_ERROR_DATA_NONE = new byte[0]; + static final InetAddress EXPECTED_INTERNAL_ADDR = + InetAddresses.parseNumericAddress("198.51.100.10"); + static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR = + new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN); + static final IkeTrafficSelector EXPECTED_INBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); + + // Static state to reduce setup/teardown + static Context sContext = InstrumentationRegistry.getContext(); + static ConnectivityManager sCM = + (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + static TestNetworkManager sTNM; + + private static final int TIMEOUT_MS = 500; + + // Constants to be used for providing different IP addresses for each tests + private static final byte IP_ADDR_LAST_BYTE_MAX = (byte) 100; + private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_LOCAL = + InetAddresses.parseNumericAddress("192.0.2.1").getAddress(); + private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_REMOTE = + InetAddresses.parseNumericAddress("198.51.100.1").getAddress(); + private static final byte[] NEXT_AVAILABLE_IP4_ADDR_LOCAL = INITIAL_AVAILABLE_IP4_ADDR_LOCAL; + private static final byte[] NEXT_AVAILABLE_IP4_ADDR_REMOTE = INITIAL_AVAILABLE_IP4_ADDR_REMOTE; + + ParcelFileDescriptor mTunFd; + TestNetworkCallback mTunNetworkCallback; + Network mTunNetwork; + IkeTunUtils mTunUtils; + + InetAddress mLocalAddress; + InetAddress mRemoteAddress; + + Executor mUserCbExecutor; + TestIkeSessionCallback mIkeSessionCallback; + TestChildSessionCallback mFirstChildSessionCallback; + + // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass + // methods. + @BeforeClass + public static void setUpPermissionBeforeClass() throws Exception { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and + // a standard permission is insufficient. So we shell out the appop, to give us the + // right appop permissions. + setAppOp(OP_MANAGE_IPSEC_TUNNELS, true); + } + + // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass + // methods. + @AfterClass + public static void tearDownPermissionAfterClass() throws Exception { + setAppOp(OP_MANAGE_IPSEC_TUNNELS, false); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } + + @Before + public void setUp() throws Exception { + mLocalAddress = getNextAvailableIpv4AddressLocal(); + mRemoteAddress = getNextAvailableIpv4AddressRemote(); + setUpTestNetwork(mLocalAddress); + + mUserCbExecutor = Executors.newSingleThreadExecutor(); + mIkeSessionCallback = new TestIkeSessionCallback(); + mFirstChildSessionCallback = new TestChildSessionCallback(); + } + + @After + public void tearDown() throws Exception { + tearDownTestNetwork(); + + resetNextAvailableAddress(NEXT_AVAILABLE_IP4_ADDR_LOCAL, INITIAL_AVAILABLE_IP4_ADDR_LOCAL); + resetNextAvailableAddress( + NEXT_AVAILABLE_IP4_ADDR_REMOTE, INITIAL_AVAILABLE_IP4_ADDR_REMOTE); + } + + void setUpTestNetwork(InetAddress localAddr) throws Exception { + int prefixLen = localAddr instanceof Inet4Address ? IP4_PREFIX_LEN : IP4_PREFIX_LEN; + + TestNetworkInterface testIface = + sTNM.createTunInterface(new LinkAddress[] {new LinkAddress(localAddr, prefixLen)}); + + mTunFd = testIface.getFileDescriptor(); + mTunNetworkCallback = + TestNetworkUtils.setupAndGetTestNetwork( + sCM, sTNM, testIface.getInterfaceName(), new Binder()); + mTunNetwork = mTunNetworkCallback.getNetworkBlocking(); + mTunUtils = new IkeTunUtils(mTunFd); + } + + void tearDownTestNetwork() throws Exception { + sCM.unregisterNetworkCallback(mTunNetworkCallback); + + sTNM.teardownTestNetwork(mTunNetwork); + mTunFd.close(); + } + + private static void setAppOp(int appop, boolean allow) { + String opName = AppOpsManager.opToName(appop); + for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { + String cmd = + String.format( + "appops set %s %s %s", + pkg, // Package name + opName, // Appop + (allow ? "allow" : "deny")); // Action + Log.d("IKE", "CTS setAppOp cmd " + cmd); + + String result = SystemUtil.runShellCommand(cmd); + } + } + + Inet4Address getNextAvailableIpv4AddressLocal() throws Exception { + return (Inet4Address) + getNextAvailableAddress( + NEXT_AVAILABLE_IP4_ADDR_LOCAL, + INITIAL_AVAILABLE_IP4_ADDR_LOCAL, + false /* isIp6 */); + } + + Inet4Address getNextAvailableIpv4AddressRemote() throws Exception { + return (Inet4Address) + getNextAvailableAddress( + NEXT_AVAILABLE_IP4_ADDR_REMOTE, + INITIAL_AVAILABLE_IP4_ADDR_REMOTE, + false /* isIp6 */); + } + + InetAddress getNextAvailableAddress( + byte[] nextAddressBytes, byte[] initialAddressBytes, boolean isIp6) throws Exception { + int addressLen = isIp6 ? IP6_ADDRESS_LEN : IP4_ADDRESS_LEN; + + synchronized (nextAddressBytes) { + if (nextAddressBytes[addressLen - 1] == IP_ADDR_LAST_BYTE_MAX) { + resetNextAvailableAddress(nextAddressBytes, initialAddressBytes); + } + + InetAddress address = InetAddress.getByAddress(nextAddressBytes); + nextAddressBytes[addressLen - 1]++; + return address; + } + } + + private void resetNextAvailableAddress(byte[] nextAddressBytes, byte[] initialAddressBytes) { + synchronized (nextAddressBytes) { + System.arraycopy( + nextAddressBytes, 0, initialAddressBytes, 0, initialAddressBytes.length); + } + } + + static class TestIkeSessionCallback implements IkeSessionCallback { + private CompletableFuture mFutureIkeConfig = + new CompletableFuture<>(); + private CompletableFuture mFutureOnClosedCall = new CompletableFuture<>(); + private CompletableFuture mFutureOnClosedException = + new CompletableFuture<>(); + + private int mOnErrorExceptionsCount = 0; + private ArrayTrackRecord mOnErrorExceptionsTrackRecord = + new ArrayTrackRecord<>(); + + @Override + public void onOpened(@NonNull IkeSessionConfiguration sessionConfiguration) { + mFutureIkeConfig.complete(sessionConfiguration); + } + + @Override + public void onClosed() { + mFutureOnClosedCall.complete(true /* unused */); + } + + @Override + public void onClosedExceptionally(@NonNull IkeException exception) { + mFutureOnClosedException.complete(exception); + } + + @Override + public void onError(@NonNull IkeProtocolException exception) { + mOnErrorExceptionsTrackRecord.add(exception); + } + + public IkeSessionConfiguration awaitIkeConfig() throws Exception { + return mFutureIkeConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public IkeException awaitOnClosedException() throws Exception { + return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public IkeProtocolException awaitNextOnErrorException() { + return mOnErrorExceptionsTrackRecord.poll( + (long) TIMEOUT_MS, + mOnErrorExceptionsCount++, + (transform) -> { + return true; + }); + } + + public void awaitOnClosed() throws Exception { + mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + static class TestChildSessionCallback implements ChildSessionCallback { + private CompletableFuture mFutureChildConfig = + new CompletableFuture<>(); + private CompletableFuture mFutureOnClosedCall = new CompletableFuture<>(); + private CompletableFuture mFutureOnClosedException = + new CompletableFuture<>(); + + private int mCreatedIpSecTransformCount = 0; + private int mDeletedIpSecTransformCount = 0; + private ArrayTrackRecord mCreatedIpSecTransformsTrackRecord = + new ArrayTrackRecord<>(); + private ArrayTrackRecord mDeletedIpSecTransformsTrackRecord = + new ArrayTrackRecord<>(); + + @Override + public void onOpened(@NonNull ChildSessionConfiguration sessionConfiguration) { + mFutureChildConfig.complete(sessionConfiguration); + } + + @Override + public void onClosed() { + mFutureOnClosedCall.complete(true /* unused */); + } + + @Override + public void onClosedExceptionally(@NonNull IkeException exception) { + mFutureOnClosedException.complete(exception); + } + + @Override + public void onIpSecTransformCreated(@NonNull IpSecTransform ipSecTransform, int direction) { + mCreatedIpSecTransformsTrackRecord.add( + new IpSecTransformCallRecord(ipSecTransform, direction)); + } + + @Override + public void onIpSecTransformDeleted(@NonNull IpSecTransform ipSecTransform, int direction) { + mDeletedIpSecTransformsTrackRecord.add( + new IpSecTransformCallRecord(ipSecTransform, direction)); + } + + public ChildSessionConfiguration awaitChildConfig() throws Exception { + return mFutureChildConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public IkeException awaitOnClosedException() throws Exception { + return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public IpSecTransformCallRecord awaitNextCreatedIpSecTransform() { + return mCreatedIpSecTransformsTrackRecord.poll( + (long) TIMEOUT_MS, + mCreatedIpSecTransformCount++, + (transform) -> { + return true; + }); + } + + public IpSecTransformCallRecord awaitNextDeletedIpSecTransform() { + return mDeletedIpSecTransformsTrackRecord.poll( + (long) TIMEOUT_MS, + mDeletedIpSecTransformCount++, + (transform) -> { + return true; + }); + } + + public void awaitOnClosed() throws Exception { + mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + /** + * This class represents a created or deleted IpSecTransfrom that is provided by + * ChildSessionCallback + */ + static class IpSecTransformCallRecord { + public final IpSecTransform ipSecTransform; + public final int direction; + + IpSecTransformCallRecord(IpSecTransform ipSecTransform, @PolicyDirection int direction) { + this.ipSecTransform = ipSecTransform; + this.direction = direction; + } + } + + // TODO(b/148689509): Verify IKE Session setup using EAP and digital-signature-based auth + + // TODO(b/148689509): Verify hostname based creation +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index bc2bec665f..f07c710ba9 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -31,13 +31,15 @@ import java.util.Map; /** Shared parameters and util methods for testing different components of IKE */ abstract class IkeTestBase { - private static final int MIN_PORT = 0; - private static final int MAX_PORT = 65535; + static final int MIN_PORT = 0; + static final int MAX_PORT = 65535; private static final int INBOUND_TS_START_PORT = MIN_PORT; private static final int INBOUND_TS_END_PORT = 65520; private static final int OUTBOUND_TS_START_PORT = 16; private static final int OUTBOUND_TS_END_PORT = MAX_PORT; + static final int IP4_ADDRESS_LEN = 4; + static final int IP6_ADDRESS_LEN = 16; static final int IP4_PREFIX_LEN = 32; static final int IP6_PREFIX_LEN = 64; diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java new file mode 100644 index 0000000000..5a8258d57b --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -0,0 +1,243 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.ipsec.ike.cts.PacketUtils.BytePayload; +import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.Ip4Header; +import static android.net.ipsec.ike.cts.PacketUtils.Ip6Header; +import static android.net.ipsec.ike.cts.PacketUtils.IpHeader; +import static android.net.ipsec.ike.cts.PacketUtils.Payload; +import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader; +import static android.system.OsConstants.IPPROTO_UDP; + +import static org.junit.Assert.fail; + +import android.os.ParcelFileDescriptor; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.Arrays; + +public class IkeTunUtils extends TunUtils { + private static final int PORT_LEN = 2; + + private static final int NON_ESP_MARKER_LEN = 4; + private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN]; + + private static final int IKE_HEADER_LEN = 28; + private static final int IKE_INIT_SPI_OFFSET = 0; + private static final int IKE_IS_RESP_BYTE_OFFSET = 19; + private static final int IKE_MSG_ID_OFFSET = 20; + + public IkeTunUtils(ParcelFileDescriptor tunFd) { + super(tunFd); + } + + /** + * Await the expected IKE request and inject an IKE response. + * + * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER. + */ + public byte[] awaitReqAndInjectResp( + long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, byte[] respIkePkt) + throws Exception { + byte[] request = + awaitIkePacket( + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap); + + // Build response header by flipping address and port + InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); + InetAddress dstAddr = getAddress(request, true /* shouldGetSource */); + int srcPort = getPort(request, false /* shouldGetSource */); + int dstPort = getPort(request, true /* shouldGetSource */); + + byte[] response = + buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, expectedUseEncap, respIkePkt); + injectPacket(response); + return request; + } + + private byte[] awaitIkePacket( + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedResp, + boolean expectedUseEncap) + throws Exception { + long endTime = System.currentTimeMillis() + TIMEOUT; + int startIndex = 0; + synchronized (mPackets) { + while (System.currentTimeMillis() < endTime) { + byte[] ikePkt = + getFirstMatchingPacket( + (pkt) -> { + return isIke( + pkt, + expectedInitIkeSpi, + expectedMsgId, + expectedResp, + expectedUseEncap); + }, + startIndex); + if (ikePkt != null) { + return ikePkt; // We've found the packet we're looking for. + } + + startIndex = mPackets.size(); + + // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout + long waitTimeout = endTime - System.currentTimeMillis(); + if (waitTimeout > 0) { + mPackets.wait(waitTimeout); + } + } + + String direction = expectedResp ? "response" : "request"; + fail( + "No such IKE " + + direction + + " found with Initiator SPI " + + expectedInitIkeSpi + + " and message ID " + + expectedMsgId); + } + return null; + } + + private static boolean isIke( + byte[] pkt, + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedResp, + boolean expectedUseEncap) { + int ipProtocolOffset = 0; + int ikeOffset = 0; + if (isIpv6(pkt)) { + // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap. + ipProtocolOffset = IP6_PROTO_OFFSET; + ikeOffset = IP6_HDRLEN + UDP_HDRLEN; + } else { + // Use default IPv4 header length (assuming no options) + ipProtocolOffset = IP4_PROTO_OFFSET; + ikeOffset = IP4_HDRLEN + UDP_HDRLEN; + + if (expectedUseEncap) { + if (hasNonEspMarker(pkt)) { + ikeOffset += NON_ESP_MARKER_LEN; + } else { + return false; + } + } + } + + return pkt[ipProtocolOffset] == IPPROTO_UDP + && areSpiAndMsgIdEqual( + pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); + } + + private static boolean hasNonEspMarker(byte[] pkt) { + ByteBuffer buffer = ByteBuffer.wrap(pkt); + int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; + if (buffer.remaining() < ikeOffset) return false; + + buffer.get(new byte[ikeOffset]); // Skip IP and UDP header + byte[] nonEspMarker = new byte[NON_ESP_MARKER_LEN]; + if (buffer.remaining() < NON_ESP_MARKER_LEN) return false; + + buffer.get(nonEspMarker); + return Arrays.equals(NON_ESP_MARKER, nonEspMarker); + } + + private static boolean areSpiAndMsgIdEqual( + byte[] pkt, + int ikeOffset, + long expectedIkeInitSpi, + int expectedMsgId, + boolean expectedResp) { + if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false; + + ByteBuffer buffer = ByteBuffer.wrap(pkt); + buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER) + + // Check message ID. + buffer.get(new byte[IKE_MSG_ID_OFFSET]); + int msgId = buffer.getInt(); + return expectedMsgId == msgId; + + // TODO: Check SPI and packet direction + } + + private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { + int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; + int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; + int ipOffset = shouldGetSource ? srcIpOffset : srcIpOffset + ipLen; + + ByteBuffer buffer = ByteBuffer.wrap(pkt); + buffer.get(new byte[ipOffset]); + byte[] ipAddrBytes = new byte[ipLen]; + buffer.get(ipAddrBytes); + return InetAddress.getByAddress(ipAddrBytes); + } + + private static int getPort(byte[] pkt, boolean shouldGetSource) { + ByteBuffer buffer = ByteBuffer.wrap(pkt); + int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; + int portOffset = shouldGetSource ? srcPortOffset : srcPortOffset + PORT_LEN; + + buffer.get(new byte[portOffset]); + return Short.toUnsignedInt(buffer.getShort()); + } + + private static byte[] buildIkePacket( + InetAddress srcAddr, + InetAddress dstAddr, + int srcPort, + int dstPort, + boolean useEncap, + byte[] ikePacket) + throws Exception { + if (useEncap) { + ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER_LEN + ikePacket.length); + buffer.put(NON_ESP_MARKER); + buffer.put(ikePacket); + ikePacket = buffer.array(); + } + + UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(ikePacket)); + IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt); + return ipPkt.getPacketBytes(); + } + + private static IpHeader getIpHeader( + int protocol, InetAddress src, InetAddress dst, Payload payload) { + if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { + throw new IllegalArgumentException("Invalid src/dst address combination"); + } + + if (src instanceof Inet6Address) { + return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); + } else { + return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); + } + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java index 71450ea9c0..cb1d8269d7 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java @@ -47,18 +47,18 @@ public class TunUtils { private static final String TAG = TunUtils.class.getSimpleName(); private static final int DATA_BUFFER_LEN = 4096; - private static final int TIMEOUT = 100; + static final int TIMEOUT = 100; - private static final int IP4_PROTO_OFFSET = 9; - private static final int IP6_PROTO_OFFSET = 6; + static final int IP4_PROTO_OFFSET = 9; + static final int IP6_PROTO_OFFSET = 6; - private static final int IP4_ADDR_OFFSET = 12; - private static final int IP4_ADDR_LEN = 4; - private static final int IP6_ADDR_OFFSET = 8; - private static final int IP6_ADDR_LEN = 16; + static final int IP4_ADDR_OFFSET = 12; + static final int IP4_ADDR_LEN = 4; + static final int IP6_ADDR_OFFSET = 8; + static final int IP6_ADDR_LEN = 16; + final List mPackets = new ArrayList<>(); private final ParcelFileDescriptor mTunFd; - private final List mPackets = new ArrayList<>(); private final Thread mReaderThread; public TunUtils(ParcelFileDescriptor tunFd) { @@ -107,7 +107,7 @@ public class TunUtils { return Arrays.copyOf(inBytes, bytesRead); } - private byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { + byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { synchronized (mPackets) { for (int i = startIndex; i < mPackets.size(); i++) { byte[] pkt = mPackets.get(i); @@ -198,7 +198,7 @@ public class TunUtils { } } - private static boolean isIpv6(byte[] pkt) { + static boolean isIpv6(byte[] pkt) { // First nibble shows IP version. 0x60 for IPv6 return (pkt[0] & (byte) 0xF0) == (byte) 0x60; } From e4a9287bfee4cf4dc15d5b9dc8a6b0a782a5b9ed Mon Sep 17 00:00:00 2001 From: Dominic Lemire Date: Wed, 15 Apr 2020 19:20:48 -0700 Subject: [PATCH 1052/1415] Fix error message in RestrictBackgroundNetworkTest Fixed the error message when the expected number of broadcasts is exceeded. Bug: 147139427 Test: atest hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Change-Id: I7e69dca81abdb29a9eb7d110266edbe483e17a01 Merged-In: I7e69dca81abdb29a9eb7d110266edbe483e17a01 --- .../hostside/AbstractRestrictBackgroundNetworkTestCase.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 29ba68c4cf..1db0417fc9 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -30,6 +30,7 @@ import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupp import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -177,7 +178,9 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { do { attempts++; count = getNumberBroadcastsReceived(receiverName, ACTION_RESTRICT_BACKGROUND_CHANGED); - if (count >= expectedCount) { + assertFalse("Expected count " + expectedCount + " but actual is " + count, + count > expectedCount); + if (count == expectedCount) { break; } Log.d(TAG, "Expecting count " + expectedCount + " but actual is " + count + " after " From 403541e847c61d7f8b80aac6d3bf4dabae497de7 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 30 Apr 2020 22:30:20 -0700 Subject: [PATCH 1053/1415] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I25406448298353ba63a04099c709ea266851d24f --- Tethering/res/values-mcc310-mnc004-ne/strings.xml | 2 +- Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml | 6 +++--- Tethering/res/values-mcc311-mnc480-ne/strings.xml | 2 +- Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml | 6 +++--- Tethering/res/values-zh-rTW/strings.xml | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml index 12d6c2cfba..d074f15699 100644 --- a/Tethering/res/values-mcc310-mnc004-ne/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -16,7 +16,7 @@ - "Tethering has no internet" + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" "यन्त्रहरू कनेक्ट गर्न सकिएन" "टेदरिङ निष्क्रिय पार्नुहोस्" "हटस्पट वा टेदरिङ सक्रिय छ" diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml index 05b90692ea..528a1e5292 100644 --- a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -16,9 +16,9 @@ - "無法透過數據連線連上網際網路" + "無法透過網路共用連上網際網路" "裝置無法連線" - "關閉數據連線" - "無線基地台或數據連線已開啟" + "關閉網路共用" + "無線基地台或網路共用已開啟" "使用漫遊服務可能須支付額外費用" diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml index 0a0aa217c3..1503244f50 100644 --- a/Tethering/res/values-mcc311-mnc480-ne/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -16,7 +16,7 @@ - "Tethering has no internet" + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" "यन्त्रहरू कनेक्ट गर्न सकिएन" "टेदरिङ निष्क्रिय पार्नुहोस्" "हटस्पट वा टेदरिङ सक्रिय छ" diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml index ea01b943fb..cd653df1da 100644 --- a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -16,9 +16,9 @@ - "無法透過數據連線連上網際網路" + "無法透過網路共用連上網際網路" "裝置無法連線" - "關閉數據連線" - "無線基地台或數據連線已開啟" + "關閉網路共用" + "無線基地台或網路共用已開啟" "使用漫遊服務可能須支付額外費用" diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9d738a76eb..50a50bf7a9 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -16,11 +16,11 @@ - "數據連線或無線基地台已啟用" + "網路共用或無線基地台已啟用" "輕觸即可進行設定。" - "數據連線已停用" + "網路共用已停用" "詳情請洽你的管理員" - "無線基地台與數據連線狀態" + "無線基地台與網路共用狀態" From 120a7db874068c0cc9c3b3f5a288f3f2093b5c35 Mon Sep 17 00:00:00 2001 From: evitayan Date: Tue, 7 Apr 2020 15:16:08 -0700 Subject: [PATCH 1054/1415] Initial CL for testing IkeSession creation This commit: -Extend TunUtils for processing IKE packets -Add IkeSessionBaseTest containing common functionality for all IkeSession tests -Add end-to-end test for IKEv2 PSK verifying creating IKE SA, creating child SAs and closing sessions -Add basic tests for error scenarios Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ie6c18591ffcc883abbf0484d9a59dfda61b33257 Merged-In: Ie6c18591ffcc883abbf0484d9a59dfda61b33257 --- tests/cts/net/ipsec/Android.bp | 1 + .../ipsec/ike/cts/IkeSessionParamsTest.java | 19 +- .../ike/cts/IkeSessionParamsTestBase.java | 85 ---- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 258 ++++++++++++ .../net/ipsec/ike/cts/IkeSessionTestBase.java | 374 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeTestBase.java | 6 +- .../net/ipsec/ike/cts/IkeTunUtils.java | 243 ++++++++++++ .../android/net/ipsec/ike/cts/TunUtils.java | 20 +- 8 files changed, 904 insertions(+), 102 deletions(-) delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp index 1d9128b7fe..124e93c650 100644 --- a/tests/cts/net/ipsec/Android.bp +++ b/tests/cts/net/ipsec/Android.bp @@ -33,6 +33,7 @@ android_test { "androidx.test.ext.junit", "compatibility-device-util-axt", "ctstestrunner-axt", + "net-tests-utils", ], platform_apis: true, diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java index 6fc7cb3634..c767b78120 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java @@ -46,6 +46,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.net.ipsec.ike.testutils.CertUtils; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -63,7 +64,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) -public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { +public final class IkeSessionParamsTest extends IkeSessionTestBase { private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(20L); private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(10L); private static final int DPD_DELAY_SECONDS = (int) TimeUnit.MINUTES.toSeconds(10L); @@ -105,6 +106,9 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { @Before public void setUp() throws Exception { + // This address is never used except for setting up the test network + setUpTestNetwork(IPV4_ADDRESS_LOCAL); + mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); mClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); mClientIntermediateCaCertOne = @@ -114,6 +118,11 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { mClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); } + @After + public void tearDown() throws Exception { + tearDownTestNetwork(); + } + private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() { return new EapSessionConfig.Builder() .setEapIdentity(EAP_IDENTITY) @@ -131,7 +140,7 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { */ private IkeSessionParams.Builder createIkeParamsBuilderMinimum() { return new IkeSessionParams.Builder(sContext) - .setNetwork(sTunNetwork) + .setNetwork(mTunNetwork) .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) .addSaProposal(SA_PROPOSAL) .setLocalIdentification(LOCAL_ID) @@ -145,7 +154,7 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { * @see #createIkeParamsBuilderMinimum */ private void verifyIkeParamsMinimum(IkeSessionParams sessionParams) { - assertEquals(sTunNetwork, sessionParams.getNetwork()); + assertEquals(mTunNetwork, sessionParams.getNetwork()); assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); @@ -268,7 +277,7 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { */ private IkeSessionParams.Builder createIkeParamsBuilderMinimumWithoutAuth() { return new IkeSessionParams.Builder(sContext) - .setNetwork(sTunNetwork) + .setNetwork(mTunNetwork) .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) .addSaProposal(SA_PROPOSAL) .setLocalIdentification(LOCAL_ID) @@ -282,7 +291,7 @@ public final class IkeSessionParamsTest extends IkeSessionParamsTestBase { * @see #createIkeParamsBuilderMinimumWithoutAuth */ private void verifyIkeParamsMinimumWithoutAuth(IkeSessionParams sessionParams) { - assertEquals(sTunNetwork, sessionParams.getNetwork()); + assertEquals(mTunNetwork, sessionParams.getNetwork()); assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java deleted file mode 100644 index c3e3ba353c..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTestBase.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.LinkAddress; -import android.net.Network; -import android.net.TestNetworkInterface; -import android.net.TestNetworkManager; -import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; -import android.os.Binder; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.platform.test.annotations.AppModeFull; - -import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") -abstract class IkeSessionParamsTestBase extends IkeTestBase { - // Static state to reduce setup/teardown - static ConnectivityManager sCM; - static TestNetworkManager sTNM; - static ParcelFileDescriptor sTunFd; - static TestNetworkCallback sTunNetworkCallback; - static Network sTunNetwork; - - static Context sContext = InstrumentationRegistry.getContext(); - static IBinder sBinder = new Binder(); - - // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass - // methods. - @BeforeClass - public static void setUpTestNetworkBeforeClass() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(); - sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); - sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); - - TestNetworkInterface testIface = - sTNM.createTunInterface( - new LinkAddress[] {new LinkAddress(IPV4_ADDRESS_LOCAL, IP4_PREFIX_LEN)}); - - sTunFd = testIface.getFileDescriptor(); - sTunNetworkCallback = - TestNetworkUtils.setupAndGetTestNetwork( - sCM, sTNM, testIface.getInterfaceName(), sBinder); - sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); - } - - // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass - // methods. - @AfterClass - public static void tearDownTestNetworkAfterClass() throws Exception { - sCM.unregisterNetworkCallback(sTunNetworkCallback); - - sTNM.teardownTestNetwork(sTunNetwork); - sTunFd.close(); - - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .dropShellPermissionIdentity(); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java new file mode 100644 index 0000000000..ed67dd1bd7 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -0,0 +1,258 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static com.android.internal.util.HexDump.hexStringToByteArray; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.net.ipsec.ike.exceptions.IkeException; +import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.platform.test.annotations.AppModeFull; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.Arrays; + +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +public class IkeSessionPskTest extends IkeSessionTestBase { + // Test vectors for success workflow + private static final String SUCCESS_IKE_INIT_RESP = + "46B8ECA1E0D72A18B45427679F9245D421202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0080030000080300000203000008" + + "0200000200000008040000022800008800020000A7AA3435D088EC1A2B7C2A47" + + "1FA1B85F1066C9B2006E7C353FB5B5FDBC2A88347ED2C6F5B7A265D03AE34039" + + "6AAC0145CFCC93F8BDB219DDFF22A603B8856A5DC59B6FAB7F17C5660CF38670" + + "8794FC72F273ADEB7A4F316519794AED6F8AB61F95DFB360FAF18C6C8CABE471" + + "6E18FE215348C2E582171A57FC41146B16C4AFE429000024A634B61C0E5C90C6" + + "8D8818B0955B125A9B1DF47BBD18775710792E651083105C2900001C00004004" + + "406FA3C5685A16B9B72C7F2EEE9993462C619ABE2900001C00004005AF905A87" + + "0A32222AA284A7070585601208A282F0290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + private static final String SUCCESS_IKE_AUTH_RESP = + "46B8ECA1E0D72A18B45427679F9245D42E20232000000001000000EC240000D0" + + "0D06D37198F3F0962DE8170D66F1A9008267F98CDD956D984BDCED2FC7FAF84A" + + "A6664EF25049B46B93C9ED420488E0C172AA6635BF4011C49792EF2B88FE7190" + + "E8859FEEF51724FD20C46E7B9A9C3DC4708EF7005707A18AB747C903ABCEAC5C" + + "6ECF5A5FC13633DCE3844A920ED10EF202F115DBFBB5D6D2D7AB1F34EB08DE7C" + + "A54DCE0A3A582753345CA2D05A0EFDB9DC61E81B2483B7D13EEE0A815D37252C" + + "23D2F29E9C30658227D2BB0C9E1A481EAA80BC6BE9006BEDC13E925A755A0290" + + "AEC4164D29997F52ED7DCC2E"; + private static final String SUCCESS_CREATE_CHILD_RESP = + "46B8ECA1E0D72A18B45427679F9245D42E20242000000002000000CC210000B0" + + "484565D4AF6546274674A8DE339E9C9584EE2326AB9260F41C4D0B6C5B02D1D" + + "2E8394E3CDE3094895F2ACCABCDCA8E82960E5196E9622BD13745FC8D6A2BED" + + "E561FF5D9975421BC463C959A3CBA3478256B6D278159D99B512DDF56AC1658" + + "63C65A986F395FE8B1476124B91F83FD7865304EB95B22CA4DD9601DA7A2533" + + "ABF4B36EB1B8CD09522F6A600032316C74E562E6756D9D49D945854E2ABDC4C" + + "3AF36305353D60D40B58BE44ABF82"; + private static final String SUCCESS_DELETE_CHILD_RESP = + "46B8ECA1E0D72A18B45427679F9245D42E202520000000030000004C2A000030" + + "0C5CEB882DBCA65CE32F4C53909335F1365C91C555316C5E9D9FB553F7AA916" + + "EF3A1D93460B7FABAF0B4B854"; + private static final String SUCCESS_DELETE_IKE_RESP = + "46B8ECA1E0D72A18B45427679F9245D42E202520000000040000004C00000030" + + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" + + "6743A7CEB2BE34AC00095A5B8"; + + private static final long IKE_INIT_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); + + private static final TunnelModeChildSessionParams CHILD_PARAMS = + new TunnelModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .build(); + + private IkeSessionParams createIkeSessionParams(InetAddress mRemoteAddress) { + return new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(mRemoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) + .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) + .setAuthPsk(IKE_PSK) + .build(); + } + + private IkeSession openIkeSession(IkeSessionParams ikeParams) { + return new IkeSession( + sContext, + ikeParams, + CHILD_PARAMS, + mUserCbExecutor, + mIkeSessionCallback, + mFirstChildSessionCallback); + } + + @Test + public void testIkeSessionSetupAndManageChildSas() throws Exception { + // Open IKE Session + IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + int expectedMsgId = 0; + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + false /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); + + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + + // Verify opening IKE Session + IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); + assertNotNull(ikeConfig); + assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); + assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); + assertTrue(ikeConfig.getPcscfServers().isEmpty()); + assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); + + IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); + assertNotNull(ikeConnectInfo); + assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); + assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); + assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); + + // Verify opening first Child Session + ChildSessionConfiguration firstChildConfig = mFirstChildSessionCallback.awaitChildConfig(); + assertNotNull(firstChildConfig); + assertEquals( + Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); + assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); + assertEquals( + Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR), + firstChildConfig.getInternalAddresses()); + assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); + assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); + assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + + // Open additional Child Session + TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); + ikeSession.openChildSession(CHILD_PARAMS, additionalChildCb); + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_CREATE_CHILD_RESP)); + + // Verify opening additional Child Session + ChildSessionConfiguration additionalChildConfig = additionalChildCb.awaitChildConfig(); + assertNotNull(additionalChildConfig); + assertEquals( + Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); + assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); + assertTrue(additionalChildConfig.getInternalAddresses().isEmpty()); + assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); + assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); + assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + + // Close additional Child Session + ikeSession.closeChildSession(additionalChildCb); + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); + + additionalChildCb.awaitOnClosed(); + + // Close IKE Session + ikeSession.close(); + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); + + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + + // TODO: verify IpSecTransform pair is created and deleted + } + + @Test + public void testIkeSessionKill() throws Exception { + // Open IKE Session + IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + int expectedMsgId = 0; + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + false /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); + + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + + ikeSession.kill(); + + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } + + @Test + public void testIkeInitFail() throws Exception { + String ikeInitFailRespHex = + "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; + + // Open IKE Session + IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + int expectedMsgId = 0; + mTunUtils.awaitReqAndInjectResp( + IKE_INIT_SPI, + expectedMsgId++, + false /* expectedUseEncap */, + hexStringToByteArray(ikeInitFailRespHex)); + + IkeException exception = mIkeSessionCallback.awaitOnClosedException(); + assertNotNull(exception); + assertTrue(exception instanceof IkeProtocolException); + IkeProtocolException protocolException = (IkeProtocolException) exception; + assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, protocolException.getErrorType()); + assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); + } + + // TODO(b/148689509): Verify rekey process and handling IKE_AUTH failure +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java new file mode 100644 index 0000000000..deba8fd985 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -0,0 +1,374 @@ +/* + * 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 + * + * 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.ipsec.ike.cts; + +import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; + +import android.annotation.NonNull; +import android.app.AppOpsManager; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.InetAddresses; +import android.net.IpSecTransform; +import android.net.LinkAddress; +import android.net.Network; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.annotations.PolicyDirection; +import android.net.ipsec.ike.ChildSessionCallback; +import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.ipsec.ike.IkeSessionCallback; +import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; +import android.net.ipsec.ike.exceptions.IkeException; +import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.os.Binder; +import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.AppModeFull; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.compatibility.common.util.SystemUtil; +import com.android.testutils.ArrayTrackRecord; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Package private base class for testing IkeSessionParams and IKE exchanges. + * + *

    Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use + * the test network + */ +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +abstract class IkeSessionTestBase extends IkeTestBase { + // Package-wide common expected results that will be shared by all IKE/Child SA creation tests + static final String EXPECTED_REMOTE_APP_VERSION_EMPTY = ""; + static final byte[] EXPECTED_PROTOCOL_ERROR_DATA_NONE = new byte[0]; + static final InetAddress EXPECTED_INTERNAL_ADDR = + InetAddresses.parseNumericAddress("198.51.100.10"); + static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR = + new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN); + static final IkeTrafficSelector EXPECTED_INBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); + + // Static state to reduce setup/teardown + static Context sContext = InstrumentationRegistry.getContext(); + static ConnectivityManager sCM = + (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + static TestNetworkManager sTNM; + + private static final int TIMEOUT_MS = 500; + + // Constants to be used for providing different IP addresses for each tests + private static final byte IP_ADDR_LAST_BYTE_MAX = (byte) 100; + private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_LOCAL = + InetAddresses.parseNumericAddress("192.0.2.1").getAddress(); + private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_REMOTE = + InetAddresses.parseNumericAddress("198.51.100.1").getAddress(); + private static final byte[] NEXT_AVAILABLE_IP4_ADDR_LOCAL = INITIAL_AVAILABLE_IP4_ADDR_LOCAL; + private static final byte[] NEXT_AVAILABLE_IP4_ADDR_REMOTE = INITIAL_AVAILABLE_IP4_ADDR_REMOTE; + + ParcelFileDescriptor mTunFd; + TestNetworkCallback mTunNetworkCallback; + Network mTunNetwork; + IkeTunUtils mTunUtils; + + InetAddress mLocalAddress; + InetAddress mRemoteAddress; + + Executor mUserCbExecutor; + TestIkeSessionCallback mIkeSessionCallback; + TestChildSessionCallback mFirstChildSessionCallback; + + // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass + // methods. + @BeforeClass + public static void setUpPermissionBeforeClass() throws Exception { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and + // a standard permission is insufficient. So we shell out the appop, to give us the + // right appop permissions. + setAppOp(OP_MANAGE_IPSEC_TUNNELS, true); + } + + // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass + // methods. + @AfterClass + public static void tearDownPermissionAfterClass() throws Exception { + setAppOp(OP_MANAGE_IPSEC_TUNNELS, false); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } + + @Before + public void setUp() throws Exception { + mLocalAddress = getNextAvailableIpv4AddressLocal(); + mRemoteAddress = getNextAvailableIpv4AddressRemote(); + setUpTestNetwork(mLocalAddress); + + mUserCbExecutor = Executors.newSingleThreadExecutor(); + mIkeSessionCallback = new TestIkeSessionCallback(); + mFirstChildSessionCallback = new TestChildSessionCallback(); + } + + @After + public void tearDown() throws Exception { + tearDownTestNetwork(); + + resetNextAvailableAddress(NEXT_AVAILABLE_IP4_ADDR_LOCAL, INITIAL_AVAILABLE_IP4_ADDR_LOCAL); + resetNextAvailableAddress( + NEXT_AVAILABLE_IP4_ADDR_REMOTE, INITIAL_AVAILABLE_IP4_ADDR_REMOTE); + } + + void setUpTestNetwork(InetAddress localAddr) throws Exception { + int prefixLen = localAddr instanceof Inet4Address ? IP4_PREFIX_LEN : IP4_PREFIX_LEN; + + TestNetworkInterface testIface = + sTNM.createTunInterface(new LinkAddress[] {new LinkAddress(localAddr, prefixLen)}); + + mTunFd = testIface.getFileDescriptor(); + mTunNetworkCallback = + TestNetworkUtils.setupAndGetTestNetwork( + sCM, sTNM, testIface.getInterfaceName(), new Binder()); + mTunNetwork = mTunNetworkCallback.getNetworkBlocking(); + mTunUtils = new IkeTunUtils(mTunFd); + } + + void tearDownTestNetwork() throws Exception { + sCM.unregisterNetworkCallback(mTunNetworkCallback); + + sTNM.teardownTestNetwork(mTunNetwork); + mTunFd.close(); + } + + private static void setAppOp(int appop, boolean allow) { + String opName = AppOpsManager.opToName(appop); + for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { + String cmd = + String.format( + "appops set %s %s %s", + pkg, // Package name + opName, // Appop + (allow ? "allow" : "deny")); // Action + Log.d("IKE", "CTS setAppOp cmd " + cmd); + + String result = SystemUtil.runShellCommand(cmd); + } + } + + Inet4Address getNextAvailableIpv4AddressLocal() throws Exception { + return (Inet4Address) + getNextAvailableAddress( + NEXT_AVAILABLE_IP4_ADDR_LOCAL, + INITIAL_AVAILABLE_IP4_ADDR_LOCAL, + false /* isIp6 */); + } + + Inet4Address getNextAvailableIpv4AddressRemote() throws Exception { + return (Inet4Address) + getNextAvailableAddress( + NEXT_AVAILABLE_IP4_ADDR_REMOTE, + INITIAL_AVAILABLE_IP4_ADDR_REMOTE, + false /* isIp6 */); + } + + InetAddress getNextAvailableAddress( + byte[] nextAddressBytes, byte[] initialAddressBytes, boolean isIp6) throws Exception { + int addressLen = isIp6 ? IP6_ADDRESS_LEN : IP4_ADDRESS_LEN; + + synchronized (nextAddressBytes) { + if (nextAddressBytes[addressLen - 1] == IP_ADDR_LAST_BYTE_MAX) { + resetNextAvailableAddress(nextAddressBytes, initialAddressBytes); + } + + InetAddress address = InetAddress.getByAddress(nextAddressBytes); + nextAddressBytes[addressLen - 1]++; + return address; + } + } + + private void resetNextAvailableAddress(byte[] nextAddressBytes, byte[] initialAddressBytes) { + synchronized (nextAddressBytes) { + System.arraycopy( + nextAddressBytes, 0, initialAddressBytes, 0, initialAddressBytes.length); + } + } + + static class TestIkeSessionCallback implements IkeSessionCallback { + private CompletableFuture mFutureIkeConfig = + new CompletableFuture<>(); + private CompletableFuture mFutureOnClosedCall = new CompletableFuture<>(); + private CompletableFuture mFutureOnClosedException = + new CompletableFuture<>(); + + private int mOnErrorExceptionsCount = 0; + private ArrayTrackRecord mOnErrorExceptionsTrackRecord = + new ArrayTrackRecord<>(); + + @Override + public void onOpened(@NonNull IkeSessionConfiguration sessionConfiguration) { + mFutureIkeConfig.complete(sessionConfiguration); + } + + @Override + public void onClosed() { + mFutureOnClosedCall.complete(true /* unused */); + } + + @Override + public void onClosedExceptionally(@NonNull IkeException exception) { + mFutureOnClosedException.complete(exception); + } + + @Override + public void onError(@NonNull IkeProtocolException exception) { + mOnErrorExceptionsTrackRecord.add(exception); + } + + public IkeSessionConfiguration awaitIkeConfig() throws Exception { + return mFutureIkeConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public IkeException awaitOnClosedException() throws Exception { + return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public IkeProtocolException awaitNextOnErrorException() { + return mOnErrorExceptionsTrackRecord.poll( + (long) TIMEOUT_MS, + mOnErrorExceptionsCount++, + (transform) -> { + return true; + }); + } + + public void awaitOnClosed() throws Exception { + mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + static class TestChildSessionCallback implements ChildSessionCallback { + private CompletableFuture mFutureChildConfig = + new CompletableFuture<>(); + private CompletableFuture mFutureOnClosedCall = new CompletableFuture<>(); + private CompletableFuture mFutureOnClosedException = + new CompletableFuture<>(); + + private int mCreatedIpSecTransformCount = 0; + private int mDeletedIpSecTransformCount = 0; + private ArrayTrackRecord mCreatedIpSecTransformsTrackRecord = + new ArrayTrackRecord<>(); + private ArrayTrackRecord mDeletedIpSecTransformsTrackRecord = + new ArrayTrackRecord<>(); + + @Override + public void onOpened(@NonNull ChildSessionConfiguration sessionConfiguration) { + mFutureChildConfig.complete(sessionConfiguration); + } + + @Override + public void onClosed() { + mFutureOnClosedCall.complete(true /* unused */); + } + + @Override + public void onClosedExceptionally(@NonNull IkeException exception) { + mFutureOnClosedException.complete(exception); + } + + @Override + public void onIpSecTransformCreated(@NonNull IpSecTransform ipSecTransform, int direction) { + mCreatedIpSecTransformsTrackRecord.add( + new IpSecTransformCallRecord(ipSecTransform, direction)); + } + + @Override + public void onIpSecTransformDeleted(@NonNull IpSecTransform ipSecTransform, int direction) { + mDeletedIpSecTransformsTrackRecord.add( + new IpSecTransformCallRecord(ipSecTransform, direction)); + } + + public ChildSessionConfiguration awaitChildConfig() throws Exception { + return mFutureChildConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public IkeException awaitOnClosedException() throws Exception { + return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public IpSecTransformCallRecord awaitNextCreatedIpSecTransform() { + return mCreatedIpSecTransformsTrackRecord.poll( + (long) TIMEOUT_MS, + mCreatedIpSecTransformCount++, + (transform) -> { + return true; + }); + } + + public IpSecTransformCallRecord awaitNextDeletedIpSecTransform() { + return mDeletedIpSecTransformsTrackRecord.poll( + (long) TIMEOUT_MS, + mDeletedIpSecTransformCount++, + (transform) -> { + return true; + }); + } + + public void awaitOnClosed() throws Exception { + mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + /** + * This class represents a created or deleted IpSecTransfrom that is provided by + * ChildSessionCallback + */ + static class IpSecTransformCallRecord { + public final IpSecTransform ipSecTransform; + public final int direction; + + IpSecTransformCallRecord(IpSecTransform ipSecTransform, @PolicyDirection int direction) { + this.ipSecTransform = ipSecTransform; + this.direction = direction; + } + } + + // TODO(b/148689509): Verify IKE Session setup using EAP and digital-signature-based auth + + // TODO(b/148689509): Verify hostname based creation +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index bc2bec665f..f07c710ba9 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -31,13 +31,15 @@ import java.util.Map; /** Shared parameters and util methods for testing different components of IKE */ abstract class IkeTestBase { - private static final int MIN_PORT = 0; - private static final int MAX_PORT = 65535; + static final int MIN_PORT = 0; + static final int MAX_PORT = 65535; private static final int INBOUND_TS_START_PORT = MIN_PORT; private static final int INBOUND_TS_END_PORT = 65520; private static final int OUTBOUND_TS_START_PORT = 16; private static final int OUTBOUND_TS_END_PORT = MAX_PORT; + static final int IP4_ADDRESS_LEN = 4; + static final int IP6_ADDRESS_LEN = 16; static final int IP4_PREFIX_LEN = 32; static final int IP6_PREFIX_LEN = 64; diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java new file mode 100644 index 0000000000..5a8258d57b --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -0,0 +1,243 @@ +/* + * 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.ipsec.ike.cts; + +import static android.net.ipsec.ike.cts.PacketUtils.BytePayload; +import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.Ip4Header; +import static android.net.ipsec.ike.cts.PacketUtils.Ip6Header; +import static android.net.ipsec.ike.cts.PacketUtils.IpHeader; +import static android.net.ipsec.ike.cts.PacketUtils.Payload; +import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; +import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader; +import static android.system.OsConstants.IPPROTO_UDP; + +import static org.junit.Assert.fail; + +import android.os.ParcelFileDescriptor; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.Arrays; + +public class IkeTunUtils extends TunUtils { + private static final int PORT_LEN = 2; + + private static final int NON_ESP_MARKER_LEN = 4; + private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN]; + + private static final int IKE_HEADER_LEN = 28; + private static final int IKE_INIT_SPI_OFFSET = 0; + private static final int IKE_IS_RESP_BYTE_OFFSET = 19; + private static final int IKE_MSG_ID_OFFSET = 20; + + public IkeTunUtils(ParcelFileDescriptor tunFd) { + super(tunFd); + } + + /** + * Await the expected IKE request and inject an IKE response. + * + * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER. + */ + public byte[] awaitReqAndInjectResp( + long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, byte[] respIkePkt) + throws Exception { + byte[] request = + awaitIkePacket( + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap); + + // Build response header by flipping address and port + InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); + InetAddress dstAddr = getAddress(request, true /* shouldGetSource */); + int srcPort = getPort(request, false /* shouldGetSource */); + int dstPort = getPort(request, true /* shouldGetSource */); + + byte[] response = + buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, expectedUseEncap, respIkePkt); + injectPacket(response); + return request; + } + + private byte[] awaitIkePacket( + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedResp, + boolean expectedUseEncap) + throws Exception { + long endTime = System.currentTimeMillis() + TIMEOUT; + int startIndex = 0; + synchronized (mPackets) { + while (System.currentTimeMillis() < endTime) { + byte[] ikePkt = + getFirstMatchingPacket( + (pkt) -> { + return isIke( + pkt, + expectedInitIkeSpi, + expectedMsgId, + expectedResp, + expectedUseEncap); + }, + startIndex); + if (ikePkt != null) { + return ikePkt; // We've found the packet we're looking for. + } + + startIndex = mPackets.size(); + + // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout + long waitTimeout = endTime - System.currentTimeMillis(); + if (waitTimeout > 0) { + mPackets.wait(waitTimeout); + } + } + + String direction = expectedResp ? "response" : "request"; + fail( + "No such IKE " + + direction + + " found with Initiator SPI " + + expectedInitIkeSpi + + " and message ID " + + expectedMsgId); + } + return null; + } + + private static boolean isIke( + byte[] pkt, + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedResp, + boolean expectedUseEncap) { + int ipProtocolOffset = 0; + int ikeOffset = 0; + if (isIpv6(pkt)) { + // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap. + ipProtocolOffset = IP6_PROTO_OFFSET; + ikeOffset = IP6_HDRLEN + UDP_HDRLEN; + } else { + // Use default IPv4 header length (assuming no options) + ipProtocolOffset = IP4_PROTO_OFFSET; + ikeOffset = IP4_HDRLEN + UDP_HDRLEN; + + if (expectedUseEncap) { + if (hasNonEspMarker(pkt)) { + ikeOffset += NON_ESP_MARKER_LEN; + } else { + return false; + } + } + } + + return pkt[ipProtocolOffset] == IPPROTO_UDP + && areSpiAndMsgIdEqual( + pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); + } + + private static boolean hasNonEspMarker(byte[] pkt) { + ByteBuffer buffer = ByteBuffer.wrap(pkt); + int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; + if (buffer.remaining() < ikeOffset) return false; + + buffer.get(new byte[ikeOffset]); // Skip IP and UDP header + byte[] nonEspMarker = new byte[NON_ESP_MARKER_LEN]; + if (buffer.remaining() < NON_ESP_MARKER_LEN) return false; + + buffer.get(nonEspMarker); + return Arrays.equals(NON_ESP_MARKER, nonEspMarker); + } + + private static boolean areSpiAndMsgIdEqual( + byte[] pkt, + int ikeOffset, + long expectedIkeInitSpi, + int expectedMsgId, + boolean expectedResp) { + if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false; + + ByteBuffer buffer = ByteBuffer.wrap(pkt); + buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER) + + // Check message ID. + buffer.get(new byte[IKE_MSG_ID_OFFSET]); + int msgId = buffer.getInt(); + return expectedMsgId == msgId; + + // TODO: Check SPI and packet direction + } + + private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { + int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; + int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; + int ipOffset = shouldGetSource ? srcIpOffset : srcIpOffset + ipLen; + + ByteBuffer buffer = ByteBuffer.wrap(pkt); + buffer.get(new byte[ipOffset]); + byte[] ipAddrBytes = new byte[ipLen]; + buffer.get(ipAddrBytes); + return InetAddress.getByAddress(ipAddrBytes); + } + + private static int getPort(byte[] pkt, boolean shouldGetSource) { + ByteBuffer buffer = ByteBuffer.wrap(pkt); + int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; + int portOffset = shouldGetSource ? srcPortOffset : srcPortOffset + PORT_LEN; + + buffer.get(new byte[portOffset]); + return Short.toUnsignedInt(buffer.getShort()); + } + + private static byte[] buildIkePacket( + InetAddress srcAddr, + InetAddress dstAddr, + int srcPort, + int dstPort, + boolean useEncap, + byte[] ikePacket) + throws Exception { + if (useEncap) { + ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER_LEN + ikePacket.length); + buffer.put(NON_ESP_MARKER); + buffer.put(ikePacket); + ikePacket = buffer.array(); + } + + UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(ikePacket)); + IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt); + return ipPkt.getPacketBytes(); + } + + private static IpHeader getIpHeader( + int protocol, InetAddress src, InetAddress dst, Payload payload) { + if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { + throw new IllegalArgumentException("Invalid src/dst address combination"); + } + + if (src instanceof Inet6Address) { + return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); + } else { + return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); + } + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java index 71450ea9c0..cb1d8269d7 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java @@ -47,18 +47,18 @@ public class TunUtils { private static final String TAG = TunUtils.class.getSimpleName(); private static final int DATA_BUFFER_LEN = 4096; - private static final int TIMEOUT = 100; + static final int TIMEOUT = 100; - private static final int IP4_PROTO_OFFSET = 9; - private static final int IP6_PROTO_OFFSET = 6; + static final int IP4_PROTO_OFFSET = 9; + static final int IP6_PROTO_OFFSET = 6; - private static final int IP4_ADDR_OFFSET = 12; - private static final int IP4_ADDR_LEN = 4; - private static final int IP6_ADDR_OFFSET = 8; - private static final int IP6_ADDR_LEN = 16; + static final int IP4_ADDR_OFFSET = 12; + static final int IP4_ADDR_LEN = 4; + static final int IP6_ADDR_OFFSET = 8; + static final int IP6_ADDR_LEN = 16; + final List mPackets = new ArrayList<>(); private final ParcelFileDescriptor mTunFd; - private final List mPackets = new ArrayList<>(); private final Thread mReaderThread; public TunUtils(ParcelFileDescriptor tunFd) { @@ -107,7 +107,7 @@ public class TunUtils { return Arrays.copyOf(inBytes, bytesRead); } - private byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { + byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { synchronized (mPackets) { for (int i = startIndex; i < mPackets.size(); i++) { byte[] pkt = mPackets.get(i); @@ -198,7 +198,7 @@ public class TunUtils { } } - private static boolean isIpv6(byte[] pkt) { + static boolean isIpv6(byte[] pkt) { // First nibble shows IP version. 0x60 for IPv6 return (pkt[0] & (byte) 0xF0) == (byte) 0x60; } From da5dfd9f0dc8c663e75c89e345769e24c11e2bf9 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 24 Apr 2020 15:47:24 +0800 Subject: [PATCH 1055/1415] [SP18.3] Adapt TestableNetworkStatsProviderCbBinder This is a no-op refactoring to adapt new test provider callback. Also this patch adapts TestLooper to allow better control on delay messages that will be verified in subsequent tests. Test: atest OffloadControllerTest Bug: 149467454 Change-Id: Icfd6ff289d6689ae2d5753d3fe472516c808dc7a --- .../tethering/OffloadControllerTest.java | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index 088a663190..6d7c4284a7 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -31,13 +31,12 @@ import static com.android.networkstack.tethering.OffloadController.StatsType.STA import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; -import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals; +import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals; import static junit.framework.Assert.assertNotNull; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; @@ -46,7 +45,6 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -63,10 +61,9 @@ import android.net.LinkProperties; import android.net.NetworkStats; import android.net.NetworkStats.Entry; import android.net.RouteInfo; -import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.util.SharedLog; import android.os.Handler; -import android.os.Looper; +import android.os.test.TestLooper; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.test.mock.MockContentResolver; @@ -75,7 +72,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.TestableNetworkStatsProviderCbBinder; import org.junit.After; import org.junit.Before; @@ -109,13 +106,15 @@ public class OffloadControllerTest { @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; @Mock private NetworkStatsManager mStatsManager; - @Mock private INetworkStatsProviderCallback mTetherStatsProviderCb; + // Late init since methods must be called by the thread that created this object. + private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb; private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider; private final ArgumentCaptor mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class); private final ArgumentCaptor mControlCallbackCaptor = ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class); private MockContentResolver mContentResolver; + private final TestLooper mTestLooper = new TestLooper(); private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() { @Override int getPerformPollInterval() { @@ -151,11 +150,11 @@ public class OffloadControllerTest { } private void waitForIdle() { - HandlerUtilsKt.waitForIdle(new Handler(Looper.getMainLooper()), WAIT_FOR_IDLE_TIMEOUT); + mTestLooper.dispatchAll(); } private OffloadController makeOffloadController() throws Exception { - OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()), + OffloadController offload = new OffloadController(new Handler(mTestLooper.getLooper()), mHardware, mContentResolver, mStatsManager, new SharedLog("test"), mDeps); final ArgumentCaptor tetherStatsProviderCaptor = @@ -164,6 +163,7 @@ public class OffloadControllerTest { tetherStatsProviderCaptor.capture()); mTetherStatsProvider = tetherStatsProviderCaptor.getValue(); assertNotNull(mTetherStatsProvider); + mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder(); mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb); return offload; } @@ -459,20 +459,12 @@ public class OffloadControllerTest { .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321)); - assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStats)); - assertTrue(orderInsensitiveEquals(expectedUidStats, uidStats)); - - final ArgumentCaptor ifaceStatsCaptor = ArgumentCaptor.forClass( - NetworkStats.class); - final ArgumentCaptor uidStatsCaptor = ArgumentCaptor.forClass( - NetworkStats.class); + assertNetworkStatsEquals(expectedIfaceStats, ifaceStats); + assertNetworkStatsEquals(expectedUidStats, uidStats); // Force pushing stats update to verify the stats reported. mTetherStatsProvider.pushTetherStats(); - verify(mTetherStatsProviderCb, times(1)) - .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); - assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStatsCaptor.getValue())); - assertTrue(orderInsensitiveEquals(expectedUidStats, uidStatsCaptor.getValue())); + mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStats, expectedUidStats); when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( new ForwardedStats(100000, 100000)); @@ -498,11 +490,10 @@ public class OffloadControllerTest { .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321)); - assertTrue(orderInsensitiveEquals(expectedIfaceStatsAccu, ifaceStatsAccu)); - assertTrue(orderInsensitiveEquals(expectedUidStatsAccu, uidStatsAccu)); + assertNetworkStatsEquals(expectedIfaceStatsAccu, ifaceStatsAccu); + assertNetworkStatsEquals(expectedUidStatsAccu, uidStatsAccu); // Verify that only diff of stats is reported. - reset(mTetherStatsProviderCb); mTetherStatsProvider.pushTetherStats(); final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) @@ -511,10 +502,8 @@ public class OffloadControllerTest { final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); - verify(mTetherStatsProviderCb, times(1)) - .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); - assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue())); - assertTrue(orderInsensitiveEquals(expectedUidStatsDiff, uidStatsCaptor.getValue())); + mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStatsDiff, + expectedUidStatsDiff); } @Test @@ -591,7 +580,7 @@ public class OffloadControllerTest { OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); callback.onStoppedLimitReached(); - verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); + mTetherStatsProviderCb.expectNotifyStatsUpdated(); } @Test @@ -695,8 +684,8 @@ public class OffloadControllerTest { verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); // TODO: verify the exact stats reported. - verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); - verifyNoMoreInteractions(mTetherStatsProviderCb); + mTetherStatsProviderCb.expectNotifyStatsUpdated(); + mTetherStatsProviderCb.assertNoCallback(); verifyNoMoreInteractions(mHardware); } @@ -760,8 +749,8 @@ public class OffloadControllerTest { // Verify forwarded stats behaviour. verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); - verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); - verifyNoMoreInteractions(mTetherStatsProviderCb); + mTetherStatsProviderCb.expectNotifyStatsUpdated(); + mTetherStatsProviderCb.assertNoCallback(); // TODO: verify local prefixes and downstreams are also pushed to the HAL. verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); From 9c50628e9516159209c8f6788336c5b29359ac2f Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 24 Apr 2020 19:29:27 +0800 Subject: [PATCH 1056/1415] [SP18.4] Add unit test for polling network stats in OffloadController Test: atest OffloadControllerTest Bug: 149467454 Change-Id: I9b9c9c096a2366aaf383d5c2d567db6682f02dad --- .../tethering/OffloadController.java | 3 +- .../tethering/OffloadControllerTest.java | 60 ++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java index 1817f35f1d..c0638636bb 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadController.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java @@ -77,7 +77,8 @@ public class OffloadController { private static final boolean DBG = false; private static final String ANYIP = "0.0.0.0"; private static final ForwardedStats EMPTY_STATS = new ForwardedStats(); - private static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; + @VisibleForTesting + static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; @VisibleForTesting enum StatsType { diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index 6d7c4284a7..f71cd211b2 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -26,6 +26,7 @@ import static android.net.NetworkStats.UID_TETHERING; import static android.net.RouteInfo.RTN_UNICAST; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; +import static com.android.networkstack.tethering.OffloadController.DEFAULT_PERFORM_POLL_INTERVAL_MS; import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE; import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; @@ -45,6 +46,7 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -61,6 +63,7 @@ import android.net.LinkProperties; import android.net.NetworkStats; import android.net.NetworkStats.Entry; import android.net.RouteInfo; +import android.net.netstats.provider.NetworkStatsProvider; import android.net.util.SharedLog; import android.os.Handler; import android.os.test.TestLooper; @@ -118,7 +121,7 @@ public class OffloadControllerTest { private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() { @Override int getPerformPollInterval() { - return 0; + return -1; // Disabled. } }; @@ -149,6 +152,15 @@ public class OffloadControllerTest { Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0); } + private void setOffloadPollInterval(int interval) { + mDeps = new OffloadController.Dependencies() { + @Override + int getPerformPollInterval() { + return interval; + } + }; + } + private void waitForIdle() { mTestLooper.dispatchAll(); } @@ -769,4 +781,50 @@ public class OffloadControllerTest { verifyNoMoreInteractions(mHardware); } + @Test + public void testOnSetAlert() throws Exception { + setupFunctioningHardwareInterface(); + enableOffload(); + setOffloadPollInterval(DEFAULT_PERFORM_POLL_INTERVAL_MS); + final OffloadController offload = makeOffloadController(); + offload.start(); + + // Initialize with fake eth upstream. + final String ethernetIface = "eth1"; + InOrder inOrder = inOrder(mHardware); + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(ethernetIface); + offload.setUpstreamLinkProperties(lp); + // Previous upstream was null, so no stats are fetched. + inOrder.verify(mHardware, never()).getForwardedStats(any()); + + // Verify that set quota to 0 will immediately triggers an callback. + mTetherStatsProvider.onSetAlert(0); + waitForIdle(); + mTetherStatsProviderCb.expectNotifyAlertReached(); + + // Verify that notifyAlertReached never fired if quota is not yet reached. + when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( + new ForwardedStats(0, 0)); + mTetherStatsProvider.onSetAlert(100); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.assertNoCallback(); + + // Verify that notifyAlertReached fired when quota is reached. + when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( + new ForwardedStats(50, 50)); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.expectNotifyAlertReached(); + + // Verify that set quota with UNLIMITED won't trigger any callback, and won't fetch + // any stats since the polling is stopped. + reset(mHardware); + mTetherStatsProvider.onSetAlert(NetworkStatsProvider.QUOTA_UNLIMITED); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.assertNoCallback(); + verify(mHardware, never()).getForwardedStats(any()); + } } From 9606a22037cf4dc485075eb6dc5d024d54703302 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 30 Apr 2020 15:21:55 +0800 Subject: [PATCH 1057/1415] [SP18.5] Create offload controller poll interval to resource Test: atest TetheringConfigurationTest Bug: 149467454 Change-Id: I8b4ad920a4945504914d3741a9fba5c096fbf452 --- Tethering/res/values/config.xml | 7 +++++++ Tethering/res/values/overlayable.xml | 1 + .../tethering/TetheringConfiguration.java | 20 +++++++++++++++++++ .../tethering/TetheringConfigurationTest.java | 19 ++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index effc24ac4d..c999221963 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -62,6 +62,13 @@ + + 5000 + diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index aeac437e24..9d4e747327 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -78,6 +78,12 @@ public class TetheringConfiguration { public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER = "tether_enable_legacy_dhcp_server"; + /** + * Default value that used to periodic polls tether offload stats from tethering offload HAL + * to make the data warnings work. + */ + public static final int DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS = 5000; + public final String[] tetherableUsbRegexs; public final String[] tetherableWifiRegexs; public final String[] tetherableWifiP2pRegexs; @@ -96,6 +102,8 @@ public class TetheringConfiguration { public final int activeDataSubId; + private final int mOffloadPollInterval; + public TetheringConfiguration(Context ctx, SharedLog log, int id) { final SharedLog configLog = log.forSubComponent("config"); @@ -129,6 +137,10 @@ public class TetheringConfiguration { R.integer.config_mobile_hotspot_provision_check_period, 0 /* No periodic re-check */); + mOffloadPollInterval = getResourceInteger(res, + R.integer.config_tether_offload_poll_interval, + DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); + configLog.log(toString()); } @@ -189,6 +201,9 @@ public class TetheringConfiguration { dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges); dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS); + pw.print("offloadPollInterval: "); + pw.println(mOffloadPollInterval); + dumpStringArray(pw, "provisioningApp", provisioningApp); pw.print("provisioningAppNoUi: "); pw.println(provisioningAppNoUi); @@ -208,6 +223,7 @@ public class TetheringConfiguration { makeString(tetherableBluetoothRegexs))); sj.add(String.format("isDunRequired:%s", isDunRequired)); sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically)); + sj.add(String.format("offloadPollInterval:%d", mOffloadPollInterval)); sj.add(String.format("preferredUpstreamIfaceTypes:%s", toIntArray(preferredUpstreamIfaceTypes))); sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); @@ -246,6 +262,10 @@ public class TetheringConfiguration { return (tm != null) ? tm.isTetheringApnRequired() : false; } + public int getOffloadPollInterval() { + return mOffloadPollInterval; + } + private static Collection getUpstreamIfaceTypes(Resources res, boolean dunRequired) { final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types); final ArrayList upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index 07ddea43f4..e8ba5b8168 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -115,6 +115,8 @@ public class TetheringConfigurationTest { when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn( new String[0]); + when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn( + TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); when(mResources.getStringArray(R.array.config_tether_usb_regexs)).thenReturn(new String[0]); when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) .thenReturn(new String[]{ "test_wlan\\d" }); @@ -313,6 +315,23 @@ public class TetheringConfigurationTest { assertFalse(cfg.enableLegacyDhcpServer); } + @Test + public void testOffloadIntervalByResource() { + final TetheringConfiguration intervalByDefault = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertEquals(TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, + intervalByDefault.getOffloadPollInterval()); + + final int[] testOverrides = {0, 3000, -1}; + for (final int override : testOverrides) { + when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn( + override); + final TetheringConfiguration overrideByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertEquals(override, overrideByRes.getOffloadPollInterval()); + } + } + @Test public void testGetResourcesBySubId() { setUpResourceForSubId(); From 0630f383af6c349e965666d84c505ed305d4a5a8 Mon Sep 17 00:00:00 2001 From: Jeongik Cha Date: Mon, 4 May 2020 16:19:40 +0900 Subject: [PATCH 1058/1415] Use stable networkstack-aidl-interfaces Test: m nothing Bug: 133526962 Change-Id: I507f40866d04db5ed3361831e01eaa4dfaf20bed --- Tethering/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 27297c4457..0647ed8248 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -27,7 +27,7 @@ java_defaults { "androidx.annotation_annotation", "netd_aidl_interface-V3-java", "netlink-client", - "networkstack-aidl-interfaces-unstable-java", + "networkstack-aidl-interfaces-java", "android.hardware.tetheroffload.config-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "net-utils-framework-common", From efb185744313b3baf4b579a9eb6f8640cd603c78 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Mon, 4 May 2020 13:34:29 -0700 Subject: [PATCH 1059/1415] Test that idle apps get network when device charges. This is a partial revert of the change that removed the parole (Icd7b6eff8777f9b53a10eca521b73988f58f2d84). Bug: 151802309 Test: atest --rerun-until-failure 10 com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: I65f5ff20cdd342905e1afd1f4897017aa60682d3 --- .../net/hostside/AbstractAppIdleTestCase.java | 6 +++--- .../cts/net/NetworkPolicyTestsPreparer.java | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 51bdf8e502..5fe4573847 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -50,7 +50,7 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork public final void tearDown() throws Exception { super.tearDown(); - turnBatteryOff(); + executeSilentShellCommand("cmd battery reset"); setAppIdle(false); } @@ -131,11 +131,11 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork @RequiredProperties({BATTERY_SAVER_MODE}) @Test public void testAppIdleNetworkAccess_whenCharging() throws Exception { - // Check that idle app doesn't get network when charging + // Check that app is paroled when charging setAppIdle(true); assertBackgroundNetworkAccess(false); turnBatteryOff(); - assertBackgroundNetworkAccess(false); + assertBackgroundNetworkAccess(true); turnBatteryOn(); assertBackgroundNetworkAccess(false); diff --git a/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java b/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java index dfce7da467..b0facec119 100644 --- a/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java +++ b/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java @@ -24,6 +24,9 @@ import com.android.tradefed.targetprep.ITargetPreparer; public class NetworkPolicyTestsPreparer implements ITargetPreparer { private ITestDevice mDevice; private String mOriginalAppStandbyEnabled; + private String mOriginalBatteryStatsConstants; + private final static String KEY_STABLE_CHARGING_DELAY_MS = "battery_charged_delay_ms"; + private final static int DESIRED_STABLE_CHARGING_DELAY_MS = 0; @Override public void setUp(TestInformation testInformation) throws DeviceNotAvailableException { @@ -31,12 +34,18 @@ public class NetworkPolicyTestsPreparer implements ITargetPreparer { mOriginalAppStandbyEnabled = getAppStandbyEnabled(); setAppStandbyEnabled("1"); LogUtil.CLog.d("Original app_standby_enabled: " + mOriginalAppStandbyEnabled); + + mOriginalBatteryStatsConstants = getBatteryStatsConstants(); + setBatteryStatsConstants( + KEY_STABLE_CHARGING_DELAY_MS + "=" + DESIRED_STABLE_CHARGING_DELAY_MS); + LogUtil.CLog.d("Original battery_saver_constants: " + mOriginalBatteryStatsConstants); } @Override public void tearDown(TestInformation testInformation, Throwable e) throws DeviceNotAvailableException { setAppStandbyEnabled(mOriginalAppStandbyEnabled); + setBatteryStatsConstants(mOriginalBatteryStatsConstants); } private void setAppStandbyEnabled(String appStandbyEnabled) throws DeviceNotAvailableException { @@ -51,6 +60,15 @@ public class NetworkPolicyTestsPreparer implements ITargetPreparer { return executeCmd("settings get global app_standby_enabled").trim(); } + private void setBatteryStatsConstants(String batteryStatsConstants) + throws DeviceNotAvailableException { + executeCmd("settings put global battery_stats_constants \"" + batteryStatsConstants + "\""); + } + + private String getBatteryStatsConstants() throws DeviceNotAvailableException { + return executeCmd("settings get global battery_stats_constants"); + } + private String executeCmd(String cmd) throws DeviceNotAvailableException { final String output = mDevice.executeShellCommand(cmd).trim(); LogUtil.CLog.d("Output for '%s': %s", cmd, output); From 54755042663852bbef59bf530804234d89e8487e Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 30 Apr 2020 17:36:32 +0800 Subject: [PATCH 1060/1415] [SP18.6] Make offload controller poll interval configurable Test: atest TetheringTests Bug: 149467454 Change-Id: I0b07a0b520dedb479bf863fbfe898ae85b84b0f3 --- .../tethering/OffloadController.java | 20 +++++++------- .../networkstack/tethering/Tethering.java | 8 +++++- .../tethering/OffloadControllerTest.java | 27 +++++++++---------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java index c0638636bb..88c77b07e7 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadController.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java @@ -26,6 +26,8 @@ import static android.net.NetworkStats.UID_TETHERING; import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; +import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.usage.NetworkStatsManager; @@ -77,8 +79,6 @@ public class OffloadController { private static final boolean DBG = false; private static final String ANYIP = "0.0.0.0"; private static final ForwardedStats EMPTY_STATS = new ForwardedStats(); - @VisibleForTesting - static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; @VisibleForTesting enum StatsType { @@ -135,11 +135,9 @@ public class OffloadController { private final Dependencies mDeps; // TODO: Put more parameters in constructor into dependency object. - static class Dependencies { - int getPerformPollInterval() { - // TODO: Consider make this configurable. - return DEFAULT_PERFORM_POLL_INTERVAL_MS; - } + interface Dependencies { + @NonNull + TetheringConfiguration getTetherConfig(); } public OffloadController(Handler h, OffloadHardwareInterface hwi, @@ -453,12 +451,16 @@ public class OffloadController { if (mHandler.hasCallbacks(mScheduledPollingTask)) { mHandler.removeCallbacks(mScheduledPollingTask); } - mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval()); + mHandler.postDelayed(mScheduledPollingTask, + mDeps.getTetherConfig().getOffloadPollInterval()); } private boolean isPollingStatsNeeded() { return started() && mRemainingAlertQuota > 0 - && !TextUtils.isEmpty(currentUpstreamInterface()); + && !TextUtils.isEmpty(currentUpstreamInterface()) + && mDeps.getTetherConfig() != null + && mDeps.getTetherConfig().getOffloadPollInterval() + >= DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; } private boolean maybeUpdateDataLimit(String iface) { diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 00b94a8bbf..dbb4506282 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -273,7 +273,13 @@ public class Tethering { mHandler = mTetherMasterSM.getHandler(); mOffloadController = new OffloadController(mHandler, mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(), - statsManager, mLog, new OffloadController.Dependencies()); + statsManager, mLog, new OffloadController.Dependencies() { + + @Override + public TetheringConfiguration getTetherConfig() { + return mConfig; + } + }); mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new LinkedHashSet<>(); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index f71cd211b2..b291438937 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -26,10 +26,10 @@ import static android.net.NetworkStats.UID_TETHERING; import static android.net.RouteInfo.RTN_UNICAST; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; -import static com.android.networkstack.tethering.OffloadController.DEFAULT_PERFORM_POLL_INTERVAL_MS; import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE; import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; +import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals; @@ -109,6 +109,7 @@ public class OffloadControllerTest { @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; @Mock private NetworkStatsManager mStatsManager; + @Mock private TetheringConfiguration mTetherConfig; // Late init since methods must be called by the thread that created this object. private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb; private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider; @@ -120,8 +121,8 @@ public class OffloadControllerTest { private final TestLooper mTestLooper = new TestLooper(); private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() { @Override - int getPerformPollInterval() { - return -1; // Disabled. + public TetheringConfiguration getTetherConfig() { + return mTetherConfig; } }; @@ -133,6 +134,7 @@ public class OffloadControllerTest { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolver); FakeSettingsProvider.clearSettingsProvider(); + when(mTetherConfig.getOffloadPollInterval()).thenReturn(-1); // Disabled. } @After public void tearDown() throws Exception { @@ -153,12 +155,7 @@ public class OffloadControllerTest { } private void setOffloadPollInterval(int interval) { - mDeps = new OffloadController.Dependencies() { - @Override - int getPerformPollInterval() { - return interval; - } - }; + when(mTetherConfig.getOffloadPollInterval()).thenReturn(interval); } private void waitForIdle() { @@ -364,9 +361,9 @@ public class OffloadControllerTest { stacked.setInterfaceName("stacked"); stacked.addLinkAddress(new LinkAddress("192.0.2.129/25")); stacked.addRoute(new RouteInfo(null, InetAddress.getByName("192.0.2.254"), null, - RTN_UNICAST)); + RTN_UNICAST)); stacked.addRoute(new RouteInfo(null, InetAddress.getByName("fe80::bad:f00"), null, - RTN_UNICAST)); + RTN_UNICAST)); assertTrue(lp.addStackedLink(stacked)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). @@ -785,7 +782,7 @@ public class OffloadControllerTest { public void testOnSetAlert() throws Exception { setupFunctioningHardwareInterface(); enableOffload(); - setOffloadPollInterval(DEFAULT_PERFORM_POLL_INTERVAL_MS); + setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); final OffloadController offload = makeOffloadController(); offload.start(); @@ -807,14 +804,14 @@ public class OffloadControllerTest { when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( new ForwardedStats(0, 0)); mTetherStatsProvider.onSetAlert(100); - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); mTetherStatsProviderCb.assertNoCallback(); // Verify that notifyAlertReached fired when quota is reached. when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( new ForwardedStats(50, 50)); - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); mTetherStatsProviderCb.expectNotifyAlertReached(); @@ -822,7 +819,7 @@ public class OffloadControllerTest { // any stats since the polling is stopped. reset(mHardware); mTetherStatsProvider.onSetAlert(NetworkStatsProvider.QUOTA_UNLIMITED); - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); mTetherStatsProviderCb.assertNoCallback(); verify(mHardware, never()).getForwardedStats(any()); From 8bf2e7e05b11e5cfe708feebb60fe91c4bf8ac1f Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 2 Apr 2020 18:47:19 +0800 Subject: [PATCH 1061/1415] Add tether BPF offload config to device config and resource The tether bpf offload can be enabled by resource config and device config. The device config has higher priority and it could override this config which is set by resource config. Bug: 149997301 Test: -build, flash, boot -atest TetheringConfigurationTest Change-Id: I9c26852d2c926786e141ece6da53df3801c049b2 --- Tethering/res/values/config.xml | 6 +++ Tethering/res/values/overlayable.xml | 5 ++ .../tethering/TetheringConfiguration.java | 42 +++++++++++++++-- .../tethering/TetheringConfigurationTest.java | 46 +++++++++++++++++++ 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index c999221963..0ea459a6cf 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -55,6 +55,12 @@ "bt-pan" + + true + false diff --git a/Tethering/res/values/overlayable.xml b/Tethering/res/values/overlayable.xml index 4c78a74d53..288dd5ddf3 100644 --- a/Tethering/res/values/overlayable.xml +++ b/Tethering/res/values/overlayable.xml @@ -23,6 +23,11 @@ + + diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 9d4e747327..91a6e29a05 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -72,6 +72,12 @@ public class TetheringConfiguration { private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; + /** + * Override enabling BPF offload configuration for tethering. + */ + public static final String OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD = + "override_tether_enable_bpf_offload"; + /** * Use the old dnsmasq DHCP server for tethering instead of the framework implementation. */ @@ -95,6 +101,8 @@ public class TetheringConfiguration { public final String[] legacyDhcpRanges; public final String[] defaultIPv4DNS; public final boolean enableLegacyDhcpServer; + // TODO: Add to TetheringConfigurationParcel if required. + public final boolean enableBpfOffload; public final String[] provisioningApp; public final String provisioningAppNoUi; @@ -124,11 +132,12 @@ public class TetheringConfiguration { isDunRequired = checkDunRequired(ctx); chooseUpstreamAutomatically = getResourceBoolean( - res, R.bool.config_tether_upstream_automatic); + res, R.bool.config_tether_upstream_automatic, false /** default value */); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); + enableBpfOffload = getEnableBpfOffload(res); enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); @@ -208,6 +217,9 @@ public class TetheringConfiguration { pw.print("provisioningAppNoUi: "); pw.println(provisioningAppNoUi); + pw.print("enableBpfOffload: "); + pw.println(enableBpfOffload); + pw.print("enableLegacyDhcpServer: "); pw.println(enableLegacyDhcpServer); } @@ -228,6 +240,7 @@ public class TetheringConfiguration { toIntArray(preferredUpstreamIfaceTypes))); sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi)); + sj.add(String.format("enableBpfOffload:%s", enableBpfOffload)); sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer)); return String.format("TetheringConfiguration{%s}", sj.toString()); } @@ -332,11 +345,11 @@ public class TetheringConfiguration { } } - private static boolean getResourceBoolean(Resources res, int resId) { + private static boolean getResourceBoolean(Resources res, int resId, boolean defaultValue) { try { return res.getBoolean(resId); } catch (Resources.NotFoundException e404) { - return false; + return defaultValue; } } @@ -357,8 +370,29 @@ public class TetheringConfiguration { } } + private boolean getEnableBpfOffload(final Resources res) { + // Get BPF offload config + // Priority 1: Device config + // Priority 2: Resource config + // Priority 3: Default value + final boolean resourceValue = getResourceBoolean( + res, R.bool.config_tether_enable_bpf_offload, true /** default value */); + + // Due to the limitation of static mock for testing, using #getProperty directly instead + // of getDeviceConfigBoolean. getDeviceConfigBoolean is not invoked because it uses + // #getBoolean to get the boolean device config. The test can't know that the returned + // boolean value comes from device config or default value (because of null property + // string). Because the test would like to verify null property boolean string case, + // use DeviceConfig.getProperty here. See also the test case testBpfOffload{*} in + // TetheringConfigurationTest.java. + final String value = DeviceConfig.getProperty( + NAMESPACE_CONNECTIVITY, OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD); + return (value != null) ? Boolean.parseBoolean(value) : resourceValue; + } + private boolean getEnableLegacyDhcpServer(final Resources res) { - return getResourceBoolean(res, R.bool.config_tether_enable_legacy_dhcp_server) + return getResourceBoolean( + res, R.bool.config_tether_enable_legacy_dhcp_server, false /** default value */) || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index e8ba5b8168..fbfa871f76 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -127,6 +127,8 @@ public class TetheringConfigurationTest { .thenReturn(new String[0]); when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); + initializeBpfOffloadConfiguration(true, null /* unset */); + mHasTelephonyManager = true; mMockContext = new MockContext(mContext); mEnableLegacyDhcpServer = false; @@ -278,6 +280,50 @@ public class TetheringConfigurationTest { assertFalse(upstreamIterator.hasNext()); } + private void initializeBpfOffloadConfiguration( + final boolean fromRes, final String fromDevConfig) { + when(mResources.getBoolean(R.bool.config_tether_enable_bpf_offload)).thenReturn(fromRes); + doReturn(fromDevConfig).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD))); + } + + @Test + public void testBpfOffloadEnabledByResource() { + initializeBpfOffloadConfiguration(true, null /* unset */); + final TetheringConfiguration enableByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByRes.enableBpfOffload); + } + + @Test + public void testBpfOffloadEnabledByDeviceConfigOverride() { + for (boolean res : new boolean[]{true, false}) { + initializeBpfOffloadConfiguration(res, "true"); + final TetheringConfiguration enableByDevConOverride = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByDevConOverride.enableBpfOffload); + } + } + + @Test + public void testBpfOffloadDisabledByResource() { + initializeBpfOffloadConfiguration(false, null /* unset */); + final TetheringConfiguration disableByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(disableByRes.enableBpfOffload); + } + + @Test + public void testBpfOffloadDisabledByDeviceConfigOverride() { + for (boolean res : new boolean[]{true, false}) { + initializeBpfOffloadConfiguration(res, "false"); + final TetheringConfiguration disableByDevConOverride = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(disableByDevConOverride.enableBpfOffload); + } + } + @Test public void testNewDhcpServerDisabled() { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( From 3d8fa889b42f56c3e858bccbbc545595df5ff5e2 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Sun, 12 Apr 2020 14:27:18 +0800 Subject: [PATCH 1062/1415] Use device option to control BPF offload features If BPF offload device config is not enabled: - Does not add/remove offload forwarding rules through disabling IP neighbor monitor. - Does not apply the RA MTU reduction. Bug: 149997301 Test: atest IpServerTest Change-Id: I2d6f80f0229f580c4b16243a064e889a6c37f77a --- Tethering/src/android/net/ip/IpServer.java | 34 +++++++-- .../networkstack/tethering/Tethering.java | 2 +- .../unit/src/android/net/ip/IpServerTest.java | 71 ++++++++++++++++--- 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 83727bcdc6..ca485f5da5 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -227,6 +227,7 @@ public class IpServer extends StateMachine { private final int mInterfaceType; private final LinkProperties mLinkProperties; private final boolean mUsingLegacyDhcp; + private final boolean mUsingBpfOffload; private final Dependencies mDeps; @@ -304,7 +305,8 @@ public class IpServer extends StateMachine { public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, - INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) { + INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload, + Dependencies deps) { super(ifaceName, looper); mLog = log.forSubComponent(ifaceName); mNetd = netd; @@ -314,6 +316,7 @@ public class IpServer extends StateMachine { mInterfaceType = interfaceType; mLinkProperties = new LinkProperties(); mUsingLegacyDhcp = usingLegacyDhcp; + mUsingBpfOffload = usingBpfOffload; mDeps = deps; resetLinkProperties(); mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; @@ -321,8 +324,15 @@ public class IpServer extends StateMachine { mIpNeighborMonitor = mDeps.getIpNeighborMonitor(getHandler(), mLog, new MyNeighborEventConsumer()); - if (!mIpNeighborMonitor.start()) { - mLog.e("Failed to create IpNeighborMonitor on " + mIfaceName); + + // IP neighbor monitor monitors the neighbor event for adding/removing offload + // forwarding rules per client. If BPF offload is not supported, don't start listening + // neighbor events. See updateIpv6ForwardingRules, addIpv6ForwardingRule, + // removeIpv6ForwardingRule. + if (mUsingBpfOffload) { + if (!mIpNeighborMonitor.start()) { + mLog.e("Failed to create IpNeighborMonitor on " + mIfaceName); + } } mInitialState = new InitialState(); @@ -715,12 +725,12 @@ public class IpServer extends StateMachine { final String upstreamIface = v6only.getInterfaceName(); params = new RaParams(); - // We advertise an mtu lower by 16, which is the closest multiple of 8 >= 14, - // the ethernet header size. This makes kernel ebpf tethering offload happy. - // This hack should be reverted once we have the kernel fixed up. + // When BPF offload is enabled, we advertise an mtu lower by 16, which is the closest + // multiple of 8 >= 14, the ethernet header size. This makes kernel ebpf tethering + // offload happy. This hack should be reverted once we have the kernel fixed up. // Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu) // see RouterAdvertisementDaemon.java putMtu() - params.mtu = v6only.getMtu() - 16; + params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu(); params.hasDefaultRoute = v6only.hasIpv6DefaultRoute(); if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface); @@ -844,6 +854,11 @@ public class IpServer extends StateMachine { } private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) { + // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF + // offload is disabled. Add this check just in case. + // TODO: Perhaps remove this protection check. + if (!mUsingBpfOffload) return; + try { mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel()); mIpv6ForwardingRules.put(rule.address, rule); @@ -853,6 +868,11 @@ public class IpServer extends StateMachine { } private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) { + // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF + // offload is disabled. Add this check just in case. + // TODO: Perhaps remove this protection check. + if (!mUsingBpfOffload) return; + try { mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel()); if (removeFromMap) { diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 00b94a8bbf..a31d5478ee 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -2289,7 +2289,7 @@ public class Tethering { final TetherState tetherState = new TetherState( new IpServer(iface, mLooper, interfaceType, mLog, mNetd, makeControlCallback(), mConfig.enableLegacyDhcpServer, - mDeps.getIpServerDependencies())); + mConfig.enableBpfOffload, mDeps.getIpServerDependencies())); mTetherStates.put(iface, tetherState); tetherState.ipServer.start(); } diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index f9be7b9d36..b9622da9d2 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -106,6 +106,7 @@ public class IpServerTest { private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1"; private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; private static final int DHCP_LEASE_TIME_SECS = 3600; + private static final boolean DEFAULT_USING_BPF_OFFLOAD = true; private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams( IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */); @@ -130,10 +131,11 @@ public class IpServerTest { private NeighborEventConsumer mNeighborEventConsumer; private void initStateMachine(int interfaceType) throws Exception { - initStateMachine(interfaceType, false /* usingLegacyDhcp */); + initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD); } - private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception { + private void initStateMachine(int interfaceType, boolean usingLegacyDhcp, + boolean usingBpfOffload) throws Exception { doAnswer(inv -> { final IDhcpServerCallbacks cb = inv.getArgument(2); new Thread(() -> { @@ -165,7 +167,7 @@ public class IpServerTest { mIpServer = new IpServer( IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, - mCallback, usingLegacyDhcp, mDependencies); + mCallback, usingLegacyDhcp, usingBpfOffload, mDependencies); mIpServer.start(); mNeighborEventConsumer = neighborCaptor.getValue(); @@ -179,12 +181,13 @@ public class IpServerTest { private void initTetheredStateMachine(int interfaceType, String upstreamIface) throws Exception { - initTetheredStateMachine(interfaceType, upstreamIface, false); + initTetheredStateMachine(interfaceType, upstreamIface, false, + DEFAULT_USING_BPF_OFFLOAD); } private void initTetheredStateMachine(int interfaceType, String upstreamIface, - boolean usingLegacyDhcp) throws Exception { - initStateMachine(interfaceType, usingLegacyDhcp); + boolean usingLegacyDhcp, boolean usingBpfOffload) throws Exception { + initStateMachine(interfaceType, usingLegacyDhcp, usingBpfOffload); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); if (upstreamIface != null) { LinkProperties lp = new LinkProperties(); @@ -204,7 +207,8 @@ public class IpServerTest { when(mDependencies.getIpNeighborMonitor(any(), any(), any())) .thenReturn(mIpNeighborMonitor); mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, - mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies); + mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD, + mDependencies); mIpServer.start(); mLooper.dispatchAll(); verify(mCallback).updateInterfaceState( @@ -494,7 +498,8 @@ public class IpServerTest { @Test public void doesNotStartDhcpServerIfDisabled() throws Exception { - initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */); + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */, + DEFAULT_USING_BPF_OFFLOAD); dispatchTetherConnectionChanged(UPSTREAM_IFACE); verify(mDependencies, never()).makeDhcpServer(any(), any(), any()); @@ -577,7 +582,8 @@ public class IpServerTest { @Test public void addRemoveipv6ForwardingRules() throws Exception { - initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */); + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + DEFAULT_USING_BPF_OFFLOAD); final int myIfindex = TEST_IFACE_PARAMS.index; final int notMyIfindex = myIfindex - 1; @@ -678,6 +684,53 @@ public class IpServerTest { reset(mNetd); } + @Test + public void enableDisableUsingBpfOffload() throws Exception { + final int myIfindex = TEST_IFACE_PARAMS.index; + final InetAddress neigh = InetAddresses.parseNumericAddress("2001:db8::1"); + final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); + final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00"); + + reset(mNetd); + + // Expect that rules can be only added/removed when the BPF offload config is enabled. + // Note that the usingBpfOffload false case is not a realistic test case. Because IP + // neighbor monitor doesn't start if BPF offload is disabled, there should have no + // neighbor event listening. This is used for testing the protection check just in case. + // TODO: Perhaps remove this test once we don't need this check anymore. + for (boolean usingBpfOffload : new boolean[]{true, false}) { + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + usingBpfOffload); + + // A neighbor is added. + recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA); + if (usingBpfOffload) { + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA)); + } else { + verify(mNetd, never()).tetherOffloadRuleAdd(any()); + } + reset(mNetd); + + // A neighbor is deleted. + recvDelNeigh(myIfindex, neigh, NUD_STALE, macA); + if (usingBpfOffload) { + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull)); + } else { + verify(mNetd, never()).tetherOffloadRuleRemove(any()); + } + reset(mNetd); + } + } + + @Test + public void doesNotStartIpNeighborMonitorIfBpfOffloadDisabled() throws Exception { + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + false /* usingBpfOffload */); + + // IP neighbor monitor doesn't start if BPF offload is disabled. + verify(mIpNeighborMonitor, never()).start(); + } + private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any()); verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks( From f941ae9c03aec4566785434d08d6e37c376f41b3 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 6 May 2020 14:55:29 +0800 Subject: [PATCH 1063/1415] Tag CtsTetheringTest for sim card required Bug: 155598732 Test: atest CtsTetheringTest Change-Id: I79f841682049707d7cc26bf1ecc3e5affc86d196 --- tests/cts/tethering/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/tethering/AndroidTest.xml b/tests/cts/tethering/AndroidTest.xml index 25051ba55c..d0a2bce811 100644 --- a/tests/cts/tethering/AndroidTest.xml +++ b/tests/cts/tethering/AndroidTest.xml @@ -16,6 +16,7 @@

    If not set, the default value is false. + */ + public DhcpServingParamsParcelExt setChangePrefixOnDecline(boolean changePrefixOnDecline) { + this.changePrefixOnDecline = changePrefixOnDecline; + return this; + } + private static int[] toIntArray(@NonNull Collection addrs) { int[] res = new int[addrs.size()]; int i = 0; diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index d993306b17..de537871a7 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -50,6 +50,7 @@ import android.net.shared.NetdUtils; import android.net.shared.RouteUtils; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; +import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.os.Handler; import android.os.Looper; @@ -60,6 +61,7 @@ import android.util.Log; import android.util.SparseArray; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.internal.util.MessageUtils; import com.android.internal.util.State; @@ -115,6 +117,15 @@ public class IpServer extends StateMachine { private static final String ETHERNET_IFACE_ADDR = "192.168.50.1"; private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24; + // TODO: remove this constant after introducing PrivateAddressCoordinator. + private static final List NCM_PREFIXES = Collections.unmodifiableList( + Arrays.asList( + new IpPrefix("192.168.42.0/24"), + new IpPrefix("192.168.51.0/24"), + new IpPrefix("192.168.52.0/24"), + new IpPrefix("192.168.53.0/24") + )); + // TODO: have PanService use some visible version of this constant private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1"; private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; @@ -212,6 +223,8 @@ public class IpServer extends StateMachine { public static final int CMD_IPV6_TETHER_UPDATE = BASE_IPSERVER + 10; // new neighbor cache entry on our interface public static final int CMD_NEIGHBOR_EVENT = BASE_IPSERVER + 11; + // request from DHCP server that it wants to have a new prefix + public static final int CMD_NEW_PREFIX_REQUEST = BASE_IPSERVER + 12; private final State mInitialState; private final State mLocalHotspotState; @@ -462,7 +475,7 @@ public class IpServer extends StateMachine { handleError(); } } - }, new DhcpLeaseCallback()); + }, new DhcpEventCallback()); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -475,7 +488,7 @@ public class IpServer extends StateMachine { } } - private class DhcpLeaseCallback extends IDhcpEventCallbacks.Stub { + private class DhcpEventCallback extends IDhcpEventCallbacks.Stub { @Override public void onLeasesChanged(List leaseParcelables) { final ArrayList leases = new ArrayList<>(); @@ -509,8 +522,9 @@ public class IpServer extends StateMachine { } @Override - public void onNewPrefixRequest(IpPrefix currentPrefix) { - //TODO: add specific implementation. + public void onNewPrefixRequest(@NonNull final IpPrefix currentPrefix) { + Objects.requireNonNull(currentPrefix); + sendMessage(CMD_NEW_PREFIX_REQUEST, currentPrefix); } @Override @@ -524,26 +538,38 @@ public class IpServer extends StateMachine { } } + private RouteInfo getDirectConnectedRoute(@NonNull final LinkAddress ipv4Address) { + Objects.requireNonNull(ipv4Address); + return new RouteInfo(PrefixUtils.asIpPrefix(ipv4Address), null, mIfaceName, RTN_UNICAST); + } + + private DhcpServingParamsParcel makeServingParams(@NonNull final Inet4Address defaultRouter, + @NonNull final Inet4Address dnsServer, @NonNull LinkAddress serverAddr, + @Nullable Inet4Address clientAddr) { + final boolean changePrefixOnDecline = + (mInterfaceType == TetheringManager.TETHERING_NCM && clientAddr == null); + return new DhcpServingParamsParcelExt() + .setDefaultRouters(defaultRouter) + .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) + .setDnsServers(dnsServer) + .setServerAddr(serverAddr) + .setMetered(true) + .setSingleClientAddr(clientAddr) + .setChangePrefixOnDecline(changePrefixOnDecline); + // TODO: also advertise link MTU + } + private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) { if (mUsingLegacyDhcp) { return true; } final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress(); - final int prefixLen = serverLinkAddr.getPrefixLength(); final Inet4Address clientAddr = clientLinkAddr == null ? null : (Inet4Address) clientLinkAddr.getAddress(); - final DhcpServingParamsParcel params; - params = new DhcpServingParamsParcelExt() - .setDefaultRouters(addr) - .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) - .setDnsServers(addr) - .setServerAddr(serverLinkAddr) - .setMetered(true) - .setSingleClientAddr(clientAddr); - // TODO: also advertise link MTU - + final DhcpServingParamsParcel params = makeServingParams(addr /* defaultRouter */, + addr /* dnsServer */, serverLinkAddr, clientAddr); mDhcpServerStartIndex++; mDeps.makeDhcpServer( mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex)); @@ -570,7 +596,7 @@ public class IpServer extends StateMachine { }); mDhcpServer = null; } catch (RemoteException e) { - mLog.e("Error stopping DHCP", e); + mLog.e("Error stopping DHCP server", e); // Not much more we can do here } } @@ -652,31 +678,33 @@ public class IpServer extends StateMachine { return false; } - // Directly-connected route. - final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), - mIpv4Address.getPrefixLength()); - final RouteInfo route = new RouteInfo(ipv4Prefix, null, null, RTN_UNICAST); if (enabled) { mLinkProperties.addLinkAddress(mIpv4Address); - mLinkProperties.addRoute(route); + mLinkProperties.addRoute(getDirectConnectedRoute(mIpv4Address)); } else { mLinkProperties.removeLinkAddress(mIpv4Address); - mLinkProperties.removeRoute(route); + mLinkProperties.removeRoute(getDirectConnectedRoute(mIpv4Address)); } - return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } - private String getRandomWifiIPv4Address() { + private Inet4Address getRandomIPv4Address(@NonNull final byte[] rawAddr) { + final byte[] ipv4Addr = rawAddr; + ipv4Addr[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF); try { - byte[] bytes = parseNumericAddress(WIFI_HOST_IFACE_ADDR).getAddress(); - bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF); - return InetAddress.getByAddress(bytes).getHostAddress(); - } catch (Exception e) { - return WIFI_HOST_IFACE_ADDR; + return (Inet4Address) InetAddress.getByAddress(ipv4Addr); + } catch (UnknownHostException e) { + mLog.e("Failed to construct Inet4Address from raw IPv4 addr"); + return null; } } + private String getRandomWifiIPv4Address() { + final Inet4Address ipv4Addr = + getRandomIPv4Address(parseNumericAddress(WIFI_HOST_IFACE_ADDR).getAddress()); + return ipv4Addr != null ? ipv4Addr.getHostAddress() : WIFI_HOST_IFACE_ADDR; + } + private boolean startIPv6() { mInterfaceParams = mDeps.getInterfaceParams(mIfaceName); if (mInterfaceParams == null) { @@ -761,21 +789,43 @@ public class IpServer extends StateMachine { mLastIPv6UpstreamIfindex = upstreamIfindex; } + private void removeRoutesFromLocalNetwork(@NonNull final List toBeRemoved) { + final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork( + mNetd, toBeRemoved); + if (removalFailures > 0) { + mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", + removalFailures)); + } + + for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route); + } + + private void addRoutesToLocalNetwork(@NonNull final List toBeAdded) { + try { + // It's safe to call networkAddInterface() even if + // the interface is already in the local_network. + mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName); + try { + // Add routes from local network. Note that adding routes that + // already exist does not cause an error (EEXIST is silently ignored). + RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded); + } catch (IllegalStateException e) { + mLog.e("Failed to add IPv4/v6 routes to local table: " + e); + return; + } + } catch (ServiceSpecificException | RemoteException e) { + mLog.e("Failed to add " + mIfaceName + " to local table: ", e); + return; + } + + for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route); + } + private void configureLocalIPv6Routes( HashSet deprecatedPrefixes, HashSet newPrefixes) { // [1] Remove the routes that are deprecated. if (!deprecatedPrefixes.isEmpty()) { - final ArrayList toBeRemoved = - getLocalRoutesFor(mIfaceName, deprecatedPrefixes); - // Remove routes from local network. - final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork( - mNetd, toBeRemoved); - if (removalFailures > 0) { - mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", - removalFailures)); - } - - for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route); + removeRoutesFromLocalNetwork(getLocalRoutesFor(mIfaceName, deprecatedPrefixes)); } // [2] Add only the routes that have not previously been added. @@ -786,24 +836,7 @@ public class IpServer extends StateMachine { } if (!addedPrefixes.isEmpty()) { - final ArrayList toBeAdded = - getLocalRoutesFor(mIfaceName, addedPrefixes); - try { - // It's safe to call networkAddInterface() even if - // the interface is already in the local_network. - mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName); - try { - // Add routes from local network. Note that adding routes that - // already exist does not cause an error (EEXIST is silently ignored). - RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded); - } catch (IllegalStateException e) { - mLog.e("Failed to add IPv6 routes to local table: " + e); - } - } catch (ServiceSpecificException | RemoteException e) { - mLog.e("Failed to add " + mIfaceName + " to local table: ", e); - } - - for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route); + addRoutesToLocalNetwork(getLocalRoutesFor(mIfaceName, addedPrefixes)); } } } @@ -945,6 +978,80 @@ public class IpServer extends StateMachine { } } + // TODO: call PrivateAddressCoordinator.requestDownstreamAddress instead of this temporary + // logic. + private Inet4Address requestDownstreamAddress(@NonNull final IpPrefix currentPrefix) { + final int oldIndex = NCM_PREFIXES.indexOf(currentPrefix); + if (oldIndex == -1) { + mLog.e("current prefix isn't supported for NCM link: " + currentPrefix); + return null; + } + + final IpPrefix newPrefix = NCM_PREFIXES.get((oldIndex + 1) % NCM_PREFIXES.size()); + return getRandomIPv4Address(newPrefix.getRawAddress()); + } + + private void handleNewPrefixRequest(@NonNull final IpPrefix currentPrefix) { + if (!currentPrefix.contains(mIpv4Address.getAddress()) + || currentPrefix.getPrefixLength() != mIpv4Address.getPrefixLength()) { + Log.e(TAG, "Invalid prefix: " + currentPrefix); + return; + } + + final LinkAddress deprecatedLinkAddress = mIpv4Address; + final Inet4Address srvAddr = requestDownstreamAddress(currentPrefix); + if (srvAddr == null) { + mLog.e("Fail to request a new downstream prefix"); + return; + } + mIpv4Address = new LinkAddress(srvAddr, currentPrefix.getPrefixLength()); + + // Add new IPv4 address on the interface. + if (!mInterfaceCtrl.addAddress(srvAddr, currentPrefix.getPrefixLength())) { + mLog.e("Failed to add new IP " + srvAddr); + return; + } + + // Remove deprecated routes from local network. + removeRoutesFromLocalNetwork( + Collections.singletonList(getDirectConnectedRoute(deprecatedLinkAddress))); + mLinkProperties.removeLinkAddress(deprecatedLinkAddress); + + // Add new routes to local network. + addRoutesToLocalNetwork( + Collections.singletonList(getDirectConnectedRoute(mIpv4Address))); + mLinkProperties.addLinkAddress(mIpv4Address); + + // Update local DNS caching server with new IPv4 address, otherwise, dnsmasq doesn't + // listen on the interface configured with new IPv4 address, that results DNS validation + // failure of downstream client even if appropriate routes have been configured. + try { + mNetd.tetherApplyDnsInterfaces(); + } catch (ServiceSpecificException | RemoteException e) { + mLog.e("Failed to update local DNS caching server"); + return; + } + sendLinkProperties(); + + // Notify DHCP server that new prefix/route has been applied on IpServer. + final Inet4Address clientAddr = mStaticIpv4ClientAddr == null ? null : + (Inet4Address) mStaticIpv4ClientAddr.getAddress(); + final DhcpServingParamsParcel params = makeServingParams(srvAddr /* defaultRouter */, + srvAddr /* dnsServer */, mIpv4Address /* serverLinkAddress */, clientAddr); + try { + mDhcpServer.updateParams(params, new OnHandlerStatusCallback() { + @Override + public void callback(int statusCode) { + if (statusCode != STATUS_SUCCESS) { + mLog.e("Error updating DHCP serving params: " + statusCode); + } + } + }); + } catch (RemoteException e) { + mLog.e("Error updating DHCP serving params", e); + } + } + private byte getHopLimit(String upstreamIface) { try { int upstreamHopLimit = Integer.parseUnsignedInt( @@ -1056,11 +1163,9 @@ public class IpServer extends StateMachine { } try { - final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), - mIpv4Address.getPrefixLength()); - NetdUtils.tetherInterface(mNetd, mIfaceName, ipv4Prefix); + NetdUtils.tetherInterface(mNetd, mIfaceName, PrefixUtils.asIpPrefix(mIpv4Address)); } catch (RemoteException | ServiceSpecificException | IllegalStateException e) { - mLog.e("Error Tethering: " + e); + mLog.e("Error Tethering", e); mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; return; } @@ -1115,6 +1220,9 @@ public class IpServer extends StateMachine { mLastError = TetheringManager.TETHER_ERROR_INTERNAL_ERROR; transitionTo(mInitialState); break; + case CMD_NEW_PREFIX_REQUEST: + handleNewPrefixRequest((IpPrefix) message.obj); + break; default: return false; } diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index b9622da9d2..cd1ff607b4 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -18,6 +18,7 @@ package android.net.ip; import static android.net.INetd.IF_STATE_UP; import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; @@ -38,6 +39,7 @@ import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -67,6 +69,7 @@ import android.net.MacAddress; import android.net.RouteInfo; import android.net.TetherOffloadRuleParcel; import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpEventCallbacks; import android.net.dhcp.IDhcpServer; import android.net.dhcp.IDhcpServerCallbacks; import android.net.ip.IpNeighborMonitor.NeighborEvent; @@ -94,6 +97,7 @@ import org.mockito.MockitoAnnotations; import java.net.Inet4Address; import java.net.InetAddress; import java.util.Arrays; +import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest @@ -496,6 +500,59 @@ public class IpServerTest { assertDhcpStarted(new IpPrefix("192.168.49.0/24")); } + @Test + public void startsDhcpServerOnNcm() throws Exception { + initStateMachine(TETHERING_NCM); + dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); + dispatchTetherConnectionChanged(UPSTREAM_IFACE); + + assertDhcpStarted(new IpPrefix("192.168.42.0/24")); + } + + @Test + public void testOnNewPrefixRequest() throws Exception { + initStateMachine(TETHERING_NCM); + dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); + + final IDhcpEventCallbacks eventCallbacks; + final ArgumentCaptor dhcpEventCbsCaptor = + ArgumentCaptor.forClass(IDhcpEventCallbacks.class); + verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks( + any(), dhcpEventCbsCaptor.capture()); + eventCallbacks = dhcpEventCbsCaptor.getValue(); + assertDhcpStarted(new IpPrefix("192.168.42.0/24")); + + // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals + // onNewPrefixRequest callback. + eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); + mLooper.dispatchAll(); + + final ArgumentCaptor lpCaptor = + ArgumentCaptor.forClass(LinkProperties.class); + InOrder inOrder = inOrder(mNetd, mCallback); + inOrder.verify(mCallback).updateInterfaceState( + mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR); + inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); + inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); + // One for ipv4 route, one for ipv6 link local route. + inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), + any(), any()); + inOrder.verify(mNetd).tetherApplyDnsInterfaces(); + inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); + verifyNoMoreInteractions(mCallback); + + final LinkProperties linkProperties = lpCaptor.getValue(); + final List linkAddresses = linkProperties.getLinkAddresses(); + assertEquals(1, linkProperties.getLinkAddresses().size()); + assertEquals(1, linkProperties.getRoutes().size()); + final IpPrefix prefix = new IpPrefix(linkAddresses.get(0).getAddress(), + linkAddresses.get(0).getPrefixLength()); + assertNotEquals(prefix, new IpPrefix("192.168.42.0/24")); + + verify(mDhcpServer).updateParams(mDhcpParamsCaptor.capture(), any()); + assertDhcpServingParams(mDhcpParamsCaptor.getValue(), prefix); + } + @Test public void doesNotStartDhcpServerIfDisabled() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */, @@ -731,19 +788,26 @@ public class IpServerTest { verify(mIpNeighborMonitor, never()).start(); } - private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { - verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any()); - verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks( - any(), any()); - final DhcpServingParamsParcel params = mDhcpParamsCaptor.getValue(); + private void assertDhcpServingParams(final DhcpServingParamsParcel params, + final IpPrefix prefix) { // Last address byte is random - assertTrue(expectedPrefix.contains(intToInet4AddressHTH(params.serverAddr))); - assertEquals(expectedPrefix.getPrefixLength(), params.serverAddrPrefixLength); + assertTrue(prefix.contains(intToInet4AddressHTH(params.serverAddr))); + assertEquals(prefix.getPrefixLength(), params.serverAddrPrefixLength); assertEquals(1, params.defaultRouters.length); assertEquals(params.serverAddr, params.defaultRouters[0]); assertEquals(1, params.dnsServers.length); assertEquals(params.serverAddr, params.dnsServers[0]); assertEquals(DHCP_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs); + if (mIpServer.interfaceType() == TETHERING_NCM) { + assertTrue(params.changePrefixOnDecline); + } + } + + private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { + verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any()); + verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks( + any(), any()); + assertDhcpServingParams(mDhcpParamsCaptor.getValue(), expectedPrefix); } /** From bd2cbe6c736237926b7bb69926a176ccc9738351 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 12 May 2020 00:08:27 +0800 Subject: [PATCH 1085/1415] Make members final in TetheringService 1. Move isTetheringSupport logic from TetheringService to Tethering. 2. Small readability improvement in TetheringTest. Also change config_tether_upstream_automatic from false to true in TetheringTest. So TetheringTests would default run automatic select upstream flow instead of selecting by legacy perferred network type list. Bug: 153609486 Test: atest TetheringTest Change-Id: I5a82a6347f62d3a7031db5c56e8e0c8530dafd8f Merged-In: I5a82a6347f62d3a7031db5c56e8e0c8530dafd8f (cherry picked from commit 569870320a0c468609ddd7d96dae1b5845b99205) --- .../networkstack/tethering/Tethering.java | 36 +++- .../tethering/TetheringService.java | 187 +++++++----------- .../tethering/TetheringServiceTest.java | 19 +- .../networkstack/tethering/TetheringTest.java | 56 +++--- 4 files changed, 140 insertions(+), 158 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 2a5e6200e5..04ad43f6e2 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -109,8 +109,10 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceSpecificException; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -228,6 +230,7 @@ public class Tethering { private final ConnectedClientsTracker mConnectedClientsTracker; private final TetheringThreadExecutor mExecutor; private final TetheringNotificationUpdater mNotificationUpdater; + private final UserManager mUserManager; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; // All the usage of mTetheringEventCallback should run in the same thread. private ITetheringEventCallback mTetheringEventCallback = null; @@ -305,23 +308,24 @@ public class Tethering { mStateReceiver = new StateReceiver(); - final UserManager userManager = (UserManager) mContext.getSystemService( - Context.USER_SERVICE); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mTetheringRestriction = new UserRestrictionActionListener( - userManager, this, mNotificationUpdater); + mUserManager, this, mNotificationUpdater); mExecutor = new TetheringThreadExecutor(mHandler); mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor); mNetdCallback = new NetdCallback(); // Load tethering configuration. updateConfiguration(); + + startStateMachineUpdaters(); } /** * Start to register callbacks. * Call this function when tethering is ready to handle callback events. */ - public void startStateMachineUpdaters() { + private void startStateMachineUpdaters() { try { mNetd.registerUnsolicitedEventListener(mNetdCallback); } catch (RemoteException e) { @@ -779,7 +783,7 @@ public class Tethering { // TODO: Figure out how to update for local hotspot mode interfaces. private void sendTetherStateChangedBroadcast() { - if (!mDeps.isTetheringSupported()) return; + if (!isTetheringSupported()) return; final ArrayList availableList = new ArrayList<>(); final ArrayList tetherList = new ArrayList<>(); @@ -1020,14 +1024,14 @@ public class Tethering { @VisibleForTesting protected static class UserRestrictionActionListener { - private final UserManager mUserManager; + private final UserManager mUserMgr; private final Tethering mWrapper; private final TetheringNotificationUpdater mNotificationUpdater; public boolean mDisallowTethering; public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper, @NonNull TetheringNotificationUpdater updater) { - mUserManager = um; + mUserMgr = um; mWrapper = wrapper; mNotificationUpdater = updater; mDisallowTethering = false; @@ -1037,7 +1041,7 @@ public class Tethering { // getUserRestrictions gets restriction for this process' user, which is the primary // user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary // user. See UserManager.DISALLOW_CONFIG_TETHERING. - final Bundle restrictions = mUserManager.getUserRestrictions(); + final Bundle restrictions = mUserMgr.getUserRestrictions(); final boolean newlyDisallowed = restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING); final boolean prevDisallowed = mDisallowTethering; @@ -1988,7 +1992,7 @@ public class Tethering { mHandler.post(() -> { mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission)); final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel(); - parcel.tetheringSupported = mDeps.isTetheringSupported(); + parcel.tetheringSupported = isTetheringSupported(); parcel.upstreamNetwork = mTetherUpstream; parcel.config = mConfig.toStableParcelable(); parcel.states = @@ -2111,6 +2115,20 @@ public class Tethering { } } + // if ro.tether.denied = true we default to no tethering + // gservices could set the secure setting to 1 though to enable it on a build where it + // had previously been turned off. + boolean isTetheringSupported() { + final int defaultVal = + SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1; + final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.TETHER_SUPPORTED, defaultVal) != 0; + final boolean tetherEnabledInSettings = tetherSupported + && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); + + return tetherEnabledInSettings && hasTetherableConfiguration(); + } + void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { // Binder.java closes the resource for us. @SuppressWarnings("resource") diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java index af349f2b92..7d01273842 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -40,15 +40,12 @@ import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.ip.IpServer; -import android.net.util.SharedLog; import android.os.Binder; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.ResultReceiver; -import android.os.SystemProperties; -import android.os.UserManager; import android.provider.Settings; import android.util.Log; @@ -68,21 +65,14 @@ import java.io.PrintWriter; public class TetheringService extends Service { private static final String TAG = TetheringService.class.getSimpleName(); - private final SharedLog mLog = new SharedLog(TAG); private TetheringConnector mConnector; - private Context mContext; - private TetheringDependencies mDeps; - private Tethering mTethering; - private UserManager mUserManager; @Override public void onCreate() { - mLog.mark("onCreate"); - mDeps = getTetheringDependencies(); - mContext = mDeps.getContext(); - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - mTethering = makeTethering(mDeps); - mTethering.startStateMachineUpdaters(); + final TetheringDependencies deps = makeTetheringDependencies(); + // The Tethering object needs a fully functional context to start, so this can't be done + // in the constructor. + mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this); } /** @@ -94,21 +84,10 @@ public class TetheringService extends Service { return new Tethering(deps); } - /** - * Create a binder connector for the system server to communicate with the tethering. - */ - private synchronized IBinder makeConnector() { - if (mConnector == null) { - mConnector = new TetheringConnector(mTethering, TetheringService.this); - } - return mConnector; - } - @NonNull @Override public IBinder onBind(Intent intent) { - mLog.mark("onBind"); - return makeConnector(); + return mConnector; } private static class TetheringConnector extends ITetheringConnector.Stub { @@ -248,7 +227,7 @@ public class TetheringService extends Service { listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); return true; } - if (!mService.isTetheringSupported()) { + if (!mTethering.isTetheringSupported()) { listener.onResult(TETHER_ERROR_UNSUPPORTED); return true; } @@ -266,7 +245,7 @@ public class TetheringService extends Service { receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null); return true; } - if (!mService.isTetheringSupported()) { + if (!mTethering.isTetheringSupported()) { receiver.send(TETHER_ERROR_UNSUPPORTED, null); return true; } @@ -300,20 +279,6 @@ public class TetheringService extends Service { } } - // if ro.tether.denied = true we default to no tethering - // gservices could set the secure setting to 1 though to enable it on a build where it - // had previously been turned off. - private boolean isTetheringSupported() { - final int defaultVal = - SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1; - final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.TETHER_SUPPORTED, defaultVal) != 0; - final boolean tetherEnabledInSettings = tetherSupported - && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); - - return tetherEnabledInSettings && mTethering.hasTetherableConfiguration(); - } - /** * Check if the package is a allowed to write settings. This also accounts that such an access * happened. @@ -332,87 +297,79 @@ public class TetheringService extends Service { * An injection method for testing. */ @VisibleForTesting - public TetheringDependencies getTetheringDependencies() { - if (mDeps == null) { - mDeps = new TetheringDependencies() { - @Override - public NetworkRequest getDefaultNetworkRequest() { - // TODO: b/147280869, add a proper system API to replace this. - final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder() - .clearCapabilities() - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - return trackDefaultRequest; - } + public TetheringDependencies makeTetheringDependencies() { + return new TetheringDependencies() { + @Override + public NetworkRequest getDefaultNetworkRequest() { + // TODO: b/147280869, add a proper system API to replace this. + final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder() + .clearCapabilities() + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + return trackDefaultRequest; + } - @Override - public Looper getTetheringLooper() { - final HandlerThread tetherThread = new HandlerThread("android.tethering"); - tetherThread.start(); - return tetherThread.getLooper(); - } + @Override + public Looper getTetheringLooper() { + final HandlerThread tetherThread = new HandlerThread("android.tethering"); + tetherThread.start(); + return tetherThread.getLooper(); + } - @Override - public boolean isTetheringSupported() { - return TetheringService.this.isTetheringSupported(); - } + @Override + public Context getContext() { + return TetheringService.this; + } - @Override - public Context getContext() { - return TetheringService.this; - } + @Override + public IpServer.Dependencies getIpServerDependencies() { + return new IpServer.Dependencies() { + @Override + public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, + DhcpServerCallbacks cb) { + try { + final INetworkStackConnector service = getNetworkStackConnector(); + if (service == null) return; - @Override - public IpServer.Dependencies getIpServerDependencies() { - return new IpServer.Dependencies() { - @Override - public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, - DhcpServerCallbacks cb) { + service.makeDhcpServer(ifName, params, cb); + } catch (RemoteException e) { + Log.e(TAG, "Fail to make dhcp server"); try { - final INetworkStackConnector service = getNetworkStackConnector(); - if (service == null) return; - - service.makeDhcpServer(ifName, params, cb); - } catch (RemoteException e) { - Log.e(TAG, "Fail to make dhcp server"); - try { - cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); - } catch (RemoteException re) { } - } + cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); + } catch (RemoteException re) { } } - }; - } - - // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring - // networkStackClient. - static final int NETWORKSTACK_TIMEOUT_MS = 60_000; - private INetworkStackConnector getNetworkStackConnector() { - IBinder connector; - try { - final long before = System.currentTimeMillis(); - while ((connector = NetworkStack.getService()) == null) { - if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { - Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); - return null; - } - Thread.sleep(200); - } - } catch (InterruptedException e) { - Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector"); - return null; } - return INetworkStackConnector.Stub.asInterface(connector); - } + }; + } - @Override - public BluetoothAdapter getBluetoothAdapter() { - return BluetoothAdapter.getDefaultAdapter(); + // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring + // networkStackClient. + static final int NETWORKSTACK_TIMEOUT_MS = 60_000; + private INetworkStackConnector getNetworkStackConnector() { + IBinder connector; + try { + final long before = System.currentTimeMillis(); + while ((connector = NetworkStack.getService()) == null) { + if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { + Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); + return null; + } + Thread.sleep(200); + } + } catch (InterruptedException e) { + Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector"); + return null; } - }; - } - return mDeps; + return INetworkStackConnector.Stub.asInterface(connector); + } + + @Override + public BluetoothAdapter getBluetoothAdapter() { + return BluetoothAdapter.getDefaultAdapter(); + } + }; } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index 7df9fc6850..3dc6a1300d 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -83,8 +83,7 @@ public final class TetheringServiceTest { mTetheringConnector = mockConnector.getTetheringConnector(); final MockTetheringService service = mockConnector.getService(); mTethering = service.getTethering(); - verify(mTethering).startStateMachineUpdaters(); - when(mTethering.hasTetherableConfiguration()).thenReturn(true); + when(mTethering.isTetheringSupported()).thenReturn(true); } @After @@ -97,7 +96,7 @@ public final class TetheringServiceTest { when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).tether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -109,7 +108,7 @@ public final class TetheringServiceTest { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).untether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -121,7 +120,7 @@ public final class TetheringServiceTest { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).setUsbTethering(true /* enable */); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -133,7 +132,7 @@ public final class TetheringServiceTest { final TetheringRequestParcel request = new TetheringRequestParcel(); request.tetheringType = TETHERING_WIFI; mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).startTethering(eq(request), eq(result)); verifyNoMoreInteractions(mTethering); } @@ -143,7 +142,7 @@ public final class TetheringServiceTest { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).stopTethering(TETHERING_WIFI); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -154,7 +153,7 @@ public final class TetheringServiceTest { final ResultReceiver result = new ResultReceiver(null); mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI), eq(result), eq(true) /* showEntitlementUi */); verifyNoMoreInteractions(mTethering); @@ -181,7 +180,7 @@ public final class TetheringServiceTest { public void testStopAllTethering() throws Exception { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).untetherAll(); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -191,7 +190,7 @@ public final class TetheringServiceTest { public void testIsTetheringSupported() throws Exception { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 2bd8ae0288..00174e6d8b 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -485,18 +485,6 @@ public class TetheringTest { MockitoAnnotations.initMocks(this); when(mResources.getStringArray(R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); - when(mResources.getStringArray(R.array.config_tether_usb_regexs)) - .thenReturn(new String[] { "test_rndis\\d" }); - when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) - .thenReturn(new String[]{ "test_wlan\\d" }); - when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) - .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" }); - when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) - .thenReturn(new String[0]); - when(mResources.getStringArray(R.array.config_tether_ncm_regexs)) - .thenReturn(new String[] { "test_ncm\\d" }); - when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); - when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false); when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); when(mNetd.interfaceGetList()) @@ -515,6 +503,7 @@ public class TetheringTest { mServiceContext = new TestContext(mContext); mContentResolver = new MockContentResolver(mServiceContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + setTetheringSupported(true /* supported */); mIntents = new Vector<>(); mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -525,7 +514,6 @@ public class TetheringTest { mServiceContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_TETHER_STATE_CHANGED)); mTethering = makeTethering(); - mTethering.startStateMachineUpdaters(); verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any()); verify(mNetd).registerUnsolicitedEventListener(any()); final ArgumentCaptor phoneListenerCaptor = @@ -536,6 +524,31 @@ public class TetheringTest { mPhoneStateListener = phoneListenerCaptor.getValue(); } + private void setTetheringSupported(final boolean supported) { + Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED, + supported ? 1 : 0); + when(mUserManager.hasUserRestriction( + UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(!supported); + // Setup tetherable configuration. + when(mResources.getStringArray(R.array.config_tether_usb_regexs)) + .thenReturn(new String[] { "test_rndis\\d" }); + when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) + .thenReturn(new String[]{ "test_wlan\\d" }); + when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) + .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" }); + when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) + .thenReturn(new String[0]); + when(mResources.getStringArray(R.array.config_tether_ncm_regexs)) + .thenReturn(new String[] { "test_ncm\\d" }); + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); + when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true); + } + + private void initTetheringUpstream(UpstreamNetworkState upstreamState) { + when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); + when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState); + } + private Tethering makeTethering() { mTetheringDependencies.reset(); return new Tethering(mTetheringDependencies); @@ -672,9 +685,7 @@ public class TetheringTest { } private void prepareUsbTethering(UpstreamNetworkState upstreamState) { - when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) - .thenReturn(upstreamState); + initTetheringUpstream(upstreamState); // Emulate pressing the USB tethering button in Settings UI. mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null); @@ -700,7 +711,7 @@ public class TetheringTest { verify(mNetd, times(1)).interfaceGetList(); // UpstreamNetworkMonitor should receive selected upstream - verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any()); + verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream(); verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network); } @@ -872,8 +883,7 @@ public class TetheringTest { // Then 464xlat comes up upstreamState = buildMobile464xlatUpstreamState(); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) - .thenReturn(upstreamState); + initTetheringUpstream(upstreamState); // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES. mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage( @@ -1344,9 +1354,7 @@ public class TetheringTest { callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); // 2. Enable wifi tethering. UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); - when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) - .thenReturn(upstreamState); + initTetheringUpstream(upstreamState); when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true); mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true); mLooper.dispatchAll(); @@ -1723,7 +1731,7 @@ public class TetheringTest { final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM) mTetheringDependencies.mUpstreamNetworkMonitorMasterSM; final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState); + initTetheringUpstream(upstreamState); stateMachine.chooseUpstreamType(true); verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network)); @@ -1735,7 +1743,7 @@ public class TetheringTest { final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM) mTetheringDependencies.mUpstreamNetworkMonitorMasterSM; final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState); + initTetheringUpstream(upstreamState); stateMachine.chooseUpstreamType(true); stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState); From 74174690d1014242ce48b1cfb140aa2d4ce13be9 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 14 May 2020 11:04:00 +0800 Subject: [PATCH 1086/1415] Fix READ_DEVICE_CONFIG permission denied problem in TetheringTests Bug: 156557122 Test: atest TetheringTests Change-Id: Id9c0397306f3872fc23520d1354f338035a96dc9 --- .../tethering/TetheringConfiguration.java | 33 ++++++++++--------- .../tethering/EntitlementManagerTest.java | 5 ++- .../tethering/TetheringConfigurationTest.java | 25 +++++++------- .../networkstack/tethering/TetheringTest.java | 4 +-- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 91a6e29a05..48a600dfe6 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -132,7 +132,7 @@ public class TetheringConfiguration { isDunRequired = checkDunRequired(ctx); chooseUpstreamAutomatically = getResourceBoolean( - res, R.bool.config_tether_upstream_automatic, false /** default value */); + res, R.bool.config_tether_upstream_automatic, false /** defaultValue */); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); legacyDhcpRanges = getLegacyDhcpRanges(res); @@ -375,30 +375,31 @@ public class TetheringConfiguration { // Priority 1: Device config // Priority 2: Resource config // Priority 3: Default value - final boolean resourceValue = getResourceBoolean( + final boolean defaultValue = getResourceBoolean( res, R.bool.config_tether_enable_bpf_offload, true /** default value */); - // Due to the limitation of static mock for testing, using #getProperty directly instead - // of getDeviceConfigBoolean. getDeviceConfigBoolean is not invoked because it uses - // #getBoolean to get the boolean device config. The test can't know that the returned - // boolean value comes from device config or default value (because of null property - // string). Because the test would like to verify null property boolean string case, - // use DeviceConfig.getProperty here. See also the test case testBpfOffload{*} in - // TetheringConfigurationTest.java. - final String value = DeviceConfig.getProperty( - NAMESPACE_CONNECTIVITY, OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD); - return (value != null) ? Boolean.parseBoolean(value) : resourceValue; + return getDeviceConfigBoolean(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, defaultValue); } private boolean getEnableLegacyDhcpServer(final Resources res) { return getResourceBoolean( - res, R.bool.config_tether_enable_legacy_dhcp_server, false /** default value */) - || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER); + res, R.bool.config_tether_enable_legacy_dhcp_server, false /** defaultValue */) + || getDeviceConfigBoolean( + TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */); + } + + private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) { + // Due to the limitation of static mock for testing, using #getDeviceConfigProperty instead + // of DeviceConfig#getBoolean. If using #getBoolean here, the test can't know that the + // returned boolean value comes from device config or default value (because of null + // property string). See the test case testBpfOffload{*} in TetheringConfigurationTest.java. + final String value = getDeviceConfigProperty(name); + return value != null ? Boolean.parseBoolean(value) : defaultValue; } @VisibleForTesting - protected boolean getDeviceConfigBoolean(final String name) { - return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, false /** defaultValue */); + protected String getDeviceConfigProperty(String name) { + return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name); } private Resources getResources(Context ctx, int subId) { diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java index cdd0e243e3..72fa916b9e 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java @@ -147,9 +147,8 @@ public final class EntitlementManagerTest { doReturn(false).when( () -> SystemProperties.getBoolean( eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean())); - doReturn(false).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn(null).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), anyString())); when(mResources.getStringArray(R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index fbfa871f76..1999ad786e 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -30,7 +30,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.when; @@ -109,9 +108,9 @@ public class TetheringConfigurationTest { .mockStatic(DeviceConfig.class) .strictness(Strictness.WARN) .startMocking(); - doReturn(false).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn(null).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn( new String[0]); @@ -328,9 +327,9 @@ public class TetheringConfigurationTest { public void testNewDhcpServerDisabled() { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( true); - doReturn(false).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn("false").when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); final TetheringConfiguration enableByRes = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -338,9 +337,9 @@ public class TetheringConfigurationTest { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); - doReturn(true).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn("true").when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); final TetheringConfiguration enableByDevConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -351,9 +350,9 @@ public class TetheringConfigurationTest { public void testNewDhcpServerEnabled() { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); - doReturn(false).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn("false").when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index b665acc271..7734a3c61e 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -312,8 +312,8 @@ public class TetheringTest { } @Override - protected boolean getDeviceConfigBoolean(final String name) { - return false; + protected String getDeviceConfigProperty(final String name) { + return null; } @Override From b816d1a932a49cc3a1def84d48e753ef60ddd42f Mon Sep 17 00:00:00 2001 From: Jay Aliomer Date: Wed, 15 Apr 2020 19:00:28 -0400 Subject: [PATCH 1087/1415] Adding UiModeManager Custom Tests Added tests for setting custom time Fixes: 153352890 Test: atest UiModeManagerTest Change-Id: Id25e57d752779f3ab6a9d76fb4a8aa425967c316 From 30e4e9a202429c4a63b21fb5779d0a16f3d41cfb Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Fri, 15 May 2020 02:35:01 +0000 Subject: [PATCH 1088/1415] Address aosp/1272946 leftover comment Verify that entitlement check bypass with TETHER_ERROR_NO_ERROR response. Bug: 152829363 Test: atests CtsTetheringTest Change-Id: I6272d7b297bdf0e641612a09ffe12942cc2b42e1 Merged-In: I6272d7b297bdf0e641612a09ffe12942cc2b42e1 (cherry picked from commit 92133d472ffbe6301db00c93060d76d90cdd02d2, aosp/1307453) --- .../tethering/cts/TetheringManagerTest.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index bbb9403334..8665c7ed5e 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -26,7 +26,6 @@ import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; -import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; @@ -59,7 +58,10 @@ import android.net.TetheringManager.TetheringRequest; import android.net.cts.util.CtsNetUtils; import android.net.wifi.WifiManager; import android.os.Bundle; +import android.os.PersistableBundle; import android.os.ResultReceiver; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import androidx.annotation.NonNull; @@ -676,6 +678,26 @@ public class TetheringManagerTest { mTM.requestLatestTetheringEntitlementResult( TETHERING_WIFI, false, c -> c.run(), null); } catch (IllegalArgumentException expect) { } + + // Override carrier config to ignore entitlement check. + final PersistableBundle bundle = new PersistableBundle(); + bundle.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, false); + overrideCarrierConfig(bundle); + + // Verify that requestLatestTetheringEntitlementResult() can get entitlement + // result TETHER_ERROR_NO_ERROR due to provisioning bypassed. + assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI, false, c -> c.run(), listener), TETHER_ERROR_NO_ERROR); + + // Reset carrier config. + overrideCarrierConfig(null); + } + + private void overrideCarrierConfig(PersistableBundle bundle) { + final CarrierConfigManager configManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + configManager.overrideConfig(subId, bundle); } @Test From fb735de0e87b41a4bddf53043796ab2a01101466 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Sat, 11 Apr 2020 02:56:37 +0800 Subject: [PATCH 1089/1415] Fix flaky test for DnsResolverTest It's possible that private DNS setting is not in the state we expected when we tried to enable strict mode during tests. The problem here is that there are 2 setting Uris(mode and specifier) relating to strict mode, each of them might trigger private DNS setting changing evnet in ConnectivityService. Previously, we tried to enable strict mode with first set private DNS mode and then private DNS specifier. This may result in 2 consecutive private DNS changes events with very short intervals, which caused conflicts between DnsResolver / NetworkMonitor and lead to flaky tests. So 1. Change the order (mode and specifier) for enabling strict mode. 2. Change private DNS mode only when needed. (If original mode is "hostname", then we only need to set specifier) Bug: 153624005 Bug: 153624702 Test: atest DnsResolverTest --rerun-until-failure 100 Change-Id: Iaed6285677f74a5ee6cc6684534ddc0758b25974 --- .../src/android/net/cts/DnsResolverTest.java | 35 +++--------- .../android/net/cts/MultinetworkApiTest.java | 23 ++------ .../android/net/cts/util/CtsNetUtils.java | 53 ++++++++++++++++--- 3 files changed, 57 insertions(+), 54 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 1cc49f900a..28753ffc41 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -86,7 +86,6 @@ public class DnsResolverTest extends AndroidTestCase { static final int CANCEL_RETRY_TIMES = 5; static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; - static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; private ContentResolver mCR; private ConnectivityManager mCM; @@ -107,32 +106,15 @@ public class DnsResolverTest extends AndroidTestCase { mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - storePrivateDnsSetting(); + mCtsNetUtils.storePrivateDnsSetting(); } @Override protected void tearDown() throws Exception { - restorePrivateDnsSetting(); + mCtsNetUtils.restorePrivateDnsSetting(); super.tearDown(); } - private void storePrivateDnsSetting() { - // Store private DNS setting - mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - private void restorePrivateDnsSetting() throws InterruptedException { - // restore private DNS setting - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); - if ("hostname".equals(mOldMode)) { - Settings.Global.putString( - mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); - mCtsNetUtils.awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", - mCM.getActiveNetwork(), mOldDnsSpecifier, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); - } - } - private static String byteArrayToHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int i = 0; i < bytes.length; ++i) { @@ -416,16 +398,13 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { final Network networkForPrivateDns = (network != null) ? network : mCM.getActiveNetwork(); assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, - PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, true); final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, executor, null, callback); @@ -688,9 +667,7 @@ public class DnsResolverTest extends AndroidTestCase { final Network[] testNetworks = getTestableNetworks(); // Set an invalid private DNS server - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(INVALID_PRIVATE_DNS_SERVER); final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; for (Network network : testNetworks) { // This test cannot be ran with null network because we need to explicitly pass a @@ -699,7 +676,7 @@ public class DnsResolverTest extends AndroidTestCase { // wait for private DNS setting propagating mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, false); + network, INVALID_PRIVATE_DNS_SERVER, false); final CountDownLatch latch = new CountDownLatch(1); final DnsResolver.Callback> errorCallback = diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index f123187d86..985e313a92 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -41,7 +41,6 @@ public class MultinetworkApiTest extends AndroidTestCase { private static final String TAG = "MultinetworkNativeApiTest"; static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; - static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; /** * @return 0 on success @@ -69,7 +68,7 @@ public class MultinetworkApiTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - storePrivateDnsSetting(); + mCtsNetUtils.storePrivateDnsSetting(); } @Override @@ -77,18 +76,6 @@ public class MultinetworkApiTest extends AndroidTestCase { super.tearDown(); } - private void storePrivateDnsSetting() { - // Store private DNS setting - mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - private void restorePrivateDnsSetting() { - // restore private DNS setting - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); - } - private Network[] getTestableNetworks() { final ArrayList testableNetworks = new ArrayList(); for (Network network : mCM.getAllNetworks()) { @@ -239,17 +226,15 @@ public class MultinetworkApiTest extends AndroidTestCase { // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 try { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { // Wait for private DNS setting to propagate. mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", - network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + network, GOOGLE_PRIVATE_DNS_SERVER, true); runResNnxDomainCheck(network.getNetworkHandle()); } } finally { - restorePrivateDnsSetting(); + mCtsNetUtils.restorePrivateDnsSetting(); } } } 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 824146fedf..df2de4f057 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 @@ -28,6 +28,7 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; @@ -39,6 +40,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.wifi.WifiManager; +import android.provider.Settings; import android.system.Os; import android.system.OsConstants; import android.util.Log; @@ -58,7 +60,9 @@ public final class CtsNetUtils { private static final int DURATION = 10000; private static final int SOCKET_TIMEOUT_MS = 2000; private static final int PRIVATE_DNS_PROBE_MS = 1_000; + private static final int PRIVATE_DNS_INTERVAL_MS = 500; + public static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; public static final int HTTP_PORT = 80; public static final String TEST_HOST = "connectivitycheck.gstatic.com"; public static final String HTTP_REQUEST = @@ -69,15 +73,19 @@ public final class CtsNetUtils { public static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; - private Context mContext; - private ConnectivityManager mCm; - private WifiManager mWifiManager; + private final Context mContext; + private final ConnectivityManager mCm; + private final ContentResolver mCR; + private final WifiManager mWifiManager; private TestNetworkCallback mCellNetworkCallback; + private String mOldPrivateDnsMode; + private String mOldPrivateDnsSpecifier; public CtsNetUtils(Context context) { mContext = context; mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mCR = context.getContentResolver(); } // Toggle WiFi twice, leaving it in the state it started in @@ -249,9 +257,42 @@ public final class CtsNetUtils { return s; } + public void storePrivateDnsSetting() { + // Store private DNS setting + mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldPrivateDnsSpecifier = Settings.Global.getString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER); + } + + public void restorePrivateDnsSetting() throws InterruptedException { + if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) { + return; + } + // restore private DNS setting + if ("hostname".equals(mOldPrivateDnsMode)) { + setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); + awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", + mCm.getActiveNetwork(), + mOldPrivateDnsSpecifier, true); + } else { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + } + } + + public void setPrivateDnsStrictMode(String server) { + // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures + // that if the previous private DNS mode was not "hostname", the system only sees one + // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two. + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server); + final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER. + if (!"hostname".equals(mode)) { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + } + } + public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, - @NonNull String server, int timeoutMs, - boolean requiresValidatedServers) throws InterruptedException { + @NonNull String server, boolean requiresValidatedServers) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); NetworkCallback callback = new NetworkCallback() { @@ -266,7 +307,7 @@ public final class CtsNetUtils { } }; mCm.registerNetworkCallback(request, callback); - assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS)); + assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); mCm.unregisterNetworkCallback(callback); // Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do // this, then the test could complete before the NetworkMonitor private DNS probe From 66c5773f791832a9ad01a796813d38d8b13f35c9 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Tue, 3 Mar 2020 17:02:12 -0800 Subject: [PATCH 1090/1415] Ensure airplane mode is off. If the device is put into airplane mode before the network tests run, the tests fail. This ensures that airplane mode is off before the tests run. Bug: 150788500 Test: atest CtsHostsideNetworkTests Change-Id: I7a84be751e5e9efb534d48c6d8ff457875ebe716 --- .../cts/net/NetworkPolicyTestsPreparer.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java b/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java index b0facec119..23aca24788 100644 --- a/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java +++ b/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java @@ -23,6 +23,7 @@ import com.android.tradefed.targetprep.ITargetPreparer; public class NetworkPolicyTestsPreparer implements ITargetPreparer { private ITestDevice mDevice; + private boolean mOriginalAirplaneModeEnabled; private String mOriginalAppStandbyEnabled; private String mOriginalBatteryStatsConstants; private final static String KEY_STABLE_CHARGING_DELAY_MS = "battery_charged_delay_ms"; @@ -39,15 +40,29 @@ public class NetworkPolicyTestsPreparer implements ITargetPreparer { setBatteryStatsConstants( KEY_STABLE_CHARGING_DELAY_MS + "=" + DESIRED_STABLE_CHARGING_DELAY_MS); LogUtil.CLog.d("Original battery_saver_constants: " + mOriginalBatteryStatsConstants); + + mOriginalAirplaneModeEnabled = getAirplaneModeEnabled(); + // Turn off airplane mode in case another test left the device in that state. + setAirplaneModeEnabled(false); + LogUtil.CLog.d("Original airplane mode state: " + mOriginalAirplaneModeEnabled); } @Override public void tearDown(TestInformation testInformation, Throwable e) throws DeviceNotAvailableException { + setAirplaneModeEnabled(mOriginalAirplaneModeEnabled); setAppStandbyEnabled(mOriginalAppStandbyEnabled); setBatteryStatsConstants(mOriginalBatteryStatsConstants); } + private void setAirplaneModeEnabled(boolean enable) throws DeviceNotAvailableException { + executeCmd("cmd connectivity airplane-mode " + (enable ? "enable" : "disable")); + } + + private boolean getAirplaneModeEnabled() throws DeviceNotAvailableException { + return "enabled".equals(executeCmd("cmd connectivity airplane-mode").trim()); + } + private void setAppStandbyEnabled(String appStandbyEnabled) throws DeviceNotAvailableException { if ("null".equals(appStandbyEnabled)) { executeCmd("settings delete global app_standby_enabled"); From 402077cc3aeb11b35f9abf63c703017f75be911d Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Sun, 17 May 2020 08:17:28 +0000 Subject: [PATCH 1091/1415] Fix flaky test for DnsResolverTest It's possible that private DNS setting is not in the state we expected when we tried to enable strict mode during tests. The problem here is that there are 2 setting Uris(mode and specifier) relating to strict mode, each of them might trigger private DNS setting changing evnet in ConnectivityService. Previously, we tried to enable strict mode with first set private DNS mode and then private DNS specifier. This may result in 2 consecutive private DNS changes events with very short intervals, which caused conflicts between DnsResolver / NetworkMonitor and lead to flaky tests. So 1. Change the order (mode and specifier) for enabling strict mode. 2. Change private DNS mode only when needed. (If original mode is "hostname", then we only need to set specifier) Bug: 153624005 Bug: 153624702 Test: atest DnsResolverTest --rerun-until-failure 100 Merged-In: Iaed6285677f74a5ee6cc6684534ddc0758b25974 Change-Id: I566bdfa98dc070247b52fe29ca1f31cbd1bb8cc2 (cherry picked from commit 877af1ee3ed2c3a9e9256e216709908d2beb3bfb) --- .../src/android/net/cts/DnsResolverTest.java | 35 +++--------- .../android/net/cts/MultinetworkApiTest.java | 23 ++------ .../android/net/cts/util/CtsNetUtils.java | 53 ++++++++++++++++--- 3 files changed, 57 insertions(+), 54 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 1cc49f900a..28753ffc41 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -86,7 +86,6 @@ public class DnsResolverTest extends AndroidTestCase { static final int CANCEL_RETRY_TIMES = 5; static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; - static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; private ContentResolver mCR; private ConnectivityManager mCM; @@ -107,32 +106,15 @@ public class DnsResolverTest extends AndroidTestCase { mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - storePrivateDnsSetting(); + mCtsNetUtils.storePrivateDnsSetting(); } @Override protected void tearDown() throws Exception { - restorePrivateDnsSetting(); + mCtsNetUtils.restorePrivateDnsSetting(); super.tearDown(); } - private void storePrivateDnsSetting() { - // Store private DNS setting - mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - private void restorePrivateDnsSetting() throws InterruptedException { - // restore private DNS setting - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); - if ("hostname".equals(mOldMode)) { - Settings.Global.putString( - mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); - mCtsNetUtils.awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", - mCM.getActiveNetwork(), mOldDnsSpecifier, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); - } - } - private static String byteArrayToHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int i = 0; i < bytes.length; ++i) { @@ -416,16 +398,13 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { final Network networkForPrivateDns = (network != null) ? network : mCM.getActiveNetwork(); assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, - PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, true); final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, executor, null, callback); @@ -688,9 +667,7 @@ public class DnsResolverTest extends AndroidTestCase { final Network[] testNetworks = getTestableNetworks(); // Set an invalid private DNS server - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(INVALID_PRIVATE_DNS_SERVER); final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; for (Network network : testNetworks) { // This test cannot be ran with null network because we need to explicitly pass a @@ -699,7 +676,7 @@ public class DnsResolverTest extends AndroidTestCase { // wait for private DNS setting propagating mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, false); + network, INVALID_PRIVATE_DNS_SERVER, false); final CountDownLatch latch = new CountDownLatch(1); final DnsResolver.Callback> errorCallback = diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index f123187d86..985e313a92 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -41,7 +41,6 @@ public class MultinetworkApiTest extends AndroidTestCase { private static final String TAG = "MultinetworkNativeApiTest"; static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; - static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; /** * @return 0 on success @@ -69,7 +68,7 @@ public class MultinetworkApiTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - storePrivateDnsSetting(); + mCtsNetUtils.storePrivateDnsSetting(); } @Override @@ -77,18 +76,6 @@ public class MultinetworkApiTest extends AndroidTestCase { super.tearDown(); } - private void storePrivateDnsSetting() { - // Store private DNS setting - mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - private void restorePrivateDnsSetting() { - // restore private DNS setting - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); - } - private Network[] getTestableNetworks() { final ArrayList testableNetworks = new ArrayList(); for (Network network : mCM.getAllNetworks()) { @@ -239,17 +226,15 @@ public class MultinetworkApiTest extends AndroidTestCase { // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 try { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { // Wait for private DNS setting to propagate. mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", - network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + network, GOOGLE_PRIVATE_DNS_SERVER, true); runResNnxDomainCheck(network.getNetworkHandle()); } } finally { - restorePrivateDnsSetting(); + mCtsNetUtils.restorePrivateDnsSetting(); } } } 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 824146fedf..df2de4f057 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 @@ -28,6 +28,7 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; @@ -39,6 +40,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.wifi.WifiManager; +import android.provider.Settings; import android.system.Os; import android.system.OsConstants; import android.util.Log; @@ -58,7 +60,9 @@ public final class CtsNetUtils { private static final int DURATION = 10000; private static final int SOCKET_TIMEOUT_MS = 2000; private static final int PRIVATE_DNS_PROBE_MS = 1_000; + private static final int PRIVATE_DNS_INTERVAL_MS = 500; + public static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; public static final int HTTP_PORT = 80; public static final String TEST_HOST = "connectivitycheck.gstatic.com"; public static final String HTTP_REQUEST = @@ -69,15 +73,19 @@ public final class CtsNetUtils { public static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; - private Context mContext; - private ConnectivityManager mCm; - private WifiManager mWifiManager; + private final Context mContext; + private final ConnectivityManager mCm; + private final ContentResolver mCR; + private final WifiManager mWifiManager; private TestNetworkCallback mCellNetworkCallback; + private String mOldPrivateDnsMode; + private String mOldPrivateDnsSpecifier; public CtsNetUtils(Context context) { mContext = context; mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mCR = context.getContentResolver(); } // Toggle WiFi twice, leaving it in the state it started in @@ -249,9 +257,42 @@ public final class CtsNetUtils { return s; } + public void storePrivateDnsSetting() { + // Store private DNS setting + mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldPrivateDnsSpecifier = Settings.Global.getString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER); + } + + public void restorePrivateDnsSetting() throws InterruptedException { + if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) { + return; + } + // restore private DNS setting + if ("hostname".equals(mOldPrivateDnsMode)) { + setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); + awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", + mCm.getActiveNetwork(), + mOldPrivateDnsSpecifier, true); + } else { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + } + } + + public void setPrivateDnsStrictMode(String server) { + // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures + // that if the previous private DNS mode was not "hostname", the system only sees one + // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two. + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server); + final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER. + if (!"hostname".equals(mode)) { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + } + } + public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, - @NonNull String server, int timeoutMs, - boolean requiresValidatedServers) throws InterruptedException { + @NonNull String server, boolean requiresValidatedServers) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); NetworkCallback callback = new NetworkCallback() { @@ -266,7 +307,7 @@ public final class CtsNetUtils { } }; mCm.registerNetworkCallback(request, callback); - assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS)); + assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); mCm.unregisterNetworkCallback(callback); // Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do // this, then the test could complete before the NetworkMonitor private DNS probe From 5dd02e3103bd55a3114fb7c25b161370ae28117f Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Mon, 18 May 2020 19:55:29 +0800 Subject: [PATCH 1092/1415] Fix CtsNetTestCasesLatestSdk fail on Q platform The CtsNetTestCasesLatestSdk needs to build against platform (for hidden API access), The JNI library libnativedns_jni used by CtsNetTestCasesLatestSdk needs to build against stable SDK (for running on Q). To fulfill the combination, property jni_uses_sdk_apis must be set. Bug: 151122313 Bug: 150904735 Bug: 150918852 Test: atest CtsNetTestCasesLatestSdk on R and Q platforms Change-Id: I5db3cb28829847e74412d270db7d17b81c5e26a2 --- tests/cts/net/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 46fae33b9b..93a6d916dd 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -77,6 +77,7 @@ android_test { android_test { name: "CtsNetTestCasesLatestSdk", defaults: ["CtsNetTestCasesDefaults"], + jni_uses_sdk_apis: true, min_sdk_version: "29", target_sdk_version: "29", test_suites: [ From 2a1656d3f88a8cb849fde9b3fd6fb7e2310e1ef8 Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 17 Apr 2020 16:18:44 +0800 Subject: [PATCH 1093/1415] TetheringServiceTest: test caller permission Bug: 154869719 Test: atest TetheringTests Change-Id: I7beea3f011d930e433443ed62d772a3f8cce5d78 --- Tethering/tests/unit/AndroidManifest.xml | 3 - .../tethering/TetheringServiceTest.java | 374 +++++++++++++++--- 2 files changed, 325 insertions(+), 52 deletions(-) diff --git a/Tethering/tests/unit/AndroidManifest.xml b/Tethering/tests/unit/AndroidManifest.xml index 31eaabff52..355342f643 100644 --- a/Tethering/tests/unit/AndroidManifest.xml +++ b/Tethering/tests/unit/AndroidManifest.xml @@ -16,9 +16,6 @@ - - - 0) mUiAutomation.adoptShellPermissionIdentity(permissions); + try { + when(mTethering.isTetheringSupported()).thenReturn(true); + test.runTetheringCall(new TestTetheringResult()); + } finally { + mUiAutomation.dropShellPermissionIdentity(); + } + } + + private void verifyNoMoreInteractionsForTethering() { + verifyNoMoreInteractions(mTethering); + verifyNoMoreInteractions(mITetheringEventCallback); + reset(mTethering, mITetheringEventCallback); + } + + private void runTether(final TestTetheringResult result) throws Exception { + when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); + verify(mTethering).isTetheringSupported(); + verify(mTethering).tether(TEST_IFACE_NAME); + result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testTether() throws Exception { - when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); + runAsNoPermission((result) -> { + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runTether(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runTether(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runUnTether(final TestTetheringResult result) throws Exception { + when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); verify(mTethering).isTetheringSupported(); - verify(mTethering).tether(TEST_IFACE_NAME); - verifyNoMoreInteractions(mTethering); + verify(mTethering).untether(TEST_IFACE_NAME); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testUntether() throws Exception { - when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, - result); + runAsNoPermission((result) -> { + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runUnTether(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runUnTether(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runSetUsbTethering(final TestTetheringResult result) throws Exception { + when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR); + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, + TEST_ATTRIBUTION_TAG, result); verify(mTethering).isTetheringSupported(); - verify(mTethering).untether(TEST_IFACE_NAME); - verifyNoMoreInteractions(mTethering); + verify(mTethering).setUsbTethering(true /* enable */); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testSetUsbTethering() throws Exception { - when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR); - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, - TEST_ATTRIBUTION_TAG, result); + runAsNoPermission((result) -> { + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, + TEST_ATTRIBUTION_TAG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runSetUsbTethering(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runSetUsbTethering(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + + } + + private void runStartTethering(final TestTetheringResult result, + final TetheringRequestParcel request) throws Exception { + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); verify(mTethering).isTetheringSupported(); - verify(mTethering).setUsbTethering(true /* enable */); - verifyNoMoreInteractions(mTethering); - result.assertResult(TETHER_ERROR_NO_ERROR); + verify(mTethering).startTethering(eq(request), eq(result)); } @Test public void testStartTethering() throws Exception { - final TestTetheringResult result = new TestTetheringResult(); final TetheringRequestParcel request = new TetheringRequestParcel(); request.tetheringType = TETHERING_WIFI; - mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetheringSupported(); - verify(mTethering).startTethering(eq(request), eq(result)); - verifyNoMoreInteractions(mTethering); + + runAsNoPermission((result) -> { + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runStartTethering(result, request); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runStartTethering(result, request); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); } @Test - public void testStopTethering() throws Exception { - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, - result); + public void testStartTetheringWithExemptFromEntitlementCheck() throws Exception { + final TetheringRequestParcel request = new TetheringRequestParcel(); + request.tetheringType = TETHERING_WIFI; + request.exemptFromEntitlementCheck = true; + + runAsTetherPrivileged((result) -> { + runStartTethering(result, request); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runStopTethering(final TestTetheringResult result) throws Exception { + mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, + TEST_ATTRIBUTION_TAG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).stopTethering(TETHERING_WIFI); - verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test - public void testRequestLatestTetheringEntitlementResult() throws Exception { - final ResultReceiver result = new ResultReceiver(null); + public void testStopTethering() throws Exception { + runAsNoPermission((result) -> { + mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, + TEST_ATTRIBUTION_TAG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runStopTethering(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runStopTethering(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runRequestLatestTetheringEntitlementResult() throws Exception { + final MyResultReceiver result = new MyResultReceiver(null); mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); verify(mTethering).isTetheringSupported(); verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI), eq(result), eq(true) /* showEntitlementUi */); + } + + @Test + public void testRequestLatestTetheringEntitlementResult() throws Exception { + // Run as no permission. + final MyResultReceiver result = new MyResultReceiver(null); + mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, + true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractions(mTethering); + + runAsTetherPrivileged((none) -> { + runRequestLatestTetheringEntitlementResult(); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((none) -> { + runRequestLatestTetheringEntitlementResult(); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runRegisterTetheringEventCallback() throws Exception { + mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback)); } @Test public void testRegisterTetheringEventCallback() throws Exception { - mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, + runAsNoPermission((result) -> { + mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mITetheringEventCallback).onCallbackStopped( + TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((none) -> { + runRegisterTetheringEventCallback(); + verifyNoMoreInteractionsForTethering(); + }); + + runAsAccessNetworkState((none) -> { + runRegisterTetheringEventCallback(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runUnregisterTetheringEventCallback() throws Exception { + mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, TEST_CALLER_PKG); - verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback)); - verifyNoMoreInteractions(mTethering); + verify(mTethering).unregisterTetheringEventCallback(eq(mITetheringEventCallback)); } @Test public void testUnregisterTetheringEventCallback() throws Exception { - mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, - TEST_CALLER_PKG); - verify(mTethering).unregisterTetheringEventCallback( - eq(mITetheringEventCallback)); - verifyNoMoreInteractions(mTethering); + runAsNoPermission((result) -> { + mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mITetheringEventCallback).onCallbackStopped( + TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((none) -> { + runUnregisterTetheringEventCallback(); + verifyNoMoreInteractionsForTethering(); + }); + + runAsAccessNetworkState((none) -> { + runUnregisterTetheringEventCallback(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runStopAllTethering(final TestTetheringResult result) throws Exception { + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); + verify(mTethering).isTetheringSupported(); + verify(mTethering).untetherAll(); + result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testStopAllTethering() throws Exception { - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); + runAsNoPermission((result) -> { + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runStopAllTethering(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runStopAllTethering(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runIsTetheringSupported(final TestTetheringResult result) throws Exception { + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); verify(mTethering).isTetheringSupported(); - verify(mTethering).untetherAll(); - verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testIsTetheringSupported() throws Exception { - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetheringSupported(); - verifyNoMoreInteractions(mTethering); - result.assertResult(TETHER_ERROR_NO_ERROR); + runAsNoPermission((result) -> { + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runIsTetheringSupported(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runIsTetheringSupported(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); } } From dfa54804146a1061d4e1116f8d929b312029d286 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 18 May 2020 17:26:23 +0000 Subject: [PATCH 1094/1415] Revert "Fix flaky test for DnsResolverTest" This reverts commit fb735de0e87b41a4bddf53043796ab2a01101466. Reason for revert: This CL made whole test failed. Bug: 153624005 Bug: 150952393 Bug: 151122313 Change-Id: I083529616dbf80421ea6a322bb57d2bb0f2bca62 --- .../src/android/net/cts/DnsResolverTest.java | 35 +++++++++--- .../android/net/cts/MultinetworkApiTest.java | 23 ++++++-- .../android/net/cts/util/CtsNetUtils.java | 53 +++---------------- 3 files changed, 54 insertions(+), 57 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 28753ffc41..1cc49f900a 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -86,6 +86,7 @@ public class DnsResolverTest extends AndroidTestCase { static final int CANCEL_RETRY_TIMES = 5; static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; + static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; private ContentResolver mCR; private ConnectivityManager mCM; @@ -106,15 +107,32 @@ public class DnsResolverTest extends AndroidTestCase { mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - mCtsNetUtils.storePrivateDnsSetting(); + storePrivateDnsSetting(); } @Override protected void tearDown() throws Exception { - mCtsNetUtils.restorePrivateDnsSetting(); + restorePrivateDnsSetting(); super.tearDown(); } + private void storePrivateDnsSetting() { + // Store private DNS setting + mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); + } + + private void restorePrivateDnsSetting() throws InterruptedException { + // restore private DNS setting + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); + if ("hostname".equals(mOldMode)) { + Settings.Global.putString( + mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); + mCtsNetUtils.awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", + mCM.getActiveNetwork(), mOldDnsSpecifier, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + } + } + private static String byteArrayToHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int i = 0; i < bytes.length; ++i) { @@ -398,13 +416,16 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 - mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { final Network networkForPrivateDns = (network != null) ? network : mCM.getActiveNetwork(); assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, true); + networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, + PRIVATE_DNS_SETTING_TIMEOUT_MS, true); final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, executor, null, callback); @@ -667,7 +688,9 @@ public class DnsResolverTest extends AndroidTestCase { final Network[] testNetworks = getTestableNetworks(); // Set an invalid private DNS server - mCtsNetUtils.setPrivateDnsStrictMode(INVALID_PRIVATE_DNS_SERVER); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; for (Network network : testNetworks) { // This test cannot be ran with null network because we need to explicitly pass a @@ -676,7 +699,7 @@ public class DnsResolverTest extends AndroidTestCase { // wait for private DNS setting propagating mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - network, INVALID_PRIVATE_DNS_SERVER, false); + network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, false); final CountDownLatch latch = new CountDownLatch(1); final DnsResolver.Callback> errorCallback = diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index 985e313a92..f123187d86 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -41,6 +41,7 @@ public class MultinetworkApiTest extends AndroidTestCase { private static final String TAG = "MultinetworkNativeApiTest"; static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; + static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; /** * @return 0 on success @@ -68,7 +69,7 @@ public class MultinetworkApiTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - mCtsNetUtils.storePrivateDnsSetting(); + storePrivateDnsSetting(); } @Override @@ -76,6 +77,18 @@ public class MultinetworkApiTest extends AndroidTestCase { super.tearDown(); } + private void storePrivateDnsSetting() { + // Store private DNS setting + mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); + } + + private void restorePrivateDnsSetting() { + // restore private DNS setting + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); + } + private Network[] getTestableNetworks() { final ArrayList testableNetworks = new ArrayList(); for (Network network : mCM.getAllNetworks()) { @@ -226,15 +239,17 @@ public class MultinetworkApiTest extends AndroidTestCase { // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 try { - mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { // Wait for private DNS setting to propagate. mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", - network, GOOGLE_PRIVATE_DNS_SERVER, true); + network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); runResNnxDomainCheck(network.getNetworkHandle()); } } finally { - mCtsNetUtils.restorePrivateDnsSetting(); + restorePrivateDnsSetting(); } } } 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 df2de4f057..824146fedf 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 @@ -28,7 +28,6 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; -import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; @@ -40,7 +39,6 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.wifi.WifiManager; -import android.provider.Settings; import android.system.Os; import android.system.OsConstants; import android.util.Log; @@ -60,9 +58,7 @@ public final class CtsNetUtils { private static final int DURATION = 10000; private static final int SOCKET_TIMEOUT_MS = 2000; private static final int PRIVATE_DNS_PROBE_MS = 1_000; - private static final int PRIVATE_DNS_INTERVAL_MS = 500; - public static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; public static final int HTTP_PORT = 80; public static final String TEST_HOST = "connectivitycheck.gstatic.com"; public static final String HTTP_REQUEST = @@ -73,19 +69,15 @@ public final class CtsNetUtils { public static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; - private final Context mContext; - private final ConnectivityManager mCm; - private final ContentResolver mCR; - private final WifiManager mWifiManager; + private Context mContext; + private ConnectivityManager mCm; + private WifiManager mWifiManager; private TestNetworkCallback mCellNetworkCallback; - private String mOldPrivateDnsMode; - private String mOldPrivateDnsSpecifier; public CtsNetUtils(Context context) { mContext = context; mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - mCR = context.getContentResolver(); } // Toggle WiFi twice, leaving it in the state it started in @@ -257,42 +249,9 @@ public final class CtsNetUtils { return s; } - public void storePrivateDnsSetting() { - // Store private DNS setting - mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldPrivateDnsSpecifier = Settings.Global.getString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - public void restorePrivateDnsSetting() throws InterruptedException { - if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) { - return; - } - // restore private DNS setting - if ("hostname".equals(mOldPrivateDnsMode)) { - setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); - awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", - mCm.getActiveNetwork(), - mOldPrivateDnsSpecifier, true); - } else { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); - } - } - - public void setPrivateDnsStrictMode(String server) { - // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures - // that if the previous private DNS mode was not "hostname", the system only sees one - // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two. - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server); - final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER. - if (!"hostname".equals(mode)) { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - } - } - public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, - @NonNull String server, boolean requiresValidatedServers) throws InterruptedException { + @NonNull String server, int timeoutMs, + boolean requiresValidatedServers) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); NetworkCallback callback = new NetworkCallback() { @@ -307,7 +266,7 @@ public final class CtsNetUtils { } }; mCm.registerNetworkCallback(request, callback); - assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS)); mCm.unregisterNetworkCallback(callback); // Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do // this, then the test could complete before the NetworkMonitor private DNS probe From ce6a5df07384ff39fd95e20ac70ec58a939f8321 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 19 May 2020 01:52:29 +0000 Subject: [PATCH 1095/1415] Revert "Fix flaky test for DnsResolverTest" This reverts commit dd9608b7d1147a4eaf36ea634b9fc2f0feca1145. Reason for revert: This CL made whole test failed. Bug: 153624005 Bug: 150952393 Bug: 151122313 Merged-In: I083529616dbf80421ea6a322bb57d2bb0f2bca62 Change-Id: I002c39d6535fb31b13bc463812517fe1882f1884 (cherry picked from commit 98015badd01863fa4a79c089f371d9a50f2ae98c) --- .../src/android/net/cts/DnsResolverTest.java | 35 +++++++++--- .../android/net/cts/MultinetworkApiTest.java | 23 ++++++-- .../android/net/cts/util/CtsNetUtils.java | 53 +++---------------- 3 files changed, 54 insertions(+), 57 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 28753ffc41..1cc49f900a 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -86,6 +86,7 @@ public class DnsResolverTest extends AndroidTestCase { static final int CANCEL_RETRY_TIMES = 5; static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; + static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; private ContentResolver mCR; private ConnectivityManager mCM; @@ -106,15 +107,32 @@ public class DnsResolverTest extends AndroidTestCase { mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - mCtsNetUtils.storePrivateDnsSetting(); + storePrivateDnsSetting(); } @Override protected void tearDown() throws Exception { - mCtsNetUtils.restorePrivateDnsSetting(); + restorePrivateDnsSetting(); super.tearDown(); } + private void storePrivateDnsSetting() { + // Store private DNS setting + mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); + } + + private void restorePrivateDnsSetting() throws InterruptedException { + // restore private DNS setting + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); + if ("hostname".equals(mOldMode)) { + Settings.Global.putString( + mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); + mCtsNetUtils.awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", + mCM.getActiveNetwork(), mOldDnsSpecifier, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + } + } + private static String byteArrayToHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int i = 0; i < bytes.length; ++i) { @@ -398,13 +416,16 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 - mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { final Network networkForPrivateDns = (network != null) ? network : mCM.getActiveNetwork(); assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, true); + networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, + PRIVATE_DNS_SETTING_TIMEOUT_MS, true); final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, executor, null, callback); @@ -667,7 +688,9 @@ public class DnsResolverTest extends AndroidTestCase { final Network[] testNetworks = getTestableNetworks(); // Set an invalid private DNS server - mCtsNetUtils.setPrivateDnsStrictMode(INVALID_PRIVATE_DNS_SERVER); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; for (Network network : testNetworks) { // This test cannot be ran with null network because we need to explicitly pass a @@ -676,7 +699,7 @@ public class DnsResolverTest extends AndroidTestCase { // wait for private DNS setting propagating mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - network, INVALID_PRIVATE_DNS_SERVER, false); + network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, false); final CountDownLatch latch = new CountDownLatch(1); final DnsResolver.Callback> errorCallback = diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index 985e313a92..f123187d86 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -41,6 +41,7 @@ public class MultinetworkApiTest extends AndroidTestCase { private static final String TAG = "MultinetworkNativeApiTest"; static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; + static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; /** * @return 0 on success @@ -68,7 +69,7 @@ public class MultinetworkApiTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - mCtsNetUtils.storePrivateDnsSetting(); + storePrivateDnsSetting(); } @Override @@ -76,6 +77,18 @@ public class MultinetworkApiTest extends AndroidTestCase { super.tearDown(); } + private void storePrivateDnsSetting() { + // Store private DNS setting + mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); + } + + private void restorePrivateDnsSetting() { + // restore private DNS setting + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); + } + private Network[] getTestableNetworks() { final ArrayList testableNetworks = new ArrayList(); for (Network network : mCM.getAllNetworks()) { @@ -226,15 +239,17 @@ public class MultinetworkApiTest extends AndroidTestCase { // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 try { - mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { // Wait for private DNS setting to propagate. mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", - network, GOOGLE_PRIVATE_DNS_SERVER, true); + network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); runResNnxDomainCheck(network.getNetworkHandle()); } } finally { - mCtsNetUtils.restorePrivateDnsSetting(); + restorePrivateDnsSetting(); } } } 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 df2de4f057..824146fedf 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 @@ -28,7 +28,6 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; -import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; @@ -40,7 +39,6 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.wifi.WifiManager; -import android.provider.Settings; import android.system.Os; import android.system.OsConstants; import android.util.Log; @@ -60,9 +58,7 @@ public final class CtsNetUtils { private static final int DURATION = 10000; private static final int SOCKET_TIMEOUT_MS = 2000; private static final int PRIVATE_DNS_PROBE_MS = 1_000; - private static final int PRIVATE_DNS_INTERVAL_MS = 500; - public static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; public static final int HTTP_PORT = 80; public static final String TEST_HOST = "connectivitycheck.gstatic.com"; public static final String HTTP_REQUEST = @@ -73,19 +69,15 @@ public final class CtsNetUtils { public static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; - private final Context mContext; - private final ConnectivityManager mCm; - private final ContentResolver mCR; - private final WifiManager mWifiManager; + private Context mContext; + private ConnectivityManager mCm; + private WifiManager mWifiManager; private TestNetworkCallback mCellNetworkCallback; - private String mOldPrivateDnsMode; - private String mOldPrivateDnsSpecifier; public CtsNetUtils(Context context) { mContext = context; mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - mCR = context.getContentResolver(); } // Toggle WiFi twice, leaving it in the state it started in @@ -257,42 +249,9 @@ public final class CtsNetUtils { return s; } - public void storePrivateDnsSetting() { - // Store private DNS setting - mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldPrivateDnsSpecifier = Settings.Global.getString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - public void restorePrivateDnsSetting() throws InterruptedException { - if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) { - return; - } - // restore private DNS setting - if ("hostname".equals(mOldPrivateDnsMode)) { - setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); - awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", - mCm.getActiveNetwork(), - mOldPrivateDnsSpecifier, true); - } else { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); - } - } - - public void setPrivateDnsStrictMode(String server) { - // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures - // that if the previous private DNS mode was not "hostname", the system only sees one - // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two. - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server); - final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER. - if (!"hostname".equals(mode)) { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - } - } - public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, - @NonNull String server, boolean requiresValidatedServers) throws InterruptedException { + @NonNull String server, int timeoutMs, + boolean requiresValidatedServers) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); NetworkCallback callback = new NetworkCallback() { @@ -307,7 +266,7 @@ public final class CtsNetUtils { } }; mCm.registerNetworkCallback(request, callback); - assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS)); mCm.unregisterNetworkCallback(callback); // Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do // this, then the test could complete before the NetworkMonitor private DNS probe From e196a61cbbcbf54e4bca9eec7c640d980a411888 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 19 May 2020 05:34:35 +0000 Subject: [PATCH 1096/1415] Fix CtsNetTestCasesLatestSdk fail on Q platform The CtsNetTestCasesLatestSdk needs to build against platform (for hidden API access), The JNI library libnativedns_jni used by CtsNetTestCasesLatestSdk needs to build against stable SDK (for running on Q). To fulfill the combination, property jni_uses_sdk_apis must be set. Bug: 151122313 Bug: 150904735 Bug: 150918852 Test: atest CtsNetTestCasesLatestSdk on R and Q platforms Merged-In: I5db3cb28829847e74412d270db7d17b81c5e26a2 Change-Id: I8e9af302b487199b144f4fd791bc39d57f002fe2 (cherry picked from commit 452ef123caa60eeebc1744b14137197c47704d6b) --- tests/cts/net/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 46fae33b9b..93a6d916dd 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -77,6 +77,7 @@ android_test { android_test { name: "CtsNetTestCasesLatestSdk", defaults: ["CtsNetTestCasesDefaults"], + jni_uses_sdk_apis: true, min_sdk_version: "29", target_sdk_version: "29", test_suites: [ From f021c464fdb713934ec2b0bf1a9efd9216c1166e Mon Sep 17 00:00:00 2001 From: Chen Zhu Date: Fri, 8 May 2020 15:26:32 -0700 Subject: [PATCH 1097/1415] Apply MainlineTestModuleController to tethering cts tests to only run them when com.google.android.tethering is installed on device. This does not change any existing CTS run. The logic only applies when the test triggered by mts-tradefed to make sure it runs appropriate set of tests against the device. For example, the test will be skipped when running MTS on Q because tethering and wifi are not on Q devices. Bug: 154845935 Test: m mts && mts-tradefed run mts-tethering Change-Id: I9e6bd60982d4ef67538ad506e7008366bbf35363 --- tests/cts/tethering/AndroidTest.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/cts/tethering/AndroidTest.xml b/tests/cts/tethering/AndroidTest.xml index d0a2bce811..e752e3a82a 100644 --- a/tests/cts/tethering/AndroidTest.xml +++ b/tests/cts/tethering/AndroidTest.xml @@ -28,4 +28,8 @@ + + + From f4394e83f844265399148e827c8c1930e64eba08 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 20 May 2020 11:44:05 +0800 Subject: [PATCH 1098/1415] Fix TetheringServiceTest test WRITE_SETTINGS permission failure AdoptShellPermissionIdentity can not pass permission check by Settings#checkAndNoteWriteSettingsOperation. It would compare the caller uid and its package name. See error below: 1. java.lang.SecurityException: Specified package com.android.shell under uid 10239 but it is really 2000 2. java.lang.SecurityException: uid 10245 does not have android.permission.UPDATE_APP_OPS_STATS. Override the method and test if caller hold WRITE_SETTINGS directly. Bug: 154869719 Test: TetheringTests, TetheringCoverageTests, NetworkStackNextTests, NetworkStackCoverageTests Change-Id: I2a60c4d66ef30028f9663159f85464ea815248e2 --- .../networkstack/tethering/TetheringService.java | 7 ++++--- .../tethering/MockTetheringService.java | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java index 7d01273842..c11e86258d 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -264,10 +264,11 @@ public class TetheringService extends Service { if (onlyAllowPrivileged || mTethering.isTetherProvisioningRequired()) return false; int uid = Binder.getCallingUid(); + // If callerPkg's uid is not same as Binder.getCallingUid(), // checkAndNoteWriteSettingsOperation will return false and the operation will be // denied. - return TetheringService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg, + return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg, callingAttributionTag, false /* throwException */); } @@ -285,8 +286,8 @@ public class TetheringService extends Service { * * @return {@code true} iff the package is allowed to write settings. */ - // TODO: Remove method and replace with direct call once R code is pushed to AOSP - private static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, + @VisibleForTesting + boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag, boolean throwException) { return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage, diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java index 1c81c1247d..071a290e65 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java @@ -15,13 +15,20 @@ */ package com.android.networkstack.tethering; +import static android.Manifest.permission.WRITE_SETTINGS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import static org.mockito.Mockito.mock; +import android.content.Context; import android.content.Intent; import android.net.ITetheringConnector; import android.os.Binder; import android.os.IBinder; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + public class MockTetheringService extends TetheringService { private final Tethering mTethering = mock(Tethering.class); @@ -35,6 +42,15 @@ public class MockTetheringService extends TetheringService { return mTethering; } + @Override + boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, + @NonNull String callingPackage, @Nullable String callingAttributionTag, + boolean throwException) { + // Test this does not verify the calling package / UID, as calling package could be shell + // and not match the UID. + return context.checkCallingOrSelfPermission(WRITE_SETTINGS) == PERMISSION_GRANTED; + } + public Tethering getTethering() { return mTethering; } From 0a0d71f1ec25dcbddbc7d50d04b4d1c327c90a91 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 20 May 2020 15:03:35 -0700 Subject: [PATCH 1099/1415] Add cts for TEMPORARILY_NOT_METERED Bug: 155993662 Test: atest NetworkRequestTest Change-Id: I6838dff70e6608f166119b99750db3bc59c59e42 --- .../net/src/android/net/cts/NetworkRequestTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index f32ee9e1eb..e8af1b38f2 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -18,6 +18,7 @@ package android.net.cts; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; @@ -86,6 +87,16 @@ public class NetworkRequestTest { verifyNoCapabilities(nr); } + @Test + public void testTemporarilyNotMeteredCapability() { + assertTrue(new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build() + .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertFalse(new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build() + .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + } + private void verifyNoCapabilities(NetworkRequest nr) { // NetworkCapabilities.mNetworkCapabilities is defined as type long final int MAX_POSSIBLE_CAPABILITY = Long.SIZE; From 677a1c155474d3023e81d38962213ba3e0fc5e32 Mon Sep 17 00:00:00 2001 From: evitayan Date: Wed, 6 May 2020 18:47:53 -0700 Subject: [PATCH 1100/1415] Exit test if device does not support IPsec tunnel Bug: 155926216 Test: CtsIkeTestCases Change-Id: I4e426b8f3509e56e7e2e7532e216533ad8bfbc2f --- .../android/net/ipsec/ike/cts/IkeSessionPskTest.java | 12 +++++++++--- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 6 ++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index ed67dd1bd7..336d12dad1 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -122,7 +122,9 @@ public class IkeSessionPskTest extends IkeSessionTestBase { } @Test - public void testIkeSessionSetupAndManageChildSas() throws Exception { + public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception { + if (!hasTunnelsFeature()) return; + // Open IKE Session IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); int expectedMsgId = 0; @@ -210,7 +212,9 @@ public class IkeSessionPskTest extends IkeSessionTestBase { } @Test - public void testIkeSessionKill() throws Exception { + public void testIkeSessionKillWithTunnelMode() throws Exception { + if (!hasTunnelsFeature()) return; + // Open IKE Session IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); int expectedMsgId = 0; @@ -254,5 +258,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); } - // TODO(b/148689509): Verify rekey process and handling IKE_AUTH failure + // TODO(b/155821007): Verify rekey process and handling IKE_AUTH failure + + // TODO(b/155821007): Test creating transport mode Child SA } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index deba8fd985..1c1ffc922f 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -20,6 +20,7 @@ import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpSecTransform; @@ -368,6 +369,11 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + /** Package private method to check if device has IPsec tunnels feature */ + static boolean hasTunnelsFeature() { + return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + } + // TODO(b/148689509): Verify IKE Session setup using EAP and digital-signature-based auth // TODO(b/148689509): Verify hostname based creation From ae36797b69ef3aff9bd4e1a7e3fe9ae54144d78b Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 20 May 2020 15:03:35 -0700 Subject: [PATCH 1101/1415] Add cts for TEMPORARILY_NOT_METERED Bug: 155993662 Test: atest NetworkRequestTest Change-Id: I6838dff70e6608f166119b99750db3bc59c59e42 Merged-In: I6838dff70e6608f166119b99750db3bc59c59e42 --- .../net/src/android/net/cts/NetworkRequestTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index f32ee9e1eb..e8af1b38f2 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -18,6 +18,7 @@ package android.net.cts; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; @@ -86,6 +87,16 @@ public class NetworkRequestTest { verifyNoCapabilities(nr); } + @Test + public void testTemporarilyNotMeteredCapability() { + assertTrue(new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build() + .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertFalse(new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build() + .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + } + private void verifyNoCapabilities(NetworkRequest nr) { // NetworkCapabilities.mNetworkCapabilities is defined as type long final int MAX_POSSIBLE_CAPABILITY = Long.SIZE; From 8e28d8789da87caefec18d93e37b9f500cfe796a Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 20 May 2020 18:56:37 -0700 Subject: [PATCH 1102/1415] Create NetworkAgent CTS for NET_CAP_TEMP_NOT_METERED Test: atest NetworkAgentTest Bug: 155993662 Change-Id: Ic968bf37075c23e9ea7d98eaec7f4f37d9ebc337 --- .../src/android/net/cts/NetworkAgentTest.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 03b961bc4b..2824db7464 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -592,4 +592,50 @@ class NetworkAgentTest { assertNull(it.uri) } } + + @Test + fun testTemporarilyUnmeteredCapability() { + // This test will create a networks with/without NET_CAPABILITY_TEMPORARILY_NOT_METERED + // and check that the callback reflects the capability changes. + // First create a request to make sure the network is kept up + val request1 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback1 = TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also { + registerNetworkCallback(request1, it) + } + requestNetwork(request1, callback1) + + // Then file the interesting request + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback() + requestNetwork(request, callback) + + // Connect the network + createConnectedNetworkAgent().let { (agent, _) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + + // Send TEMP_NOT_METERED and check that the callback is called appropriately. + val nc1 = NetworkCapabilities(agent.nc) + .addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + agent.sendNetworkCapabilities(nc1) + callback.expectCapabilitiesThat(agent.network) { + it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + } + + // Remove TEMP_NOT_METERED and check that the callback is called appropriately. + val nc2 = NetworkCapabilities(agent.nc) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + agent.sendNetworkCapabilities(nc2) + callback.expectCapabilitiesThat(agent.network) { + !it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + } + } + + // tearDown() will unregister the requests and agents + } } From d6e36d820e6defa4e1357e01f8f46ae3535ce27c Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Sat, 11 Apr 2020 02:56:37 +0800 Subject: [PATCH 1103/1415] Deflaky test for DnsResolverTest It's possible that private DNS setting is not in the state we expected when we tried to enable strict mode during tests. The problem here is that there are 2 setting Uris(mode and specifier) relating to strict mode, each of them might trigger private DNS setting changing evnet in ConnectivityService. Previously, we tried to enable strict mode with first set private DNS mode and then private DNS specifier. This may result in 2 consecutive private DNS changes events with very short intervals, which caused conflicts between DnsResolver / NetworkMonitor and lead to flaky tests. So 0. Use opportunistic as default mode if no default mode existed. 1. Change the order (mode and specifier) for enabling strict mode. 2. Change private DNS mode only when needed. (If original mode is "hostname", then we only need to set specifier) Bug: 153624005 Bug: 151122313 Bug: 150952393 Test: atest DnsResolverTest --rerun-until-failure 100 Test: forrest (git_master, cts/networking/gce-all) Test: forrest (git_rvc-dev, atest CtsNetTestCases) Test: forrest (git_rvc-dev, mts/dnsresolver/device-all) Change-Id: I224a6493c87cebaf0bf954c2644e2945ccd50db1 --- .../src/android/net/cts/DnsResolverTest.java | 35 ++--------- .../android/net/cts/MultinetworkApiTest.java | 23 ++----- .../android/net/cts/util/CtsNetUtils.java | 62 +++++++++++++++++-- 3 files changed, 66 insertions(+), 54 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 1cc49f900a..28753ffc41 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -86,7 +86,6 @@ public class DnsResolverTest extends AndroidTestCase { static final int CANCEL_RETRY_TIMES = 5; static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; - static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; private ContentResolver mCR; private ConnectivityManager mCM; @@ -107,32 +106,15 @@ public class DnsResolverTest extends AndroidTestCase { mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - storePrivateDnsSetting(); + mCtsNetUtils.storePrivateDnsSetting(); } @Override protected void tearDown() throws Exception { - restorePrivateDnsSetting(); + mCtsNetUtils.restorePrivateDnsSetting(); super.tearDown(); } - private void storePrivateDnsSetting() { - // Store private DNS setting - mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - private void restorePrivateDnsSetting() throws InterruptedException { - // restore private DNS setting - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); - if ("hostname".equals(mOldMode)) { - Settings.Global.putString( - mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); - mCtsNetUtils.awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", - mCM.getActiveNetwork(), mOldDnsSpecifier, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); - } - } - private static String byteArrayToHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int i = 0; i < bytes.length; ++i) { @@ -416,16 +398,13 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { final Network networkForPrivateDns = (network != null) ? network : mCM.getActiveNetwork(); assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, - PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, true); final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, executor, null, callback); @@ -688,9 +667,7 @@ public class DnsResolverTest extends AndroidTestCase { final Network[] testNetworks = getTestableNetworks(); // Set an invalid private DNS server - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(INVALID_PRIVATE_DNS_SERVER); final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; for (Network network : testNetworks) { // This test cannot be ran with null network because we need to explicitly pass a @@ -699,7 +676,7 @@ public class DnsResolverTest extends AndroidTestCase { // wait for private DNS setting propagating mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, false); + network, INVALID_PRIVATE_DNS_SERVER, false); final CountDownLatch latch = new CountDownLatch(1); final DnsResolver.Callback> errorCallback = diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index f123187d86..985e313a92 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -41,7 +41,6 @@ public class MultinetworkApiTest extends AndroidTestCase { private static final String TAG = "MultinetworkNativeApiTest"; static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; - static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; /** * @return 0 on success @@ -69,7 +68,7 @@ public class MultinetworkApiTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - storePrivateDnsSetting(); + mCtsNetUtils.storePrivateDnsSetting(); } @Override @@ -77,18 +76,6 @@ public class MultinetworkApiTest extends AndroidTestCase { super.tearDown(); } - private void storePrivateDnsSetting() { - // Store private DNS setting - mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - private void restorePrivateDnsSetting() { - // restore private DNS setting - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); - } - private Network[] getTestableNetworks() { final ArrayList testableNetworks = new ArrayList(); for (Network network : mCM.getAllNetworks()) { @@ -239,17 +226,15 @@ public class MultinetworkApiTest extends AndroidTestCase { // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 try { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { // Wait for private DNS setting to propagate. mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", - network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + network, GOOGLE_PRIVATE_DNS_SERVER, true); runResNnxDomainCheck(network.getNetworkHandle()); } } finally { - restorePrivateDnsSetting(); + mCtsNetUtils.restorePrivateDnsSetting(); } } } 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 824146fedf..f39b184914 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 @@ -17,6 +17,7 @@ package android.net.cts.util; import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -28,6 +29,7 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; @@ -39,6 +41,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.wifi.WifiManager; +import android.provider.Settings; import android.system.Os; import android.system.OsConstants; import android.util.Log; @@ -59,6 +62,7 @@ public final class CtsNetUtils { private static final int SOCKET_TIMEOUT_MS = 2000; private static final int PRIVATE_DNS_PROBE_MS = 1_000; + public static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; public static final int HTTP_PORT = 80; public static final String TEST_HOST = "connectivitycheck.gstatic.com"; public static final String HTTP_REQUEST = @@ -69,15 +73,19 @@ public final class CtsNetUtils { public static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; - private Context mContext; - private ConnectivityManager mCm; - private WifiManager mWifiManager; + private final Context mContext; + private final ConnectivityManager mCm; + private final ContentResolver mCR; + private final WifiManager mWifiManager; private TestNetworkCallback mCellNetworkCallback; + private String mOldPrivateDnsMode; + private String mOldPrivateDnsSpecifier; public CtsNetUtils(Context context) { mContext = context; mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mCR = context.getContentResolver(); } // Toggle WiFi twice, leaving it in the state it started in @@ -249,9 +257,51 @@ public final class CtsNetUtils { return s; } + public void storePrivateDnsSetting() { + // Store private DNS setting + mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldPrivateDnsSpecifier = Settings.Global.getString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER); + // It's possible that there is no private DNS default value in Settings. + // Give it a proper default mode which is opportunistic mode. + if (mOldPrivateDnsMode == null) { + mOldPrivateDnsSpecifier = ""; + mOldPrivateDnsMode = PRIVATE_DNS_MODE_OPPORTUNISTIC; + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, mOldPrivateDnsSpecifier); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + } + } + + public void restorePrivateDnsSetting() throws InterruptedException { + if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) { + return; + } + // restore private DNS setting + if ("hostname".equals(mOldPrivateDnsMode)) { + setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); + awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", + mCm.getActiveNetwork(), + mOldPrivateDnsSpecifier, true); + } else { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + } + } + + public void setPrivateDnsStrictMode(String server) { + // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures + // that if the previous private DNS mode was not "hostname", the system only sees one + // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two. + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server); + final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER. + if (!"hostname".equals(mode)) { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + } + } + public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, - @NonNull String server, int timeoutMs, - boolean requiresValidatedServers) throws InterruptedException { + @NonNull String server, boolean requiresValidatedServers) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); NetworkCallback callback = new NetworkCallback() { @@ -266,7 +316,7 @@ public final class CtsNetUtils { } }; mCm.registerNetworkCallback(request, callback); - assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS)); + assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); mCm.unregisterNetworkCallback(callback); // Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do // this, then the test could complete before the NetworkMonitor private DNS probe From dfe46ffb884ad355c7d48e6d6bac50e18116f0a6 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 20 May 2020 18:56:37 -0700 Subject: [PATCH 1104/1415] Create NetworkAgent CTS for NET_CAP_TEMP_NOT_METERED Test: atest NetworkAgentTest Bug: 155993662 Change-Id: Ic968bf37075c23e9ea7d98eaec7f4f37d9ebc337 Merged-In: Ic968bf37075c23e9ea7d98eaec7f4f37d9ebc337 --- .../src/android/net/cts/NetworkAgentTest.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 03b961bc4b..2824db7464 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -592,4 +592,50 @@ class NetworkAgentTest { assertNull(it.uri) } } + + @Test + fun testTemporarilyUnmeteredCapability() { + // This test will create a networks with/without NET_CAPABILITY_TEMPORARILY_NOT_METERED + // and check that the callback reflects the capability changes. + // First create a request to make sure the network is kept up + val request1 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback1 = TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also { + registerNetworkCallback(request1, it) + } + requestNetwork(request1, callback1) + + // Then file the interesting request + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback() + requestNetwork(request, callback) + + // Connect the network + createConnectedNetworkAgent().let { (agent, _) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + + // Send TEMP_NOT_METERED and check that the callback is called appropriately. + val nc1 = NetworkCapabilities(agent.nc) + .addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + agent.sendNetworkCapabilities(nc1) + callback.expectCapabilitiesThat(agent.network) { + it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + } + + // Remove TEMP_NOT_METERED and check that the callback is called appropriately. + val nc2 = NetworkCapabilities(agent.nc) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + agent.sendNetworkCapabilities(nc2) + callback.expectCapabilitiesThat(agent.network) { + !it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + } + } + + // tearDown() will unregister the requests and agents + } } From 214a8ea198404594817fbfb68fae6d1307694ba1 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 5 Feb 2020 11:02:02 -0800 Subject: [PATCH 1105/1415] Add CTS tests for ConnectivityDiagnostics callbacks. Verify that the callbacks onConnectivityReport() and onNetworkConnectivityReported() are invoked by the System when expected. ConnectivityDiagnosticsManager provides an API for registering callbacks with the System. These callbacks allow the System to notify registered and permissioned callbacks on Network validation, suspected data stalls, and Network connectivity reported. Bug: 148032944 Test: android.net.cts.ConnectivityDiagnosticsManagerTest Change-Id: I748229d41c16adf1561e03aa597d5aac00f12912 --- .../ConnectivityDiagnosticsManagerTest.java | 232 +++++++++++++++++- 1 file changed, 221 insertions(+), 11 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 9d357055d1..6687fdcbfb 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -17,19 +17,49 @@ package android.net.cts; import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityDiagnosticsManager; +import android.net.ConnectivityManager; +import android.net.LinkAddress; +import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.os.Binder; import android.os.Build; +import android.os.IBinder; +import android.os.PersistableBundle; +import android.os.Process; +import android.util.Pair; import androidx.test.InstrumentationRegistry; +import com.android.testutils.ArrayTrackRecord; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,33 +69,71 @@ import java.util.concurrent.Executor; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q public class ConnectivityDiagnosticsManagerTest { + private static final int CALLBACK_TIMEOUT_MILLIS = 5000; + private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500; + private static final Executor INLINE_EXECUTOR = x -> x.run(); - private static final NetworkRequest DEFAULT_REQUEST = new NetworkRequest.Builder().build(); + + private static final NetworkRequest TEST_NETWORK_REQUEST = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_TEST) + .removeCapability(NET_CAPABILITY_TRUSTED) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .build(); + + // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests + // for it. + private static final TestNetworkCallback TEST_NETWORK_CALLBACK = new TestNetworkCallback(); + + private static final IBinder BINDER = new Binder(); private Context mContext; + private ConnectivityManager mConnectivityManager; private ConnectivityDiagnosticsManager mCdm; - private ConnectivityDiagnosticsCallback mCallback; + private Network mTestNetwork; @Before public void setUp() throws Exception { mContext = InstrumentationRegistry.getContext(); + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class); - mCallback = new ConnectivityDiagnosticsCallback() {}; + mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, TEST_NETWORK_CALLBACK); + } + + @After + public void tearDown() throws Exception { + mConnectivityManager.unregisterNetworkCallback(TEST_NETWORK_CALLBACK); + + if (mTestNetwork != null) { + runWithShellPermissionIdentity(() -> { + final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); + tnm.teardownTestNetwork(mTestNetwork); + }); + } } @Test - public void testRegisterConnectivityDiagnosticsCallback() { - mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback); + public void testRegisterConnectivityDiagnosticsCallback() throws Exception { + mTestNetwork = setUpTestNetwork(); + + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); } @Test public void testRegisterDuplicateConnectivityDiagnosticsCallback() { - mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback); + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); try { - mCdm.registerConnectivityDiagnosticsCallback( - DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); fail("Registering the same callback twice should throw an IllegalArgumentException"); } catch (IllegalArgumentException expected) { } @@ -73,13 +141,155 @@ public class ConnectivityDiagnosticsManagerTest { @Test public void testUnregisterConnectivityDiagnosticsCallback() { - mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback); - mCdm.unregisterConnectivityDiagnosticsCallback(mCallback); + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + mCdm.unregisterConnectivityDiagnosticsCallback(cb); } @Test public void testUnregisterUnknownConnectivityDiagnosticsCallback() { // Expected to silently ignore the unregister() call - mCdm.unregisterConnectivityDiagnosticsCallback(mCallback); + mCdm.unregisterConnectivityDiagnosticsCallback(new TestConnectivityDiagnosticsCallback()); + } + + @Test + public void testOnConnectivityReportAvailable() throws Exception { + mTestNetwork = setUpTestNetwork(); + + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); + } + + @Test + public void testOnNetworkConnectivityReportedTrue() throws Exception { + verifyOnNetworkConnectivityReported(true /* hasConnectivity */); + } + + @Test + public void testOnNetworkConnectivityReportedFalse() throws Exception { + verifyOnNetworkConnectivityReported(false /* hasConnectivity */); + } + + private void verifyOnNetworkConnectivityReported(boolean hasConnectivity) throws Exception { + mTestNetwork = setUpTestNetwork(); + + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + + // onConnectivityReportAvailable always invoked when the test network is established + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); + + mConnectivityManager.reportNetworkConnectivity(mTestNetwork, hasConnectivity); + + cb.expectOnNetworkConnectivityReported(mTestNetwork, hasConnectivity); + + // if hasConnectivity does not match the network's known connectivity, it will be + // revalidated which will trigger another onConnectivityReportAvailable callback. + if (!hasConnectivity) { + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + } + + cb.assertNoCallback(); + } + + @NonNull + private Network waitForConnectivityServiceIdleAndGetNetwork() throws InterruptedException { + // Get a new Network. This requires going through the ConnectivityService thread. Once it + // completes, all previously enqueued messages on the ConnectivityService main Handler have + // completed. + final TestNetworkCallback callback = new TestNetworkCallback(); + mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, callback); + final Network network = callback.waitForAvailable(); + mConnectivityManager.unregisterNetworkCallback(callback); + assertNotNull(network); + return network; + } + + /** + * Registers a test NetworkAgent with ConnectivityService with limited capabilities, which leads + * to the Network being validated. + */ + @NonNull + private Network setUpTestNetwork() throws Exception { + final int[] administratorUids = new int[] {Process.myUid()}; + runWithShellPermissionIdentity( + () -> { + final TestNetworkManager tnm = + mContext.getSystemService(TestNetworkManager.class); + final TestNetworkInterface tni = tnm.createTunInterface(new LinkAddress[0]); + tnm.setupTestNetwork(tni.getInterfaceName(), administratorUids, BINDER); + }); + return waitForConnectivityServiceIdleAndGetNetwork(); + } + + private static class TestConnectivityDiagnosticsCallback + extends ConnectivityDiagnosticsCallback { + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + + @Override + public void onConnectivityReportAvailable(ConnectivityReport report) { + mHistory.add(report); + } + + @Override + public void onDataStallSuspected(DataStallReport report) { + mHistory.add(report); + } + + @Override + public void onNetworkConnectivityReported(Network network, boolean hasConnectivity) { + mHistory.add(new Pair(network, hasConnectivity)); + } + + public void expectOnConnectivityReportAvailable( + @NonNull Network network, @NonNull String interfaceName) { + final ConnectivityReport result = + (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.getNetwork()); + + final NetworkCapabilities nc = result.getNetworkCapabilities(); + assertNotNull(nc); + assertTrue(nc.hasTransport(TRANSPORT_TEST)); + assertNotNull(result.getLinkProperties()); + assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); + + final PersistableBundle extras = result.getAdditionalInfo(); + assertTrue(extras.containsKey(KEY_NETWORK_VALIDATION_RESULT)); + final int validationResult = extras.getInt(KEY_NETWORK_VALIDATION_RESULT); + assertEquals("Network validation result is not 'valid'", + NETWORK_VALIDATION_RESULT_VALID, validationResult); + + assertTrue(extras.containsKey(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK)); + final int probesSucceeded = extras.getInt(KEY_NETWORK_VALIDATION_RESULT); + assertTrue("PROBES_SUCCEEDED mask not in expected range", probesSucceeded >= 0); + + assertTrue(extras.containsKey(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK)); + final int probesAttempted = extras.getInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK); + assertTrue("PROBES_ATTEMPTED mask not in expected range", probesAttempted >= 0); + } + + public void expectOnNetworkConnectivityReported( + @NonNull Network network, boolean hasConnectivity) { + final Pair result = + (Pair) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.first /* network */); + assertEquals(hasConnectivity, result.second /* hasConnectivity */); + } + + public void assertNoCallback() { + // If no more callbacks exist, there should be nothing left in the ReadHead + assertNull("Unexpected event in history", + mHistory.poll(NO_CALLBACK_INVOKED_TIMEOUT, x -> true)); + } } } From d1e42d7e64a3f50784a0ae21a3adfa523fd84182 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 15 Apr 2020 13:43:45 -0700 Subject: [PATCH 1106/1415] Add CTS testing for ConnectivityDiagnostics Data Stall callback. Verify that onDataStallSuspected() is invoked by the System when expected. ConnectivityDiagnosticsManager provides an API for registering callbacks with the System. These callbacks allow the System to notify registered and permissioned callbacks on Network validation, suspected data stalls, and Network connectivity reported. Bug: 148032944 Test: atest ConnectivityDiagnosticsManagerTest Change-Id: If6ceae9d2bbcabf88298d2d8c39cad5275fbd1ef --- .../ConnectivityDiagnosticsManagerTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 6687fdcbfb..8cacb4351d 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -23,6 +23,12 @@ import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_ import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID; import static android.net.ConnectivityDiagnosticsManager.DataStallReport; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_TCP_METRICS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE; +import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; import static android.net.NetworkCapabilities.TRANSPORT_TEST; @@ -71,6 +77,10 @@ import java.util.concurrent.Executor; public class ConnectivityDiagnosticsManagerTest { private static final int CALLBACK_TIMEOUT_MILLIS = 5000; private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500; + private static final long TIMESTAMP = 123456789L; + private static final int DNS_CONSECUTIVE_TIMEOUTS = 5; + private static final int COLLECTION_PERIOD_MILLIS = 5000; + private static final int FAIL_RATE_PERCENTAGE = 100; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -166,6 +176,46 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } + @Test + public void testOnDataStallSuspected_DnsEvents() throws Exception { + final PersistableBundle extras = new PersistableBundle(); + extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, DNS_CONSECUTIVE_TIMEOUTS); + + verifyOnDataStallSuspected(DETECTION_METHOD_DNS_EVENTS, TIMESTAMP, extras); + } + + @Test + public void testOnDataStallSuspected_TcpMetrics() throws Exception { + final PersistableBundle extras = new PersistableBundle(); + extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS, COLLECTION_PERIOD_MILLIS); + extras.putInt(KEY_TCP_PACKET_FAIL_RATE, FAIL_RATE_PERCENTAGE); + + verifyOnDataStallSuspected(DETECTION_METHOD_TCP_METRICS, TIMESTAMP, extras); + } + + private void verifyOnDataStallSuspected( + int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras) + throws Exception { + mTestNetwork = setUpTestNetwork(); + + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + + runWithShellPermissionIdentity( + () -> mConnectivityManager.simulateDataStall( + detectionMethod, timestampMillis, mTestNetwork, extras), + android.Manifest.permission.MANAGE_TEST_NETWORKS); + + cb.expectOnDataStallSuspected( + mTestNetwork, interfaceName, detectionMethod, timestampMillis, extras); + cb.assertNoCallback(); + } + @Test public void testOnNetworkConnectivityReportedTrue() throws Exception { verifyOnNetworkConnectivityReported(true /* hasConnectivity */); @@ -278,6 +328,27 @@ public class ConnectivityDiagnosticsManagerTest { assertTrue("PROBES_ATTEMPTED mask not in expected range", probesAttempted >= 0); } + public void expectOnDataStallSuspected( + @NonNull Network network, + @NonNull String interfaceName, + int detectionMethod, + long timestampMillis, + @NonNull PersistableBundle extras) { + final DataStallReport result = + (DataStallReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.getNetwork()); + assertEquals(detectionMethod, result.getDetectionMethod()); + assertEquals(timestampMillis, result.getReportTimestamp()); + + final NetworkCapabilities nc = result.getNetworkCapabilities(); + assertNotNull(nc); + assertTrue(nc.hasTransport(TRANSPORT_TEST)); + assertNotNull(result.getLinkProperties()); + assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); + + assertTrue(persistableBundleEquals(extras, result.getStallDetails())); + } + public void expectOnNetworkConnectivityReported( @NonNull Network network, boolean hasConnectivity) { final Pair result = From 4ddd1debbd2c68fee816a8b5b8e744eaedc3ae82 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 15 May 2020 11:27:22 -0700 Subject: [PATCH 1107/1415] Test Data Stall with unknown detection type. This CL adds a CTS test for Data Stall events to ConnectivityDiagnostics. This makes sure that new DataStall detection methods are passed to ConnectivityDiagnostics callbacks with the appropriate detection method bit mask. Bug: 156294356 Bug: 148032944 Test: atest ConnectivityDiagnosticsManagerTest Change-Id: Id6f1bff59b08192f09ebcc4578a3c233fd1c2768 --- .../ConnectivityDiagnosticsManagerTest.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 8cacb4351d..0248f971dc 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -81,6 +81,8 @@ public class ConnectivityDiagnosticsManagerTest { private static final int DNS_CONSECUTIVE_TIMEOUTS = 5; private static final int COLLECTION_PERIOD_MILLIS = 5000; private static final int FAIL_RATE_PERCENTAGE = 100; + private static final int UNKNOWN_DETECTION_METHOD = 4; + private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -193,9 +195,28 @@ public class ConnectivityDiagnosticsManagerTest { verifyOnDataStallSuspected(DETECTION_METHOD_TCP_METRICS, TIMESTAMP, extras); } + @Test + public void testOnDataStallSuspected_UnknownDetectionMethod() throws Exception { + verifyOnDataStallSuspected( + UNKNOWN_DETECTION_METHOD, + FILTERED_UNKNOWN_DETECTION_METHOD, + TIMESTAMP, + PersistableBundle.EMPTY); + } + private void verifyOnDataStallSuspected( int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras) throws Exception { + // Input detection method is expected to match received detection method + verifyOnDataStallSuspected(detectionMethod, detectionMethod, timestampMillis, extras); + } + + private void verifyOnDataStallSuspected( + int inputDetectionMethod, + int expectedDetectionMethod, + long timestampMillis, + @NonNull PersistableBundle extras) + throws Exception { mTestNetwork = setUpTestNetwork(); final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); @@ -208,11 +229,11 @@ public class ConnectivityDiagnosticsManagerTest { runWithShellPermissionIdentity( () -> mConnectivityManager.simulateDataStall( - detectionMethod, timestampMillis, mTestNetwork, extras), + inputDetectionMethod, timestampMillis, mTestNetwork, extras), android.Manifest.permission.MANAGE_TEST_NETWORKS); cb.expectOnDataStallSuspected( - mTestNetwork, interfaceName, detectionMethod, timestampMillis, extras); + mTestNetwork, interfaceName, expectedDetectionMethod, timestampMillis, extras); cb.assertNoCallback(); } From 34e71a5b684b800657167ecc8b23a6ef8a72a265 Mon Sep 17 00:00:00 2001 From: evitayan Date: Tue, 5 May 2020 17:52:11 -0700 Subject: [PATCH 1108/1415] Cleanup of IkeSessionPskTest - Add java doc in IkeSessionTestBase about the necessity to use different addresses and Networks in each test - Use ArrayTrackRecord in Test Session Callback to retrieve the latest result. - Verify that IpSecTransform pair is created and deleted Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ib747c8cdfe1827e8df2aa7544e28e98a177d3d1c --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 51 +++++++++++-------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 19 ++++--- .../net/ipsec/ike/cts/IkeTunUtils.java | 4 +- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 336d12dad1..fb93398b26 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -99,19 +99,17 @@ public class IkeSessionPskTest extends IkeSessionTestBase { .addInternalAddressRequest(AF_INET6) .build(); - private IkeSessionParams createIkeSessionParams(InetAddress mRemoteAddress) { - return new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(mRemoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) - .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) - .setAuthPsk(IKE_PSK) - .build(); - } - - private IkeSession openIkeSession(IkeSessionParams ikeParams) { + private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + IkeSessionParams ikeParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(remoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) + .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) + .setAuthPsk(IKE_PSK) + .build(); return new IkeSession( sContext, ikeParams, @@ -126,7 +124,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { if (!hasTunnelsFeature()) return; // Open IKE Session - IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( IKE_INIT_SPI, @@ -167,6 +165,9 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + assertNotNull(mFirstChildSessionCallback.awaitNextCreatedIpSecTransform()); + assertNotNull(mFirstChildSessionCallback.awaitNextCreatedIpSecTransform()); + // Open additional Child Session TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); ikeSession.openChildSession(CHILD_PARAMS, additionalChildCb); @@ -183,9 +184,12 @@ public class IkeSessionPskTest extends IkeSessionTestBase { Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); assertTrue(additionalChildConfig.getInternalAddresses().isEmpty()); - assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); - assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); - assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + assertTrue(additionalChildConfig.getInternalSubnets().isEmpty()); + assertTrue(additionalChildConfig.getInternalDnsServers().isEmpty()); + assertTrue(additionalChildConfig.getInternalDhcpServers().isEmpty()); + + assertNotNull(additionalChildCb.awaitNextCreatedIpSecTransform()); + assertNotNull(additionalChildCb.awaitNextCreatedIpSecTransform()); // Close additional Child Session ikeSession.closeChildSession(additionalChildCb); @@ -195,6 +199,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { true /* expectedUseEncap */, hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); + assertNotNull(additionalChildCb.awaitNextDeletedIpSecTransform()); + assertNotNull(additionalChildCb.awaitNextDeletedIpSecTransform()); additionalChildCb.awaitOnClosed(); // Close IKE Session @@ -205,10 +211,12 @@ public class IkeSessionPskTest extends IkeSessionTestBase { true /* expectedUseEncap */, hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); + assertNotNull(mFirstChildSessionCallback.awaitNextDeletedIpSecTransform()); + assertNotNull(mFirstChildSessionCallback.awaitNextDeletedIpSecTransform()); mFirstChildSessionCallback.awaitOnClosed(); mIkeSessionCallback.awaitOnClosed(); - // TODO: verify IpSecTransform pair is created and deleted + // TODO: verify created and deleted IpSecTransform pair and their directions } @Test @@ -216,7 +224,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { if (!hasTunnelsFeature()) return; // Open IKE Session - IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( IKE_INIT_SPI, @@ -231,7 +239,6 @@ public class IkeSessionPskTest extends IkeSessionTestBase { hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); ikeSession.kill(); - mFirstChildSessionCallback.awaitOnClosed(); mIkeSessionCallback.awaitOnClosed(); } @@ -242,7 +249,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; // Open IKE Session - IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( IKE_INIT_SPI, @@ -250,6 +257,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { false /* expectedUseEncap */, hexStringToByteArray(ikeInitFailRespHex)); + mFirstChildSessionCallback.awaitOnClosed(); + IkeException exception = mIkeSessionCallback.awaitOnClosedException(); assertNotNull(exception); assertTrue(exception instanceof IkeProtocolException); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 1c1ffc922f..279d088b3c 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -40,7 +40,6 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.platform.test.annotations.AppModeFull; -import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -66,6 +65,13 @@ import java.util.concurrent.TimeUnit; * *

    Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use * the test network + * + *

    All IKE Sessions running in test mode will generate SPIs deterministically. That is to say + * each IKE Session will always generate the same IKE INIT SPI and test vectors are generated based + * on this deterministic IKE SPI. Each test will use different local and remote addresses to avoid + * the case that the next test try to allocate the same SPI before the previous test has released + * it, since SPI resources are not released in testing thread. Similarly, each test MUST use + * different Network instances to avoid sharing the same IkeSocket and hitting IKE SPI collision. */ @RunWith(AndroidJUnit4.class) @AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") @@ -117,7 +123,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { InstrumentationRegistry.getInstrumentation() .getUiAutomation() .adoptShellPermissionIdentity(); - sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + sTNM = sContext.getSystemService(TestNetworkManager.class); // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and // a standard permission is insufficient. So we shell out the appop, to give us the @@ -150,10 +156,6 @@ abstract class IkeSessionTestBase extends IkeTestBase { @After public void tearDown() throws Exception { tearDownTestNetwork(); - - resetNextAvailableAddress(NEXT_AVAILABLE_IP4_ADDR_LOCAL, INITIAL_AVAILABLE_IP4_ADDR_LOCAL); - resetNextAvailableAddress( - NEXT_AVAILABLE_IP4_ADDR_REMOTE, INITIAL_AVAILABLE_IP4_ADDR_REMOTE); } void setUpTestNetwork(InetAddress localAddr) throws Exception { @@ -186,9 +188,8 @@ abstract class IkeSessionTestBase extends IkeTestBase { pkg, // Package name opName, // Appop (allow ? "allow" : "deny")); // Action - Log.d("IKE", "CTS setAppOp cmd " + cmd); - String result = SystemUtil.runShellCommand(cmd); + SystemUtil.runShellCommand(cmd); } } @@ -230,6 +231,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + /** Testing callback that allows caller to block current thread until a method get called */ static class TestIkeSessionCallback implements IkeSessionCallback { private CompletableFuture mFutureIkeConfig = new CompletableFuture<>(); @@ -283,6 +285,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + /** Testing callback that allows caller to block current thread until a method get called */ static class TestChildSessionCallback implements ChildSessionCallback { private CompletableFuture mFutureChildConfig = new CompletableFuture<>(); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index 5a8258d57b..f52b88ba3a 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -121,7 +121,9 @@ public class IkeTunUtils extends TunUtils { + " and message ID " + expectedMsgId); } - return null; + + throw new IllegalStateException( + "Hit an impossible case where fail() didn't throw an exception"); } private static boolean isIke( From 6b94c31626e13a0ede67b7850e29b339e834a2ea Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Wed, 25 Mar 2020 16:04:32 -0700 Subject: [PATCH 1109/1415] tethering: offload: Netlink Req Send netlink request over fd for offload config before completing init sequence. Provides existing conntrack entries to IPA. Resolves issue where there are NAT misses in IPA due to IPA only having the conntrack entries added after tethering starts. Bug: 149109043 Test: OffloadHardwareInterfaceTest Change-Id: Iaf3e847e92f205b55f10fa85c17b9f3995d52099 --- .../tethering/OffloadHardwareInterface.java | 33 ++++++++++++++++ .../OffloadHardwareInterfaceTest.java | 39 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index fe92204c25..33b9d00e70 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -16,8 +16,11 @@ package com.android.networkstack.tethering; +import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP; +import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; import static android.net.util.TetheringUtils.uint16; +import android.annotation.NonNull; import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; import android.hardware.tetheroffload.control.V1_0.IOffloadControl; import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; @@ -25,6 +28,7 @@ import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; import android.net.netlink.NetlinkSocket; +import android.net.netlink.StructNlMsgHdr; import android.net.util.SharedLog; import android.net.util.SocketUtils; import android.os.Handler; @@ -37,9 +41,11 @@ import android.system.OsConstants; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; +import java.io.InterruptedIOException; import java.io.IOException; import java.net.SocketAddress; import java.net.SocketException; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.NoSuchElementException; @@ -63,6 +69,11 @@ public class OffloadHardwareInterface { private static final int NF_NETLINK_CONNTRACK_NEW = 1; private static final int NF_NETLINK_CONNTRACK_UPDATE = 2; private static final int NF_NETLINK_CONNTRACK_DESTROY = 4; + // Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h + public static final short NFNL_SUBSYS_CTNETLINK = 1; + public static final short IPCTNL_MSG_CT_GET = 1; + + private final long NETLINK_MESSAGE_TIMEOUT_MS = 500; private final Handler mHandler; private final SharedLog mLog; @@ -226,6 +237,9 @@ public class OffloadHardwareInterface { NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); if (h1 == null) return false; + sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET), + (short) (NLM_F_REQUEST | NLM_F_DUMP)); + final NativeHandle h2 = mDeps.createConntrackSocket( NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); if (h2 == null) { @@ -252,6 +266,25 @@ public class OffloadHardwareInterface { return results.mSuccess; } + @VisibleForTesting + public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) { + final int length = StructNlMsgHdr.STRUCT_SIZE; + final byte[] msg = new byte[length]; + final StructNlMsgHdr nlh = new StructNlMsgHdr(); + final ByteBuffer byteBuffer = ByteBuffer.wrap(msg); + nlh.nlmsg_len = length; + nlh.nlmsg_type = type; + nlh.nlmsg_flags = flags; + nlh.nlmsg_seq = 1; + nlh.pack(byteBuffer); + try { + NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length, + NETLINK_MESSAGE_TIMEOUT_MS); + } catch (ErrnoException | InterruptedIOException e) { + mLog.e("Unable to send netfilter message, error: " + e); + } + } + private void closeFdInNativeHandle(final NativeHandle h) { try { h.close(); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java index f8ff1cb29c..c543fad62d 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java @@ -17,13 +17,17 @@ package com.android.networkstack.tethering; import static android.net.util.TetheringUtils.uint16; +import static android.system.OsConstants.SOCK_STREAM; +import static android.system.OsConstants.AF_UNIX; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; import android.hardware.tetheroffload.control.V1_0.IOffloadControl; @@ -31,11 +35,14 @@ import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; +import android.net.netlink.StructNlMsgHdr; import android.net.util.SharedLog; import android.os.Handler; import android.os.NativeHandle; import android.os.test.TestLooper; +import android.system.ErrnoException; import android.system.OsConstants; +import android.system.Os; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -47,6 +54,9 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.io.FileDescriptor; +import java.io.OutputStream; +import java.nio.ByteBuffer; import java.util.ArrayList; @RunWith(AndroidJUnit4.class) @@ -64,6 +74,10 @@ public final class OffloadHardwareInterfaceTest { @Mock private IOffloadControl mIOffloadControl; @Mock private NativeHandle mNativeHandle; + // Random values to test Netlink message. + private static final short TEST_TYPE = 184; + private static final short TEST_FLAGS = 263; + class MyDependencies extends OffloadHardwareInterface.Dependencies { MyDependencies(SharedLog log) { super(log); @@ -203,6 +217,31 @@ public final class OffloadHardwareInterfaceTest { eq(uint16(udpParams.dst.port))); } + @Test + public void testNetlinkMessage() throws Exception { + FileDescriptor writeSocket = new FileDescriptor(); + FileDescriptor readSocket = new FileDescriptor(); + try { + Os.socketpair(AF_UNIX, SOCK_STREAM, 0, writeSocket, readSocket); + } catch (ErrnoException e) { + fail(); + return; + } + when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket); + + mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS); + + ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE); + int read = Os.read(readSocket, buffer); + + buffer.flip(); + assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt()); + assertEquals(TEST_TYPE, buffer.getShort()); + assertEquals(TEST_FLAGS, buffer.getShort()); + assertEquals(1 /* seq */, buffer.getInt()); + assertEquals(0 /* pid */, buffer.getInt()); + } + private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { final NatTimeoutUpdate params = new NatTimeoutUpdate(); params.proto = proto; From d63c4f35de30777533ae38e4e64e9fb53e24947e Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 21 May 2020 17:38:28 +0800 Subject: [PATCH 1110/1415] Adjust TTL for ipv6 tethering If upstream is cellular, set the TTL in Router Advertisements to "network-set TTL - 1" for carrier requirement. For other non-cellular upstream, set TTL as "network-set TTL + 1" to preventing arbitrary distinction between tethered and untethered traffic. Bug: 154776299 Test: atest TetheringTests Change-Id: I7f2696a642f96c6aafb5613b980bf5bcdd08bbda --- Tethering/src/android/net/ip/IpServer.java | 13 ++-- .../tethering/IPv6TetheringCoordinator.java | 19 +++++- .../unit/src/android/net/ip/IpServerTest.java | 62 ++++++++++++++++--- .../IPv6TetheringCoordinatorTest.java | 4 +- 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index de537871a7..659d344acf 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -738,7 +738,7 @@ public class IpServer extends StateMachine { // // TODO: Evaluate using a data structure than is more directly suited to // communicating only the relevant information. - private void updateUpstreamIPv6LinkProperties(LinkProperties v6only) { + private void updateUpstreamIPv6LinkProperties(LinkProperties v6only, int ttlAdjustment) { if (mRaDaemon == null) return; // Avoid unnecessary work on spurious updates. @@ -761,7 +761,7 @@ public class IpServer extends StateMachine { params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu(); params.hasDefaultRoute = v6only.hasIpv6DefaultRoute(); - if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface); + if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment); for (LinkAddress linkAddr : v6only.getLinkAddresses()) { if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue; @@ -1052,12 +1052,11 @@ public class IpServer extends StateMachine { } } - private byte getHopLimit(String upstreamIface) { + private byte getHopLimit(String upstreamIface, int adjustTTL) { try { int upstreamHopLimit = Integer.parseUnsignedInt( mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit")); - // Add one hop to account for this forwarding device - upstreamHopLimit++; + upstreamHopLimit = upstreamHopLimit + adjustTTL; // Cap the hop limit to 255. return (byte) Integer.min(upstreamHopLimit, 255); } catch (Exception e) { @@ -1145,7 +1144,7 @@ public class IpServer extends StateMachine { transitionTo(mUnavailableState); break; case CMD_IPV6_TETHER_UPDATE: - updateUpstreamIPv6LinkProperties((LinkProperties) message.obj); + updateUpstreamIPv6LinkProperties((LinkProperties) message.obj, message.arg1); break; default: return NOT_HANDLED; @@ -1209,7 +1208,7 @@ public class IpServer extends StateMachine { if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName); break; case CMD_IPV6_TETHER_UPDATE: - updateUpstreamIPv6LinkProperties((LinkProperties) message.obj); + updateUpstreamIPv6LinkProperties((LinkProperties) message.obj, message.arg1); sendLinkProperties(); break; case CMD_IP_FORWARDING_ENABLE_ERROR: diff --git a/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java b/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java index d450c46de7..f3dcaa2529 100644 --- a/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java @@ -161,11 +161,28 @@ public class IPv6TetheringCoordinator { private void updateIPv6TetheringInterfaces() { for (IpServer ipServer : mNotifyList) { final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer); - ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); + ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, getTtlAdjustment(), 0, lp); break; } } + private int getTtlAdjustment() { + if (mUpstreamNetworkState == null || mUpstreamNetworkState.networkCapabilities == null) { + return 0; + } + + // If upstream is cellular, set the TTL in Router Advertisements to "network-set TTL" - 1 + // for carrier requirement. + if (mUpstreamNetworkState.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_CELLULAR)) { + return -1; + } + + // For other non-cellular upstream, set TTL as "network-set TTL" + 1 to preventing arbitrary + // distinction between tethered and untethered traffic. + return 1; + } + private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) { final Downstream ds = findDownstream(ipServer); if (ds == null) return null; diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index cd1ff607b4..307ebf17d2 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -17,6 +17,7 @@ package android.net.ip; import static android.net.INetd.IF_STATE_UP; +import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; @@ -74,6 +75,7 @@ import android.net.dhcp.IDhcpServer; import android.net.dhcp.IDhcpServerCallbacks; import android.net.ip.IpNeighborMonitor.NeighborEvent; import android.net.ip.IpNeighborMonitor.NeighborEventConsumer; +import android.net.ip.RouterAdvertisementDaemon.RaParams; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.SharedLog; @@ -196,7 +198,7 @@ public class IpServerTest { if (upstreamIface != null) { LinkProperties lp = new LinkProperties(); lp.setInterfaceName(upstreamIface); - dispatchTetherConnectionChanged(upstreamIface, lp); + dispatchTetherConnectionChanged(upstreamIface, lp, 0); } reset(mNetd, mCallback); } @@ -694,7 +696,7 @@ public class IpServerTest { InOrder inOrder = inOrder(mNetd); LinkProperties lp = new LinkProperties(); lp.setInterfaceName(UPSTREAM_IFACE2); - dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp); + dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1); inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA)); inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB)); @@ -702,7 +704,7 @@ public class IpServerTest { reset(mNetd); // When the upstream is lost, rules are removed. - dispatchTetherConnectionChanged(null, null); + dispatchTetherConnectionChanged(null, null, 0); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB)); reset(mNetd); @@ -715,19 +717,19 @@ public class IpServerTest { // Rules can be added again once upstream IPv6 connectivity is available. lp.setInterfaceName(UPSTREAM_IFACE); - dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp); + dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); // If upstream IPv6 connectivity is lost, rules are removed. reset(mNetd); - dispatchTetherConnectionChanged(UPSTREAM_IFACE, null); + dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); // When the interface goes down, rules are removed. lp.setInterfaceName(UPSTREAM_IFACE); - dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp); + dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); @@ -788,6 +790,49 @@ public class IpServerTest { verify(mIpNeighborMonitor, never()).start(); } + private LinkProperties buildIpv6OnlyLinkProperties(final String iface) { + final LinkProperties linkProp = new LinkProperties(); + linkProp.setInterfaceName(iface); + linkProp.addLinkAddress(new LinkAddress("2001:db8::1/64")); + linkProp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, iface, RTN_UNICAST)); + final InetAddress dns = InetAddresses.parseNumericAddress("2001:4860:4860::8888"); + linkProp.addDnsServer(dns); + + return linkProp; + } + + @Test + public void testAdjustTtlValue() throws Exception { + final ArgumentCaptor raParamsCaptor = + ArgumentCaptor.forClass(RaParams.class); + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); + verify(mRaDaemon).buildNewRa(any(), raParamsCaptor.capture()); + final RaParams noV6Params = raParamsCaptor.getValue(); + assertEquals(65, noV6Params.hopLimit); + reset(mRaDaemon); + + when(mNetd.getProcSysNet( + INetd.IPV6, INetd.CONF, UPSTREAM_IFACE, "hop_limit")).thenReturn("64"); + final LinkProperties lp = buildIpv6OnlyLinkProperties(UPSTREAM_IFACE); + dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 1); + verify(mRaDaemon).buildNewRa(any(), raParamsCaptor.capture()); + final RaParams nonCellularParams = raParamsCaptor.getValue(); + assertEquals(65, nonCellularParams.hopLimit); + reset(mRaDaemon); + + dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0); + verify(mRaDaemon).buildNewRa(any(), raParamsCaptor.capture()); + final RaParams noUpstream = raParamsCaptor.getValue(); + assertEquals(65, nonCellularParams.hopLimit); + reset(mRaDaemon); + + dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1); + verify(mRaDaemon).buildNewRa(any(), raParamsCaptor.capture()); + final RaParams cellularParams = raParamsCaptor.getValue(); + assertEquals(63, cellularParams.hopLimit); + reset(mRaDaemon); + } + private void assertDhcpServingParams(final DhcpServingParamsParcel params, final IpPrefix prefix) { // Last address byte is random @@ -838,9 +883,10 @@ public class IpServerTest { * @param upstreamIface String name of upstream interface (or null) * @param v6lp IPv6 LinkProperties of the upstream interface, or null for an IPv4-only upstream. */ - private void dispatchTetherConnectionChanged(String upstreamIface, LinkProperties v6lp) { + private void dispatchTetherConnectionChanged(String upstreamIface, LinkProperties v6lp, + int ttlAdjustment) { dispatchTetherConnectionChanged(upstreamIface); - mIpServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, v6lp); + mIpServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, ttlAdjustment, 0, v6lp); mLooper.dispatchAll(); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java index 820f255145..f2b5314e5a 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java @@ -128,7 +128,7 @@ public class IPv6TetheringCoordinatorTest { final UpstreamNetworkState mobileUpstream = createDualStackUpstream(TRANSPORT_CELLULAR); final ArgumentCaptor lp = ArgumentCaptor.forClass(LinkProperties.class); mIPv6TetheringCoordinator.updateUpstreamNetworkState(mobileUpstream); - verify(firstServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(0), eq(0), + verify(firstServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(-1), eq(0), lp.capture()); final LinkProperties v6OnlyLink = lp.getValue(); assertOnlyOneV6AddressAndNoV4(v6OnlyLink); @@ -140,7 +140,7 @@ public class IPv6TetheringCoordinatorTest { mNotifyList.remove(firstServer); mIPv6TetheringCoordinator.removeActiveDownstream(firstServer); verify(firstServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); - verify(secondServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(0), eq(0), + verify(secondServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(-1), eq(0), lp.capture()); final LinkProperties localOnlyLink = lp.getValue(); assertNotNull(localOnlyLink); From 5a86f4b18a42d25f40b0f28717a65179a8383913 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 10 Feb 2020 23:39:36 +0800 Subject: [PATCH 1111/1415] Add a cts test for PermissionMonitor security problem Add a cts test to check whether app can have netd sytem permission even the app didn't grant the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. Bug: 144679405 Test: atest android.net.cts.ConnectivityManagerTest Change-Id: I2c717a11bda43db166a55d343eb752ab45947fe8 Merged-In: I2c717a11bda43db166a55d343eb752ab45947fe8 (cherry picked from commit 1bc6b39789dfc836fdb30d45914b0ba43736a87b, ag/10285567) --- tests/cts/net/AndroidManifest.xml | 1 + .../net/cts/ConnectivityManagerTest.java | 45 ++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index baf914f1ac..a7e2bd780a 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -26,6 +26,7 @@ + diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 1ee08ffa7a..baf5c2e302 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -16,13 +16,17 @@ package android.net.cts; +import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.content.pm.PackageManager.FEATURE_ETHERNET; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; -import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.content.pm.PackageManager.FEATURE_USB_HOST; +import static android.content.pm.PackageManager.FEATURE_WIFI; +import static android.content.pm.PackageManager.GET_PERMISSIONS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver; import static android.net.cts.util.CtsNetUtils.HTTP_PORT; @@ -45,6 +49,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.ConnectivityManager; @@ -59,10 +64,12 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; +import android.net.NetworkUtils; import android.net.SocketKeepalive; import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; +import android.os.Binder; import android.os.Build; import android.os.Looper; import android.os.MessageQueue; @@ -78,6 +85,8 @@ import android.util.Pair; import androidx.test.InstrumentationRegistry; +import com.android.internal.util.ArrayUtils; + import libcore.io.Streams; import java.io.FileDescriptor; @@ -1280,4 +1289,38 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue("" + greater + " expected to be greater than or equal to " + lesser, greater >= lesser); } + + /** + * Verifies that apps are not allowed to access restricted networks even if they declare the + * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests. + * See. b/144679405. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + public void testRestrictedNetworkPermission() throws Exception { + // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package. + final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(), + GET_PERMISSIONS); + final int index = ArrayUtils.indexOf( + app.requestedPermissions, CONNECTIVITY_USE_RESTRICTED_NETWORKS); + assertTrue(index >= 0); + assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED); + + // Ensure that NetworkUtils.queryUserAccess always returns false since this package should + // not have netd system permission to call this function. + final Network wifiNetwork = ensureWifiConnected(); + assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId)); + + // Ensure that this package cannot bind to any restricted network that's currently + // connected. + Network[] networks = mCm.getAllNetworks(); + for (Network network : networks) { + NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { + try { + network.bindSocket(new Socket()); + fail("Bind to restricted network " + network + " unexpectedly succeeded"); + } catch (IOException expected) {} + } + } + } } From 2f5879f6c733ad7583bb624a829b85bf6a97f82c Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 14 May 2020 12:55:05 +0900 Subject: [PATCH 1112/1415] Fix and deflake ConnectivityManagerTest - Migrate the test to JUnit4, as JUnit3 cannot use assumeTrue - Skip IPv4 keepalive tests on networks that do not have native IPv4. - Refactor usage of adoptShellPermissionIdentity to use try / finally or runAsShellPermissionIdentity: test failures could lead to permission failures in other tests due to mismatched adopt/drop. - Fix ensureWifiConnected to support the "wifi enabled but not fully connected" case. Bug: 150949391 Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest \ --rerun-until-failure 50 Change-Id: I7459753b1068e1760a95337760db58d1df213fad --- .../net/cts/ConnectivityManagerTest.java | 190 +++++++++++------- 1 file changed, 116 insertions(+), 74 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index baf5c2e302..d498ed9885 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -40,6 +40,16 @@ import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.AF_UNSPEC; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.app.Instrumentation; @@ -78,17 +88,22 @@ import android.os.SystemProperties; import android.os.VintfRuntimeInfo; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; -import android.test.AndroidTestCase; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.ArrayUtils; import libcore.io.Streams; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; @@ -114,7 +129,8 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class ConnectivityManagerTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class ConnectivityManagerTest { private static final String TAG = ConnectivityManagerTest.class.getSimpleName(); @@ -126,7 +142,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500; private static final int MAX_KEEPALIVE_RETRY_COUNT = 3; private static final int MIN_KEEPALIVE_INTERVAL = 10; - private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000; + + // Changing meteredness on wifi involves reconnecting, which can take several seconds (involves + // re-associating, DHCP...) + private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 30_000; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; // device could have only one interface: data, wifi. @@ -150,22 +169,19 @@ public class ConnectivityManagerTest extends AndroidTestCase { private PackageManager mPackageManager; private final HashMap mNetworks = new HashMap(); - boolean mWifiConnectAttempted; + boolean mWifiWasDisabled; private UiAutomation mUiAutomation; private CtsNetUtils mCtsNetUtils; - private boolean mShellPermissionIdentityAdopted; - @Override - protected void setUp() throws Exception { - super.setUp(); - Looper.prepare(); - mContext = getContext(); + @Before + public void setUp() throws Exception { mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mContext = mInstrumentation.getContext(); mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); mCtsNetUtils = new CtsNetUtils(mContext); - mWifiConnectAttempted = false; + mWifiWasDisabled = false; // Get com.android.internal.R.array.networkAttributes int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android"); @@ -182,20 +198,17 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (Exception e) {} } mUiAutomation = mInstrumentation.getUiAutomation(); - mShellPermissionIdentityAdopted = false; } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { // Return WiFi to its original disabled state after tests that explicitly connect. - if (mWifiConnectAttempted) { + if (mWifiWasDisabled) { mCtsNetUtils.disconnectFromWifi(null); } if (mCtsNetUtils.cellConnectAttempted()) { mCtsNetUtils.disconnectFromCell(); } - dropShellPermissionIdentity(); - super.tearDown(); } /** @@ -204,13 +217,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { * automatically in tearDown(). */ private Network ensureWifiConnected() { - if (mWifiManager.isWifiEnabled()) { - return mCtsNetUtils.getWifiNetwork(); - } - mWifiConnectAttempted = true; + mWifiWasDisabled = !mWifiManager.isWifiEnabled(); + // Even if wifi is enabled, the network may not be connected or ready yet return mCtsNetUtils.connectToWifi(); } + @Test public void testIsNetworkTypeValid() { assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE)); assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI)); @@ -240,12 +252,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } + @Test public void testSetNetworkPreference() { // getNetworkPreference() and setNetworkPreference() are both deprecated so they do // not preform any action. Verify they are at least still callable. mCm.setNetworkPreference(mCm.getNetworkPreference()); } + @Test public void testGetActiveNetworkInfo() { NetworkInfo ni = mCm.getActiveNetworkInfo(); @@ -254,6 +268,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue(ni.getState() == State.CONNECTED); } + @Test public void testGetActiveNetwork() { Network network = mCm.getActiveNetwork(); assertNotNull("You must have an active network connection to complete CTS", network); @@ -266,6 +281,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue(ni.getState() == State.CONNECTED); } + @Test public void testGetNetworkInfo() { for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { if (shouldBeSupported(type)) { @@ -284,6 +300,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + @Test public void testGetAllNetworkInfo() { NetworkInfo[] ni = mCm.getAllNetworkInfo(); assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); @@ -307,6 +324,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * and that they are made from different IP addresses. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testOpenConnection() throws Exception { boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); @@ -386,6 +404,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (UnsupportedOperationException expected) {} } + @Test public void testStartUsingNetworkFeature() { final String invalidateFeature = "invalidateFeature"; @@ -415,6 +434,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported()); } + @Test public void testIsNetworkSupported() { for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { boolean supported = mCm.isNetworkSupported(type); @@ -426,12 +446,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + @Test public void testRequestRouteToHost() { for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { assertRequestRouteToHostUnsupported(type, HOST_ADDRESS); } } + @Test public void testTest() { mCm.getBackgroundDataSetting(); } @@ -452,6 +474,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?). */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRegisterNetworkCallback() { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); @@ -493,6 +516,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * of a {@code NetworkCallback}. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRegisterNetworkCallback_withPendingIntent() { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); @@ -538,6 +562,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * see if we get a callback for an INTERNET request. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + @Test public void testRequestNetworkCallback() { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.requestNetwork(new NetworkRequest.Builder() @@ -561,6 +586,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * fail. Use WIFI and switch Wi-Fi off. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRequestNetworkCallback_onUnavailable() { final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); if (previousWifiEnabledState) { @@ -598,6 +624,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { /** Verify restricted networks cannot be requested. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + @Test public void testRestrictedNetworks() { // Verify we can request unrestricted networks: NetworkRequest request = new NetworkRequest.Builder() @@ -719,6 +746,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * for metered and unmetered networks. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testGetMultipathPreference() throws Exception { final ContentResolver resolver = mContext.getContentResolver(); ensureWifiConnected(); @@ -887,18 +915,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { keepalivesPerTransport, nc); } - private void adoptShellPermissionIdentity() { - mUiAutomation.adoptShellPermissionIdentity(); - mShellPermissionIdentityAdopted = true; - } - - private void dropShellPermissionIdentity() { - if (mShellPermissionIdentityAdopted) { - mUiAutomation.dropShellPermissionIdentity(); - mShellPermissionIdentityAdopted = false; - } - } - private static boolean isTcpKeepaliveSupportedByKernel() { final String kVersionString = VintfRuntimeInfo.getKernelVersion(); return compareMajorMinorVersion(kVersionString, "4.8") >= 0; @@ -933,6 +949,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * Verifies that version string compare logic returns expected result for various cases. * Note that only major and minor number are compared. */ + @Test public void testMajorMinorVersionCompare() { assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8")); assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1")); @@ -952,6 +969,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * keepalives is set to 0. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testKeepaliveWifiUnsupported() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device" @@ -961,32 +979,36 @@ public class ConnectivityManagerTest extends AndroidTestCase { final Network network = ensureWifiConnected(); if (getSupportedKeepalivesForNet(network) != 0) return; + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); - - assertEquals(0, createConcurrentSocketKeepalives(network, 1, 0)); - assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); - - dropShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0)); + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); + }); } @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testCreateTcpKeepalive() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi"); return; } - adoptShellPermissionIdentity(); - final Network network = ensureWifiConnected(); if (getSupportedKeepalivesForNet(network) == 0) return; + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive // needs to be supported except if the kernel doesn't support it. if (!isTcpKeepaliveSupportedByKernel()) { // Sanity check to ensure the callback result is expected. - assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); + runWithShellPermissionIdentity(() -> { + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); + }); Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " + VintfRuntimeInfo.getKernelVersion()); return; @@ -1000,6 +1022,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Should able to start keep alive offload when socket is idle. final Executor executor = mContext.getMainExecutor(); final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + + mUiAutomation.adoptShellPermissionIdentity(); try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { sk.start(MIN_KEEPALIVE_INTERVAL); callback.expectStarted(); @@ -1021,6 +1045,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Stop. sk.stop(); callback.expectStopped(); + } finally { + mUiAutomation.dropShellPermissionIdentity(); } // Ensure socket is still connected. @@ -1049,9 +1075,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue // that has not been read. + mUiAutomation.adoptShellPermissionIdentity(); try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { sk.start(MIN_KEEPALIVE_INTERVAL); callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); + } finally { + mUiAutomation.dropShellPermissionIdentity(); } } } @@ -1096,7 +1125,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } private @NonNull ArrayList createConcurrentNattSocketKeepalives( - @NonNull Network network, int requestCount, + @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount, @NonNull TestSocketKeepaliveCallback callback) throws Exception { final Executor executor = mContext.getMainExecutor(); @@ -1104,7 +1133,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Initialize a real NaT-T socket. final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); - final InetAddress srcAddr = getFirstV4Address(network); final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); assertNotNull(srcAddr); assertNotNull(dstAddr); @@ -1145,11 +1173,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { * @return the total number of keepalives created. */ private int createConcurrentSocketKeepalives( - @NonNull Network network, int nattCount, int tcpCount) throws Exception { + @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount) + throws Exception { final ArrayList kalist = new ArrayList<>(); final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); - kalist.addAll(createConcurrentNattSocketKeepalives(network, nattCount, callback)); + kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback)); kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback)); final int ret = kalist.size(); @@ -1169,6 +1198,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * get leaked after iterations. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testSocketKeepaliveLimitWifi() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device" @@ -1181,33 +1211,39 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (supported == 0) { return; } + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. + assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); - // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. - assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); - - // Verifies that Nat-T keepalives can be established. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); - // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0)); + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, + 0)); + }); // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. - if (isTcpKeepaliveSupportedByKernel()) { - assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported + 1)); + if (!isTcpKeepaliveSupportedByKernel()) return; + + runWithShellPermissionIdentity(() -> { + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, + supported + 1)); // Verifies that different types can be established at the same time. - assertEquals(supported, createConcurrentSocketKeepalives(network, + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported / 2, supported - supported / 2)); // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported)); - assertEquals(supported, createConcurrentSocketKeepalives(network, + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, + supported)); + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported / 2, supported - supported / 2)); - } - - dropShellPermissionIdentity(); + }); } /** @@ -1215,6 +1251,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * don't get leaked after iterations. */ @AppModeFull(reason = "Cannot request network in instant app mode") + @Test public void testSocketKeepaliveLimitTelephony() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" @@ -1231,18 +1268,19 @@ public class ConnectivityManagerTest extends AndroidTestCase { final Network network = mCtsNetUtils.connectToCell(); final int supported = getSupportedKeepalivesForNet(network); + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); - - // Verifies that the supported keepalive slots meet minimum requirement. - assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); - - // Verifies that Nat-T keepalives can be established. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); - // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0)); - - dropShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + // Verifies that the supported keepalive slots meet minimum requirement. + assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, + 0)); + }); } private int getIntResourceForName(@NonNull String resName) { @@ -1255,6 +1293,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * Verifies that the keepalive slots are limited as customized for unprivileged requests. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testSocketKeepaliveUnprivileged() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device" @@ -1267,6 +1306,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (supported == 0) { return; } + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); // Resource ID might be shifted on devices that compiled with different symbols. // Thus, resolve ID at runtime is needed. @@ -1282,7 +1323,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { final int expectedUnprivileged = Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); assertEquals(expectedUnprivileged, - createConcurrentSocketKeepalives(network, supported + 1, 0)); + createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0)); } private static void assertGreaterOrEqual(long greater, long lesser) { @@ -1296,6 +1337,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * See. b/144679405. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRestrictedNetworkPermission() throws Exception { // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package. final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(), From aa660b56cf82d320e5158241e5462beb70301702 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 25 May 2020 18:22:22 +0900 Subject: [PATCH 1113/1415] Use Q permission on Q for startCaptivePortalApp on Q startCaptivePortalApp was guarded by CONNECTIVITY_INTERNAL instead of NETWORK_SETTINGS: change the permission adopted by shell on Q to match the platform. Test: atest CaptivePortalTest on a Q device Bug: 150904735 Change-Id: I24b6907d164aba07df0f5a1a3715669e99cddd88 --- tests/cts/net/src/android/net/cts/CaptivePortalTest.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 4418e1740e..0816aba750 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -16,6 +16,7 @@ package android.net.cts +import android.Manifest.permission.CONNECTIVITY_INTERNAL import android.Manifest.permission.NETWORK_SETTINGS import android.Manifest.permission.READ_DEVICE_CONFIG import android.Manifest.permission.WRITE_DEVICE_CONFIG @@ -31,6 +32,7 @@ import android.net.NetworkRequest import android.net.Uri import android.net.cts.util.CtsNetUtils import android.net.wifi.WifiManager +import android.os.Build import android.os.ConditionVariable import android.platform.test.annotations.AppModeFull import android.provider.DeviceConfig @@ -164,7 +166,10 @@ class CaptivePortalTest { "access." assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) - doAsShell(NETWORK_SETTINGS) { cm.startCaptivePortalApp(network) } + val startPortalAppPermission = + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) CONNECTIVITY_INTERNAL + else NETWORK_SETTINGS + doAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " + "page was still not fetched ${TEST_TIMEOUT_MS}ms after startCaptivePortalApp.") From 6dfe6412a2b16535329745b436dc889c53248601 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 25 May 2020 19:21:21 +0900 Subject: [PATCH 1114/1415] Skip testTemporarilyNotMeteredCapability on Q The capability did not exist on Q. Bug: 155993662 Test: atest NetworkRequestTest Change-Id: I94e874e37cadadd90397278bf519db68db48a50f --- tests/cts/net/src/android/net/cts/NetworkRequestTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index e8af1b38f2..d118c8a0ca 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -87,7 +87,7 @@ public class NetworkRequestTest { verifyNoCapabilities(nr); } - @Test + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testTemporarilyNotMeteredCapability() { assertTrue(new NetworkRequest.Builder() .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build() From 8c91b0feaf0fe34a7d62f0df8f7b0cd86161f8fe Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 26 May 2020 00:40:14 +0000 Subject: [PATCH 1115/1415] Fix and deflake ConnectivityManagerTest - Migrate the test to JUnit4, as JUnit3 cannot use assumeTrue - Skip IPv4 keepalive tests on networks that do not have native IPv4. - Refactor usage of adoptShellPermissionIdentity to use try / finally or runAsShellPermissionIdentity: test failures could lead to permission failures in other tests due to mismatched adopt/drop. - Fix ensureWifiConnected to support the "wifi enabled but not fully connected" case. Bug: 150949391 Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest \ --rerun-until-failure 50 Original-Change: https://android-review.googlesource.com/1310419 Merged-In: I7459753b1068e1760a95337760db58d1df213fad Change-Id: I7459753b1068e1760a95337760db58d1df213fad --- .../net/cts/ConnectivityManagerTest.java | 190 +++++++++++------- 1 file changed, 116 insertions(+), 74 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index baf5c2e302..d498ed9885 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -40,6 +40,16 @@ import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.AF_UNSPEC; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.app.Instrumentation; @@ -78,17 +88,22 @@ import android.os.SystemProperties; import android.os.VintfRuntimeInfo; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; -import android.test.AndroidTestCase; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.ArrayUtils; import libcore.io.Streams; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; @@ -114,7 +129,8 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class ConnectivityManagerTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class ConnectivityManagerTest { private static final String TAG = ConnectivityManagerTest.class.getSimpleName(); @@ -126,7 +142,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500; private static final int MAX_KEEPALIVE_RETRY_COUNT = 3; private static final int MIN_KEEPALIVE_INTERVAL = 10; - private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000; + + // Changing meteredness on wifi involves reconnecting, which can take several seconds (involves + // re-associating, DHCP...) + private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 30_000; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; // device could have only one interface: data, wifi. @@ -150,22 +169,19 @@ public class ConnectivityManagerTest extends AndroidTestCase { private PackageManager mPackageManager; private final HashMap mNetworks = new HashMap(); - boolean mWifiConnectAttempted; + boolean mWifiWasDisabled; private UiAutomation mUiAutomation; private CtsNetUtils mCtsNetUtils; - private boolean mShellPermissionIdentityAdopted; - @Override - protected void setUp() throws Exception { - super.setUp(); - Looper.prepare(); - mContext = getContext(); + @Before + public void setUp() throws Exception { mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mContext = mInstrumentation.getContext(); mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); mCtsNetUtils = new CtsNetUtils(mContext); - mWifiConnectAttempted = false; + mWifiWasDisabled = false; // Get com.android.internal.R.array.networkAttributes int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android"); @@ -182,20 +198,17 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (Exception e) {} } mUiAutomation = mInstrumentation.getUiAutomation(); - mShellPermissionIdentityAdopted = false; } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { // Return WiFi to its original disabled state after tests that explicitly connect. - if (mWifiConnectAttempted) { + if (mWifiWasDisabled) { mCtsNetUtils.disconnectFromWifi(null); } if (mCtsNetUtils.cellConnectAttempted()) { mCtsNetUtils.disconnectFromCell(); } - dropShellPermissionIdentity(); - super.tearDown(); } /** @@ -204,13 +217,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { * automatically in tearDown(). */ private Network ensureWifiConnected() { - if (mWifiManager.isWifiEnabled()) { - return mCtsNetUtils.getWifiNetwork(); - } - mWifiConnectAttempted = true; + mWifiWasDisabled = !mWifiManager.isWifiEnabled(); + // Even if wifi is enabled, the network may not be connected or ready yet return mCtsNetUtils.connectToWifi(); } + @Test public void testIsNetworkTypeValid() { assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE)); assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI)); @@ -240,12 +252,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } + @Test public void testSetNetworkPreference() { // getNetworkPreference() and setNetworkPreference() are both deprecated so they do // not preform any action. Verify they are at least still callable. mCm.setNetworkPreference(mCm.getNetworkPreference()); } + @Test public void testGetActiveNetworkInfo() { NetworkInfo ni = mCm.getActiveNetworkInfo(); @@ -254,6 +268,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue(ni.getState() == State.CONNECTED); } + @Test public void testGetActiveNetwork() { Network network = mCm.getActiveNetwork(); assertNotNull("You must have an active network connection to complete CTS", network); @@ -266,6 +281,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue(ni.getState() == State.CONNECTED); } + @Test public void testGetNetworkInfo() { for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { if (shouldBeSupported(type)) { @@ -284,6 +300,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + @Test public void testGetAllNetworkInfo() { NetworkInfo[] ni = mCm.getAllNetworkInfo(); assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); @@ -307,6 +324,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * and that they are made from different IP addresses. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testOpenConnection() throws Exception { boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); @@ -386,6 +404,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (UnsupportedOperationException expected) {} } + @Test public void testStartUsingNetworkFeature() { final String invalidateFeature = "invalidateFeature"; @@ -415,6 +434,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported()); } + @Test public void testIsNetworkSupported() { for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { boolean supported = mCm.isNetworkSupported(type); @@ -426,12 +446,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + @Test public void testRequestRouteToHost() { for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { assertRequestRouteToHostUnsupported(type, HOST_ADDRESS); } } + @Test public void testTest() { mCm.getBackgroundDataSetting(); } @@ -452,6 +474,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?). */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRegisterNetworkCallback() { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); @@ -493,6 +516,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * of a {@code NetworkCallback}. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRegisterNetworkCallback_withPendingIntent() { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); @@ -538,6 +562,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * see if we get a callback for an INTERNET request. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + @Test public void testRequestNetworkCallback() { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.requestNetwork(new NetworkRequest.Builder() @@ -561,6 +586,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * fail. Use WIFI and switch Wi-Fi off. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRequestNetworkCallback_onUnavailable() { final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); if (previousWifiEnabledState) { @@ -598,6 +624,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { /** Verify restricted networks cannot be requested. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + @Test public void testRestrictedNetworks() { // Verify we can request unrestricted networks: NetworkRequest request = new NetworkRequest.Builder() @@ -719,6 +746,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * for metered and unmetered networks. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testGetMultipathPreference() throws Exception { final ContentResolver resolver = mContext.getContentResolver(); ensureWifiConnected(); @@ -887,18 +915,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { keepalivesPerTransport, nc); } - private void adoptShellPermissionIdentity() { - mUiAutomation.adoptShellPermissionIdentity(); - mShellPermissionIdentityAdopted = true; - } - - private void dropShellPermissionIdentity() { - if (mShellPermissionIdentityAdopted) { - mUiAutomation.dropShellPermissionIdentity(); - mShellPermissionIdentityAdopted = false; - } - } - private static boolean isTcpKeepaliveSupportedByKernel() { final String kVersionString = VintfRuntimeInfo.getKernelVersion(); return compareMajorMinorVersion(kVersionString, "4.8") >= 0; @@ -933,6 +949,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * Verifies that version string compare logic returns expected result for various cases. * Note that only major and minor number are compared. */ + @Test public void testMajorMinorVersionCompare() { assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8")); assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1")); @@ -952,6 +969,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * keepalives is set to 0. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testKeepaliveWifiUnsupported() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device" @@ -961,32 +979,36 @@ public class ConnectivityManagerTest extends AndroidTestCase { final Network network = ensureWifiConnected(); if (getSupportedKeepalivesForNet(network) != 0) return; + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); - - assertEquals(0, createConcurrentSocketKeepalives(network, 1, 0)); - assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); - - dropShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0)); + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); + }); } @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testCreateTcpKeepalive() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi"); return; } - adoptShellPermissionIdentity(); - final Network network = ensureWifiConnected(); if (getSupportedKeepalivesForNet(network) == 0) return; + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive // needs to be supported except if the kernel doesn't support it. if (!isTcpKeepaliveSupportedByKernel()) { // Sanity check to ensure the callback result is expected. - assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); + runWithShellPermissionIdentity(() -> { + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); + }); Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " + VintfRuntimeInfo.getKernelVersion()); return; @@ -1000,6 +1022,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Should able to start keep alive offload when socket is idle. final Executor executor = mContext.getMainExecutor(); final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + + mUiAutomation.adoptShellPermissionIdentity(); try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { sk.start(MIN_KEEPALIVE_INTERVAL); callback.expectStarted(); @@ -1021,6 +1045,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Stop. sk.stop(); callback.expectStopped(); + } finally { + mUiAutomation.dropShellPermissionIdentity(); } // Ensure socket is still connected. @@ -1049,9 +1075,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue // that has not been read. + mUiAutomation.adoptShellPermissionIdentity(); try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { sk.start(MIN_KEEPALIVE_INTERVAL); callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); + } finally { + mUiAutomation.dropShellPermissionIdentity(); } } } @@ -1096,7 +1125,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } private @NonNull ArrayList createConcurrentNattSocketKeepalives( - @NonNull Network network, int requestCount, + @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount, @NonNull TestSocketKeepaliveCallback callback) throws Exception { final Executor executor = mContext.getMainExecutor(); @@ -1104,7 +1133,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Initialize a real NaT-T socket. final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); - final InetAddress srcAddr = getFirstV4Address(network); final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); assertNotNull(srcAddr); assertNotNull(dstAddr); @@ -1145,11 +1173,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { * @return the total number of keepalives created. */ private int createConcurrentSocketKeepalives( - @NonNull Network network, int nattCount, int tcpCount) throws Exception { + @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount) + throws Exception { final ArrayList kalist = new ArrayList<>(); final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); - kalist.addAll(createConcurrentNattSocketKeepalives(network, nattCount, callback)); + kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback)); kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback)); final int ret = kalist.size(); @@ -1169,6 +1198,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * get leaked after iterations. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testSocketKeepaliveLimitWifi() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device" @@ -1181,33 +1211,39 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (supported == 0) { return; } + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. + assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); - // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. - assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); - - // Verifies that Nat-T keepalives can be established. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); - // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0)); + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, + 0)); + }); // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. - if (isTcpKeepaliveSupportedByKernel()) { - assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported + 1)); + if (!isTcpKeepaliveSupportedByKernel()) return; + + runWithShellPermissionIdentity(() -> { + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, + supported + 1)); // Verifies that different types can be established at the same time. - assertEquals(supported, createConcurrentSocketKeepalives(network, + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported / 2, supported - supported / 2)); // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported)); - assertEquals(supported, createConcurrentSocketKeepalives(network, + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, + supported)); + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported / 2, supported - supported / 2)); - } - - dropShellPermissionIdentity(); + }); } /** @@ -1215,6 +1251,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * don't get leaked after iterations. */ @AppModeFull(reason = "Cannot request network in instant app mode") + @Test public void testSocketKeepaliveLimitTelephony() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" @@ -1231,18 +1268,19 @@ public class ConnectivityManagerTest extends AndroidTestCase { final Network network = mCtsNetUtils.connectToCell(); final int supported = getSupportedKeepalivesForNet(network); + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); - - // Verifies that the supported keepalive slots meet minimum requirement. - assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); - - // Verifies that Nat-T keepalives can be established. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); - // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0)); - - dropShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + // Verifies that the supported keepalive slots meet minimum requirement. + assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, + 0)); + }); } private int getIntResourceForName(@NonNull String resName) { @@ -1255,6 +1293,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * Verifies that the keepalive slots are limited as customized for unprivileged requests. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testSocketKeepaliveUnprivileged() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device" @@ -1267,6 +1306,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (supported == 0) { return; } + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); // Resource ID might be shifted on devices that compiled with different symbols. // Thus, resolve ID at runtime is needed. @@ -1282,7 +1323,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { final int expectedUnprivileged = Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); assertEquals(expectedUnprivileged, - createConcurrentSocketKeepalives(network, supported + 1, 0)); + createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0)); } private static void assertGreaterOrEqual(long greater, long lesser) { @@ -1296,6 +1337,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * See. b/144679405. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRestrictedNetworkPermission() throws Exception { // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package. final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(), From e878df691e4d7f820a6c190343a0396c1988d420 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 26 May 2020 00:40:42 +0000 Subject: [PATCH 1116/1415] Use Q permission on Q for startCaptivePortalApp on Q startCaptivePortalApp was guarded by CONNECTIVITY_INTERNAL instead of NETWORK_SETTINGS: change the permission adopted by shell on Q to match the platform. Test: atest CaptivePortalTest on a Q device Bug: 150904735 Original-Change: https://android-review.googlesource.com/1316081 Merged-In: I24b6907d164aba07df0f5a1a3715669e99cddd88 Change-Id: I24b6907d164aba07df0f5a1a3715669e99cddd88 --- tests/cts/net/src/android/net/cts/CaptivePortalTest.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 4418e1740e..0816aba750 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -16,6 +16,7 @@ package android.net.cts +import android.Manifest.permission.CONNECTIVITY_INTERNAL import android.Manifest.permission.NETWORK_SETTINGS import android.Manifest.permission.READ_DEVICE_CONFIG import android.Manifest.permission.WRITE_DEVICE_CONFIG @@ -31,6 +32,7 @@ import android.net.NetworkRequest import android.net.Uri import android.net.cts.util.CtsNetUtils import android.net.wifi.WifiManager +import android.os.Build import android.os.ConditionVariable import android.platform.test.annotations.AppModeFull import android.provider.DeviceConfig @@ -164,7 +166,10 @@ class CaptivePortalTest { "access." assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) - doAsShell(NETWORK_SETTINGS) { cm.startCaptivePortalApp(network) } + val startPortalAppPermission = + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) CONNECTIVITY_INTERNAL + else NETWORK_SETTINGS + doAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " + "page was still not fetched ${TEST_TIMEOUT_MS}ms after startCaptivePortalApp.") From d79613570deb2ed4ed2b0e19b51f07aa2be5f4af Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 26 May 2020 00:41:04 +0000 Subject: [PATCH 1117/1415] Skip testTemporarilyNotMeteredCapability on Q The capability did not exist on Q. Bug: 155993662 Test: atest NetworkRequestTest Original-Change: https://android-review.googlesource.com/1316082 Merged-In: I94e874e37cadadd90397278bf519db68db48a50f Change-Id: I94e874e37cadadd90397278bf519db68db48a50f --- tests/cts/net/src/android/net/cts/NetworkRequestTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index e8af1b38f2..d118c8a0ca 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -87,7 +87,7 @@ public class NetworkRequestTest { verifyNoCapabilities(nr); } - @Test + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testTemporarilyNotMeteredCapability() { assertTrue(new NetworkRequest.Builder() .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build() From e79e02e5c4a3bef48331f72ecc6ae166eac7700d Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 25 May 2020 14:03:00 +0800 Subject: [PATCH 1118/1415] Remove platform cert from Tethering tests Bug: 156866746 Test: atest TetheringTests, TetheringCoverageTests Change-Id: I7c539f1f4a447b5913164b222601c6113c6fe645 --- Tethering/tests/integration/Android.bp | 1 - Tethering/tests/unit/Android.bp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp index 3305ed0844..ed69b7d63c 100644 --- a/Tethering/tests/integration/Android.bp +++ b/Tethering/tests/integration/Android.bp @@ -63,7 +63,6 @@ android_test { // NetworkStackTests. android_test { name: "TetheringCoverageTests", - certificate: "platform", platform_apis: true, test_suites: ["device-tests", "mts"], test_config: "AndroidTest_Coverage.xml", diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp index 9b7d68309f..d1e8f5fc77 100644 --- a/Tethering/tests/unit/Android.bp +++ b/Tethering/tests/unit/Android.bp @@ -82,7 +82,7 @@ android_library { android_test { name: "TetheringTests", - certificate: "platform", + platform_apis: true, test_suites: [ "device-tests", "mts", From fd4a967604904a1fcbbef710dfef7e618fce3daa Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Fri, 22 May 2020 16:27:28 +0000 Subject: [PATCH 1119/1415] Deflaky test for DnsResolverTest It's possible that private DNS setting is not in the state we expected when we tried to enable strict mode during tests. The problem here is that there are 2 setting Uris(mode and specifier) relating to strict mode, each of them might trigger private DNS setting changing evnet in ConnectivityService. Previously, we tried to enable strict mode with first set private DNS mode and then private DNS specifier. This may result in 2 consecutive private DNS changes events with very short intervals, which caused conflicts between DnsResolver / NetworkMonitor and lead to flaky tests. So 0. Use opportunistic as default mode if no default mode existed. 1. Change the order (mode and specifier) for enabling strict mode. 2. Change private DNS mode only when needed. (If original mode is "hostname", then we only need to set specifier) Bug: 153624005 Bug: 151122313 Bug: 150952393 Test: atest DnsResolverTest --rerun-until-failure 100 Test: forrest (git_master, cts/networking/gce-all) Test: forrest (git_rvc-dev, atest CtsNetTestCases) Test: forrest (git_rvc-dev, mts/dnsresolver/device-all) Merged-In: I224a6493c87cebaf0bf954c2644e2945ccd50db1 Change-Id: Ib61ad7bd510341366ebbbb72aa451e5809ee3e9d (cherry picked from commit 7561b1499c1b8da0334b32c0452d49113d9e4806) --- .../src/android/net/cts/DnsResolverTest.java | 35 ++--------- .../android/net/cts/MultinetworkApiTest.java | 23 ++----- .../android/net/cts/util/CtsNetUtils.java | 62 +++++++++++++++++-- 3 files changed, 66 insertions(+), 54 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 1cc49f900a..28753ffc41 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -86,7 +86,6 @@ public class DnsResolverTest extends AndroidTestCase { static final int CANCEL_RETRY_TIMES = 5; static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; - static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; private ContentResolver mCR; private ConnectivityManager mCM; @@ -107,32 +106,15 @@ public class DnsResolverTest extends AndroidTestCase { mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - storePrivateDnsSetting(); + mCtsNetUtils.storePrivateDnsSetting(); } @Override protected void tearDown() throws Exception { - restorePrivateDnsSetting(); + mCtsNetUtils.restorePrivateDnsSetting(); super.tearDown(); } - private void storePrivateDnsSetting() { - // Store private DNS setting - mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - private void restorePrivateDnsSetting() throws InterruptedException { - // restore private DNS setting - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); - if ("hostname".equals(mOldMode)) { - Settings.Global.putString( - mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); - mCtsNetUtils.awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", - mCM.getActiveNetwork(), mOldDnsSpecifier, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); - } - } - private static String byteArrayToHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int i = 0; i < bytes.length; ++i) { @@ -416,16 +398,13 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { final Network networkForPrivateDns = (network != null) ? network : mCM.getActiveNetwork(); assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, - PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, true); final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, executor, null, callback); @@ -688,9 +667,7 @@ public class DnsResolverTest extends AndroidTestCase { final Network[] testNetworks = getTestableNetworks(); // Set an invalid private DNS server - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(INVALID_PRIVATE_DNS_SERVER); final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; for (Network network : testNetworks) { // This test cannot be ran with null network because we need to explicitly pass a @@ -699,7 +676,7 @@ public class DnsResolverTest extends AndroidTestCase { // wait for private DNS setting propagating mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, false); + network, INVALID_PRIVATE_DNS_SERVER, false); final CountDownLatch latch = new CountDownLatch(1); final DnsResolver.Callback> errorCallback = diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index f123187d86..985e313a92 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -41,7 +41,6 @@ public class MultinetworkApiTest extends AndroidTestCase { private static final String TAG = "MultinetworkNativeApiTest"; static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; - static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; /** * @return 0 on success @@ -69,7 +68,7 @@ public class MultinetworkApiTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - storePrivateDnsSetting(); + mCtsNetUtils.storePrivateDnsSetting(); } @Override @@ -77,18 +76,6 @@ public class MultinetworkApiTest extends AndroidTestCase { super.tearDown(); } - private void storePrivateDnsSetting() { - // Store private DNS setting - mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); - } - - private void restorePrivateDnsSetting() { - // restore private DNS setting - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier); - } - private Network[] getTestableNetworks() { final ArrayList testableNetworks = new ArrayList(); for (Network network : mCM.getAllNetworks()) { @@ -239,17 +226,15 @@ public class MultinetworkApiTest extends AndroidTestCase { // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 try { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); for (Network network : getTestableNetworks()) { // Wait for private DNS setting to propagate. mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", - network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, true); + network, GOOGLE_PRIVATE_DNS_SERVER, true); runResNnxDomainCheck(network.getNetworkHandle()); } } finally { - restorePrivateDnsSetting(); + mCtsNetUtils.restorePrivateDnsSetting(); } } } 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 824146fedf..f39b184914 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 @@ -17,6 +17,7 @@ package android.net.cts.util; import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -28,6 +29,7 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; @@ -39,6 +41,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.wifi.WifiManager; +import android.provider.Settings; import android.system.Os; import android.system.OsConstants; import android.util.Log; @@ -59,6 +62,7 @@ public final class CtsNetUtils { private static final int SOCKET_TIMEOUT_MS = 2000; private static final int PRIVATE_DNS_PROBE_MS = 1_000; + public static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; public static final int HTTP_PORT = 80; public static final String TEST_HOST = "connectivitycheck.gstatic.com"; public static final String HTTP_REQUEST = @@ -69,15 +73,19 @@ public final class CtsNetUtils { public static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; - private Context mContext; - private ConnectivityManager mCm; - private WifiManager mWifiManager; + private final Context mContext; + private final ConnectivityManager mCm; + private final ContentResolver mCR; + private final WifiManager mWifiManager; private TestNetworkCallback mCellNetworkCallback; + private String mOldPrivateDnsMode; + private String mOldPrivateDnsSpecifier; public CtsNetUtils(Context context) { mContext = context; mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mCR = context.getContentResolver(); } // Toggle WiFi twice, leaving it in the state it started in @@ -249,9 +257,51 @@ public final class CtsNetUtils { return s; } + public void storePrivateDnsSetting() { + // Store private DNS setting + mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldPrivateDnsSpecifier = Settings.Global.getString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER); + // It's possible that there is no private DNS default value in Settings. + // Give it a proper default mode which is opportunistic mode. + if (mOldPrivateDnsMode == null) { + mOldPrivateDnsSpecifier = ""; + mOldPrivateDnsMode = PRIVATE_DNS_MODE_OPPORTUNISTIC; + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, mOldPrivateDnsSpecifier); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + } + } + + public void restorePrivateDnsSetting() throws InterruptedException { + if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) { + return; + } + // restore private DNS setting + if ("hostname".equals(mOldPrivateDnsMode)) { + setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); + awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", + mCm.getActiveNetwork(), + mOldPrivateDnsSpecifier, true); + } else { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + } + } + + public void setPrivateDnsStrictMode(String server) { + // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures + // that if the previous private DNS mode was not "hostname", the system only sees one + // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two. + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server); + final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER. + if (!"hostname".equals(mode)) { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + } + } + public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, - @NonNull String server, int timeoutMs, - boolean requiresValidatedServers) throws InterruptedException { + @NonNull String server, boolean requiresValidatedServers) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); NetworkCallback callback = new NetworkCallback() { @@ -266,7 +316,7 @@ public final class CtsNetUtils { } }; mCm.registerNetworkCallback(request, callback); - assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS)); + assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); mCm.unregisterNetworkCallback(callback); // Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do // this, then the test could complete before the NetworkMonitor private DNS probe From 46b3c762bbbca6c42544ae8bed973fd98314d7bf Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 26 May 2020 17:12:40 +0900 Subject: [PATCH 1120/1415] Skip NetworkStatsBinderTest on Q The fix verified by that test is only applied on R+. Test: atest NetworkStatsBinderTest Bug: 150904735 Change-Id: I5ac69a121e5fa1b927ec94f3873f5c31b9031419 --- .../net/cts/NetworkStatsBinderTest.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java b/tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java index 1f3162fdd1..1a48983028 100644 --- a/tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java @@ -18,12 +18,15 @@ package android.net.cts; import static android.os.Process.INVALID_UID; +import static org.junit.Assert.assertEquals; + 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.Build; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; @@ -31,8 +34,15 @@ import android.test.AndroidTestCase; import android.util.SparseArray; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.CollectionUtils; +import com.android.testutils.DevSdkIgnoreRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -41,17 +51,22 @@ import java.util.List; import java.util.function.Function; import java.util.function.Predicate; -public class NetworkStatsBinderTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class NetworkStatsBinderTest { // 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; + @Rule + public DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule( + Build.VERSION_CODES.Q /* ignoreClassUpTo */); + private final SparseArray> mUidStatsQueryOpArray = new SparseArray<>(); - @Override - protected void setUp() throws Exception { + @Before + public 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)); @@ -75,6 +90,7 @@ public class NetworkStatsBinderTest extends AndroidTestCase { return INVALID_UID; } + @Test public void testAccessUidStatsFromBinder() throws Exception { final int myUid = Process.myUid(); final List testUidList = new ArrayList<>(); From 908f1d33651e5674562321e4f948056697e0dbe4 Mon Sep 17 00:00:00 2001 From: evitayan Date: Thu, 7 May 2020 15:58:25 -0700 Subject: [PATCH 1121/1415] Verify creation and deletion of IpSecTransform pair - Verify that inbound and outbound IpSecTransforms are created when a Child Session is created - Verify that when Child Session is deleted, the IpSecTransform pair is deleted Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: If142b3fb2ac791322921beeab1bc8d43db255317 --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 26 +++++---- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 54 +++++++++++++++++++ 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index fb93398b26..ca7ee1fe49 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -165,8 +165,11 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); - assertNotNull(mFirstChildSessionCallback.awaitNextCreatedIpSecTransform()); - assertNotNull(mFirstChildSessionCallback.awaitNextCreatedIpSecTransform()); + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); // Open additional Child Session TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); @@ -188,8 +191,11 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertTrue(additionalChildConfig.getInternalDnsServers().isEmpty()); assertTrue(additionalChildConfig.getInternalDhcpServers().isEmpty()); - assertNotNull(additionalChildCb.awaitNextCreatedIpSecTransform()); - assertNotNull(additionalChildCb.awaitNextCreatedIpSecTransform()); + IpSecTransformCallRecord additionalTransformRecordA = + additionalChildCb.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord additionalTransformRecordB = + additionalChildCb.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(additionalTransformRecordA, additionalTransformRecordB); // Close additional Child Session ikeSession.closeChildSession(additionalChildCb); @@ -199,8 +205,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { true /* expectedUseEncap */, hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); - assertNotNull(additionalChildCb.awaitNextDeletedIpSecTransform()); - assertNotNull(additionalChildCb.awaitNextDeletedIpSecTransform()); + verifyDeleteIpSecTransformPair( + additionalChildCb, additionalTransformRecordA, additionalTransformRecordB); additionalChildCb.awaitOnClosed(); // Close IKE Session @@ -211,12 +217,10 @@ public class IkeSessionPskTest extends IkeSessionTestBase { true /* expectedUseEncap */, hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); - assertNotNull(mFirstChildSessionCallback.awaitNextDeletedIpSecTransform()); - assertNotNull(mFirstChildSessionCallback.awaitNextDeletedIpSecTransform()); + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); mFirstChildSessionCallback.awaitOnClosed(); mIkeSessionCallback.awaitOnClosed(); - - // TODO: verify created and deleted IpSecTransform pair and their directions } @Test @@ -245,7 +249,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { @Test public void testIkeInitFail() throws Exception { - String ikeInitFailRespHex = + final String ikeInitFailRespHex = "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; // Open IKE Session diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 279d088b3c..e49f75fabb 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -17,12 +17,16 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.InetAddresses; +import android.net.IpSecManager; import android.net.IpSecTransform; import android.net.LinkAddress; import android.net.Network; @@ -55,6 +59,9 @@ import org.junit.runner.RunWith; import java.net.Inet4Address; import java.net.InetAddress; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -370,6 +377,53 @@ abstract class IkeSessionTestBase extends IkeTestBase { this.ipSecTransform = ipSecTransform; this.direction = direction; } + + @Override + public int hashCode() { + return Objects.hash(ipSecTransform, direction); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof IpSecTransformCallRecord)) return false; + + IpSecTransformCallRecord record = (IpSecTransformCallRecord) o; + return ipSecTransform.equals(record.ipSecTransform) && direction == record.direction; + } + } + + static void verifyCreateIpSecTransformPair( + IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) { + IpSecTransform transformA = transformRecordA.ipSecTransform; + IpSecTransform transformB = transformRecordB.ipSecTransform; + + assertNotNull(transformA); + assertNotNull(transformB); + + Set expectedDirections = new HashSet<>(); + expectedDirections.add(IpSecManager.DIRECTION_IN); + expectedDirections.add(IpSecManager.DIRECTION_OUT); + + Set resultDirections = new HashSet<>(); + resultDirections.add(transformRecordA.direction); + resultDirections.add(transformRecordB.direction); + + assertEquals(expectedDirections, resultDirections); + } + + static void verifyDeleteIpSecTransformPair( + TestChildSessionCallback childCb, + IpSecTransformCallRecord expectedTransformRecordA, + IpSecTransformCallRecord expectedTransformRecordB) { + Set expectedTransforms = new HashSet<>(); + expectedTransforms.add(expectedTransformRecordA); + expectedTransforms.add(expectedTransformRecordB); + + Set resultTransforms = new HashSet<>(); + resultTransforms.add(childCb.awaitNextDeletedIpSecTransform()); + resultTransforms.add(childCb.awaitNextDeletedIpSecTransform()); + + assertEquals(expectedTransforms, resultTransforms); } /** Package private method to check if device has IPsec tunnels feature */ From 13f043a8db409b38981befb7aab17f62277ae6fe Mon Sep 17 00:00:00 2001 From: evitayan Date: Sun, 10 May 2020 21:58:24 -0700 Subject: [PATCH 1122/1415] Move common logic in testing and verification to IkeSessionTestBase This commit moves following logics to IkeSessionTestBase so that all subclasses can share it: - build ChildParams - perform IKE and first Child setup - perform deleting IKE - verifying IKE and first Child setup Bug: 155821007 Test: atest CtsIkeTestCases:IkeSessionDigitalSignatureTest Change-Id: Ib35b18240396a7b4823111e37be9a338d8ff6f06 --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 125 ++++-------------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 93 ++++++++++++- .../net/ipsec/ike/cts/IkeTunUtils.java | 69 +++++----- 3 files changed, 153 insertions(+), 134 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index ca7ee1fe49..661457ff5e 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -16,25 +16,17 @@ package android.net.ipsec.ike.cts; -import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static com.android.internal.util.HexDump.hexStringToByteArray; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.LinkAddress; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionConfiguration; -import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.platform.test.annotations.AppModeFull; @@ -45,10 +37,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.util.ArrayList; import java.util.Arrays; @RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +@AppModeFull(reason = "MANAGE_IPSEC_TUNNELS permission can't be granted to instant apps") public class IkeSessionPskTest extends IkeSessionTestBase { // Test vectors for success workflow private static final String SUCCESS_IKE_INIT_RESP = @@ -89,16 +82,6 @@ public class IkeSessionPskTest extends IkeSessionTestBase { + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" + "6743A7CEB2BE34AC00095A5B8"; - private static final long IKE_INIT_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); - - private static final TunnelModeChildSessionParams CHILD_PARAMS = - new TunnelModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addInternalAddressRequest(AF_INET) - .addInternalAddressRequest(AF_INET6) - .build(); - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { IkeSessionParams ikeParams = new IkeSessionParams.Builder(sContext) @@ -113,7 +96,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { return new IkeSession( sContext, ikeParams, - CHILD_PARAMS, + buildTunnelModeChildSessionParams(), mUserCbExecutor, mIkeSessionCallback, mFirstChildSessionCallback); @@ -125,45 +108,17 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open IKE Session IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); + performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 + int expectedMsgId = 2; - // Verify opening IKE Session - IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); - assertNotNull(ikeConfig); - assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); - assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); - assertTrue(ikeConfig.getPcscfServers().isEmpty()); - assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); - - IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); - assertNotNull(ikeConnectInfo); - assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); - assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); - assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); - - // Verify opening first Child Session - ChildSessionConfiguration firstChildConfig = mFirstChildSessionCallback.awaitChildConfig(); - assertNotNull(firstChildConfig); - assertEquals( - Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); - assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); - assertEquals( - Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR), - firstChildConfig.getInternalAddresses()); - assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); - assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); - assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TUNNEL_MODE_INBOUND_TS), + Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), + Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR)); IpSecTransformCallRecord firstTransformRecordA = mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); @@ -173,24 +128,19 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open additional Child Session TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); - ikeSession.openChildSession(CHILD_PARAMS, additionalChildCb); + ikeSession.openChildSession(buildTunnelModeChildSessionParams(), additionalChildCb); mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_CREATE_CHILD_RESP)); + SUCCESS_CREATE_CHILD_RESP); // Verify opening additional Child Session - ChildSessionConfiguration additionalChildConfig = additionalChildCb.awaitChildConfig(); - assertNotNull(additionalChildConfig); - assertEquals( - Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); - assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); - assertTrue(additionalChildConfig.getInternalAddresses().isEmpty()); - assertTrue(additionalChildConfig.getInternalSubnets().isEmpty()); - assertTrue(additionalChildConfig.getInternalDnsServers().isEmpty()); - assertTrue(additionalChildConfig.getInternalDhcpServers().isEmpty()); - + verifyChildSessionSetupBlocking( + additionalChildCb, + Arrays.asList(TUNNEL_MODE_INBOUND_TS), + Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), + new ArrayList()); IpSecTransformCallRecord additionalTransformRecordA = additionalChildCb.awaitNextCreatedIpSecTransform(); IpSecTransformCallRecord additionalTransformRecordB = @@ -200,10 +150,10 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Close additional Child Session ikeSession.closeChildSession(additionalChildCb); mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); + SUCCESS_DELETE_CHILD_RESP); verifyDeleteIpSecTransformPair( additionalChildCb, additionalTransformRecordA, additionalTransformRecordB); @@ -211,16 +161,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Close IKE Session ikeSession.close(); - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); - - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); + performCloseIkeBlocking(expectedMsgId++, SUCCESS_DELETE_IKE_RESP); + verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); } @Test @@ -229,18 +171,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open IKE Session IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); - - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); ikeSession.kill(); mFirstChildSessionCallback.awaitOnClosed(); @@ -256,10 +187,10 @@ public class IkeSessionPskTest extends IkeSessionTestBase { IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, false /* expectedUseEncap */, - hexStringToByteArray(ikeInitFailRespHex)); + ikeInitFailRespHex); mFirstChildSessionCallback.awaitOnClosed(); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index e49f75fabb..ade9813a81 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -16,9 +16,13 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import android.annotation.NonNull; import android.app.AppOpsManager; @@ -37,7 +41,9 @@ import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -60,6 +66,7 @@ import org.junit.runner.RunWith; import java.net.Inet4Address; import java.net.InetAddress; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -90,9 +97,13 @@ abstract class IkeSessionTestBase extends IkeTestBase { InetAddresses.parseNumericAddress("198.51.100.10"); static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR = new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN); - static final IkeTrafficSelector EXPECTED_INBOUND_TS = + + static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS = new IkeTrafficSelector( MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); + static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS; + + static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); // Static state to reduce setup/teardown static Context sContext = InstrumentationRegistry.getContext(); @@ -238,6 +249,45 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { + return new TunnelModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .build(); + } + + void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String ikeAuthRespHex) + throws Exception { + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 0 /* expectedMsgId */, + false /* expectedUseEncap */, + ikeInitRespHex); + + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 1 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeAuthRespHex); + } + + void performSetupIkeAndFirstChildBlocking( + String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespPktHex) + throws Exception { + // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple IKE AUTH + // request fragments and injecting multiple IKE AUTH response fragments + } + + void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId, + true /* expectedUseEncap */, + deleteIkeRespHex); + } + /** Testing callback that allows caller to block current thread until a method get called */ static class TestIkeSessionCallback implements IkeSessionCallback { private CompletableFuture mFutureIkeConfig = @@ -392,6 +442,47 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + void verifyIkeSessionSetupBlocking() throws Exception { + IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); + assertNotNull(ikeConfig); + assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); + assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); + assertTrue(ikeConfig.getPcscfServers().isEmpty()); + assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); + + IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); + assertNotNull(ikeConnectInfo); + assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); + assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); + assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); + } + + void verifyChildSessionSetupBlocking( + TestChildSessionCallback childCallback, + List expectedInboundTs, + List expectedOutboundTs, + List expectedInternalAddresses) + throws Exception { + ChildSessionConfiguration childConfig = childCallback.awaitChildConfig(); + assertNotNull(childConfig); + assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors()); + assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors()); + assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses()); + assertTrue(childConfig.getInternalSubnets().isEmpty()); + assertTrue(childConfig.getInternalDnsServers().isEmpty()); + assertTrue(childConfig.getInternalDhcpServers().isEmpty()); + } + + void verifyCloseIkeAndChildBlocking( + IpSecTransformCallRecord expectedTransformRecordA, + IpSecTransformCallRecord expectedTransformRecordB) + throws Exception { + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, expectedTransformRecordA, expectedTransformRecordB); + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } + static void verifyCreateIpSecTransformPair( IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) { IpSecTransform transformA = transformRecordA.ipSecTransform; diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index f52b88ba3a..2bff63a753 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -26,6 +26,8 @@ import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader; import static android.system.OsConstants.IPPROTO_UDP; +import static com.android.internal.util.HexDump.hexStringToByteArray; + import static org.junit.Assert.fail; import android.os.ParcelFileDescriptor; @@ -35,6 +37,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.function.Predicate; public class IkeTunUtils extends TunUtils { private static final int PORT_LEN = 2; @@ -54,17 +57,24 @@ public class IkeTunUtils extends TunUtils { /** * Await the expected IKE request and inject an IKE response. * - * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER. + * @param ikeRespDataHex IKE response hex without IP/UDP headers or NON ESP MARKER. */ public byte[] awaitReqAndInjectResp( - long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, byte[] respIkePkt) + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedUseEncap, + String ikeRespDataHex) throws Exception { byte[] request = awaitIkePacket( - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap); + (pkt) -> { + return isExpectedIkePkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap); + }); // Build response header by flipping address and port InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); @@ -73,32 +83,26 @@ public class IkeTunUtils extends TunUtils { int dstPort = getPort(request, true /* shouldGetSource */); byte[] response = - buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, expectedUseEncap, respIkePkt); + buildIkePacket( + srcAddr, + dstAddr, + srcPort, + dstPort, + expectedUseEncap, + hexStringToByteArray(ikeRespDataHex)); injectPacket(response); return request; } - private byte[] awaitIkePacket( - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp, - boolean expectedUseEncap) - throws Exception { + // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple + // request fragments and injecting multiple response fragments + + private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; int startIndex = 0; synchronized (mPackets) { while (System.currentTimeMillis() < endTime) { - byte[] ikePkt = - getFirstMatchingPacket( - (pkt) -> { - return isIke( - pkt, - expectedInitIkeSpi, - expectedMsgId, - expectedResp, - expectedUseEncap); - }, - startIndex); + byte[] ikePkt = getFirstMatchingPacket(pktVerifier, startIndex); if (ikePkt != null) { return ikePkt; // We've found the packet we're looking for. } @@ -112,21 +116,14 @@ public class IkeTunUtils extends TunUtils { } } - String direction = expectedResp ? "response" : "request"; - fail( - "No such IKE " - + direction - + " found with Initiator SPI " - + expectedInitIkeSpi - + " and message ID " - + expectedMsgId); + fail("No matching packet found"); } throw new IllegalStateException( "Hit an impossible case where fail() didn't throw an exception"); } - private static boolean isIke( + private static boolean isExpectedIkePkt( byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, @@ -153,7 +150,7 @@ public class IkeTunUtils extends TunUtils { } return pkt[ipProtocolOffset] == IPPROTO_UDP - && areSpiAndMsgIdEqual( + && isExpectedSpiAndMsgId( pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); } @@ -170,10 +167,10 @@ public class IkeTunUtils extends TunUtils { return Arrays.equals(NON_ESP_MARKER, nonEspMarker); } - private static boolean areSpiAndMsgIdEqual( + private static boolean isExpectedSpiAndMsgId( byte[] pkt, int ikeOffset, - long expectedIkeInitSpi, + long expectedInitIkeSpi, int expectedMsgId, boolean expectedResp) { if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false; From ab4bc2dd359f23841c6ea96436235a4dfc813514 Mon Sep 17 00:00:00 2001 From: evitayan Date: Sun, 10 May 2020 21:58:24 -0700 Subject: [PATCH 1123/1415] Test IKE Session setup with digital-signature-based Auth This commit adds a test for setting up IKE Session with digital-signature-based authentication. This test also verifies sending and receiving IKE fragments Bug: 155821007 Test: atest CtsIkeTestCases:IkeSessionDigitalSignatureTest Change-Id: I5829dfa955c47c0810760b7bf97372031e740f1e --- .../cts/IkeSessionDigitalSignatureTest.java | 210 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeSessionPskTest.java | 20 +- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 50 +++-- .../net/ipsec/ike/cts/IkeTunUtils.java | 166 ++++++++++---- .../android/net/ipsec/ike/cts/TunUtils.java | 2 +- 5 files changed, 383 insertions(+), 65 deletions(-) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java new file mode 100644 index 0000000000..ebf8a41f00 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java @@ -0,0 +1,210 @@ +/* + * 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.ipsec.ike.cts; + +import android.net.InetAddresses; +import android.net.LinkAddress; +import android.net.ipsec.ike.IkeDerAsn1DnIdentification; +import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTrafficSelector; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.internal.net.ipsec.ike.testutils.CertUtils; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.util.ArrayList; +import java.util.Arrays; + +import javax.security.auth.x500.X500Principal; + +/** + * Explicitly test setting up transport mode Child SA so that devices do not have + * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in + * IkeSessionPskTest and authentication method is orthogonal to Child mode. + */ +@RunWith(AndroidJUnit4.class) +public class IkeSessionDigitalSignatureTest extends IkeSessionTestBase { + private static final int EXPECTED_AUTH_REQ_FRAG_COUNT = 3; + + private static final String IKE_INIT_RESP = + "46B8ECA1E0D72A18BF3FA1C2CB1EE86F21202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0100030000080300000503000008" + + "0200000400000008040000022800008800020000328451C8A976CE69E407966A" + + "50D7320C4197A15A07267CE1B16BAFF9BDBBDEC1FDCDAAF7175ADF9AA8DB55DB" + + "2D70C012D01D914C4EDEF6E8B226868EA1D01B2ED0C4C5C86E6BFE566010EC0C" + + "33BA1C93666430B88BDA0470D82CC4F4416F49E3E361E3017C9F27811A66718B" + + "389E1800915D776D59AA528A7E1D1B7815D35144290000249FE8FABE7F43D917" + + "CE370DE2FD9C22BBC082951AC26C1BA26DE795470F2C25BC2900001C00004004" + + "AE388EC86D6D1A470D44142D01AB2E85A7AC14182900001C0000400544A235A4" + + "171C884286B170F48FFC181DB428D87D290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + private static final String IKE_AUTH_RESP_FRAG_1 = + "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000004E0240004C4" + + "00010002DF6750A2D1D5675006F9F6230BB886FFD20CFB973FD04963CFD7A528" + + "560598C58CC44178B2FCBBBBB271387AC81A664B7E7F1055B912F8C686E287C9" + + "D31684C66339151AB86DA3CF1DA664052FA97687634558A1E9E6B37E16A86BD1" + + "68D76DA5E2E1E0B7E98EB662D80D542307015D2BF134EBBBE425D6954FE8C2C4" + + "D31D16C16AA0521C3C481F873ECF25BB8B05AC6083775C1821CAAB1E35A3955D" + + "85ACC599574142E1DD5B262D6E5365CBF6EBE92FFCC16BC29EC3239456F3B202" + + "492551C0F6D752ADCCA56D506D50CC8809EF6BC56EAD005586F7168F76445FD3" + + "1366CC62D32C0C19B28210B8F813F97CD6A447C3857EFD6EC483DDA8ACD9870E" + + "5A21B9C66F0FA44496C0C3D05E8859A1A4CFC88155D0C411BABC13033DD41FA4" + + "AF08CE7734A146687F374F95634D1F26843203CA1FFD05CA3EB150CEA02FBF14" + + "712B7A1C9BC7616A086E7FCA059E7D64EFF98DB895B32F8F7002762AF7D12F23" + + "31E9DD25174C4CE273E5392BBB48F50B7A3E0187181216265F6A4FC7B91BE0AB" + + "C601A580149D4B07411AE99DDB1944B977E86ADC9746605C60A92B569EEFAFFC" + + "3A888D187B75D8F13249689FC28EBCD62B5E03AF171F3A561F0DEA3B1A75F531" + + "971157DCE1E7BC6E7789FF3E8156015BC9C521EFE48996B41471D33BF09864E4" + + "2436E8D7EB6218CDE7716DA754A924B123A63E25585BF27F4AC043A0C4AECE38" + + "BB59DD62F5C0EC657206A76CED1BD26262237DA1CA6815435992A825758DEBEC" + + "DDF598A22B8242AC4E34E70704DBA7B7B73DC3E067C1C98764F8791F84C99156" + + "947D1FFC875F36FCE24B89369C1B5BF1D4C999DCA28E72A528D0E0163C66C067" + + "E71B5E0025C13DA93313942F9EDA230B3ADC254821A4CB1A5DC9D0C5F4DC4E8E" + + "CE46B7B8C72D3C5923C9B30DF1EF7B4EDEDA8BD05C86CA0162AE1BF8F277878E" + + "607401BAA8F06E3EA873FA4C137324C4E0699277CDF649FE7F0F01945EE25FA7" + + "0E4A89737E58185B11B4CB52FD5B0497D3E3CD1CEE7B1FBB3E969DB6F4C324A1" + + "32DC6A0EA21F41332435FD99140C286F8ABBBA926953ADBEED17D30AAD953909" + + "1347EF6D87163D6B1FF32D8B11FFB2E69FAEE7FE913D3826FBA7F9D11E0E3C57" + + "27625B37D213710B5DD8965DAEFD3F491E8C029E2BF361039949BADEC31D60AC" + + "355F26EE41339C03CC9D9B01C3C7F288F0E9D6DFEE78231BDA9AC10FED135913" + + "2836B1A17CE060742B7E5B738A7177CCD59F70337BA251409C377A0FA5333204" + + "D8622BA8C06DE0BEF4F32B6D4D77BE9DE977445D8A2A08C5C38341CB7974FBFB" + + "22C8F983A7D6CEF068DDB2281E6673453521C831C1826861005AE5F37649BC64" + + "0A6360B23284861441A440F1C5AADE1AB53CA63DB17F4C314D493C4C44DE5F20" + + "75E084D080F92791F30BDD88373D50AB5A07BC72B0E7FFFA593103964E55603E" + + "F7FEB7CA0762A1A7B86B6CCAD88CD6CBC7C6935D21F5F06B2700588A2530E619" + + "DA1648AC809F3DDF56ACE5951737568FFEC7E2AB1AA0AE01B03A7F5A29CE73C0" + + "5D2801B17CAAD0121082E9952FAB16BA1C386336C62D4CF3A5019CF61609433E" + + "1C083237D47C4CF575097F7BF9000EF6B6C497A44E6480154A35669AD276BF05" + + "6CC730B4E5962B6AF96CC6D236AE85CEFDA6877173F72D2F614F6696D1F9DF07" + + "E107758B0978F69BC9DBE0CCBF252C40A3FDF7CE9104D3344F7B73593CCD73E0"; + private static final String IKE_AUTH_RESP_FRAG_2 = + "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000000F0000000D4" + + "00020002155211EA41B37BC5F20568A6AE57038EEE208F94F9B444004F1EF391" + + "2CABFCF857B9CD95FAAA9489ED10A3F5C93510820E22E23FC55ED8049E067D72" + + "3645C00E1E08611916CE72D7F0A84123B63A8F3B9E78DBBE39967B7BB074AF4D" + + "BF2178D991EDBDD01908A14A266D09236DB963B14AC33D894F0F83A580209EFD" + + "61875BB56273AA336C22D6A4D890B93E0D42435667830CC32E4F608500E18569" + + "3E6C1D88C0B5AE427333C86468E3474DAA4D1506AAB2A4021309A33DD759D0D0" + + "A8C98BF7FBEA8109361A9F194D0FD756"; + private static final String DELETE_IKE_RESP = + "46B8ECA1E0D72A18BF3FA1C2CB1EE86F2E202520000000020000004C00000030" + + "342842D8DA37C8EFB92ED37C4FBB23CBDC90445137D6A0AF489F9F03641DBA9D" + + "02F6F59FD8A7A78C7261CEB8"; + + // Using IPv4 for transport mode Child SA. IPv6 is currently infeasible because the IKE server + // that generates the test vectors is running in an IPv4 only network. + private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("172.58.35.103"), + InetAddresses.parseNumericAddress("172.58.35.103")); + + // TODO(b/157510502): Add test for IKE Session setup in IPv6 network + + private static final String LOCAL_ID_ASN1_DN = + "CN=client.test.ike.android.net, O=Android, C=US"; + private static final String REMOTE_ID_ASN1_DN = + "CN=server.test.ike.android.net, O=Android, C=US"; + + private static X509Certificate sServerCaCert; + private static X509Certificate sClientEndCert; + private static X509Certificate sClientIntermediateCaCertOne; + private static X509Certificate sClientIntermediateCaCertTwo; + private static RSAPrivateKey sClientPrivateKey; + + @BeforeClass + public static void setUpCertsBeforeClass() throws Exception { + sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); + sClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); + sClientIntermediateCaCertOne = + CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem"); + sClientIntermediateCaCertTwo = + CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem"); + sClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); + } + + private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + IkeSessionParams ikeParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(remoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification( + new IkeDerAsn1DnIdentification(new X500Principal(LOCAL_ID_ASN1_DN))) + .setRemoteIdentification( + new IkeDerAsn1DnIdentification( + new X500Principal(REMOTE_ID_ASN1_DN))) + .setAuthDigitalSignature( + sServerCaCert, + sClientEndCert, + Arrays.asList( + sClientIntermediateCaCertOne, sClientIntermediateCaCertTwo), + sClientPrivateKey) + .build(); + + return new IkeSession( + sContext, + ikeParams, + buildTransportModeChildParamsWithTs( + TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), + mUserCbExecutor, + mIkeSessionCallback, + mFirstChildSessionCallback); + } + + @Test + public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception { + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + performSetupIkeAndFirstChildBlocking( + IKE_INIT_RESP, + EXPECTED_AUTH_REQ_FRAG_COUNT /* expectedReqPktCnt */, + IKE_AUTH_RESP_FRAG_1, + IKE_AUTH_RESP_FRAG_2); + + // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 + int expectedMsgId = 2; + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TRANSPORT_MODE_INBOUND_TS), + Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), + new ArrayList()); + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); + + // Close IKE Session + ikeSession.close(); + performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP); + verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 661457ff5e..ef865afe9a 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -16,6 +16,7 @@ package android.net.ipsec.ike.cts; +import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; import static org.junit.Assert.assertArrayEquals; @@ -33,6 +34,8 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -102,6 +105,21 @@ public class IkeSessionPskTest extends IkeSessionTestBase { mFirstChildSessionCallback); } + @BeforeClass + public static void setUpTunnelPermissionBeforeClass() throws Exception { + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and + // a standard permission is insufficient. So we shell out the appop, to give us the + // right appop permissions. + setAppOp(OP_MANAGE_IPSEC_TUNNELS, true); + } + + // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass + // methods. + @AfterClass + public static void tearDownTunnelPermissionAfterClass() throws Exception { + setAppOp(OP_MANAGE_IPSEC_TUNNELS, false); + } + @Test public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception { if (!hasTunnelsFeature()) return; @@ -203,6 +221,4 @@ public class IkeSessionPskTest extends IkeSessionTestBase { } // TODO(b/155821007): Verify rekey process and handling IKE_AUTH failure - - // TODO(b/155821007): Test creating transport mode Child SA } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index ade9813a81..5b545c4394 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -15,7 +15,6 @@ package android.net.ipsec.ike.cts; -import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; @@ -43,6 +42,7 @@ import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TransportModeChildSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; import android.net.ipsec.ike.exceptions.IkeException; @@ -103,6 +103,14 @@ abstract class IkeSessionTestBase extends IkeTestBase { MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS; + // This value is align with the test vectors hex that are generated in an IPv4 environment + static final IkeTrafficSelector TRANSPORT_MODE_OUTBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("10.138.0.2"), + InetAddresses.parseNumericAddress("10.138.0.2")); + static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); // Static state to reduce setup/teardown @@ -142,19 +150,12 @@ abstract class IkeSessionTestBase extends IkeTestBase { .getUiAutomation() .adoptShellPermissionIdentity(); sTNM = sContext.getSystemService(TestNetworkManager.class); - - // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and - // a standard permission is insufficient. So we shell out the appop, to give us the - // right appop permissions. - setAppOp(OP_MANAGE_IPSEC_TUNNELS, true); } // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass // methods. @AfterClass public static void tearDownPermissionAfterClass() throws Exception { - setAppOp(OP_MANAGE_IPSEC_TUNNELS, false); - InstrumentationRegistry.getInstrumentation() .getUiAutomation() .dropShellPermissionIdentity(); @@ -197,7 +198,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { mTunFd.close(); } - private static void setAppOp(int appop, boolean allow) { + static void setAppOp(int appop, boolean allow) { String opName = AppOpsManager.opToName(appop); for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { String cmd = @@ -249,6 +250,16 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + TransportModeChildSessionParams buildTransportModeChildParamsWithTs( + IkeTrafficSelector inboundTs, IkeTrafficSelector outboundTs) { + return new TransportModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .addInboundTrafficSelectors(inboundTs) + .addOutboundTrafficSelectors(outboundTs) + .build(); + } + TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { return new TunnelModeChildSessionParams.Builder() .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) @@ -258,7 +269,14 @@ abstract class IkeSessionTestBase extends IkeTestBase { .build(); } - void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String ikeAuthRespHex) + void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) + throws Exception { + performSetupIkeAndFirstChildBlocking( + ikeInitRespHex, 1 /* expectedAuthReqPktCnt */, ikeAuthRespHexes); + } + + void performSetupIkeAndFirstChildBlocking( + String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespHexes) throws Exception { mTunUtils.awaitReqAndInjectResp( IKE_DETERMINISTIC_INITIATOR_SPI, @@ -270,14 +288,8 @@ abstract class IkeSessionTestBase extends IkeTestBase { IKE_DETERMINISTIC_INITIATOR_SPI, 1 /* expectedMsgId */, true /* expectedUseEncap */, - ikeAuthRespHex); - } - - void performSetupIkeAndFirstChildBlocking( - String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespPktHex) - throws Exception { - // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple IKE AUTH - // request fragments and injecting multiple IKE AUTH response fragments + expectedAuthReqPktCnt, + ikeAuthRespHexes); } void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { @@ -522,7 +534,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); } - // TODO(b/148689509): Verify IKE Session setup using EAP and digital-signature-based auth + // TODO(b/148689509): Verify IKE Session setup using EAP // TODO(b/148689509): Verify hostname based creation } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index 2bff63a753..a9daf6adc3 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -36,7 +36,9 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.function.Predicate; public class IkeTunUtils extends TunUtils { @@ -45,10 +47,13 @@ public class IkeTunUtils extends TunUtils { private static final int NON_ESP_MARKER_LEN = 4; private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN]; - private static final int IKE_HEADER_LEN = 28; private static final int IKE_INIT_SPI_OFFSET = 0; + private static final int IKE_FIRST_PAYLOAD_OFFSET = 16; private static final int IKE_IS_RESP_BYTE_OFFSET = 19; private static final int IKE_MSG_ID_OFFSET = 20; + private static final int IKE_HEADER_LEN = 28; + private static final int IKE_FRAG_NUM_OFFSET = 32; + private static final int IKE_PAYLOAD_TYPE_SKF = 53; public IkeTunUtils(ParcelFileDescriptor tunFd) { super(tunFd); @@ -65,16 +70,65 @@ public class IkeTunUtils extends TunUtils { boolean expectedUseEncap, String ikeRespDataHex) throws Exception { - byte[] request = - awaitIkePacket( - (pkt) -> { - return isExpectedIkePkt( - pkt, - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap); - }); + return awaitReqAndInjectResp( + expectedInitIkeSpi, + expectedMsgId, + expectedUseEncap, + 1 /* expectedReqPktCnt */, + ikeRespDataHex) + .get(0); + } + + /** + * Await the expected IKE request (or the list of IKE request fragments) and inject an IKE + * response (or a list of response fragments) + * + * @param ikeRespDataHexes IKE response hex (or a list of response fragments) without IP/UDP + * headers or NON ESP MARKER. + */ + public List awaitReqAndInjectResp( + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedUseEncap, + int expectedReqPktCnt, + String... ikeRespDataHexes) + throws Exception { + List reqList = new ArrayList<>(expectedReqPktCnt); + if (expectedReqPktCnt == 1) { + // Expecting one complete IKE packet + byte[] req = + awaitIkePacket( + (pkt) -> { + return isExpectedIkePkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap); + }); + reqList.add(req); + } else { + // Expecting "expectedReqPktCnt" number of request fragments + for (int i = 0; i < expectedReqPktCnt; i++) { + // IKE Fragment number always starts from 1 + int expectedFragNum = i + 1; + byte[] req = + awaitIkePacket( + (pkt) -> { + return isExpectedIkeFragPkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap, + expectedFragNum); + }); + reqList.add(req); + } + } + + // All request fragments have the same addresses and ports + byte[] request = reqList.get(0); // Build response header by flipping address and port InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); @@ -82,20 +136,20 @@ public class IkeTunUtils extends TunUtils { int srcPort = getPort(request, false /* shouldGetSource */); int dstPort = getPort(request, true /* shouldGetSource */); - byte[] response = - buildIkePacket( - srcAddr, - dstAddr, - srcPort, - dstPort, - expectedUseEncap, - hexStringToByteArray(ikeRespDataHex)); - injectPacket(response); - return request; - } + for (String hex : ikeRespDataHexes) { + byte[] response = + buildIkePacket( + srcAddr, + dstAddr, + srcPort, + dstPort, + expectedUseEncap, + hexStringToByteArray(hex)); + injectPacket(response); + } - // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple - // request fragments and injecting multiple response fragments + return reqList; + } private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; @@ -129,31 +183,38 @@ public class IkeTunUtils extends TunUtils { int expectedMsgId, boolean expectedResp, boolean expectedUseEncap) { - int ipProtocolOffset = 0; - int ikeOffset = 0; - if (isIpv6(pkt)) { - // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap. - ipProtocolOffset = IP6_PROTO_OFFSET; - ikeOffset = IP6_HDRLEN + UDP_HDRLEN; - } else { - // Use default IPv4 header length (assuming no options) - ipProtocolOffset = IP4_PROTO_OFFSET; - ikeOffset = IP4_HDRLEN + UDP_HDRLEN; - - if (expectedUseEncap) { - if (hasNonEspMarker(pkt)) { - ikeOffset += NON_ESP_MARKER_LEN; - } else { - return false; - } - } - } + int ipProtocolOffset = isIpv6(pkt) ? IP6_PROTO_OFFSET : IP4_PROTO_OFFSET; + int ikeOffset = getIkeOffset(pkt, expectedUseEncap); return pkt[ipProtocolOffset] == IPPROTO_UDP + && expectedUseEncap == hasNonEspMarker(pkt) && isExpectedSpiAndMsgId( pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); } + private static boolean isExpectedIkeFragPkt( + byte[] pkt, + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedResp, + boolean expectedUseEncap, + int expectedFragNum) { + return isExpectedIkePkt( + pkt, expectedInitIkeSpi, expectedMsgId, expectedResp, expectedUseEncap) + && isExpectedFragNum(pkt, getIkeOffset(pkt, expectedUseEncap), expectedFragNum); + } + + private static int getIkeOffset(byte[] pkt, boolean useEncap) { + if (isIpv6(pkt)) { + // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap. + return IP6_HDRLEN + UDP_HDRLEN; + } else { + // Use default IPv4 header length (assuming no options) + int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; + return useEncap ? ikeOffset + NON_ESP_MARKER_LEN : ikeOffset; + } + } + private static boolean hasNonEspMarker(byte[] pkt) { ByteBuffer buffer = ByteBuffer.wrap(pkt); int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; @@ -186,6 +247,25 @@ public class IkeTunUtils extends TunUtils { // TODO: Check SPI and packet direction } + private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) { + ByteBuffer buffer = ByteBuffer.wrap(pkt); + buffer.get(new byte[ikeOffset]); + buffer.mark(); // Mark this position so that later we can reset back here + + // Check if it is a fragment packet + buffer.get(new byte[IKE_FIRST_PAYLOAD_OFFSET]); + int firstPayload = Byte.toUnsignedInt(buffer.get()); + if (firstPayload != IKE_PAYLOAD_TYPE_SKF) { + return false; + } + + // Check fragment number + buffer.reset(); + buffer.get(new byte[IKE_FRAG_NUM_OFFSET]); + int fragNum = Short.toUnsignedInt(buffer.getShort()); + return expectedFragNum == fragNum; + } + private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java index cb1d8269d7..5539dbca23 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java @@ -47,7 +47,7 @@ public class TunUtils { private static final String TAG = TunUtils.class.getSimpleName(); private static final int DATA_BUFFER_LEN = 4096; - static final int TIMEOUT = 100; + static final int TIMEOUT = 500; static final int IP4_PROTO_OFFSET = 9; static final int IP6_PROTO_OFFSET = 6; From ce7032f0be3e4b280396afad71a1b4dc69dbffda Mon Sep 17 00:00:00 2001 From: evitayan Date: Sat, 16 May 2020 23:06:11 -0700 Subject: [PATCH 1124/1415] Test IKE Session setup with EAP-MSCHAPv2 Bug: 155821007 Test: atest CtsIkeTestCases Change-Id: Ie8a328c53b531027ce63edaa874c4cd0904e0068 --- .../ipsec/ike/cts/IkeSessionMschapV2Test.java | 220 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeSessionTestBase.java | 2 - .../net/ipsec/ike/cts/IkeTestBase.java | 2 +- .../net/ipsec/ike/cts/IkeTunUtils.java | 17 +- 4 files changed, 230 insertions(+), 11 deletions(-) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java new file mode 100644 index 0000000000..cb771276dc --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java @@ -0,0 +1,220 @@ +/* + * 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.ipsec.ike.cts; + +import android.net.InetAddresses; +import android.net.LinkAddress; +import android.net.eap.EapSessionConfig; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTrafficSelector; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.internal.net.ipsec.ike.testutils.CertUtils; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Explicitly test setting up transport mode Child SA so that devices do not have + * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in + * IkeSessionPskTest and authentication method is orthogonal to Child mode. + */ +@RunWith(AndroidJUnit4.class) +public class IkeSessionMschapV2Test extends IkeSessionTestBase { + private static final String IKE_INIT_RESP = + "46B8ECA1E0D72A1873F643FF94D249A921202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0080030000080300000203000008" + + "0200000200000008040000022800008800020000CC6E71E67E32CED6BCE33FBD" + + "A74113867E3FA3AE21C7C9AB44A7F8835DF602BFD6F6528B67FEE39821232380" + + "C99E8FFC0A5D767F8F38906DA41946C2299DF18C15FA69BAC08D3EDB32E8C8CA" + + "28431831561C04CB0CDE393F817151CD8DAF7A311838411F1C39BFDB5EBCF6A6" + + "1DF66DEB067362649D64607D599B56C4227819D0290000241197004CF31AD00F" + + "5E0C92E198488D8A2B6F6A25C82762AA49F565BCE9D857D72900001C00004004" + + "A0D98FEABBFB92A6C0976EE83D2AACFCCF969A6B2900001C0000400575EBF73F" + + "8EE5CC73917DE9D3F91FCD4A16A0444D290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + private static final String IKE_AUTH_RESP_1_FRAG_1 = + "46B8ECA1E0D72A1873F643FF94D249A93520232000000001000004E0240004C4" + + "00010002C4159CB756773B3F1911F4595107BC505D7A28C72F05182966076679" + + "CA68ED92E4BC5CD441C9CB315F2F449A8A521CAFED3C5F285E295FC3791D3415" + + "E3BACF66A08410DF4E35F7D88FE40DA28851C91C77A6549E186AC1B7846DF3FA" + + "0A347A5ABBCAEE19E70F0EE5966DC6242A115F29523709302EDAD2E36C8F0395" + + "CF5C42EC2D2898ECDD8A6AEDD686A70B589A981558667647F32F41E0D8913E94" + + "A6693F53E59EA8938037F562CF1DC5E6E2CDC630B5FFB08949E3172249422F7D" + + "EA069F9BAD5F96E48BADC7164A9269669AD0DF295A80C54D1D23CEA3F28AC485" + + "86D2A9850DA23823037AB7D1577B7B2364C92C36B84238357129EB4A64D33310" + + "B95DCD50CD53E78C32EFE7DC1627D9432E9BFDEE130045DE967B19F92A9D1270" + + "F1E2C6BFBAA56802F3E63510578EF1ECB6872852F286EEC790AA1FE0CAF391CB" + + "E276554922713BA4770CFE71E23F043DC620E22CC02A74F60725D18331B7F2C9" + + "276EB6FBB7CBDAA040046D7ECBE1A5D7064E04E542807C5101B941D1C81B9D5E" + + "90347B22BD4E638E2EDC98E369B51AA29BDB2CF8AA610D4B893EB83A4650717C" + + "38B4D145EE939C18DCEDF6C79933CEB3D7C116B1F188DF9DDD560951B54E4A7D" + + "80C999A32AB02BF39D7B498DAD36F1A5CBE2F64557D6401AE9DD6E0CEADA3F90" + + "540FE9114BB6B8719C9064796354F4A180A6600CAD092F8302564E409B71ACB7" + + "590F19B3AC88E7A606C718D0B97F7E4B4830F11D851C59F2255846DA22E2C805" + + "0CA2AF2ACF3B6C769D11B75B5AC9AB82ED3D90014994B1BF6FED58FBEF2D72EF" + + "8BDFE51F9A101393A7CA1ACF78FAEBF3E3CC25E09407D1E14AF351A159A13EE3" + + "9B919BA8B49942792E7527C2FB6D418C4DF427669A4BF5A1AFBBB973BAF17918" + + "9C9D520CAC2283B89A539ECE785EBE48FBB77D880A17D55C84A51F46068A4B87" + + "FF48FEEE50E1E034CC8AFF5DA92105F55EC4823E67BDFE942CA8BE0DAECBBD52" + + "E8AAF306049DC6C4CF87D987B0AC54FCE92E6AE8507965AAAC6AB8BD3405712F" + + "EE170B70BC64BDCBD86D80C7AAAF341131F9A1210D7430B17218413AE1363183" + + "5C98FA2428B1E9E987ADC9070E232310A28F4C3163E18366FFB112BADD7C5E0F" + + "D13093A7C1428F87856BA0A7E46955589ACA267CE7A04320C4BCDBB60C672404" + + "778F8D511AAB09349DAB482445D7F606F28E7FBBB18FC0F4EC0AF04F44C282F9" + + "39C6E3B955C84DADEA350667236583069B74F492D600127636FA31F63E560851" + + "2FC28B8EA5B4D01D110990B6EA46B9C2E7C7C856C240EF7A8147BA2C4344B85A" + + "453C862024B5B6814D13CDEAEF7683D539BB50CAFFC0416F269F2F9EDEC5FA30" + + "022FD7B4B186CD2020E7ED8D81ED90822EDD8B76F840DD68F09694CFF9B4F33E" + + "11DF4E601A4212881A6D4E9259001705C41E9E23D18A7F3D4A3463649A38211A" + + "5A90D0F17739A677C74E23F31C01D60B5A0F1E6A4D44FED9D25BF1E63418E1FC" + + "0B19F6F4B71DE53C62B14B82279538A82DD4BE19AB6E00AFC20F124AAB7DF21A" + + "42259BE4F40EC69B16917256F23E2C37376311D62E0A3A0EF8C2AD0C090221D5" + + "C5ECA08F08178A4D31FFDB150C609827D18AD83C7B0A43AEE0406BD3FB494B53" + + "A279FDD6447E234C926AD8CE47FFF779BB45B1FC8457C6E7D257D1359959D977" + + "CEF6906A3367DC4D454993EFDC6F1EA94E17EB3DCB00A289346B4CFD7F19B16E"; + private static final String IKE_AUTH_RESP_1_FRAG_2 = + "46B8ECA1E0D72A1873F643FF94D249A935202320000000010000008000000064" + + "00020002C61F66025E821A5E69A4DE1F591A2C32C983C3154A5003660137D685" + + "A5262B9FDF5EDC699DE4D8BD38F549E3CBD12024B45B4C86561C36C3EED839DA" + + "9860C6AA0B764C662D08F1B6A98F68CF6E3038F737C0B415AD8A8B7D702BD92A"; + private static final String IKE_AUTH_RESP_2 = + "46B8ECA1E0D72A1873F643FF94D249A92E202320000000020000008C30000070" + + "62B90C2229FD23025BC2FD7FE6341E9EE04B17264CD619BCE18975A5F88BE438" + + "D4AD4A5310057255AF568C293A29B10107E3EE3675C10AA2B26404D90C0528CC" + + "F7605A86C96A1F2635CCC6CFC90EE65E5C2A2262EB33FE520EB708423A83CB63" + + "274ECCBB102AF5DF35742657"; + private static final String IKE_AUTH_RESP_3 = + "46B8ECA1E0D72A1873F643FF94D249A92E202320000000030000004C30000030" + + "AB52C3C80123D3432C05AF457CE93C352395F73E861CD49561BA528CFE68D17D" + + "78BBF6FC41E81C2B9EA051A2"; + private static final String IKE_AUTH_RESP_4 = + "46B8ECA1E0D72A1873F643FF94D249A92E20232000000004000000CC270000B0" + + "8D3342A7AB2666AC754F4B55C5C6B1A61255E62FBCA53D5CDEEDE60DADB7915C" + + "7F962076A58BF7D39A05ED1B60FF349B6DE311AF7CEBC72B4BB9723A728A5D3E" + + "9E508B2D7A11843D279B56ADA07E608D61F5CA7638F10372A440AD1DCE44E190" + + "7B7B7A68B126EBBB86638D667D5B528D233BA8D32D7E0FAC4E1448E87396EEE6" + + "0985B79841E1229D7962AACFD8F872722EC8D5B19D4C82D6C4ADCB276127A1A7" + + "3FC84CDF85B2299BC96B64AC"; + private static final String DELETE_IKE_RESP = + "46B8ECA1E0D72A1873F643FF94D249A92E202520000000050000004C00000030" + + "622CE06C8CB132AA00567E9BC83F58B32BD7DB5130C76E385B306434DA227361" + + "D50CC19D408A8D4F36F9697F"; + + // This value is align with the test vectors hex that are generated in an IPv4 environment + private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("172.58.35.67"), + InetAddresses.parseNumericAddress("172.58.35.67")); + + private static final EapSessionConfig EAP_CONFIG = + new EapSessionConfig.Builder() + .setEapIdentity(EAP_IDENTITY) + .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) + .build(); + + private static X509Certificate sServerCaCert; + + @BeforeClass + public static void setUpCertBeforeClass() throws Exception { + sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); + } + + private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + IkeSessionParams ikeParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(remoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) + .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) + .setAuthEap(sServerCaCert, EAP_CONFIG) + .build(); + return new IkeSession( + sContext, + ikeParams, + buildTransportModeChildParamsWithTs( + TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), + mUserCbExecutor, + mIkeSessionCallback, + mFirstChildSessionCallback); + } + + @Test + public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception { + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + int expectedMsgId = 0; + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + false /* expectedUseEncap */, + IKE_INIT_RESP); + + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + IKE_AUTH_RESP_1_FRAG_1, + IKE_AUTH_RESP_1_FRAG_2); + + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + IKE_AUTH_RESP_2); + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + IKE_AUTH_RESP_3); + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + IKE_AUTH_RESP_4); + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TRANSPORT_MODE_INBOUND_TS), + Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), + new ArrayList()); + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); + + // Close IKE Session + ikeSession.close(); + performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP); + verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 5b545c4394..86e5c48ebe 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -534,7 +534,5 @@ abstract class IkeSessionTestBase extends IkeTestBase { return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); } - // TODO(b/148689509): Verify IKE Session setup using EAP - // TODO(b/148689509): Verify hostname based creation } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index f07c710ba9..c70e5372ec 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -54,7 +54,7 @@ abstract class IkeTestBase { static final int SUB_ID = 1; static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); static final String NETWORK_NAME = "android.net"; - static final String EAP_MSCHAPV2_USERNAME = "username"; + static final String EAP_MSCHAPV2_USERNAME = "mschapv2user"; static final String EAP_MSCHAPV2_PASSWORD = "password"; static final Inet4Address IPV4_ADDRESS_LOCAL = diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index a9daf6adc3..c83d5f379d 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -60,22 +60,23 @@ public class IkeTunUtils extends TunUtils { } /** - * Await the expected IKE request and inject an IKE response. + * Await the expected IKE request inject an IKE response (or a list of response fragments) * - * @param ikeRespDataHex IKE response hex without IP/UDP headers or NON ESP MARKER. + * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without + * IP/UDP headers or NON ESP MARKER. */ public byte[] awaitReqAndInjectResp( long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, - String ikeRespDataHex) + String... ikeRespDataFragmentsHex) throws Exception { return awaitReqAndInjectResp( expectedInitIkeSpi, expectedMsgId, expectedUseEncap, 1 /* expectedReqPktCnt */, - ikeRespDataHex) + ikeRespDataFragmentsHex) .get(0); } @@ -83,15 +84,15 @@ public class IkeTunUtils extends TunUtils { * Await the expected IKE request (or the list of IKE request fragments) and inject an IKE * response (or a list of response fragments) * - * @param ikeRespDataHexes IKE response hex (or a list of response fragments) without IP/UDP - * headers or NON ESP MARKER. + * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without + * IP/UDP headers or NON ESP MARKER. */ public List awaitReqAndInjectResp( long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, int expectedReqPktCnt, - String... ikeRespDataHexes) + String... ikeRespDataFragmentsHex) throws Exception { List reqList = new ArrayList<>(expectedReqPktCnt); if (expectedReqPktCnt == 1) { @@ -136,7 +137,7 @@ public class IkeTunUtils extends TunUtils { int srcPort = getPort(request, false /* shouldGetSource */); int dstPort = getPort(request, true /* shouldGetSource */); - for (String hex : ikeRespDataHexes) { + for (String hex : ikeRespDataFragmentsHex) { byte[] response = buildIkePacket( srcAddr, From c0b2dbdaf69307bb3be4cf22c78385933eb18ac2 Mon Sep 17 00:00:00 2001 From: evitayan Date: Sat, 16 May 2020 23:47:04 -0700 Subject: [PATCH 1125/1415] Test remotely initiated rekey This commit: - Adds test for remotely initiated rekey for IKE and Child SA - Makes IkeTunUtils support building and injecting requests - Adds method to parse hex to long because Long.parseLong cannot handle negative long value Bug: 155821007 Test: atest CtsIkeTestCases Change-Id: I299cf190261ac15397f9ed389adb2c69e94a6507 --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 2 +- .../ipsec/ike/cts/IkeSessionRekeyTest.java | 265 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeSessionTestBase.java | 23 +- .../net/ipsec/ike/cts/IkeTunUtils.java | 70 ++++- 4 files changed, 342 insertions(+), 18 deletions(-) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index ef865afe9a..233e1c9ad5 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -220,5 +220,5 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); } - // TODO(b/155821007): Verify rekey process and handling IKE_AUTH failure + // TODO(b/155821007): Verify handling IKE_AUTH failure } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java new file mode 100644 index 0000000000..f954fcd031 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java @@ -0,0 +1,265 @@ +/* + * 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.ipsec.ike.cts; + +import static com.android.internal.util.HexDump.hexStringToByteArray; + +import android.net.InetAddresses; +import android.net.LinkAddress; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.cts.IkeTunUtils.PortPair; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Explicitly test transport mode Child SA so that devices without FEATURE_IPSEC_TUNNELS can be test + * covered. Tunnel mode Child SA setup has been tested in IkeSessionPskTest. Rekeying process is + * independent from Child SA mode. + */ +@RunWith(AndroidJUnit4.class) +public class IkeSessionRekeyTest extends IkeSessionTestBase { + // This value is align with the test vectors hex that are generated in an IPv4 environment + private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("172.58.35.40"), + InetAddresses.parseNumericAddress("172.58.35.40")); + + private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + IkeSessionParams ikeParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(remoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) + .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) + .setAuthPsk(IKE_PSK) + .build(); + return new IkeSession( + sContext, + ikeParams, + buildTransportModeChildParamsWithTs( + TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), + mUserCbExecutor, + mIkeSessionCallback, + mFirstChildSessionCallback); + } + + private byte[] buildInboundPkt(PortPair outPktSrcDestPortPair, String inboundDataHex) + throws Exception { + // Build inbound packet by flipping the outbound packet addresses and ports + return IkeTunUtils.buildIkePacket( + mRemoteAddress, + mLocalAddress, + outPktSrcDestPortPair.dstPort, + outPktSrcDestPortPair.srcPort, + true /* useEncap */, + hexStringToByteArray(inboundDataHex)); + } + + @Test + public void testRekeyIke() throws Exception { + final String ikeInitResp = + "46B8ECA1E0D72A1866B5248CF6C7472D21202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" + + "0200000500000008040000022800008800020000920D3E830E7276908209212D" + + "E5A7F2A48706CFEF1BE8CB6E3B173B8B4E0D8C2DC626271FF1B13A88619E569E" + + "7B03C3ED2C127390749CDC7CDC711D0A8611E4457FFCBC4F0981B3288FBF58EA" + + "3E8B70E27E76AE70117FBBCB753660ADDA37EB5EB3A81BED6A374CCB7E132C2A" + + "94BFCE402DC76B19C158B533F6B1F2ABF01ACCC329000024B302CA2FB85B6CF4" + + "02313381246E3C53828D787F6DFEA6BD62D6405254AEE6242900001C00004004" + + "7A1682B06B58596533D00324886EF1F20EF276032900001C00004005BF633E31" + + "F9984B29A62E370BB2770FC09BAEA665290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + final String ikeAuthResp = + "46B8ECA1E0D72A1866B5248CF6C7472D2E20232000000001000000F0240000D4" + + "10166CA8647F56123DE74C17FA5E256043ABF73216C812EE32EE1BB01EAF4A82" + + "DC107AB3ADBFEE0DEA5EEE10BDD5D43178F4C975C7C775D252273BB037283C7F" + + "236FE34A6BCE4833816897075DB2055B9FFD66DFA45A0A89A8F70AFB59431EED" + + "A20602FB614369D12906D3355CF7298A5D25364ABBCC75A9D88E0E6581449FCD" + + "4E361A39E00EFD1FD0A69651F63DB46C12470226AA21BA5EFF48FAF0B6DDF61C" + + "B0A69392CE559495EEDB4D1C1D80688434D225D57210A424C213F7C993D8A456" + + "38153FBD194C5E247B592D1D048DB4C8"; + final String rekeyIkeCreateReq = + "46B8ECA1E0D72A1866B5248CF6C7472D2E202400000000000000013021000114" + + "13743670039E308A8409BA5FD47B67F956B36FEE88AC3B70BB5D789B8218A135" + + "1B3D83E260E87B3EDB1BF064F09D4DC2611AEDBC99951B4B2DE767BD4AA2ACC3" + + "3653549CFC66B75869DF003CDC9A137A9CC27776AD5732B34203E74BE8CA4858" + + "1D5C0D9C9CA52D680EB299B4B21C7FA25FFEE174D57015E0FF2EAED653AAD95C" + + "071ABE269A8C2C9FBC1188E07550EB992F910D4CA9689E44BA66DE0FABB2BDF9" + + "8DD377186DBB25EF9B68B027BB2A27981779D8303D88D7CE860010A42862D50B" + + "1E0DBFD3D27C36F14809D7F493B2B96A65534CF98B0C32AD5219AD77F681AC04" + + "9D5CB89A0230A91A243FA7F16251B0D9B4B65E7330BEEAC9663EF4578991EAC8" + + "46C19EBB726E7D113F1D0D601102C05E"; + final String rekeyIkeDeleteReq = + "46B8ECA1E0D72A1866B5248CF6C7472D2E20250000000001000000502A000034" + + "02E40C0C7B1ED977729F705BB9B643FAC513A1070A6EB28ECD2AEA8A441ADC05" + + "7841382A7967BBF116AE52496590B2AD"; + final String deleteIkeReq = + "7D3DEDC65407D1FC9361C8CF8C47162A2E20250800000000000000502A000034" + + "201915C9E4E9173AA9EE79F3E02FE2D4954B22085C66D164762C34D347C16E9F" + + "FC5F7F114428C54D8D915860C57B1BC1"; + final long newIkeDeterministicInitSpi = Long.parseLong("7D3DEDC65407D1FC", 16); + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp); + + // Local request message ID starts from 2 because there is one IKE_INIT message and a single + // IKE_AUTH message. + int expectedReqMsgId = 2; + int expectedRespMsgId = 0; + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TRANSPORT_MODE_INBOUND_TS), + Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), + new ArrayList()); + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); + + // Inject rekey IKE requests + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeCreateReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeDeleteReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + + // IKE has been rekeyed, reset message IDs + expectedReqMsgId = 0; + expectedRespMsgId = 0; + + // Inject delete IKE request + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq)); + mTunUtils.awaitResp( + newIkeDeterministicInitSpi, expectedRespMsgId++, true /* expectedUseEncap */); + + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } + + @Test + public void testRekeyTransportModeChildSa() throws Exception { + final String ikeInitResp = + "46B8ECA1E0D72A18CECD871146CF83A121202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" + + "0200000500000008040000022800008800020000C4904458957746BCF1C12972" + + "1D4E19EB8A584F78DE673053396D167CE0F34552DBC69BA63FE7C673B4CF4A99" + + "62481518EE985357876E8C47BAAA0DBE9C40AE47B12E52165874703586E8F786" + + "045F72EEEB238C5D1823352BED44B71B3214609276ADC0B3D42DAC820168C4E2" + + "660730DAAC92492403288805EBB9053F1AB060DA290000242D9364ACB93519FF" + + "8F8B019BAA43A40D699F59714B327B8382216EF427ED52282900001C00004004" + + "06D91438A0D6B734E152F76F5CC55A72A2E38A0A2900001C000040052EFF78B3" + + "55B37F3CE75AFF26C721B050F892C0D6290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + final String ikeAuthResp = + "46B8ECA1E0D72A18CECD871146CF83A12E20232000000001000000F0240000D4" + + "A17BC258BA2714CF536663639DD5F665A60C75E93557CD5141990A8CEEDD2017" + + "93F5B181C8569FBCD6C2A00198EC2B62D42BEFAC016B8B6BF6A7BC9CEDE3413A" + + "6C495A6B8EC941864DC3E08F57D015EA6520C4B05884960B85478FCA53DA5F17" + + "9628BB1097DA77461C71837207A9EB80720B3E6E661816EE4E14AC995B5E8441" + + "A4C3F9097CC148142BA300076C94A23EC4ADE82B1DD2B121F7E9102860A8C3BF" + + "58DDC207285A3176E924C44DE820322524E1AA438EFDFBA781B36084AED80846" + + "3B77FCED9682B6E4E476408EF3F1037E"; + final String rekeyChildCreateReq = + "46B8ECA1E0D72A18CECD871146CF83A12E202400000000000000015029000134" + + "319D74B6B155B86942143CEC1D29D21F073F24B7BEDC9BFE0F0FDD8BDB5458C0" + + "8DB93506E1A43DD0640FE7370C97F9B34FF4EC9B2DB7257A87B75632301FB68A" + + "86B54871249534CA3D01C9BEB127B669F46470E1C8AAF72574C3CEEC15B901CF" + + "5A0D6ADAE59C3CA64AC8C86689C860FAF9500E608DFE63F2DCD30510FD6FFCD5" + + "A50838574132FD1D069BCACD4C7BAF45C9B1A7689FAD132E3F56DBCFAF905A8C" + + "4145D4BA1B74A54762F8F43308D94DE05649C49D885121CE30681D51AC1E3E68" + + "AB82F9A19B99579AFE257F32DBD1037814DA577379E4F42DEDAC84502E49C933" + + "9EA83F6F5DB4401B660CB1681B023B8603D205DFDD1DE86AD8DE22B6B754F30D" + + "05EAE81A709C2CEE81386133DC3DC7B5EF8F166E48E54A0722DD0C64F4D00638" + + "40F272144C47F6ECED72A248180645DB"; + final String rekeyChildDeleteReq = + "46B8ECA1E0D72A18CECD871146CF83A12E20250000000001000000502A000034" + + "02D98DAF0432EBD991CA4F2D89C1E0EFABC6E91A3327A85D8914FB2F1485BE1B" + + "8D3415D548F7CE0DC4224E7E9D0D3355"; + final String deleteIkeReq = + "46B8ECA1E0D72A18CECD871146CF83A12E20250000000002000000502A000034" + + "095041F4026B4634F04B0AB4F9349484F7BE9AEF03E3733EEE293330043B75D2" + + "ABF5F965ED51127629585E1B1BBA787F"; + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp); + + // IKE INIT and IKE AUTH takes two exchanges. Local request message ID starts from 2 + int expectedReqMsgId = 2; + int expectedRespMsgId = 0; + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TRANSPORT_MODE_INBOUND_TS), + Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), + new ArrayList()); + IpSecTransformCallRecord oldTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord oldTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(oldTransformRecordA, oldTransformRecordB); + + // Inject rekey Child requests + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildCreateReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildDeleteReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + + // Verify IpSecTransforms are renewed + IpSecTransformCallRecord newTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord newTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(newTransformRecordA, newTransformRecordB); + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, oldTransformRecordA, oldTransformRecordB); + + // Inject delete IKE request + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, newTransformRecordA, newTransformRecordB); + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 86e5c48ebe..0f39fbd1cb 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -44,6 +44,7 @@ import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeTrafficSelector; import android.net.ipsec.ike.TransportModeChildSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.net.ipsec.ike.cts.IkeTunUtils.PortPair; import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -269,13 +270,13 @@ abstract class IkeSessionTestBase extends IkeTestBase { .build(); } - void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) + PortPair performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) throws Exception { - performSetupIkeAndFirstChildBlocking( + return performSetupIkeAndFirstChildBlocking( ikeInitRespHex, 1 /* expectedAuthReqPktCnt */, ikeAuthRespHexes); } - void performSetupIkeAndFirstChildBlocking( + PortPair performSetupIkeAndFirstChildBlocking( String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespHexes) throws Exception { mTunUtils.awaitReqAndInjectResp( @@ -284,12 +285,16 @@ abstract class IkeSessionTestBase extends IkeTestBase { false /* expectedUseEncap */, ikeInitRespHex); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 1 /* expectedMsgId */, - true /* expectedUseEncap */, - expectedAuthReqPktCnt, - ikeAuthRespHexes); + byte[] ikeAuthReqPkt = + mTunUtils + .awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 1 /* expectedMsgId */, + true /* expectedUseEncap */, + expectedAuthReqPktCnt, + ikeAuthRespHexes) + .get(0); + return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt); } void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index c83d5f379d..41cbf0baa1 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -55,6 +55,8 @@ public class IkeTunUtils extends TunUtils { private static final int IKE_FRAG_NUM_OFFSET = 32; private static final int IKE_PAYLOAD_TYPE_SKF = 53; + private static final int RSP_FLAG_MASK = 0x20; + public IkeTunUtils(ParcelFileDescriptor tunFd) { super(tunFd); } @@ -136,8 +138,7 @@ public class IkeTunUtils extends TunUtils { InetAddress dstAddr = getAddress(request, true /* shouldGetSource */); int srcPort = getPort(request, false /* shouldGetSource */); int dstPort = getPort(request, true /* shouldGetSource */); - - for (String hex : ikeRespDataFragmentsHex) { + for (String resp : ikeRespDataFragmentsHex) { byte[] response = buildIkePacket( srcAddr, @@ -145,13 +146,27 @@ public class IkeTunUtils extends TunUtils { srcPort, dstPort, expectedUseEncap, - hexStringToByteArray(hex)); + hexStringToByteArray(resp)); injectPacket(response); } return reqList; } + /** Await the expected IKE response */ + public byte[] awaitResp(long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap) + throws Exception { + return awaitIkePacket( + (pkt) -> { + return isExpectedIkePkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + true /* expectedResp*/, + expectedUseEncap); + }); + } + private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; int startIndex = 0; @@ -239,13 +254,36 @@ public class IkeTunUtils extends TunUtils { ByteBuffer buffer = ByteBuffer.wrap(pkt); buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER) + buffer.mark(); // Mark this position so that later we can reset back here - // Check message ID. + // Check SPI + buffer.get(new byte[IKE_INIT_SPI_OFFSET]); + long initSpi = buffer.getLong(); + if (expectedInitIkeSpi != initSpi) { + return false; + } + + // Check direction + buffer.reset(); + buffer.get(new byte[IKE_IS_RESP_BYTE_OFFSET]); + byte flagsByte = buffer.get(); + boolean isResp = ((flagsByte & RSP_FLAG_MASK) != 0); + if (expectedResp != isResp) { + return false; + } + + // Check message ID + buffer.reset(); buffer.get(new byte[IKE_MSG_ID_OFFSET]); - int msgId = buffer.getInt(); - return expectedMsgId == msgId; - // TODO: Check SPI and packet direction + // Both the expected message ID and the packet's msgId are signed integers, so directly + // compare them. + int msgId = buffer.getInt(); + if (expectedMsgId != msgId) { + return false; + } + + return true; } private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) { @@ -267,6 +305,22 @@ public class IkeTunUtils extends TunUtils { return expectedFragNum == fragNum; } + public static class PortPair { + public final int srcPort; + public final int dstPort; + + public PortPair(int sourcePort, int destinationPort) { + srcPort = sourcePort; + dstPort = destinationPort; + } + } + + public static PortPair getSrcDestPortPair(byte[] outboundIkePkt) throws Exception { + return new PortPair( + getPort(outboundIkePkt, true /* shouldGetSource */), + getPort(outboundIkePkt, false /* shouldGetSource */)); + } + private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; @@ -288,7 +342,7 @@ public class IkeTunUtils extends TunUtils { return Short.toUnsignedInt(buffer.getShort()); } - private static byte[] buildIkePacket( + public static byte[] buildIkePacket( InetAddress srcAddr, InetAddress dstAddr, int srcPort, From ac96b659d3810bcdca1c5e08e5cdf76c8097cb4f Mon Sep 17 00:00:00 2001 From: evitayan Date: Fri, 15 May 2020 22:52:37 -0700 Subject: [PATCH 1126/1415] Test handling authentication failure - Test receiving Authentication Failure notification - Test setting up IKE Session with first Child setup failure Bug: 155821007 Test: CtsIkeTestCases Change-Id: I4ec43a3899d67a119cd4ba19e0ffc63c277325fb --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 82 +++++++++++++++++-- 1 file changed, 74 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 233e1c9ad5..253e09dd39 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -17,18 +17,17 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import android.net.LinkAddress; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.platform.test.annotations.AppModeFull; @@ -212,13 +211,80 @@ public class IkeSessionPskTest extends IkeSessionTestBase { mFirstChildSessionCallback.awaitOnClosed(); - IkeException exception = mIkeSessionCallback.awaitOnClosedException(); - assertNotNull(exception); - assertTrue(exception instanceof IkeProtocolException); - IkeProtocolException protocolException = (IkeProtocolException) exception; + IkeProtocolException protocolException = + (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException(); assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, protocolException.getErrorType()); assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); } - // TODO(b/155821007): Verify handling IKE_AUTH failure + @Test + public void testIkeAuthHandlesAuthFailNotification() throws Exception { + final String ikeInitRespHex = + "46B8ECA1E0D72A18CF94CE3159486F002120222000000000000001502200" + + "00300000002C010100040300000C0100000C800E01000300000803000005" + + "0300000802000004000000080400000228000088000200001821AA854691" + + "FA3292DF710F0AC149ACBD0CB421608B8796C1912AF04C5B4B23936FDEC4" + + "7CB640E3EAFB56BBB562825E87AF68B40E4BAB80A49BAD44407450A4195A" + + "1DD54BD99F48D28C9F0FBA315A3401C1C3C4AD55911F514A8DF2D2467C46" + + "A73DDC1452AE81336E0F0D5EC896D2E7A77628AF2F9089F48943399DF216" + + "EFCD2900002418D2B7E4E6AF0FEFF5962CF8D68F7793B1293FEDE13331D4" + + "AB0CE9436C2EE1EC2900001C0000400457BD9AEF5B362A83DD7F3DDAA4A9" + + "9B6B4041DAF32900001C000040055A81893582701E44D4B6729A22FE06DE" + + "82A03A36290000080000402E290000100000402F00020003000400050000" + + "000800004014"; + final String ikeAuthFailRespHex = + "46B8ECA1E0D72A18CF94CE3159486F002E202320000000010000004C2900" + + "00301B9E4C8242D3BE62E7F0A537FE8B92C6EAB7153105DA421DCE43A06D" + + "AB6E4808BAC0CA1DAD6ADD0A126A41BD"; + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthFailRespHex); + + mFirstChildSessionCallback.awaitOnClosed(); + IkeProtocolException protocolException = + (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException(); + assertEquals(ERROR_TYPE_AUTHENTICATION_FAILED, protocolException.getErrorType()); + assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); + } + + @Test + public void testIkeAuthHandlesFirstChildCreationFail() throws Exception { + final String ikeInitRespHex = + "46B8ECA1E0D72A182B300285DA19E6452120222000000000000001502200" + + "00300000002C010100040300000C0100000C800E01000300000803000005" + + "0300000802000004000000080400000228000088000200005C9DE629981F" + + "DB1FC45DB6CCF15D076C1F51BD9F63C771DC089F05CCDE6247965D15C616" + + "C7B5A62342491715E4D1FEA19326477D24143E8E56AB6AD93F54B19BC32A" + + "44BC0A5B5632E57D0A3C43E466E1547D8E4EF65EA4B864A348161666E229" + + "84975A486251A17C4F096A6D5CF3DB83874B70324A31AA7ADDE2D73BADD8" + + "238029000024CF06260F7C4923295E7C91F2B8479212892DA7A519A0322F" + + "F5B2BF570B92972B2900001C00004004C7ACC2C7D58CF8C9F5E953993AF4" + + "6CAC976635B42900001C00004005B64B190DFE7BDE8B9B1475EDE67B63D6" + + "F1DBBF44290000080000402E290000100000402F00020003000400050000" + + "000800004014"; + final String ikeAuthCreateChildFailHex = + "46B8ECA1E0D72A182B300285DA19E6452E202320000000010000008C2400" + + "0070386FC9CCC67495A17915D0544390A2963A769F4A42C6FA668CEEC07F" + + "EC0C87D681DE34267023DD394F1401B5A563E71002C0CE0928D0ABC0C4570" + + "E39C2EDEF820F870AB71BD70A3F3EB5C96CA294B6D3F01677690DCF9F8CFC" + + "9584650957573502BA83E32F18207A9ADEB1FA"; + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthCreateChildFailHex); + + // Even though the child creation failed, the authentication succeeded, so the IKE Session's + // onOpened() callback is still expected + verifyIkeSessionSetupBlocking(); + + // Verify Child Creation failed + IkeProtocolException protocolException = + (IkeProtocolException) mFirstChildSessionCallback.awaitOnClosedException(); + assertEquals(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE, protocolException.getErrorType()); + assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); + + ikeSession.kill(); + mIkeSessionCallback.awaitOnClosed(); + } } From 9604af354406406dd4df72c77c676cced4f14f63 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Fri, 22 May 2020 00:27:02 +0000 Subject: [PATCH 1127/1415] Exit test if device does not support IPsec tunnel Bug: 155926216 Test: CtsIkeTestCases Change-Id: I4e426b8f3509e56e7e2e7532e216533ad8bfbc2f Merged-In: I4e426b8f3509e56e7e2e7532e216533ad8bfbc2f (cherry picked from commit eb70555351725a608afac0fb9f94a327e9236729) --- .../android/net/ipsec/ike/cts/IkeSessionPskTest.java | 12 +++++++++--- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 6 ++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index ed67dd1bd7..336d12dad1 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -122,7 +122,9 @@ public class IkeSessionPskTest extends IkeSessionTestBase { } @Test - public void testIkeSessionSetupAndManageChildSas() throws Exception { + public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception { + if (!hasTunnelsFeature()) return; + // Open IKE Session IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); int expectedMsgId = 0; @@ -210,7 +212,9 @@ public class IkeSessionPskTest extends IkeSessionTestBase { } @Test - public void testIkeSessionKill() throws Exception { + public void testIkeSessionKillWithTunnelMode() throws Exception { + if (!hasTunnelsFeature()) return; + // Open IKE Session IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); int expectedMsgId = 0; @@ -254,5 +258,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); } - // TODO(b/148689509): Verify rekey process and handling IKE_AUTH failure + // TODO(b/155821007): Verify rekey process and handling IKE_AUTH failure + + // TODO(b/155821007): Test creating transport mode Child SA } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index deba8fd985..1c1ffc922f 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -20,6 +20,7 @@ import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpSecTransform; @@ -368,6 +369,11 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + /** Package private method to check if device has IPsec tunnels feature */ + static boolean hasTunnelsFeature() { + return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + } + // TODO(b/148689509): Verify IKE Session setup using EAP and digital-signature-based auth // TODO(b/148689509): Verify hostname based creation From f580c71a43e72ea4b97858db83e2f93711dca3f1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 22 May 2020 03:24:20 +0000 Subject: [PATCH 1128/1415] Cleanup of IkeSessionPskTest - Add java doc in IkeSessionTestBase about the necessity to use different addresses and Networks in each test - Use ArrayTrackRecord in Test Session Callback to retrieve the latest result. - Verify that IpSecTransform pair is created and deleted Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: Ib747c8cdfe1827e8df2aa7544e28e98a177d3d1c Merged-In: Ib747c8cdfe1827e8df2aa7544e28e98a177d3d1c (cherry picked from commit f729d7a112e83e04c008b0bbeed333238482d3e9) --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 51 +++++++++++-------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 19 ++++--- .../net/ipsec/ike/cts/IkeTunUtils.java | 4 +- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 336d12dad1..fb93398b26 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -99,19 +99,17 @@ public class IkeSessionPskTest extends IkeSessionTestBase { .addInternalAddressRequest(AF_INET6) .build(); - private IkeSessionParams createIkeSessionParams(InetAddress mRemoteAddress) { - return new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(mRemoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) - .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) - .setAuthPsk(IKE_PSK) - .build(); - } - - private IkeSession openIkeSession(IkeSessionParams ikeParams) { + private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + IkeSessionParams ikeParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(remoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) + .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) + .setAuthPsk(IKE_PSK) + .build(); return new IkeSession( sContext, ikeParams, @@ -126,7 +124,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { if (!hasTunnelsFeature()) return; // Open IKE Session - IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( IKE_INIT_SPI, @@ -167,6 +165,9 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + assertNotNull(mFirstChildSessionCallback.awaitNextCreatedIpSecTransform()); + assertNotNull(mFirstChildSessionCallback.awaitNextCreatedIpSecTransform()); + // Open additional Child Session TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); ikeSession.openChildSession(CHILD_PARAMS, additionalChildCb); @@ -183,9 +184,12 @@ public class IkeSessionPskTest extends IkeSessionTestBase { Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); assertTrue(additionalChildConfig.getInternalAddresses().isEmpty()); - assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); - assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); - assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + assertTrue(additionalChildConfig.getInternalSubnets().isEmpty()); + assertTrue(additionalChildConfig.getInternalDnsServers().isEmpty()); + assertTrue(additionalChildConfig.getInternalDhcpServers().isEmpty()); + + assertNotNull(additionalChildCb.awaitNextCreatedIpSecTransform()); + assertNotNull(additionalChildCb.awaitNextCreatedIpSecTransform()); // Close additional Child Session ikeSession.closeChildSession(additionalChildCb); @@ -195,6 +199,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { true /* expectedUseEncap */, hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); + assertNotNull(additionalChildCb.awaitNextDeletedIpSecTransform()); + assertNotNull(additionalChildCb.awaitNextDeletedIpSecTransform()); additionalChildCb.awaitOnClosed(); // Close IKE Session @@ -205,10 +211,12 @@ public class IkeSessionPskTest extends IkeSessionTestBase { true /* expectedUseEncap */, hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); + assertNotNull(mFirstChildSessionCallback.awaitNextDeletedIpSecTransform()); + assertNotNull(mFirstChildSessionCallback.awaitNextDeletedIpSecTransform()); mFirstChildSessionCallback.awaitOnClosed(); mIkeSessionCallback.awaitOnClosed(); - // TODO: verify IpSecTransform pair is created and deleted + // TODO: verify created and deleted IpSecTransform pair and their directions } @Test @@ -216,7 +224,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { if (!hasTunnelsFeature()) return; // Open IKE Session - IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( IKE_INIT_SPI, @@ -231,7 +239,6 @@ public class IkeSessionPskTest extends IkeSessionTestBase { hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); ikeSession.kill(); - mFirstChildSessionCallback.awaitOnClosed(); mIkeSessionCallback.awaitOnClosed(); } @@ -242,7 +249,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; // Open IKE Session - IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress)); + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( IKE_INIT_SPI, @@ -250,6 +257,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { false /* expectedUseEncap */, hexStringToByteArray(ikeInitFailRespHex)); + mFirstChildSessionCallback.awaitOnClosed(); + IkeException exception = mIkeSessionCallback.awaitOnClosedException(); assertNotNull(exception); assertTrue(exception instanceof IkeProtocolException); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 1c1ffc922f..279d088b3c 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -40,7 +40,6 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.platform.test.annotations.AppModeFull; -import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -66,6 +65,13 @@ import java.util.concurrent.TimeUnit; * *

    Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use * the test network + * + *

    All IKE Sessions running in test mode will generate SPIs deterministically. That is to say + * each IKE Session will always generate the same IKE INIT SPI and test vectors are generated based + * on this deterministic IKE SPI. Each test will use different local and remote addresses to avoid + * the case that the next test try to allocate the same SPI before the previous test has released + * it, since SPI resources are not released in testing thread. Similarly, each test MUST use + * different Network instances to avoid sharing the same IkeSocket and hitting IKE SPI collision. */ @RunWith(AndroidJUnit4.class) @AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") @@ -117,7 +123,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { InstrumentationRegistry.getInstrumentation() .getUiAutomation() .adoptShellPermissionIdentity(); - sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + sTNM = sContext.getSystemService(TestNetworkManager.class); // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and // a standard permission is insufficient. So we shell out the appop, to give us the @@ -150,10 +156,6 @@ abstract class IkeSessionTestBase extends IkeTestBase { @After public void tearDown() throws Exception { tearDownTestNetwork(); - - resetNextAvailableAddress(NEXT_AVAILABLE_IP4_ADDR_LOCAL, INITIAL_AVAILABLE_IP4_ADDR_LOCAL); - resetNextAvailableAddress( - NEXT_AVAILABLE_IP4_ADDR_REMOTE, INITIAL_AVAILABLE_IP4_ADDR_REMOTE); } void setUpTestNetwork(InetAddress localAddr) throws Exception { @@ -186,9 +188,8 @@ abstract class IkeSessionTestBase extends IkeTestBase { pkg, // Package name opName, // Appop (allow ? "allow" : "deny")); // Action - Log.d("IKE", "CTS setAppOp cmd " + cmd); - String result = SystemUtil.runShellCommand(cmd); + SystemUtil.runShellCommand(cmd); } } @@ -230,6 +231,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + /** Testing callback that allows caller to block current thread until a method get called */ static class TestIkeSessionCallback implements IkeSessionCallback { private CompletableFuture mFutureIkeConfig = new CompletableFuture<>(); @@ -283,6 +285,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + /** Testing callback that allows caller to block current thread until a method get called */ static class TestChildSessionCallback implements ChildSessionCallback { private CompletableFuture mFutureChildConfig = new CompletableFuture<>(); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index 5a8258d57b..f52b88ba3a 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -121,7 +121,9 @@ public class IkeTunUtils extends TunUtils { + " and message ID " + expectedMsgId); } - return null; + + throw new IllegalStateException( + "Hit an impossible case where fail() didn't throw an exception"); } private static boolean isIke( From e5c451c1dbf2c2fc33a20901080a6c8a0c7dce90 Mon Sep 17 00:00:00 2001 From: evitayan Date: Thu, 21 May 2020 14:28:42 -0700 Subject: [PATCH 1129/1415] Apply MainlineTestModuleController to IKE CTS Only run the tests when com.google.android.ipsec is installed on device. This CL follows aosp/11427976 as an example. Bug: 150497352 Test: m mts && mts-tradefed run mts-ipsec Change-Id: I5992c54f9c0b9f1aa9752a207660f9f6e97ccace --- tests/cts/net/ipsec/AndroidTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/net/ipsec/AndroidTest.xml b/tests/cts/net/ipsec/AndroidTest.xml index 09e5c93cf8..cd5c118dd6 100644 --- a/tests/cts/net/ipsec/AndroidTest.xml +++ b/tests/cts/net/ipsec/AndroidTest.xml @@ -27,4 +27,7 @@

    Expects caller to hold the shell permission identity. + */ + public void setAppopPrivileged(int appop, boolean allow) { + final String opName = AppOpsManager.opToName(appop); + for (final String pkg : new String[] {"com.android.shell", mContext.getPackageName()}) { + final String cmd = + String.format( + "appops set %s %s %s", + pkg, // Package name + opName, // Appop + (allow ? "allow" : "deny")); // Action + SystemUtil.runShellCommand(cmd); + } + } + + /** Sets up a test network using the provided interface name */ + public TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception { + // Build a network request + final NetworkRequest nr = + new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(TRANSPORT_TEST) + .setNetworkSpecifier(ifname) + .build(); + + final TestNetworkCallback cb = new TestNetworkCallback(); + mCm.requestNetwork(nr, cb); + + // Setup the test network after network request is filed to prevent Network from being + // reaped due to no requests matching it. + mContext.getSystemService(TestNetworkManager.class).setupTestNetwork(ifname, mBinder); + + return cb; + } + // Toggle WiFi twice, leaving it in the state it started in public void toggleWifi() { if (mWifiManager.isWifiEnabled()) { From 670639c13cb81420d0f6d8cd7ffee31eee5ef5a6 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 21 Apr 2020 17:01:28 -0700 Subject: [PATCH 1143/1415] Add basic tests for IKEv2/IPsec VPNs This change adds basic tests for all IKEv2/IPsec VPN public APIs. Additional testing for ensuring IKEv2 setup completes will be done in a subsequent CL. Bug: 148582947 Test: Ikev2VpnTest added Change-Id: Ia5d35c32525b32be4a0dc0584630f5bb9e7f1bcb --- .../net/src/android/net/cts/Ikev2VpnTest.java | 357 ++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/Ikev2VpnTest.java diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java new file mode 100644 index 0000000000..8c1cbbb6d9 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -0,0 +1,357 @@ +/* + * 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 com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.Manifest; +import android.annotation.NonNull; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.Ikev2VpnProfile; +import android.net.IpSecAlgorithm; +import android.net.ProxyInfo; +import android.net.VpnManager; +import android.net.cts.util.CtsNetUtils; +import android.platform.test.annotations.AppModeFull; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.security.auth.x500.X500Principal; + +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "Appops state changes disallowed for instant apps (OP_ACTIVATE_PLATFORM_VPN)") +public class Ikev2VpnTest { + private static final String TAG = Ikev2VpnTest.class.getSimpleName(); + + private static final String TEST_SERVER_ADDR = "2001:db8::1"; + private static final String TEST_IDENTITY = "client.cts.android.com"; + private static final List TEST_ALLOWED_ALGORITHMS = + Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM); + + private static final ProxyInfo TEST_PROXY_INFO = + ProxyInfo.buildDirectProxy("proxy.cts.android.com", 1234); + private static final int TEST_MTU = 1300; + + private static final byte[] TEST_PSK = "ikev2".getBytes(); + private static final String TEST_USER = "username"; + private static final String TEST_PASSWORD = "pa55w0rd"; + + // Static state to reduce setup/teardown + private static final Context sContext = InstrumentationRegistry.getContext(); + private static final ConnectivityManager sCM = + (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + private static final VpnManager sVpnMgr = + (VpnManager) sContext.getSystemService(Context.VPN_MANAGEMENT_SERVICE); + private static final CtsNetUtils mCtsNetUtils = new CtsNetUtils(sContext); + + private final X509Certificate mServerRootCa; + private final CertificateAndKey mUserCertKey; + + public Ikev2VpnTest() throws Exception { + // Build certificates + mServerRootCa = generateRandomCertAndKeyPair().cert; + mUserCertKey = generateRandomCertAndKeyPair(); + } + + /** + * Sets the given appop using shell commands + * + *

    This method must NEVER be called from within a shell permission, as it will attempt to + * acquire, and then drop the shell permission identity. This results in the caller losing the + * shell permission identity due to these calls not being reference counted. + */ + public void setAppop(int appop, boolean allow) { + // Requires shell permission to update appops. + runWithShellPermissionIdentity(() -> { + mCtsNetUtils.setAppopPrivileged(appop, allow); + }, Manifest.permission.MANAGE_TEST_NETWORKS); + } + + private Ikev2VpnProfile buildIkev2VpnProfileCommon( + Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks) throws Exception { + if (isRestrictedToTestNetworks) { + builder.restrictToTestNetworks(); + } + + return builder.setBypassable(true) + .setProxy(TEST_PROXY_INFO) + .setMaxMtu(TEST_MTU) + .setMetered(false) + .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS) + .build(); + } + + private Ikev2VpnProfile buildIkev2VpnProfilePsk(boolean isRestrictedToTestNetworks) + throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY).setAuthPsk(TEST_PSK); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks) + throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY) + .setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks) + throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY) + .setAuthDigitalSignature( + mUserCertKey.cert, mUserCertKey.key, mServerRootCa); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private void checkBasicIkev2VpnProfile(@NonNull Ikev2VpnProfile profile) throws Exception { + assertEquals(TEST_SERVER_ADDR, profile.getServerAddr()); + assertEquals(TEST_IDENTITY, profile.getUserIdentity()); + assertEquals(TEST_PROXY_INFO, profile.getProxyInfo()); + assertEquals(TEST_ALLOWED_ALGORITHMS, profile.getAllowedAlgorithms()); + assertTrue(profile.isBypassable()); + assertFalse(profile.isMetered()); + assertEquals(TEST_MTU, profile.getMaxMtu()); + assertFalse(profile.isRestrictedToTestNetworks()); + } + + @Test + public void testBuildIkev2VpnProfilePsk() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertArrayEquals(TEST_PSK, profile.getPresharedKey()); + + // Verify nothing else is set. + assertNull(profile.getUsername()); + assertNull(profile.getPassword()); + assertNull(profile.getServerRootCaCert()); + assertNull(profile.getRsaPrivateKey()); + assertNull(profile.getUserCert()); + } + + @Test + public void testBuildIkev2VpnProfileUsernamePassword() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfileUsernamePassword(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertEquals(TEST_USER, profile.getUsername()); + assertEquals(TEST_PASSWORD, profile.getPassword()); + assertEquals(mServerRootCa, profile.getServerRootCaCert()); + + // Verify nothing else is set. + assertNull(profile.getPresharedKey()); + assertNull(profile.getRsaPrivateKey()); + assertNull(profile.getUserCert()); + } + + @Test + public void testBuildIkev2VpnProfileDigitalSignature() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfileDigitalSignature(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertEquals(mUserCertKey.cert, profile.getUserCert()); + assertEquals(mUserCertKey.key, profile.getRsaPrivateKey()); + assertEquals(mServerRootCa, profile.getServerRootCaCert()); + + // Verify nothing else is set. + assertNull(profile.getUsername()); + assertNull(profile.getPassword()); + assertNull(profile.getPresharedKey()); + } + + private void verifyProvisionVpnProfile( + boolean hasActivateVpn, boolean hasActivatePlatformVpn, boolean expectIntent) + throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_VPN, hasActivateVpn); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, hasActivatePlatformVpn); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + final Intent intent = sVpnMgr.provisionVpnProfile(profile); + assertEquals(expectIntent, intent != null); + } + + @Test + public void testProvisionVpnProfileNoPreviousConsent() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(false /* hasActivateVpn */, + false /* hasActivatePlatformVpn */, true /* expectIntent */); + } + + @Test + public void testProvisionVpnProfilePlatformVpnConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(false /* hasActivateVpn */, + true /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testProvisionVpnProfileVpnServiceConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(true /* hasActivateVpn */, + false /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testProvisionVpnProfileAllPreConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(true /* hasActivateVpn */, + true /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testDeleteVpnProfile() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + assertNull(sVpnMgr.provisionVpnProfile(profile)); + + // Verify that deleting the profile works (even without the appop) + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + sVpnMgr.deleteProvisionedVpnProfile(); + + // Test that the profile was deleted - starting it should throw an IAE. + try { + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + sVpnMgr.startProvisionedVpnProfile(); + fail("Expected IllegalArgumentException due to missing profile"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testStartVpnProfileNoPreviousConsent() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_VPN, false); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + + // Make sure the VpnProfile is not provisioned already. + sVpnMgr.stopProvisionedVpnProfile(); + + try { + sVpnMgr.startProvisionedVpnProfile(); + fail("Expected SecurityException for missing consent"); + } catch (SecurityException expected) { + } + } + + @Test + public void testStartStopVpnProfile() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. + runWithShellPermissionIdentity(() -> { + mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(true /* isRestrictedToTestNetworks */); + assertNull(sVpnMgr.provisionVpnProfile(profile)); + + sVpnMgr.startProvisionedVpnProfile(); + // TODO: When IKEv2 setup is injectable, verify network was set up properly. + + sVpnMgr.stopProvisionedVpnProfile(); + // TODO: When IKEv2 setup is injectable, verify network is lost. + }, Manifest.permission.MANAGE_TEST_NETWORKS); + } + + private static class CertificateAndKey { + public final X509Certificate cert; + public final PrivateKey key; + + CertificateAndKey(X509Certificate cert, PrivateKey key) { + this.cert = cert; + this.key = key; + } + } + + private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception { + final Date validityBeginDate = + new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L)); + final Date validityEndDate = + new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L)); + + // Generate a keypair + final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(512); + final KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + final X500Principal dnName = new X500Principal("CN=test.android.com"); + final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator(); + certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis())); + certGen.setSubjectDN(dnName); + certGen.setIssuerDN(dnName); + certGen.setNotBefore(validityBeginDate); + certGen.setNotAfter(validityEndDate); + certGen.setPublicKey(keyPair.getPublic()); + certGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); + + final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL"); + return new CertificateAndKey(cert, keyPair.getPrivate()); + } +} From f50119bbe426c8d91c53df925993d55a9e3a9da5 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Tue, 26 May 2020 23:43:09 +0000 Subject: [PATCH 1144/1415] Verify creation and deletion of IpSecTransform pair - Verify that inbound and outbound IpSecTransforms are created when a Child Session is created - Verify that when Child Session is deleted, the IpSecTransform pair is deleted Bug: 148689509 Test: atest CtsIkeTestCases Change-Id: If142b3fb2ac791322921beeab1bc8d43db255317 Merged-In: If142b3fb2ac791322921beeab1bc8d43db255317 (cherry picked from commit a91fc43cbdfc6e58347493506fa5079a4280dca8) --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 26 +++++---- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 54 +++++++++++++++++++ 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index fb93398b26..ca7ee1fe49 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -165,8 +165,11 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); - assertNotNull(mFirstChildSessionCallback.awaitNextCreatedIpSecTransform()); - assertNotNull(mFirstChildSessionCallback.awaitNextCreatedIpSecTransform()); + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); // Open additional Child Session TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); @@ -188,8 +191,11 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertTrue(additionalChildConfig.getInternalDnsServers().isEmpty()); assertTrue(additionalChildConfig.getInternalDhcpServers().isEmpty()); - assertNotNull(additionalChildCb.awaitNextCreatedIpSecTransform()); - assertNotNull(additionalChildCb.awaitNextCreatedIpSecTransform()); + IpSecTransformCallRecord additionalTransformRecordA = + additionalChildCb.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord additionalTransformRecordB = + additionalChildCb.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(additionalTransformRecordA, additionalTransformRecordB); // Close additional Child Session ikeSession.closeChildSession(additionalChildCb); @@ -199,8 +205,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { true /* expectedUseEncap */, hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); - assertNotNull(additionalChildCb.awaitNextDeletedIpSecTransform()); - assertNotNull(additionalChildCb.awaitNextDeletedIpSecTransform()); + verifyDeleteIpSecTransformPair( + additionalChildCb, additionalTransformRecordA, additionalTransformRecordB); additionalChildCb.awaitOnClosed(); // Close IKE Session @@ -211,12 +217,10 @@ public class IkeSessionPskTest extends IkeSessionTestBase { true /* expectedUseEncap */, hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); - assertNotNull(mFirstChildSessionCallback.awaitNextDeletedIpSecTransform()); - assertNotNull(mFirstChildSessionCallback.awaitNextDeletedIpSecTransform()); + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); mFirstChildSessionCallback.awaitOnClosed(); mIkeSessionCallback.awaitOnClosed(); - - // TODO: verify created and deleted IpSecTransform pair and their directions } @Test @@ -245,7 +249,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { @Test public void testIkeInitFail() throws Exception { - String ikeInitFailRespHex = + final String ikeInitFailRespHex = "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; // Open IKE Session diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 279d088b3c..e49f75fabb 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -17,12 +17,16 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.InetAddresses; +import android.net.IpSecManager; import android.net.IpSecTransform; import android.net.LinkAddress; import android.net.Network; @@ -55,6 +59,9 @@ import org.junit.runner.RunWith; import java.net.Inet4Address; import java.net.InetAddress; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -370,6 +377,53 @@ abstract class IkeSessionTestBase extends IkeTestBase { this.ipSecTransform = ipSecTransform; this.direction = direction; } + + @Override + public int hashCode() { + return Objects.hash(ipSecTransform, direction); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof IpSecTransformCallRecord)) return false; + + IpSecTransformCallRecord record = (IpSecTransformCallRecord) o; + return ipSecTransform.equals(record.ipSecTransform) && direction == record.direction; + } + } + + static void verifyCreateIpSecTransformPair( + IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) { + IpSecTransform transformA = transformRecordA.ipSecTransform; + IpSecTransform transformB = transformRecordB.ipSecTransform; + + assertNotNull(transformA); + assertNotNull(transformB); + + Set expectedDirections = new HashSet<>(); + expectedDirections.add(IpSecManager.DIRECTION_IN); + expectedDirections.add(IpSecManager.DIRECTION_OUT); + + Set resultDirections = new HashSet<>(); + resultDirections.add(transformRecordA.direction); + resultDirections.add(transformRecordB.direction); + + assertEquals(expectedDirections, resultDirections); + } + + static void verifyDeleteIpSecTransformPair( + TestChildSessionCallback childCb, + IpSecTransformCallRecord expectedTransformRecordA, + IpSecTransformCallRecord expectedTransformRecordB) { + Set expectedTransforms = new HashSet<>(); + expectedTransforms.add(expectedTransformRecordA); + expectedTransforms.add(expectedTransformRecordB); + + Set resultTransforms = new HashSet<>(); + resultTransforms.add(childCb.awaitNextDeletedIpSecTransform()); + resultTransforms.add(childCb.awaitNextDeletedIpSecTransform()); + + assertEquals(expectedTransforms, resultTransforms); } /** Package private method to check if device has IPsec tunnels feature */ From fd9c5eb675f30091ca5ebdce88f6c33f6279139e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 26 May 2020 23:43:43 +0000 Subject: [PATCH 1145/1415] Move common logic in testing and verification to IkeSessionTestBase This commit moves following logics to IkeSessionTestBase so that all subclasses can share it: - build ChildParams - perform IKE and first Child setup - perform deleting IKE - verifying IKE and first Child setup Bug: 155821007 Test: atest CtsIkeTestCases:IkeSessionDigitalSignatureTest Change-Id: Ib35b18240396a7b4823111e37be9a338d8ff6f06 Merged-In: Ib35b18240396a7b4823111e37be9a338d8ff6f06 (cherry picked from commit 34cdddb039da37c07bacf15f4c7a5fb36e757fad) --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 125 ++++-------------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 93 ++++++++++++- .../net/ipsec/ike/cts/IkeTunUtils.java | 69 +++++----- 3 files changed, 153 insertions(+), 134 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index ca7ee1fe49..661457ff5e 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -16,25 +16,17 @@ package android.net.ipsec.ike.cts; -import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static com.android.internal.util.HexDump.hexStringToByteArray; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.LinkAddress; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionConfiguration; -import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.platform.test.annotations.AppModeFull; @@ -45,10 +37,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.util.ArrayList; import java.util.Arrays; @RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +@AppModeFull(reason = "MANAGE_IPSEC_TUNNELS permission can't be granted to instant apps") public class IkeSessionPskTest extends IkeSessionTestBase { // Test vectors for success workflow private static final String SUCCESS_IKE_INIT_RESP = @@ -89,16 +82,6 @@ public class IkeSessionPskTest extends IkeSessionTestBase { + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" + "6743A7CEB2BE34AC00095A5B8"; - private static final long IKE_INIT_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); - - private static final TunnelModeChildSessionParams CHILD_PARAMS = - new TunnelModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addInternalAddressRequest(AF_INET) - .addInternalAddressRequest(AF_INET6) - .build(); - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { IkeSessionParams ikeParams = new IkeSessionParams.Builder(sContext) @@ -113,7 +96,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { return new IkeSession( sContext, ikeParams, - CHILD_PARAMS, + buildTunnelModeChildSessionParams(), mUserCbExecutor, mIkeSessionCallback, mFirstChildSessionCallback); @@ -125,45 +108,17 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open IKE Session IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); + performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 + int expectedMsgId = 2; - // Verify opening IKE Session - IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); - assertNotNull(ikeConfig); - assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); - assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); - assertTrue(ikeConfig.getPcscfServers().isEmpty()); - assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); - - IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); - assertNotNull(ikeConnectInfo); - assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); - assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); - assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); - - // Verify opening first Child Session - ChildSessionConfiguration firstChildConfig = mFirstChildSessionCallback.awaitChildConfig(); - assertNotNull(firstChildConfig); - assertEquals( - Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); - assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); - assertEquals( - Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR), - firstChildConfig.getInternalAddresses()); - assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); - assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); - assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TUNNEL_MODE_INBOUND_TS), + Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), + Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR)); IpSecTransformCallRecord firstTransformRecordA = mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); @@ -173,24 +128,19 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open additional Child Session TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); - ikeSession.openChildSession(CHILD_PARAMS, additionalChildCb); + ikeSession.openChildSession(buildTunnelModeChildSessionParams(), additionalChildCb); mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_CREATE_CHILD_RESP)); + SUCCESS_CREATE_CHILD_RESP); // Verify opening additional Child Session - ChildSessionConfiguration additionalChildConfig = additionalChildCb.awaitChildConfig(); - assertNotNull(additionalChildConfig); - assertEquals( - Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); - assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); - assertTrue(additionalChildConfig.getInternalAddresses().isEmpty()); - assertTrue(additionalChildConfig.getInternalSubnets().isEmpty()); - assertTrue(additionalChildConfig.getInternalDnsServers().isEmpty()); - assertTrue(additionalChildConfig.getInternalDhcpServers().isEmpty()); - + verifyChildSessionSetupBlocking( + additionalChildCb, + Arrays.asList(TUNNEL_MODE_INBOUND_TS), + Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), + new ArrayList()); IpSecTransformCallRecord additionalTransformRecordA = additionalChildCb.awaitNextCreatedIpSecTransform(); IpSecTransformCallRecord additionalTransformRecordB = @@ -200,10 +150,10 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Close additional Child Session ikeSession.closeChildSession(additionalChildCb); mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); + SUCCESS_DELETE_CHILD_RESP); verifyDeleteIpSecTransformPair( additionalChildCb, additionalTransformRecordA, additionalTransformRecordB); @@ -211,16 +161,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Close IKE Session ikeSession.close(); - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); - - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); + performCloseIkeBlocking(expectedMsgId++, SUCCESS_DELETE_IKE_RESP); + verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); } @Test @@ -229,18 +171,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open IKE Session IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); - - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); ikeSession.kill(); mFirstChildSessionCallback.awaitOnClosed(); @@ -256,10 +187,10 @@ public class IkeSessionPskTest extends IkeSessionTestBase { IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, false /* expectedUseEncap */, - hexStringToByteArray(ikeInitFailRespHex)); + ikeInitFailRespHex); mFirstChildSessionCallback.awaitOnClosed(); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index e49f75fabb..ade9813a81 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -16,9 +16,13 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import android.annotation.NonNull; import android.app.AppOpsManager; @@ -37,7 +41,9 @@ import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -60,6 +66,7 @@ import org.junit.runner.RunWith; import java.net.Inet4Address; import java.net.InetAddress; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -90,9 +97,13 @@ abstract class IkeSessionTestBase extends IkeTestBase { InetAddresses.parseNumericAddress("198.51.100.10"); static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR = new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN); - static final IkeTrafficSelector EXPECTED_INBOUND_TS = + + static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS = new IkeTrafficSelector( MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); + static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS; + + static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); // Static state to reduce setup/teardown static Context sContext = InstrumentationRegistry.getContext(); @@ -238,6 +249,45 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { + return new TunnelModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .build(); + } + + void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String ikeAuthRespHex) + throws Exception { + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 0 /* expectedMsgId */, + false /* expectedUseEncap */, + ikeInitRespHex); + + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 1 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeAuthRespHex); + } + + void performSetupIkeAndFirstChildBlocking( + String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespPktHex) + throws Exception { + // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple IKE AUTH + // request fragments and injecting multiple IKE AUTH response fragments + } + + void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId, + true /* expectedUseEncap */, + deleteIkeRespHex); + } + /** Testing callback that allows caller to block current thread until a method get called */ static class TestIkeSessionCallback implements IkeSessionCallback { private CompletableFuture mFutureIkeConfig = @@ -392,6 +442,47 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + void verifyIkeSessionSetupBlocking() throws Exception { + IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); + assertNotNull(ikeConfig); + assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); + assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); + assertTrue(ikeConfig.getPcscfServers().isEmpty()); + assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); + + IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); + assertNotNull(ikeConnectInfo); + assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); + assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); + assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); + } + + void verifyChildSessionSetupBlocking( + TestChildSessionCallback childCallback, + List expectedInboundTs, + List expectedOutboundTs, + List expectedInternalAddresses) + throws Exception { + ChildSessionConfiguration childConfig = childCallback.awaitChildConfig(); + assertNotNull(childConfig); + assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors()); + assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors()); + assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses()); + assertTrue(childConfig.getInternalSubnets().isEmpty()); + assertTrue(childConfig.getInternalDnsServers().isEmpty()); + assertTrue(childConfig.getInternalDhcpServers().isEmpty()); + } + + void verifyCloseIkeAndChildBlocking( + IpSecTransformCallRecord expectedTransformRecordA, + IpSecTransformCallRecord expectedTransformRecordB) + throws Exception { + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, expectedTransformRecordA, expectedTransformRecordB); + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } + static void verifyCreateIpSecTransformPair( IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) { IpSecTransform transformA = transformRecordA.ipSecTransform; diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index f52b88ba3a..2bff63a753 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -26,6 +26,8 @@ import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader; import static android.system.OsConstants.IPPROTO_UDP; +import static com.android.internal.util.HexDump.hexStringToByteArray; + import static org.junit.Assert.fail; import android.os.ParcelFileDescriptor; @@ -35,6 +37,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.function.Predicate; public class IkeTunUtils extends TunUtils { private static final int PORT_LEN = 2; @@ -54,17 +57,24 @@ public class IkeTunUtils extends TunUtils { /** * Await the expected IKE request and inject an IKE response. * - * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER. + * @param ikeRespDataHex IKE response hex without IP/UDP headers or NON ESP MARKER. */ public byte[] awaitReqAndInjectResp( - long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, byte[] respIkePkt) + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedUseEncap, + String ikeRespDataHex) throws Exception { byte[] request = awaitIkePacket( - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap); + (pkt) -> { + return isExpectedIkePkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap); + }); // Build response header by flipping address and port InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); @@ -73,32 +83,26 @@ public class IkeTunUtils extends TunUtils { int dstPort = getPort(request, true /* shouldGetSource */); byte[] response = - buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, expectedUseEncap, respIkePkt); + buildIkePacket( + srcAddr, + dstAddr, + srcPort, + dstPort, + expectedUseEncap, + hexStringToByteArray(ikeRespDataHex)); injectPacket(response); return request; } - private byte[] awaitIkePacket( - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp, - boolean expectedUseEncap) - throws Exception { + // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple + // request fragments and injecting multiple response fragments + + private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; int startIndex = 0; synchronized (mPackets) { while (System.currentTimeMillis() < endTime) { - byte[] ikePkt = - getFirstMatchingPacket( - (pkt) -> { - return isIke( - pkt, - expectedInitIkeSpi, - expectedMsgId, - expectedResp, - expectedUseEncap); - }, - startIndex); + byte[] ikePkt = getFirstMatchingPacket(pktVerifier, startIndex); if (ikePkt != null) { return ikePkt; // We've found the packet we're looking for. } @@ -112,21 +116,14 @@ public class IkeTunUtils extends TunUtils { } } - String direction = expectedResp ? "response" : "request"; - fail( - "No such IKE " - + direction - + " found with Initiator SPI " - + expectedInitIkeSpi - + " and message ID " - + expectedMsgId); + fail("No matching packet found"); } throw new IllegalStateException( "Hit an impossible case where fail() didn't throw an exception"); } - private static boolean isIke( + private static boolean isExpectedIkePkt( byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, @@ -153,7 +150,7 @@ public class IkeTunUtils extends TunUtils { } return pkt[ipProtocolOffset] == IPPROTO_UDP - && areSpiAndMsgIdEqual( + && isExpectedSpiAndMsgId( pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); } @@ -170,10 +167,10 @@ public class IkeTunUtils extends TunUtils { return Arrays.equals(NON_ESP_MARKER, nonEspMarker); } - private static boolean areSpiAndMsgIdEqual( + private static boolean isExpectedSpiAndMsgId( byte[] pkt, int ikeOffset, - long expectedIkeInitSpi, + long expectedInitIkeSpi, int expectedMsgId, boolean expectedResp) { if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false; From 1e024e26cf5adb46ead8f3b6737cafb03b9cac72 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 28 May 2020 00:53:46 +0000 Subject: [PATCH 1146/1415] Test IKE Session setup with digital-signature-based Auth This commit adds a test for setting up IKE Session with digital-signature-based authentication. This test also verifies sending and receiving IKE fragments Bug: 155821007 Test: atest CtsIkeTestCases:IkeSessionDigitalSignatureTest Change-Id: I5829dfa955c47c0810760b7bf97372031e740f1e Merged-In: I5829dfa955c47c0810760b7bf97372031e740f1e (cherry picked from commit 3fde403c39e048e82223256ec7ca5c3ac7c93751) --- .../cts/IkeSessionDigitalSignatureTest.java | 210 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeSessionPskTest.java | 20 +- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 50 +++-- .../net/ipsec/ike/cts/IkeTunUtils.java | 166 ++++++++++---- .../android/net/ipsec/ike/cts/TunUtils.java | 2 +- 5 files changed, 383 insertions(+), 65 deletions(-) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java new file mode 100644 index 0000000000..ebf8a41f00 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java @@ -0,0 +1,210 @@ +/* + * 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.ipsec.ike.cts; + +import android.net.InetAddresses; +import android.net.LinkAddress; +import android.net.ipsec.ike.IkeDerAsn1DnIdentification; +import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTrafficSelector; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.internal.net.ipsec.ike.testutils.CertUtils; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.util.ArrayList; +import java.util.Arrays; + +import javax.security.auth.x500.X500Principal; + +/** + * Explicitly test setting up transport mode Child SA so that devices do not have + * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in + * IkeSessionPskTest and authentication method is orthogonal to Child mode. + */ +@RunWith(AndroidJUnit4.class) +public class IkeSessionDigitalSignatureTest extends IkeSessionTestBase { + private static final int EXPECTED_AUTH_REQ_FRAG_COUNT = 3; + + private static final String IKE_INIT_RESP = + "46B8ECA1E0D72A18BF3FA1C2CB1EE86F21202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0100030000080300000503000008" + + "0200000400000008040000022800008800020000328451C8A976CE69E407966A" + + "50D7320C4197A15A07267CE1B16BAFF9BDBBDEC1FDCDAAF7175ADF9AA8DB55DB" + + "2D70C012D01D914C4EDEF6E8B226868EA1D01B2ED0C4C5C86E6BFE566010EC0C" + + "33BA1C93666430B88BDA0470D82CC4F4416F49E3E361E3017C9F27811A66718B" + + "389E1800915D776D59AA528A7E1D1B7815D35144290000249FE8FABE7F43D917" + + "CE370DE2FD9C22BBC082951AC26C1BA26DE795470F2C25BC2900001C00004004" + + "AE388EC86D6D1A470D44142D01AB2E85A7AC14182900001C0000400544A235A4" + + "171C884286B170F48FFC181DB428D87D290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + private static final String IKE_AUTH_RESP_FRAG_1 = + "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000004E0240004C4" + + "00010002DF6750A2D1D5675006F9F6230BB886FFD20CFB973FD04963CFD7A528" + + "560598C58CC44178B2FCBBBBB271387AC81A664B7E7F1055B912F8C686E287C9" + + "D31684C66339151AB86DA3CF1DA664052FA97687634558A1E9E6B37E16A86BD1" + + "68D76DA5E2E1E0B7E98EB662D80D542307015D2BF134EBBBE425D6954FE8C2C4" + + "D31D16C16AA0521C3C481F873ECF25BB8B05AC6083775C1821CAAB1E35A3955D" + + "85ACC599574142E1DD5B262D6E5365CBF6EBE92FFCC16BC29EC3239456F3B202" + + "492551C0F6D752ADCCA56D506D50CC8809EF6BC56EAD005586F7168F76445FD3" + + "1366CC62D32C0C19B28210B8F813F97CD6A447C3857EFD6EC483DDA8ACD9870E" + + "5A21B9C66F0FA44496C0C3D05E8859A1A4CFC88155D0C411BABC13033DD41FA4" + + "AF08CE7734A146687F374F95634D1F26843203CA1FFD05CA3EB150CEA02FBF14" + + "712B7A1C9BC7616A086E7FCA059E7D64EFF98DB895B32F8F7002762AF7D12F23" + + "31E9DD25174C4CE273E5392BBB48F50B7A3E0187181216265F6A4FC7B91BE0AB" + + "C601A580149D4B07411AE99DDB1944B977E86ADC9746605C60A92B569EEFAFFC" + + "3A888D187B75D8F13249689FC28EBCD62B5E03AF171F3A561F0DEA3B1A75F531" + + "971157DCE1E7BC6E7789FF3E8156015BC9C521EFE48996B41471D33BF09864E4" + + "2436E8D7EB6218CDE7716DA754A924B123A63E25585BF27F4AC043A0C4AECE38" + + "BB59DD62F5C0EC657206A76CED1BD26262237DA1CA6815435992A825758DEBEC" + + "DDF598A22B8242AC4E34E70704DBA7B7B73DC3E067C1C98764F8791F84C99156" + + "947D1FFC875F36FCE24B89369C1B5BF1D4C999DCA28E72A528D0E0163C66C067" + + "E71B5E0025C13DA93313942F9EDA230B3ADC254821A4CB1A5DC9D0C5F4DC4E8E" + + "CE46B7B8C72D3C5923C9B30DF1EF7B4EDEDA8BD05C86CA0162AE1BF8F277878E" + + "607401BAA8F06E3EA873FA4C137324C4E0699277CDF649FE7F0F01945EE25FA7" + + "0E4A89737E58185B11B4CB52FD5B0497D3E3CD1CEE7B1FBB3E969DB6F4C324A1" + + "32DC6A0EA21F41332435FD99140C286F8ABBBA926953ADBEED17D30AAD953909" + + "1347EF6D87163D6B1FF32D8B11FFB2E69FAEE7FE913D3826FBA7F9D11E0E3C57" + + "27625B37D213710B5DD8965DAEFD3F491E8C029E2BF361039949BADEC31D60AC" + + "355F26EE41339C03CC9D9B01C3C7F288F0E9D6DFEE78231BDA9AC10FED135913" + + "2836B1A17CE060742B7E5B738A7177CCD59F70337BA251409C377A0FA5333204" + + "D8622BA8C06DE0BEF4F32B6D4D77BE9DE977445D8A2A08C5C38341CB7974FBFB" + + "22C8F983A7D6CEF068DDB2281E6673453521C831C1826861005AE5F37649BC64" + + "0A6360B23284861441A440F1C5AADE1AB53CA63DB17F4C314D493C4C44DE5F20" + + "75E084D080F92791F30BDD88373D50AB5A07BC72B0E7FFFA593103964E55603E" + + "F7FEB7CA0762A1A7B86B6CCAD88CD6CBC7C6935D21F5F06B2700588A2530E619" + + "DA1648AC809F3DDF56ACE5951737568FFEC7E2AB1AA0AE01B03A7F5A29CE73C0" + + "5D2801B17CAAD0121082E9952FAB16BA1C386336C62D4CF3A5019CF61609433E" + + "1C083237D47C4CF575097F7BF9000EF6B6C497A44E6480154A35669AD276BF05" + + "6CC730B4E5962B6AF96CC6D236AE85CEFDA6877173F72D2F614F6696D1F9DF07" + + "E107758B0978F69BC9DBE0CCBF252C40A3FDF7CE9104D3344F7B73593CCD73E0"; + private static final String IKE_AUTH_RESP_FRAG_2 = + "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000000F0000000D4" + + "00020002155211EA41B37BC5F20568A6AE57038EEE208F94F9B444004F1EF391" + + "2CABFCF857B9CD95FAAA9489ED10A3F5C93510820E22E23FC55ED8049E067D72" + + "3645C00E1E08611916CE72D7F0A84123B63A8F3B9E78DBBE39967B7BB074AF4D" + + "BF2178D991EDBDD01908A14A266D09236DB963B14AC33D894F0F83A580209EFD" + + "61875BB56273AA336C22D6A4D890B93E0D42435667830CC32E4F608500E18569" + + "3E6C1D88C0B5AE427333C86468E3474DAA4D1506AAB2A4021309A33DD759D0D0" + + "A8C98BF7FBEA8109361A9F194D0FD756"; + private static final String DELETE_IKE_RESP = + "46B8ECA1E0D72A18BF3FA1C2CB1EE86F2E202520000000020000004C00000030" + + "342842D8DA37C8EFB92ED37C4FBB23CBDC90445137D6A0AF489F9F03641DBA9D" + + "02F6F59FD8A7A78C7261CEB8"; + + // Using IPv4 for transport mode Child SA. IPv6 is currently infeasible because the IKE server + // that generates the test vectors is running in an IPv4 only network. + private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("172.58.35.103"), + InetAddresses.parseNumericAddress("172.58.35.103")); + + // TODO(b/157510502): Add test for IKE Session setup in IPv6 network + + private static final String LOCAL_ID_ASN1_DN = + "CN=client.test.ike.android.net, O=Android, C=US"; + private static final String REMOTE_ID_ASN1_DN = + "CN=server.test.ike.android.net, O=Android, C=US"; + + private static X509Certificate sServerCaCert; + private static X509Certificate sClientEndCert; + private static X509Certificate sClientIntermediateCaCertOne; + private static X509Certificate sClientIntermediateCaCertTwo; + private static RSAPrivateKey sClientPrivateKey; + + @BeforeClass + public static void setUpCertsBeforeClass() throws Exception { + sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); + sClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); + sClientIntermediateCaCertOne = + CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem"); + sClientIntermediateCaCertTwo = + CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem"); + sClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); + } + + private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + IkeSessionParams ikeParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(remoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification( + new IkeDerAsn1DnIdentification(new X500Principal(LOCAL_ID_ASN1_DN))) + .setRemoteIdentification( + new IkeDerAsn1DnIdentification( + new X500Principal(REMOTE_ID_ASN1_DN))) + .setAuthDigitalSignature( + sServerCaCert, + sClientEndCert, + Arrays.asList( + sClientIntermediateCaCertOne, sClientIntermediateCaCertTwo), + sClientPrivateKey) + .build(); + + return new IkeSession( + sContext, + ikeParams, + buildTransportModeChildParamsWithTs( + TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), + mUserCbExecutor, + mIkeSessionCallback, + mFirstChildSessionCallback); + } + + @Test + public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception { + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + performSetupIkeAndFirstChildBlocking( + IKE_INIT_RESP, + EXPECTED_AUTH_REQ_FRAG_COUNT /* expectedReqPktCnt */, + IKE_AUTH_RESP_FRAG_1, + IKE_AUTH_RESP_FRAG_2); + + // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 + int expectedMsgId = 2; + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TRANSPORT_MODE_INBOUND_TS), + Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), + new ArrayList()); + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); + + // Close IKE Session + ikeSession.close(); + performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP); + verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 661457ff5e..ef865afe9a 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -16,6 +16,7 @@ package android.net.ipsec.ike.cts; +import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; import static org.junit.Assert.assertArrayEquals; @@ -33,6 +34,8 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -102,6 +105,21 @@ public class IkeSessionPskTest extends IkeSessionTestBase { mFirstChildSessionCallback); } + @BeforeClass + public static void setUpTunnelPermissionBeforeClass() throws Exception { + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and + // a standard permission is insufficient. So we shell out the appop, to give us the + // right appop permissions. + setAppOp(OP_MANAGE_IPSEC_TUNNELS, true); + } + + // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass + // methods. + @AfterClass + public static void tearDownTunnelPermissionAfterClass() throws Exception { + setAppOp(OP_MANAGE_IPSEC_TUNNELS, false); + } + @Test public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception { if (!hasTunnelsFeature()) return; @@ -203,6 +221,4 @@ public class IkeSessionPskTest extends IkeSessionTestBase { } // TODO(b/155821007): Verify rekey process and handling IKE_AUTH failure - - // TODO(b/155821007): Test creating transport mode Child SA } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index ade9813a81..5b545c4394 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -15,7 +15,6 @@ package android.net.ipsec.ike.cts; -import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; @@ -43,6 +42,7 @@ import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TransportModeChildSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; import android.net.ipsec.ike.exceptions.IkeException; @@ -103,6 +103,14 @@ abstract class IkeSessionTestBase extends IkeTestBase { MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS; + // This value is align with the test vectors hex that are generated in an IPv4 environment + static final IkeTrafficSelector TRANSPORT_MODE_OUTBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("10.138.0.2"), + InetAddresses.parseNumericAddress("10.138.0.2")); + static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); // Static state to reduce setup/teardown @@ -142,19 +150,12 @@ abstract class IkeSessionTestBase extends IkeTestBase { .getUiAutomation() .adoptShellPermissionIdentity(); sTNM = sContext.getSystemService(TestNetworkManager.class); - - // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and - // a standard permission is insufficient. So we shell out the appop, to give us the - // right appop permissions. - setAppOp(OP_MANAGE_IPSEC_TUNNELS, true); } // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass // methods. @AfterClass public static void tearDownPermissionAfterClass() throws Exception { - setAppOp(OP_MANAGE_IPSEC_TUNNELS, false); - InstrumentationRegistry.getInstrumentation() .getUiAutomation() .dropShellPermissionIdentity(); @@ -197,7 +198,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { mTunFd.close(); } - private static void setAppOp(int appop, boolean allow) { + static void setAppOp(int appop, boolean allow) { String opName = AppOpsManager.opToName(appop); for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { String cmd = @@ -249,6 +250,16 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + TransportModeChildSessionParams buildTransportModeChildParamsWithTs( + IkeTrafficSelector inboundTs, IkeTrafficSelector outboundTs) { + return new TransportModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .addInboundTrafficSelectors(inboundTs) + .addOutboundTrafficSelectors(outboundTs) + .build(); + } + TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { return new TunnelModeChildSessionParams.Builder() .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) @@ -258,7 +269,14 @@ abstract class IkeSessionTestBase extends IkeTestBase { .build(); } - void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String ikeAuthRespHex) + void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) + throws Exception { + performSetupIkeAndFirstChildBlocking( + ikeInitRespHex, 1 /* expectedAuthReqPktCnt */, ikeAuthRespHexes); + } + + void performSetupIkeAndFirstChildBlocking( + String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespHexes) throws Exception { mTunUtils.awaitReqAndInjectResp( IKE_DETERMINISTIC_INITIATOR_SPI, @@ -270,14 +288,8 @@ abstract class IkeSessionTestBase extends IkeTestBase { IKE_DETERMINISTIC_INITIATOR_SPI, 1 /* expectedMsgId */, true /* expectedUseEncap */, - ikeAuthRespHex); - } - - void performSetupIkeAndFirstChildBlocking( - String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespPktHex) - throws Exception { - // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple IKE AUTH - // request fragments and injecting multiple IKE AUTH response fragments + expectedAuthReqPktCnt, + ikeAuthRespHexes); } void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { @@ -522,7 +534,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); } - // TODO(b/148689509): Verify IKE Session setup using EAP and digital-signature-based auth + // TODO(b/148689509): Verify IKE Session setup using EAP // TODO(b/148689509): Verify hostname based creation } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index 2bff63a753..a9daf6adc3 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -36,7 +36,9 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.function.Predicate; public class IkeTunUtils extends TunUtils { @@ -45,10 +47,13 @@ public class IkeTunUtils extends TunUtils { private static final int NON_ESP_MARKER_LEN = 4; private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN]; - private static final int IKE_HEADER_LEN = 28; private static final int IKE_INIT_SPI_OFFSET = 0; + private static final int IKE_FIRST_PAYLOAD_OFFSET = 16; private static final int IKE_IS_RESP_BYTE_OFFSET = 19; private static final int IKE_MSG_ID_OFFSET = 20; + private static final int IKE_HEADER_LEN = 28; + private static final int IKE_FRAG_NUM_OFFSET = 32; + private static final int IKE_PAYLOAD_TYPE_SKF = 53; public IkeTunUtils(ParcelFileDescriptor tunFd) { super(tunFd); @@ -65,16 +70,65 @@ public class IkeTunUtils extends TunUtils { boolean expectedUseEncap, String ikeRespDataHex) throws Exception { - byte[] request = - awaitIkePacket( - (pkt) -> { - return isExpectedIkePkt( - pkt, - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap); - }); + return awaitReqAndInjectResp( + expectedInitIkeSpi, + expectedMsgId, + expectedUseEncap, + 1 /* expectedReqPktCnt */, + ikeRespDataHex) + .get(0); + } + + /** + * Await the expected IKE request (or the list of IKE request fragments) and inject an IKE + * response (or a list of response fragments) + * + * @param ikeRespDataHexes IKE response hex (or a list of response fragments) without IP/UDP + * headers or NON ESP MARKER. + */ + public List awaitReqAndInjectResp( + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedUseEncap, + int expectedReqPktCnt, + String... ikeRespDataHexes) + throws Exception { + List reqList = new ArrayList<>(expectedReqPktCnt); + if (expectedReqPktCnt == 1) { + // Expecting one complete IKE packet + byte[] req = + awaitIkePacket( + (pkt) -> { + return isExpectedIkePkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap); + }); + reqList.add(req); + } else { + // Expecting "expectedReqPktCnt" number of request fragments + for (int i = 0; i < expectedReqPktCnt; i++) { + // IKE Fragment number always starts from 1 + int expectedFragNum = i + 1; + byte[] req = + awaitIkePacket( + (pkt) -> { + return isExpectedIkeFragPkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap, + expectedFragNum); + }); + reqList.add(req); + } + } + + // All request fragments have the same addresses and ports + byte[] request = reqList.get(0); // Build response header by flipping address and port InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); @@ -82,20 +136,20 @@ public class IkeTunUtils extends TunUtils { int srcPort = getPort(request, false /* shouldGetSource */); int dstPort = getPort(request, true /* shouldGetSource */); - byte[] response = - buildIkePacket( - srcAddr, - dstAddr, - srcPort, - dstPort, - expectedUseEncap, - hexStringToByteArray(ikeRespDataHex)); - injectPacket(response); - return request; - } + for (String hex : ikeRespDataHexes) { + byte[] response = + buildIkePacket( + srcAddr, + dstAddr, + srcPort, + dstPort, + expectedUseEncap, + hexStringToByteArray(hex)); + injectPacket(response); + } - // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple - // request fragments and injecting multiple response fragments + return reqList; + } private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; @@ -129,31 +183,38 @@ public class IkeTunUtils extends TunUtils { int expectedMsgId, boolean expectedResp, boolean expectedUseEncap) { - int ipProtocolOffset = 0; - int ikeOffset = 0; - if (isIpv6(pkt)) { - // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap. - ipProtocolOffset = IP6_PROTO_OFFSET; - ikeOffset = IP6_HDRLEN + UDP_HDRLEN; - } else { - // Use default IPv4 header length (assuming no options) - ipProtocolOffset = IP4_PROTO_OFFSET; - ikeOffset = IP4_HDRLEN + UDP_HDRLEN; - - if (expectedUseEncap) { - if (hasNonEspMarker(pkt)) { - ikeOffset += NON_ESP_MARKER_LEN; - } else { - return false; - } - } - } + int ipProtocolOffset = isIpv6(pkt) ? IP6_PROTO_OFFSET : IP4_PROTO_OFFSET; + int ikeOffset = getIkeOffset(pkt, expectedUseEncap); return pkt[ipProtocolOffset] == IPPROTO_UDP + && expectedUseEncap == hasNonEspMarker(pkt) && isExpectedSpiAndMsgId( pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); } + private static boolean isExpectedIkeFragPkt( + byte[] pkt, + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedResp, + boolean expectedUseEncap, + int expectedFragNum) { + return isExpectedIkePkt( + pkt, expectedInitIkeSpi, expectedMsgId, expectedResp, expectedUseEncap) + && isExpectedFragNum(pkt, getIkeOffset(pkt, expectedUseEncap), expectedFragNum); + } + + private static int getIkeOffset(byte[] pkt, boolean useEncap) { + if (isIpv6(pkt)) { + // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap. + return IP6_HDRLEN + UDP_HDRLEN; + } else { + // Use default IPv4 header length (assuming no options) + int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; + return useEncap ? ikeOffset + NON_ESP_MARKER_LEN : ikeOffset; + } + } + private static boolean hasNonEspMarker(byte[] pkt) { ByteBuffer buffer = ByteBuffer.wrap(pkt); int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; @@ -186,6 +247,25 @@ public class IkeTunUtils extends TunUtils { // TODO: Check SPI and packet direction } + private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) { + ByteBuffer buffer = ByteBuffer.wrap(pkt); + buffer.get(new byte[ikeOffset]); + buffer.mark(); // Mark this position so that later we can reset back here + + // Check if it is a fragment packet + buffer.get(new byte[IKE_FIRST_PAYLOAD_OFFSET]); + int firstPayload = Byte.toUnsignedInt(buffer.get()); + if (firstPayload != IKE_PAYLOAD_TYPE_SKF) { + return false; + } + + // Check fragment number + buffer.reset(); + buffer.get(new byte[IKE_FRAG_NUM_OFFSET]); + int fragNum = Short.toUnsignedInt(buffer.getShort()); + return expectedFragNum == fragNum; + } + private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java index cb1d8269d7..5539dbca23 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java @@ -47,7 +47,7 @@ public class TunUtils { private static final String TAG = TunUtils.class.getSimpleName(); private static final int DATA_BUFFER_LEN = 4096; - static final int TIMEOUT = 100; + static final int TIMEOUT = 500; static final int IP4_PROTO_OFFSET = 9; static final int IP6_PROTO_OFFSET = 6; From 783b9ad7f71c182f2c7d3fe619584b57495a40f2 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 28 May 2020 02:22:55 +0000 Subject: [PATCH 1147/1415] Test IKE Session setup with EAP-MSCHAPv2 Bug: 155821007 Test: atest CtsIkeTestCases Change-Id: Ie8a328c53b531027ce63edaa874c4cd0904e0068 Merged-In: Ie8a328c53b531027ce63edaa874c4cd0904e0068 (cherry picked from commit aa4b9da896a4fd37ba01f4802fdf3de72b07a911) --- .../ipsec/ike/cts/IkeSessionMschapV2Test.java | 220 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeSessionTestBase.java | 2 - .../net/ipsec/ike/cts/IkeTestBase.java | 2 +- .../net/ipsec/ike/cts/IkeTunUtils.java | 17 +- 4 files changed, 230 insertions(+), 11 deletions(-) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java new file mode 100644 index 0000000000..cb771276dc --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java @@ -0,0 +1,220 @@ +/* + * 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.ipsec.ike.cts; + +import android.net.InetAddresses; +import android.net.LinkAddress; +import android.net.eap.EapSessionConfig; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTrafficSelector; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.internal.net.ipsec.ike.testutils.CertUtils; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Explicitly test setting up transport mode Child SA so that devices do not have + * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in + * IkeSessionPskTest and authentication method is orthogonal to Child mode. + */ +@RunWith(AndroidJUnit4.class) +public class IkeSessionMschapV2Test extends IkeSessionTestBase { + private static final String IKE_INIT_RESP = + "46B8ECA1E0D72A1873F643FF94D249A921202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0080030000080300000203000008" + + "0200000200000008040000022800008800020000CC6E71E67E32CED6BCE33FBD" + + "A74113867E3FA3AE21C7C9AB44A7F8835DF602BFD6F6528B67FEE39821232380" + + "C99E8FFC0A5D767F8F38906DA41946C2299DF18C15FA69BAC08D3EDB32E8C8CA" + + "28431831561C04CB0CDE393F817151CD8DAF7A311838411F1C39BFDB5EBCF6A6" + + "1DF66DEB067362649D64607D599B56C4227819D0290000241197004CF31AD00F" + + "5E0C92E198488D8A2B6F6A25C82762AA49F565BCE9D857D72900001C00004004" + + "A0D98FEABBFB92A6C0976EE83D2AACFCCF969A6B2900001C0000400575EBF73F" + + "8EE5CC73917DE9D3F91FCD4A16A0444D290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + private static final String IKE_AUTH_RESP_1_FRAG_1 = + "46B8ECA1E0D72A1873F643FF94D249A93520232000000001000004E0240004C4" + + "00010002C4159CB756773B3F1911F4595107BC505D7A28C72F05182966076679" + + "CA68ED92E4BC5CD441C9CB315F2F449A8A521CAFED3C5F285E295FC3791D3415" + + "E3BACF66A08410DF4E35F7D88FE40DA28851C91C77A6549E186AC1B7846DF3FA" + + "0A347A5ABBCAEE19E70F0EE5966DC6242A115F29523709302EDAD2E36C8F0395" + + "CF5C42EC2D2898ECDD8A6AEDD686A70B589A981558667647F32F41E0D8913E94" + + "A6693F53E59EA8938037F562CF1DC5E6E2CDC630B5FFB08949E3172249422F7D" + + "EA069F9BAD5F96E48BADC7164A9269669AD0DF295A80C54D1D23CEA3F28AC485" + + "86D2A9850DA23823037AB7D1577B7B2364C92C36B84238357129EB4A64D33310" + + "B95DCD50CD53E78C32EFE7DC1627D9432E9BFDEE130045DE967B19F92A9D1270" + + "F1E2C6BFBAA56802F3E63510578EF1ECB6872852F286EEC790AA1FE0CAF391CB" + + "E276554922713BA4770CFE71E23F043DC620E22CC02A74F60725D18331B7F2C9" + + "276EB6FBB7CBDAA040046D7ECBE1A5D7064E04E542807C5101B941D1C81B9D5E" + + "90347B22BD4E638E2EDC98E369B51AA29BDB2CF8AA610D4B893EB83A4650717C" + + "38B4D145EE939C18DCEDF6C79933CEB3D7C116B1F188DF9DDD560951B54E4A7D" + + "80C999A32AB02BF39D7B498DAD36F1A5CBE2F64557D6401AE9DD6E0CEADA3F90" + + "540FE9114BB6B8719C9064796354F4A180A6600CAD092F8302564E409B71ACB7" + + "590F19B3AC88E7A606C718D0B97F7E4B4830F11D851C59F2255846DA22E2C805" + + "0CA2AF2ACF3B6C769D11B75B5AC9AB82ED3D90014994B1BF6FED58FBEF2D72EF" + + "8BDFE51F9A101393A7CA1ACF78FAEBF3E3CC25E09407D1E14AF351A159A13EE3" + + "9B919BA8B49942792E7527C2FB6D418C4DF427669A4BF5A1AFBBB973BAF17918" + + "9C9D520CAC2283B89A539ECE785EBE48FBB77D880A17D55C84A51F46068A4B87" + + "FF48FEEE50E1E034CC8AFF5DA92105F55EC4823E67BDFE942CA8BE0DAECBBD52" + + "E8AAF306049DC6C4CF87D987B0AC54FCE92E6AE8507965AAAC6AB8BD3405712F" + + "EE170B70BC64BDCBD86D80C7AAAF341131F9A1210D7430B17218413AE1363183" + + "5C98FA2428B1E9E987ADC9070E232310A28F4C3163E18366FFB112BADD7C5E0F" + + "D13093A7C1428F87856BA0A7E46955589ACA267CE7A04320C4BCDBB60C672404" + + "778F8D511AAB09349DAB482445D7F606F28E7FBBB18FC0F4EC0AF04F44C282F9" + + "39C6E3B955C84DADEA350667236583069B74F492D600127636FA31F63E560851" + + "2FC28B8EA5B4D01D110990B6EA46B9C2E7C7C856C240EF7A8147BA2C4344B85A" + + "453C862024B5B6814D13CDEAEF7683D539BB50CAFFC0416F269F2F9EDEC5FA30" + + "022FD7B4B186CD2020E7ED8D81ED90822EDD8B76F840DD68F09694CFF9B4F33E" + + "11DF4E601A4212881A6D4E9259001705C41E9E23D18A7F3D4A3463649A38211A" + + "5A90D0F17739A677C74E23F31C01D60B5A0F1E6A4D44FED9D25BF1E63418E1FC" + + "0B19F6F4B71DE53C62B14B82279538A82DD4BE19AB6E00AFC20F124AAB7DF21A" + + "42259BE4F40EC69B16917256F23E2C37376311D62E0A3A0EF8C2AD0C090221D5" + + "C5ECA08F08178A4D31FFDB150C609827D18AD83C7B0A43AEE0406BD3FB494B53" + + "A279FDD6447E234C926AD8CE47FFF779BB45B1FC8457C6E7D257D1359959D977" + + "CEF6906A3367DC4D454993EFDC6F1EA94E17EB3DCB00A289346B4CFD7F19B16E"; + private static final String IKE_AUTH_RESP_1_FRAG_2 = + "46B8ECA1E0D72A1873F643FF94D249A935202320000000010000008000000064" + + "00020002C61F66025E821A5E69A4DE1F591A2C32C983C3154A5003660137D685" + + "A5262B9FDF5EDC699DE4D8BD38F549E3CBD12024B45B4C86561C36C3EED839DA" + + "9860C6AA0B764C662D08F1B6A98F68CF6E3038F737C0B415AD8A8B7D702BD92A"; + private static final String IKE_AUTH_RESP_2 = + "46B8ECA1E0D72A1873F643FF94D249A92E202320000000020000008C30000070" + + "62B90C2229FD23025BC2FD7FE6341E9EE04B17264CD619BCE18975A5F88BE438" + + "D4AD4A5310057255AF568C293A29B10107E3EE3675C10AA2B26404D90C0528CC" + + "F7605A86C96A1F2635CCC6CFC90EE65E5C2A2262EB33FE520EB708423A83CB63" + + "274ECCBB102AF5DF35742657"; + private static final String IKE_AUTH_RESP_3 = + "46B8ECA1E0D72A1873F643FF94D249A92E202320000000030000004C30000030" + + "AB52C3C80123D3432C05AF457CE93C352395F73E861CD49561BA528CFE68D17D" + + "78BBF6FC41E81C2B9EA051A2"; + private static final String IKE_AUTH_RESP_4 = + "46B8ECA1E0D72A1873F643FF94D249A92E20232000000004000000CC270000B0" + + "8D3342A7AB2666AC754F4B55C5C6B1A61255E62FBCA53D5CDEEDE60DADB7915C" + + "7F962076A58BF7D39A05ED1B60FF349B6DE311AF7CEBC72B4BB9723A728A5D3E" + + "9E508B2D7A11843D279B56ADA07E608D61F5CA7638F10372A440AD1DCE44E190" + + "7B7B7A68B126EBBB86638D667D5B528D233BA8D32D7E0FAC4E1448E87396EEE6" + + "0985B79841E1229D7962AACFD8F872722EC8D5B19D4C82D6C4ADCB276127A1A7" + + "3FC84CDF85B2299BC96B64AC"; + private static final String DELETE_IKE_RESP = + "46B8ECA1E0D72A1873F643FF94D249A92E202520000000050000004C00000030" + + "622CE06C8CB132AA00567E9BC83F58B32BD7DB5130C76E385B306434DA227361" + + "D50CC19D408A8D4F36F9697F"; + + // This value is align with the test vectors hex that are generated in an IPv4 environment + private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("172.58.35.67"), + InetAddresses.parseNumericAddress("172.58.35.67")); + + private static final EapSessionConfig EAP_CONFIG = + new EapSessionConfig.Builder() + .setEapIdentity(EAP_IDENTITY) + .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) + .build(); + + private static X509Certificate sServerCaCert; + + @BeforeClass + public static void setUpCertBeforeClass() throws Exception { + sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); + } + + private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + IkeSessionParams ikeParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(remoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) + .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) + .setAuthEap(sServerCaCert, EAP_CONFIG) + .build(); + return new IkeSession( + sContext, + ikeParams, + buildTransportModeChildParamsWithTs( + TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), + mUserCbExecutor, + mIkeSessionCallback, + mFirstChildSessionCallback); + } + + @Test + public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception { + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + int expectedMsgId = 0; + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + false /* expectedUseEncap */, + IKE_INIT_RESP); + + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + IKE_AUTH_RESP_1_FRAG_1, + IKE_AUTH_RESP_1_FRAG_2); + + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + IKE_AUTH_RESP_2); + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + IKE_AUTH_RESP_3); + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId++, + true /* expectedUseEncap */, + IKE_AUTH_RESP_4); + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TRANSPORT_MODE_INBOUND_TS), + Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), + new ArrayList()); + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); + + // Close IKE Session + ikeSession.close(); + performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP); + verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 5b545c4394..86e5c48ebe 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -534,7 +534,5 @@ abstract class IkeSessionTestBase extends IkeTestBase { return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); } - // TODO(b/148689509): Verify IKE Session setup using EAP - // TODO(b/148689509): Verify hostname based creation } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java index f07c710ba9..c70e5372ec 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java @@ -54,7 +54,7 @@ abstract class IkeTestBase { static final int SUB_ID = 1; static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); static final String NETWORK_NAME = "android.net"; - static final String EAP_MSCHAPV2_USERNAME = "username"; + static final String EAP_MSCHAPV2_USERNAME = "mschapv2user"; static final String EAP_MSCHAPV2_PASSWORD = "password"; static final Inet4Address IPV4_ADDRESS_LOCAL = diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index a9daf6adc3..c83d5f379d 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -60,22 +60,23 @@ public class IkeTunUtils extends TunUtils { } /** - * Await the expected IKE request and inject an IKE response. + * Await the expected IKE request inject an IKE response (or a list of response fragments) * - * @param ikeRespDataHex IKE response hex without IP/UDP headers or NON ESP MARKER. + * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without + * IP/UDP headers or NON ESP MARKER. */ public byte[] awaitReqAndInjectResp( long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, - String ikeRespDataHex) + String... ikeRespDataFragmentsHex) throws Exception { return awaitReqAndInjectResp( expectedInitIkeSpi, expectedMsgId, expectedUseEncap, 1 /* expectedReqPktCnt */, - ikeRespDataHex) + ikeRespDataFragmentsHex) .get(0); } @@ -83,15 +84,15 @@ public class IkeTunUtils extends TunUtils { * Await the expected IKE request (or the list of IKE request fragments) and inject an IKE * response (or a list of response fragments) * - * @param ikeRespDataHexes IKE response hex (or a list of response fragments) without IP/UDP - * headers or NON ESP MARKER. + * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without + * IP/UDP headers or NON ESP MARKER. */ public List awaitReqAndInjectResp( long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, int expectedReqPktCnt, - String... ikeRespDataHexes) + String... ikeRespDataFragmentsHex) throws Exception { List reqList = new ArrayList<>(expectedReqPktCnt); if (expectedReqPktCnt == 1) { @@ -136,7 +137,7 @@ public class IkeTunUtils extends TunUtils { int srcPort = getPort(request, false /* shouldGetSource */); int dstPort = getPort(request, true /* shouldGetSource */); - for (String hex : ikeRespDataHexes) { + for (String hex : ikeRespDataFragmentsHex) { byte[] response = buildIkePacket( srcAddr, From 188e220da77a03f24b717068027e05482bafcdab Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 28 May 2020 02:23:21 +0000 Subject: [PATCH 1148/1415] Test remotely initiated rekey This commit: - Adds test for remotely initiated rekey for IKE and Child SA - Makes IkeTunUtils support building and injecting requests - Adds method to parse hex to long because Long.parseLong cannot handle negative long value Bug: 155821007 Test: atest CtsIkeTestCases Change-Id: I299cf190261ac15397f9ed389adb2c69e94a6507 Merged-In: I299cf190261ac15397f9ed389adb2c69e94a6507 (cherry picked from commit a5bff5a7b46c31dfa4ae692328edfb2b2a6462c8) --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 2 +- .../ipsec/ike/cts/IkeSessionRekeyTest.java | 265 ++++++++++++++++++ .../net/ipsec/ike/cts/IkeSessionTestBase.java | 23 +- .../net/ipsec/ike/cts/IkeTunUtils.java | 70 ++++- 4 files changed, 342 insertions(+), 18 deletions(-) create mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index ef865afe9a..233e1c9ad5 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -220,5 +220,5 @@ public class IkeSessionPskTest extends IkeSessionTestBase { assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); } - // TODO(b/155821007): Verify rekey process and handling IKE_AUTH failure + // TODO(b/155821007): Verify handling IKE_AUTH failure } diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java new file mode 100644 index 0000000000..f954fcd031 --- /dev/null +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java @@ -0,0 +1,265 @@ +/* + * 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.ipsec.ike.cts; + +import static com.android.internal.util.HexDump.hexStringToByteArray; + +import android.net.InetAddresses; +import android.net.LinkAddress; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.cts.IkeTunUtils.PortPair; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Explicitly test transport mode Child SA so that devices without FEATURE_IPSEC_TUNNELS can be test + * covered. Tunnel mode Child SA setup has been tested in IkeSessionPskTest. Rekeying process is + * independent from Child SA mode. + */ +@RunWith(AndroidJUnit4.class) +public class IkeSessionRekeyTest extends IkeSessionTestBase { + // This value is align with the test vectors hex that are generated in an IPv4 environment + private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = + new IkeTrafficSelector( + MIN_PORT, + MAX_PORT, + InetAddresses.parseNumericAddress("172.58.35.40"), + InetAddresses.parseNumericAddress("172.58.35.40")); + + private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + IkeSessionParams ikeParams = + new IkeSessionParams.Builder(sContext) + .setNetwork(mTunNetwork) + .setServerHostname(remoteAddress.getHostAddress()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) + .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) + .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) + .setAuthPsk(IKE_PSK) + .build(); + return new IkeSession( + sContext, + ikeParams, + buildTransportModeChildParamsWithTs( + TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), + mUserCbExecutor, + mIkeSessionCallback, + mFirstChildSessionCallback); + } + + private byte[] buildInboundPkt(PortPair outPktSrcDestPortPair, String inboundDataHex) + throws Exception { + // Build inbound packet by flipping the outbound packet addresses and ports + return IkeTunUtils.buildIkePacket( + mRemoteAddress, + mLocalAddress, + outPktSrcDestPortPair.dstPort, + outPktSrcDestPortPair.srcPort, + true /* useEncap */, + hexStringToByteArray(inboundDataHex)); + } + + @Test + public void testRekeyIke() throws Exception { + final String ikeInitResp = + "46B8ECA1E0D72A1866B5248CF6C7472D21202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" + + "0200000500000008040000022800008800020000920D3E830E7276908209212D" + + "E5A7F2A48706CFEF1BE8CB6E3B173B8B4E0D8C2DC626271FF1B13A88619E569E" + + "7B03C3ED2C127390749CDC7CDC711D0A8611E4457FFCBC4F0981B3288FBF58EA" + + "3E8B70E27E76AE70117FBBCB753660ADDA37EB5EB3A81BED6A374CCB7E132C2A" + + "94BFCE402DC76B19C158B533F6B1F2ABF01ACCC329000024B302CA2FB85B6CF4" + + "02313381246E3C53828D787F6DFEA6BD62D6405254AEE6242900001C00004004" + + "7A1682B06B58596533D00324886EF1F20EF276032900001C00004005BF633E31" + + "F9984B29A62E370BB2770FC09BAEA665290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + final String ikeAuthResp = + "46B8ECA1E0D72A1866B5248CF6C7472D2E20232000000001000000F0240000D4" + + "10166CA8647F56123DE74C17FA5E256043ABF73216C812EE32EE1BB01EAF4A82" + + "DC107AB3ADBFEE0DEA5EEE10BDD5D43178F4C975C7C775D252273BB037283C7F" + + "236FE34A6BCE4833816897075DB2055B9FFD66DFA45A0A89A8F70AFB59431EED" + + "A20602FB614369D12906D3355CF7298A5D25364ABBCC75A9D88E0E6581449FCD" + + "4E361A39E00EFD1FD0A69651F63DB46C12470226AA21BA5EFF48FAF0B6DDF61C" + + "B0A69392CE559495EEDB4D1C1D80688434D225D57210A424C213F7C993D8A456" + + "38153FBD194C5E247B592D1D048DB4C8"; + final String rekeyIkeCreateReq = + "46B8ECA1E0D72A1866B5248CF6C7472D2E202400000000000000013021000114" + + "13743670039E308A8409BA5FD47B67F956B36FEE88AC3B70BB5D789B8218A135" + + "1B3D83E260E87B3EDB1BF064F09D4DC2611AEDBC99951B4B2DE767BD4AA2ACC3" + + "3653549CFC66B75869DF003CDC9A137A9CC27776AD5732B34203E74BE8CA4858" + + "1D5C0D9C9CA52D680EB299B4B21C7FA25FFEE174D57015E0FF2EAED653AAD95C" + + "071ABE269A8C2C9FBC1188E07550EB992F910D4CA9689E44BA66DE0FABB2BDF9" + + "8DD377186DBB25EF9B68B027BB2A27981779D8303D88D7CE860010A42862D50B" + + "1E0DBFD3D27C36F14809D7F493B2B96A65534CF98B0C32AD5219AD77F681AC04" + + "9D5CB89A0230A91A243FA7F16251B0D9B4B65E7330BEEAC9663EF4578991EAC8" + + "46C19EBB726E7D113F1D0D601102C05E"; + final String rekeyIkeDeleteReq = + "46B8ECA1E0D72A1866B5248CF6C7472D2E20250000000001000000502A000034" + + "02E40C0C7B1ED977729F705BB9B643FAC513A1070A6EB28ECD2AEA8A441ADC05" + + "7841382A7967BBF116AE52496590B2AD"; + final String deleteIkeReq = + "7D3DEDC65407D1FC9361C8CF8C47162A2E20250800000000000000502A000034" + + "201915C9E4E9173AA9EE79F3E02FE2D4954B22085C66D164762C34D347C16E9F" + + "FC5F7F114428C54D8D915860C57B1BC1"; + final long newIkeDeterministicInitSpi = Long.parseLong("7D3DEDC65407D1FC", 16); + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp); + + // Local request message ID starts from 2 because there is one IKE_INIT message and a single + // IKE_AUTH message. + int expectedReqMsgId = 2; + int expectedRespMsgId = 0; + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TRANSPORT_MODE_INBOUND_TS), + Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), + new ArrayList()); + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); + + // Inject rekey IKE requests + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeCreateReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeDeleteReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + + // IKE has been rekeyed, reset message IDs + expectedReqMsgId = 0; + expectedRespMsgId = 0; + + // Inject delete IKE request + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq)); + mTunUtils.awaitResp( + newIkeDeterministicInitSpi, expectedRespMsgId++, true /* expectedUseEncap */); + + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } + + @Test + public void testRekeyTransportModeChildSa() throws Exception { + final String ikeInitResp = + "46B8ECA1E0D72A18CECD871146CF83A121202220000000000000015022000030" + + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" + + "0200000500000008040000022800008800020000C4904458957746BCF1C12972" + + "1D4E19EB8A584F78DE673053396D167CE0F34552DBC69BA63FE7C673B4CF4A99" + + "62481518EE985357876E8C47BAAA0DBE9C40AE47B12E52165874703586E8F786" + + "045F72EEEB238C5D1823352BED44B71B3214609276ADC0B3D42DAC820168C4E2" + + "660730DAAC92492403288805EBB9053F1AB060DA290000242D9364ACB93519FF" + + "8F8B019BAA43A40D699F59714B327B8382216EF427ED52282900001C00004004" + + "06D91438A0D6B734E152F76F5CC55A72A2E38A0A2900001C000040052EFF78B3" + + "55B37F3CE75AFF26C721B050F892C0D6290000080000402E290000100000402F" + + "00020003000400050000000800004014"; + final String ikeAuthResp = + "46B8ECA1E0D72A18CECD871146CF83A12E20232000000001000000F0240000D4" + + "A17BC258BA2714CF536663639DD5F665A60C75E93557CD5141990A8CEEDD2017" + + "93F5B181C8569FBCD6C2A00198EC2B62D42BEFAC016B8B6BF6A7BC9CEDE3413A" + + "6C495A6B8EC941864DC3E08F57D015EA6520C4B05884960B85478FCA53DA5F17" + + "9628BB1097DA77461C71837207A9EB80720B3E6E661816EE4E14AC995B5E8441" + + "A4C3F9097CC148142BA300076C94A23EC4ADE82B1DD2B121F7E9102860A8C3BF" + + "58DDC207285A3176E924C44DE820322524E1AA438EFDFBA781B36084AED80846" + + "3B77FCED9682B6E4E476408EF3F1037E"; + final String rekeyChildCreateReq = + "46B8ECA1E0D72A18CECD871146CF83A12E202400000000000000015029000134" + + "319D74B6B155B86942143CEC1D29D21F073F24B7BEDC9BFE0F0FDD8BDB5458C0" + + "8DB93506E1A43DD0640FE7370C97F9B34FF4EC9B2DB7257A87B75632301FB68A" + + "86B54871249534CA3D01C9BEB127B669F46470E1C8AAF72574C3CEEC15B901CF" + + "5A0D6ADAE59C3CA64AC8C86689C860FAF9500E608DFE63F2DCD30510FD6FFCD5" + + "A50838574132FD1D069BCACD4C7BAF45C9B1A7689FAD132E3F56DBCFAF905A8C" + + "4145D4BA1B74A54762F8F43308D94DE05649C49D885121CE30681D51AC1E3E68" + + "AB82F9A19B99579AFE257F32DBD1037814DA577379E4F42DEDAC84502E49C933" + + "9EA83F6F5DB4401B660CB1681B023B8603D205DFDD1DE86AD8DE22B6B754F30D" + + "05EAE81A709C2CEE81386133DC3DC7B5EF8F166E48E54A0722DD0C64F4D00638" + + "40F272144C47F6ECED72A248180645DB"; + final String rekeyChildDeleteReq = + "46B8ECA1E0D72A18CECD871146CF83A12E20250000000001000000502A000034" + + "02D98DAF0432EBD991CA4F2D89C1E0EFABC6E91A3327A85D8914FB2F1485BE1B" + + "8D3415D548F7CE0DC4224E7E9D0D3355"; + final String deleteIkeReq = + "46B8ECA1E0D72A18CECD871146CF83A12E20250000000002000000502A000034" + + "095041F4026B4634F04B0AB4F9349484F7BE9AEF03E3733EEE293330043B75D2" + + "ABF5F965ED51127629585E1B1BBA787F"; + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp); + + // IKE INIT and IKE AUTH takes two exchanges. Local request message ID starts from 2 + int expectedReqMsgId = 2; + int expectedRespMsgId = 0; + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TRANSPORT_MODE_INBOUND_TS), + Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), + new ArrayList()); + IpSecTransformCallRecord oldTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord oldTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(oldTransformRecordA, oldTransformRecordB); + + // Inject rekey Child requests + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildCreateReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildDeleteReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + + // Verify IpSecTransforms are renewed + IpSecTransformCallRecord newTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord newTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(newTransformRecordA, newTransformRecordB); + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, oldTransformRecordA, oldTransformRecordB); + + // Inject delete IKE request + mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq)); + mTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); + + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, newTransformRecordA, newTransformRecordB); + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } +} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 86e5c48ebe..0f39fbd1cb 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -44,6 +44,7 @@ import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeTrafficSelector; import android.net.ipsec.ike.TransportModeChildSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.net.ipsec.ike.cts.IkeTunUtils.PortPair; import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -269,13 +270,13 @@ abstract class IkeSessionTestBase extends IkeTestBase { .build(); } - void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) + PortPair performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) throws Exception { - performSetupIkeAndFirstChildBlocking( + return performSetupIkeAndFirstChildBlocking( ikeInitRespHex, 1 /* expectedAuthReqPktCnt */, ikeAuthRespHexes); } - void performSetupIkeAndFirstChildBlocking( + PortPair performSetupIkeAndFirstChildBlocking( String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespHexes) throws Exception { mTunUtils.awaitReqAndInjectResp( @@ -284,12 +285,16 @@ abstract class IkeSessionTestBase extends IkeTestBase { false /* expectedUseEncap */, ikeInitRespHex); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 1 /* expectedMsgId */, - true /* expectedUseEncap */, - expectedAuthReqPktCnt, - ikeAuthRespHexes); + byte[] ikeAuthReqPkt = + mTunUtils + .awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 1 /* expectedMsgId */, + true /* expectedUseEncap */, + expectedAuthReqPktCnt, + ikeAuthRespHexes) + .get(0); + return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt); } void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index c83d5f379d..41cbf0baa1 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -55,6 +55,8 @@ public class IkeTunUtils extends TunUtils { private static final int IKE_FRAG_NUM_OFFSET = 32; private static final int IKE_PAYLOAD_TYPE_SKF = 53; + private static final int RSP_FLAG_MASK = 0x20; + public IkeTunUtils(ParcelFileDescriptor tunFd) { super(tunFd); } @@ -136,8 +138,7 @@ public class IkeTunUtils extends TunUtils { InetAddress dstAddr = getAddress(request, true /* shouldGetSource */); int srcPort = getPort(request, false /* shouldGetSource */); int dstPort = getPort(request, true /* shouldGetSource */); - - for (String hex : ikeRespDataFragmentsHex) { + for (String resp : ikeRespDataFragmentsHex) { byte[] response = buildIkePacket( srcAddr, @@ -145,13 +146,27 @@ public class IkeTunUtils extends TunUtils { srcPort, dstPort, expectedUseEncap, - hexStringToByteArray(hex)); + hexStringToByteArray(resp)); injectPacket(response); } return reqList; } + /** Await the expected IKE response */ + public byte[] awaitResp(long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap) + throws Exception { + return awaitIkePacket( + (pkt) -> { + return isExpectedIkePkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + true /* expectedResp*/, + expectedUseEncap); + }); + } + private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; int startIndex = 0; @@ -239,13 +254,36 @@ public class IkeTunUtils extends TunUtils { ByteBuffer buffer = ByteBuffer.wrap(pkt); buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER) + buffer.mark(); // Mark this position so that later we can reset back here - // Check message ID. + // Check SPI + buffer.get(new byte[IKE_INIT_SPI_OFFSET]); + long initSpi = buffer.getLong(); + if (expectedInitIkeSpi != initSpi) { + return false; + } + + // Check direction + buffer.reset(); + buffer.get(new byte[IKE_IS_RESP_BYTE_OFFSET]); + byte flagsByte = buffer.get(); + boolean isResp = ((flagsByte & RSP_FLAG_MASK) != 0); + if (expectedResp != isResp) { + return false; + } + + // Check message ID + buffer.reset(); buffer.get(new byte[IKE_MSG_ID_OFFSET]); - int msgId = buffer.getInt(); - return expectedMsgId == msgId; - // TODO: Check SPI and packet direction + // Both the expected message ID and the packet's msgId are signed integers, so directly + // compare them. + int msgId = buffer.getInt(); + if (expectedMsgId != msgId) { + return false; + } + + return true; } private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) { @@ -267,6 +305,22 @@ public class IkeTunUtils extends TunUtils { return expectedFragNum == fragNum; } + public static class PortPair { + public final int srcPort; + public final int dstPort; + + public PortPair(int sourcePort, int destinationPort) { + srcPort = sourcePort; + dstPort = destinationPort; + } + } + + public static PortPair getSrcDestPortPair(byte[] outboundIkePkt) throws Exception { + return new PortPair( + getPort(outboundIkePkt, true /* shouldGetSource */), + getPort(outboundIkePkt, false /* shouldGetSource */)); + } + private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; @@ -288,7 +342,7 @@ public class IkeTunUtils extends TunUtils { return Short.toUnsignedInt(buffer.getShort()); } - private static byte[] buildIkePacket( + public static byte[] buildIkePacket( InetAddress srcAddr, InetAddress dstAddr, int srcPort, From a2b2ab5473542c7295ffba13bf47524c72f739bb Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 28 May 2020 05:30:58 +0000 Subject: [PATCH 1149/1415] Test handling authentication failure - Test receiving Authentication Failure notification - Test setting up IKE Session with first Child setup failure Bug: 155821007 Test: CtsIkeTestCases Change-Id: I4ec43a3899d67a119cd4ba19e0ffc63c277325fb Merged-In: I4ec43a3899d67a119cd4ba19e0ffc63c277325fb (cherry picked from commit b765ebe3f26e61093dbe9ac0df1845afc5d42d3d) --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 82 +++++++++++++++++-- 1 file changed, 74 insertions(+), 8 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 233e1c9ad5..253e09dd39 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -17,18 +17,17 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import android.net.LinkAddress; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.platform.test.annotations.AppModeFull; @@ -212,13 +211,80 @@ public class IkeSessionPskTest extends IkeSessionTestBase { mFirstChildSessionCallback.awaitOnClosed(); - IkeException exception = mIkeSessionCallback.awaitOnClosedException(); - assertNotNull(exception); - assertTrue(exception instanceof IkeProtocolException); - IkeProtocolException protocolException = (IkeProtocolException) exception; + IkeProtocolException protocolException = + (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException(); assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, protocolException.getErrorType()); assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); } - // TODO(b/155821007): Verify handling IKE_AUTH failure + @Test + public void testIkeAuthHandlesAuthFailNotification() throws Exception { + final String ikeInitRespHex = + "46B8ECA1E0D72A18CF94CE3159486F002120222000000000000001502200" + + "00300000002C010100040300000C0100000C800E01000300000803000005" + + "0300000802000004000000080400000228000088000200001821AA854691" + + "FA3292DF710F0AC149ACBD0CB421608B8796C1912AF04C5B4B23936FDEC4" + + "7CB640E3EAFB56BBB562825E87AF68B40E4BAB80A49BAD44407450A4195A" + + "1DD54BD99F48D28C9F0FBA315A3401C1C3C4AD55911F514A8DF2D2467C46" + + "A73DDC1452AE81336E0F0D5EC896D2E7A77628AF2F9089F48943399DF216" + + "EFCD2900002418D2B7E4E6AF0FEFF5962CF8D68F7793B1293FEDE13331D4" + + "AB0CE9436C2EE1EC2900001C0000400457BD9AEF5B362A83DD7F3DDAA4A9" + + "9B6B4041DAF32900001C000040055A81893582701E44D4B6729A22FE06DE" + + "82A03A36290000080000402E290000100000402F00020003000400050000" + + "000800004014"; + final String ikeAuthFailRespHex = + "46B8ECA1E0D72A18CF94CE3159486F002E202320000000010000004C2900" + + "00301B9E4C8242D3BE62E7F0A537FE8B92C6EAB7153105DA421DCE43A06D" + + "AB6E4808BAC0CA1DAD6ADD0A126A41BD"; + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthFailRespHex); + + mFirstChildSessionCallback.awaitOnClosed(); + IkeProtocolException protocolException = + (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException(); + assertEquals(ERROR_TYPE_AUTHENTICATION_FAILED, protocolException.getErrorType()); + assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); + } + + @Test + public void testIkeAuthHandlesFirstChildCreationFail() throws Exception { + final String ikeInitRespHex = + "46B8ECA1E0D72A182B300285DA19E6452120222000000000000001502200" + + "00300000002C010100040300000C0100000C800E01000300000803000005" + + "0300000802000004000000080400000228000088000200005C9DE629981F" + + "DB1FC45DB6CCF15D076C1F51BD9F63C771DC089F05CCDE6247965D15C616" + + "C7B5A62342491715E4D1FEA19326477D24143E8E56AB6AD93F54B19BC32A" + + "44BC0A5B5632E57D0A3C43E466E1547D8E4EF65EA4B864A348161666E229" + + "84975A486251A17C4F096A6D5CF3DB83874B70324A31AA7ADDE2D73BADD8" + + "238029000024CF06260F7C4923295E7C91F2B8479212892DA7A519A0322F" + + "F5B2BF570B92972B2900001C00004004C7ACC2C7D58CF8C9F5E953993AF4" + + "6CAC976635B42900001C00004005B64B190DFE7BDE8B9B1475EDE67B63D6" + + "F1DBBF44290000080000402E290000100000402F00020003000400050000" + + "000800004014"; + final String ikeAuthCreateChildFailHex = + "46B8ECA1E0D72A182B300285DA19E6452E202320000000010000008C2400" + + "0070386FC9CCC67495A17915D0544390A2963A769F4A42C6FA668CEEC07F" + + "EC0C87D681DE34267023DD394F1401B5A563E71002C0CE0928D0ABC0C4570" + + "E39C2EDEF820F870AB71BD70A3F3EB5C96CA294B6D3F01677690DCF9F8CFC" + + "9584650957573502BA83E32F18207A9ADEB1FA"; + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthCreateChildFailHex); + + // Even though the child creation failed, the authentication succeeded, so the IKE Session's + // onOpened() callback is still expected + verifyIkeSessionSetupBlocking(); + + // Verify Child Creation failed + IkeProtocolException protocolException = + (IkeProtocolException) mFirstChildSessionCallback.awaitOnClosedException(); + assertEquals(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE, protocolException.getErrorType()); + assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); + + ikeSession.kill(); + mIkeSessionCallback.awaitOnClosed(); + } } From ff0471554e8dd08f68a4bf6854739b945133dd78 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 28 May 2020 18:29:06 +0000 Subject: [PATCH 1150/1415] Test IKE Session setup in IPv6 network Bug: 148689509 Test: atest testIkeSessionSetupAndChildSessionSetupWithTunnelModeV6 Change-Id: Ia2fa9462c66a283697e0cb9dd4c475215c0eafde Merged-In: Ia2fa9462c66a283697e0cb9dd4c475215c0eafde (cherry picked from commit 71a855de7dcdc3bdbdb75c78be0f57f3055b0c72) --- .../cts/IkeSessionDigitalSignatureTest.java | 3 +- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 71 +++++++++++++++++++ .../net/ipsec/ike/cts/IkeSessionTestBase.java | 66 ++++++++++++++--- 3 files changed, 130 insertions(+), 10 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java index ebf8a41f00..9be1dc72cf 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java @@ -123,7 +123,7 @@ public class IkeSessionDigitalSignatureTest extends IkeSessionTestBase { InetAddresses.parseNumericAddress("172.58.35.103"), InetAddresses.parseNumericAddress("172.58.35.103")); - // TODO(b/157510502): Add test for IKE Session setup in IPv6 network + // TODO(b/157510502): Add test for IKE Session setup with transport mode Child in IPv6 network private static final String LOCAL_ID_ASN1_DN = "CN=client.test.ike.android.net, O=Android, C=US"; @@ -184,6 +184,7 @@ public class IkeSessionDigitalSignatureTest extends IkeSessionTestBase { performSetupIkeAndFirstChildBlocking( IKE_INIT_RESP, EXPECTED_AUTH_REQ_FRAG_COUNT /* expectedReqPktCnt */, + true /* expectedAuthUseEncap */, IKE_AUTH_RESP_FRAG_1, IKE_AUTH_RESP_FRAG_2); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 253e09dd39..0509fc0c92 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -182,6 +182,77 @@ public class IkeSessionPskTest extends IkeSessionTestBase { verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); } + @Test + public void testIkeSessionSetupAndChildSessionSetupWithTunnelModeV6() throws Exception { + if (!hasTunnelsFeature()) return; + + final String ikeInitResp = + "46B8ECA1E0D72A186F7B6C2CEB77EB9021202220000000000000011822000030" + + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" + + "0200000500000008040000022800008800020000DABAA04B38B491E2403F2125" + + "96ECF1C8EF7B1DC19A422FDD46E1756C826BB3A16404361B775D9950577B5CDF" + + "6AAA1642BD1427BDA8BC55354A97C1025E19C1E2EE2DF8A0C9406E545D829F52" + + "75695008E3B742984B8DD1770F3514213B0DF3EE8B199416DF200D248115C057" + + "1C193E4F96802E5EF48DD99CAC251882A8F7CCC329000024BC6F0F1D3653C2C7" + + "679E02CDB6A3B32B2FEE9AF52F0326D4D9AE073D56CE8922290000080000402E" + + "290000100000402F00020003000400050000000800004014"; + final String ikeAuthResp = + "46B8ECA1E0D72A186F7B6C2CEB77EB902E202320000000010000015024000134" + + "4D115AFDCDAD0310760BB664EB7D405A340869AD6EDF0AAEAD0663A9253DADCB" + + "73EBE5CD29D4FA1CDEADE0B94391B5C4CF77BCC1596ACE3CE6A7891E44888FA5" + + "46632C0EF4E6193C023C9DC59142C37D1C49D6EF5CD324EC6FC35C89E1721C78" + + "91FDCDB723D8062709950F4AA9273D26A54C9C7E86862DBC15F7B6641D2B9BAD" + + "E55069008201D12968D97B537B1518FE87B0FFA03C3EE6012C06721B1E2A3F68" + + "92108BC4A4F7063F7F94562D8B60F291A1377A836CF12BCDA7E15C1A8F3C77BB" + + "6DB7F2C833CCE4CDDED7506536621A3356CE2BC1874E7B1A1A9B447D7DF6AB09" + + "638B8AD94A781B28BB91B514B611B24DF8E8A047A10AE27BBF15C754D3D2F792" + + "D3E1CCADDAE934C98AE53A8FC3419C88AFF0355564F82A629C998012DA7BB704" + + "5307270DF326377E3E1994476902035B"; + final String deleteIkeResp = + "46B8ECA1E0D72A186F7B6C2CEB77EB902E202520000000020000005000000034" + + "CF15C299F35688E5140A48B61C95F004121BF8236201415E5CD45BA41AAB16D4" + + "90B44B9E6D5D92B5B97D24196A58C73F"; + + mLocalAddress = IPV6_ADDRESS_LOCAL; + mRemoteAddress = IPV6_ADDRESS_REMOTE; + + // Teardown current test network that uses IPv4 address and set up new network with IPv6 + // address. + tearDownTestNetwork(); + setUpTestNetwork(mLocalAddress); + + // Open IKE Session + IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + performSetupIkeAndFirstChildBlocking( + ikeInitResp, + 1 /* expectedAuthReqPktCnt */, + false /* expectedAuthUseEncap */, + ikeAuthResp); + + // Local request message ID starts from 2 because there is one IKE_INIT message and a single + // IKE_AUTH message. + int expectedMsgId = 2; + + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TUNNEL_MODE_INBOUND_TS_V6), + Arrays.asList(TUNNEL_MODE_OUTBOUND_TS_V6), + Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR_V6), + Arrays.asList(EXPECTED_DNS_SERVERS_ONE, EXPECTED_DNS_SERVERS_TWO)); + + IpSecTransformCallRecord firstTransformRecordA = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + IpSecTransformCallRecord firstTransformRecordB = + mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); + verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); + + // Close IKE Session + ikeSession.close(); + performCloseIkeBlocking(expectedMsgId++, false /* expectedUseEncap */, deleteIkeResp); + verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); + } + @Test public void testIkeSessionKillWithTunnelMode() throws Exception { if (!hasTunnelsFeature()) return; diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 0f39fbd1cb..2458b25e33 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -66,6 +66,7 @@ import org.junit.runner.RunWith; import java.net.Inet4Address; import java.net.InetAddress; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -94,15 +95,29 @@ abstract class IkeSessionTestBase extends IkeTestBase { // Package-wide common expected results that will be shared by all IKE/Child SA creation tests static final String EXPECTED_REMOTE_APP_VERSION_EMPTY = ""; static final byte[] EXPECTED_PROTOCOL_ERROR_DATA_NONE = new byte[0]; + + static final InetAddress EXPECTED_DNS_SERVERS_ONE = + InetAddresses.parseNumericAddress("8.8.8.8"); + static final InetAddress EXPECTED_DNS_SERVERS_TWO = + InetAddresses.parseNumericAddress("8.8.4.4"); + static final InetAddress EXPECTED_INTERNAL_ADDR = InetAddresses.parseNumericAddress("198.51.100.10"); static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR = new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN); + static final InetAddress EXPECTED_INTERNAL_ADDR_V6 = + InetAddresses.parseNumericAddress("2001:db8::2"); + static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR_V6 = + new LinkAddress(EXPECTED_INTERNAL_ADDR_V6, IP6_PREFIX_LEN); static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS = new IkeTrafficSelector( MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS; + static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS_V6 = + new IkeTrafficSelector( + MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR_V6, EXPECTED_INTERNAL_ADDR_V6); + static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS_V6 = DEFAULT_V6_TS; // This value is align with the test vectors hex that are generated in an IPv4 environment static final IkeTrafficSelector TRANSPORT_MODE_OUTBOUND_TS = @@ -179,7 +194,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { } void setUpTestNetwork(InetAddress localAddr) throws Exception { - int prefixLen = localAddr instanceof Inet4Address ? IP4_PREFIX_LEN : IP4_PREFIX_LEN; + int prefixLen = localAddr instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN; TestNetworkInterface testIface = sTNM.createTunInterface(new LinkAddress[] {new LinkAddress(localAddr, prefixLen)}); @@ -273,11 +288,27 @@ abstract class IkeSessionTestBase extends IkeTestBase { PortPair performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) throws Exception { return performSetupIkeAndFirstChildBlocking( - ikeInitRespHex, 1 /* expectedAuthReqPktCnt */, ikeAuthRespHexes); + ikeInitRespHex, + 1 /* expectedAuthReqPktCnt */, + true /*expectedAuthUseEncap*/, + ikeAuthRespHexes); } PortPair performSetupIkeAndFirstChildBlocking( - String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespHexes) + String ikeInitRespHex, boolean expectedAuthUseEncap, String... ikeAuthRespHexes) + throws Exception { + return performSetupIkeAndFirstChildBlocking( + ikeInitRespHex, + 1 /* expectedAuthReqPktCnt */, + expectedAuthUseEncap, + ikeAuthRespHexes); + } + + PortPair performSetupIkeAndFirstChildBlocking( + String ikeInitRespHex, + int expectedAuthReqPktCnt, + boolean expectedAuthUseEncap, + String... ikeAuthRespHexes) throws Exception { mTunUtils.awaitReqAndInjectResp( IKE_DETERMINISTIC_INITIATOR_SPI, @@ -290,7 +321,7 @@ abstract class IkeSessionTestBase extends IkeTestBase { .awaitReqAndInjectResp( IKE_DETERMINISTIC_INITIATOR_SPI, 1 /* expectedMsgId */, - true /* expectedUseEncap */, + expectedAuthUseEncap, expectedAuthReqPktCnt, ikeAuthRespHexes) .get(0); @@ -298,11 +329,13 @@ abstract class IkeSessionTestBase extends IkeTestBase { } void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { + performCloseIkeBlocking(expectedMsgId, true /* expectedUseEncap*/, deleteIkeRespHex); + } + + void performCloseIkeBlocking( + int expectedMsgId, boolean expectedUseEncap, String deleteIkeRespHex) throws Exception { mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId, - true /* expectedUseEncap */, - deleteIkeRespHex); + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId, expectedUseEncap, deleteIkeRespHex); } /** Testing callback that allows caller to block current thread until a method get called */ @@ -480,13 +513,28 @@ abstract class IkeSessionTestBase extends IkeTestBase { List expectedOutboundTs, List expectedInternalAddresses) throws Exception { + verifyChildSessionSetupBlocking( + childCallback, + expectedInboundTs, + expectedOutboundTs, + expectedInternalAddresses, + new ArrayList() /* expectedDnsServers */); + } + + void verifyChildSessionSetupBlocking( + TestChildSessionCallback childCallback, + List expectedInboundTs, + List expectedOutboundTs, + List expectedInternalAddresses, + List expectedDnsServers) + throws Exception { ChildSessionConfiguration childConfig = childCallback.awaitChildConfig(); assertNotNull(childConfig); assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors()); assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors()); assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses()); + assertEquals(expectedDnsServers, childConfig.getInternalDnsServers()); assertTrue(childConfig.getInternalSubnets().isEmpty()); - assertTrue(childConfig.getInternalDnsServers().isEmpty()); assertTrue(childConfig.getInternalDhcpServers().isEmpty()); } From e777f4076ed6a618045c77f0f6c44164cf9151f1 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 4 May 2020 16:13:54 -0700 Subject: [PATCH 1151/1415] Add Ikev2VpnTests including IKE negotiation. This commit expands IKEv2 VPN CTS testing to ensure that given a successful IKEv2 negotiation, the VPN network will be correctly set up. Additionally, it verifies that the stopProvisionedVpnProfile will teardown the VPN network. Bug: 148582947 Test: atest CtsNetTestCases:Ikev2VpnTest Change-Id: Ib6635f0068200ac0172515989fbdee5c3d49e231 --- .../net/src/android/net/cts/IkeTunUtils.java | 188 ++++++++++++++++++ .../net/src/android/net/cts/Ikev2VpnTest.java | 147 ++++++++++++-- .../cts/net/src/android/net/cts/TunUtils.java | 97 +++++---- 3 files changed, 366 insertions(+), 66 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/IkeTunUtils.java diff --git a/tests/cts/net/src/android/net/cts/IkeTunUtils.java b/tests/cts/net/src/android/net/cts/IkeTunUtils.java new file mode 100644 index 0000000000..fc25292b27 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IkeTunUtils.java @@ -0,0 +1,188 @@ +/* + * 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.net.cts.PacketUtils.BytePayload; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.IpHeader; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.net.cts.PacketUtils.UdpHeader; +import static android.net.cts.PacketUtils.getIpHeader; +import static android.system.OsConstants.IPPROTO_UDP; + +import android.os.ParcelFileDescriptor; + +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.Arrays; + +// TODO: Merge this with the version in the IPsec module (IKEv2 library) CTS tests. +/** An extension of the TunUtils class with IKE-specific packet handling. */ +public class IkeTunUtils extends TunUtils { + private static final int PORT_LEN = 2; + + private static final byte[] NON_ESP_MARKER = new byte[] {0, 0, 0, 0}; + + private static final int IKE_HEADER_LEN = 28; + private static final int IKE_SPI_LEN = 8; + private static final int IKE_IS_RESP_BYTE_OFFSET = 19; + private static final int IKE_MSG_ID_OFFSET = 20; + private static final int IKE_MSG_ID_LEN = 4; + + public IkeTunUtils(ParcelFileDescriptor tunFd) { + super(tunFd); + } + + /** + * Await an expected IKE request and inject an IKE response. + * + * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER. + */ + public byte[] awaitReqAndInjectResp(long expectedInitIkeSpi, int expectedMsgId, + boolean encapExpected, byte[] respIkePkt) throws Exception { + final byte[] request = awaitIkePacket(expectedInitIkeSpi, expectedMsgId, encapExpected); + + // Build response header by flipping address and port + final InetAddress srcAddr = getDstAddress(request); + final InetAddress dstAddr = getSrcAddress(request); + final int srcPort = getDstPort(request); + final int dstPort = getSrcPort(request); + + final byte[] response = + buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, encapExpected, respIkePkt); + injectPacket(response); + return request; + } + + private byte[] awaitIkePacket(long expectedInitIkeSpi, int expectedMsgId, boolean expectEncap) + throws Exception { + return super.awaitPacket(pkt -> isIke(pkt, expectedInitIkeSpi, expectedMsgId, expectEncap)); + } + + private static boolean isIke( + byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, boolean encapExpected) { + final int ipProtocolOffset; + final int ikeOffset; + + if (isIpv6(pkt)) { + ipProtocolOffset = IP6_PROTO_OFFSET; + ikeOffset = IP6_HDRLEN + UDP_HDRLEN; + } else { + if (encapExpected && !hasNonEspMarkerv4(pkt)) { + return false; + } + + // Use default IPv4 header length (assuming no options) + final int encapMarkerLen = encapExpected ? NON_ESP_MARKER.length : 0; + ipProtocolOffset = IP4_PROTO_OFFSET; + ikeOffset = IP4_HDRLEN + UDP_HDRLEN + encapMarkerLen; + } + + return pkt[ipProtocolOffset] == IPPROTO_UDP + && areSpiAndMsgIdEqual(pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId); + } + + /** Checks if the provided IPv4 packet has a UDP-encapsulation NON-ESP marker */ + private static boolean hasNonEspMarkerv4(byte[] ipv4Pkt) { + final int nonEspMarkerOffset = IP4_HDRLEN + UDP_HDRLEN; + if (ipv4Pkt.length < nonEspMarkerOffset + NON_ESP_MARKER.length) { + return false; + } + + final byte[] nonEspMarker = Arrays.copyOfRange( + ipv4Pkt, nonEspMarkerOffset, nonEspMarkerOffset + NON_ESP_MARKER.length); + return Arrays.equals(NON_ESP_MARKER, nonEspMarker); + } + + private static boolean areSpiAndMsgIdEqual( + byte[] pkt, int ikeOffset, long expectedIkeInitSpi, int expectedMsgId) { + if (pkt.length <= ikeOffset + IKE_HEADER_LEN) { + return false; + } + + final ByteBuffer buffer = ByteBuffer.wrap(pkt); + final long spi = buffer.getLong(ikeOffset); + final int msgId = buffer.getInt(ikeOffset + IKE_MSG_ID_OFFSET); + + return expectedIkeInitSpi == spi && expectedMsgId == msgId; + } + + private static InetAddress getSrcAddress(byte[] pkt) throws Exception { + return getAddress(pkt, true); + } + + private static InetAddress getDstAddress(byte[] pkt) throws Exception { + return getAddress(pkt, false); + } + + private static InetAddress getAddress(byte[] pkt, boolean getSrcAddr) throws Exception { + final int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; + final int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; + final int ipOffset = getSrcAddr ? srcIpOffset : srcIpOffset + ipLen; + + if (pkt.length < ipOffset + ipLen) { + // Should be impossible; getAddress() is only called with a full IKE request including + // the IP and UDP headers. + throw new IllegalArgumentException("Packet was too short to contain IP address"); + } + + return InetAddress.getByAddress(Arrays.copyOfRange(pkt, ipOffset, ipOffset + ipLen)); + } + + private static int getSrcPort(byte[] pkt) throws Exception { + return getPort(pkt, true); + } + + private static int getDstPort(byte[] pkt) throws Exception { + return getPort(pkt, false); + } + + private static int getPort(byte[] pkt, boolean getSrcPort) { + final int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; + final int portOffset = getSrcPort ? srcPortOffset : srcPortOffset + PORT_LEN; + + if (pkt.length < portOffset + PORT_LEN) { + // Should be impossible; getPort() is only called with a full IKE request including the + // IP and UDP headers. + throw new IllegalArgumentException("Packet was too short to contain port"); + } + + final ByteBuffer buffer = ByteBuffer.wrap(pkt); + return Short.toUnsignedInt(buffer.getShort(portOffset)); + } + + private static byte[] buildIkePacket( + InetAddress srcAddr, + InetAddress dstAddr, + int srcPort, + int dstPort, + boolean useEncap, + byte[] payload) + throws Exception { + // Append non-ESP marker if encap is enabled + if (useEncap) { + final ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER.length + payload.length); + buffer.put(NON_ESP_MARKER); + buffer.put(payload); + payload = buffer.array(); + } + + final UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(payload)); + final IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt); + return ipPkt.getPacketBytes(); + } +} diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index 8c1cbbb6d9..ebce5135cf 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -16,11 +16,15 @@ package android.net.cts; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; + import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -34,7 +38,12 @@ import android.content.Intent; import android.net.ConnectivityManager; import android.net.Ikev2VpnProfile; import android.net.IpSecAlgorithm; +import android.net.LinkAddress; +import android.net.Network; +import android.net.NetworkRequest; import android.net.ProxyInfo; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; import android.net.VpnManager; import android.net.cts.util.CtsNetUtils; import android.platform.test.annotations.AppModeFull; @@ -42,12 +51,14 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.HexDump; import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; import org.junit.Test; import org.junit.runner.RunWith; import java.math.BigInteger; +import java.net.InetAddress; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; @@ -64,6 +75,45 @@ import javax.security.auth.x500.X500Principal; public class Ikev2VpnTest { private static final String TAG = Ikev2VpnTest.class.getSimpleName(); + // Test vectors for IKE negotiation in test mode. + private static final String SUCCESSFUL_IKE_INIT_RESP = + "46b8eca1e0d72a18b2b5d9006d47a0022120222000000000000002d0220000300000002c01010004030000" + + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800" + + "100000b8070f159fe5141d8754ca86f72ecc28d66f514927e96cbe9eec0adb42bf2c276a0ab7" + + "a97fa93555f4be9218c14e7f286bb28c6b4fb13825a420f2ffc165854f200bab37d69c8963d4" + + "0acb831d983163aa50622fd35c182efe882cf54d6106222abcfaa597255d302f1b95ab71c142" + + "c279ea5839a180070bff73f9d03fab815f0d5ee2adec7e409d1e35979f8bd92ffd8aab13d1a0" + + "0657d816643ae767e9ae84d2ccfa2bcce1a50572be8d3748ae4863c41ae90da16271e014270f" + + "77edd5cd2e3299f3ab27d7203f93d770bacf816041cdcecd0f9af249033979da4369cb242dd9" + + "6d172e60513ff3db02de63e50eb7d7f596ada55d7946cad0af0669d1f3e2804846ab3f2a930d" + + "df56f7f025f25c25ada694e6231abbb87ee8cfd072c8481dc0b0f6b083fdc3bd89b080e49feb" + + "0288eef6fdf8a26ee2fc564a11e7385215cf2deaf2a9965638fc279c908ccdf04094988d91a2" + + "464b4a8c0326533aff5119ed79ecbd9d99a218b44f506a5eb09351e67da86698b4c58718db25" + + "d55f426fb4c76471b27a41fbce00777bc233c7f6e842e39146f466826de94f564cad8b92bfbe" + + "87c99c4c7973ec5f1eea8795e7da82819753aa7c4fcfdab77066c56b939330c4b0d354c23f83" + + "ea82fa7a64c4b108f1188379ea0eb4918ee009d804100e6bf118771b9058d42141c847d5ec37" + + "6e5ec591c71fc9dac01063c2bd31f9c783b28bf1182900002430f3d5de3449462b31dd28bc27" + + "297b6ad169bccce4f66c5399c6e0be9120166f2900001c0000400428b8df2e66f69c8584a186" + + "c5eac66783551d49b72900001c000040054e7a622e802d5cbfb96d5f30a6e433994370173529" + + "0000080000402e290000100000402f00020003000400050000000800004014"; + private static final String SUCCESSFUL_IKE_AUTH_RESP = + "46b8eca1e0d72a18b2b5d9006d47a0022e20232000000001000000e0240000c420a2500a3da4c66fa6929e" + + "600f36349ba0e38de14f78a3ad0416cba8c058735712a3d3f9a0a6ed36de09b5e9e02697e7c4" + + "2d210ac86cfbd709503cfa51e2eab8cfdc6427d136313c072968f6506a546eb5927164200592" + + "6e36a16ee994e63f029432a67bc7d37ca619e1bd6e1678df14853067ecf816b48b81e8746069" + + "406363e5aa55f13cb2afda9dbebee94256c29d630b17dd7f1ee52351f92b6e1c3d8551c513f1" + + "d74ac52a80b2041397e109fe0aeb3c105b0d4be0ae343a943398764281"; + private static final long IKE_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); + + private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); + private static final InetAddress LOCAL_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::1"); + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 128; + + // TODO: Use IPv6 address when we can generate test vectors (GCE does not allow IPv6 yet). + private static final String TEST_SERVER_ADDR_V4 = "192.0.2.2"; private static final String TEST_SERVER_ADDR = "2001:db8::1"; private static final String TEST_IDENTITY = "client.cts.android.com"; private static final List TEST_ALLOWED_ALGORITHMS = @@ -73,7 +123,7 @@ public class Ikev2VpnTest { ProxyInfo.buildDirectProxy("proxy.cts.android.com", 1234); private static final int TEST_MTU = 1300; - private static final byte[] TEST_PSK = "ikev2".getBytes(); + private static final byte[] TEST_PSK = "ikeAndroidPsk".getBytes(); private static final String TEST_USER = "username"; private static final String TEST_PASSWORD = "pa55w0rd"; @@ -115,17 +165,22 @@ public class Ikev2VpnTest { } return builder.setBypassable(true) + .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS) .setProxy(TEST_PROXY_INFO) .setMaxMtu(TEST_MTU) .setMetered(false) - .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS) .build(); } private Ikev2VpnProfile buildIkev2VpnProfilePsk(boolean isRestrictedToTestNetworks) throws Exception { + return buildIkev2VpnProfilePsk(TEST_SERVER_ADDR, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfilePsk( + String remote, boolean isRestrictedToTestNetworks) throws Exception { final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY).setAuthPsk(TEST_PSK); + new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY).setAuthPsk(TEST_PSK); return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); } @@ -300,24 +355,84 @@ public class Ikev2VpnTest { } } + private void checkStartStopVpnProfileBuildsNetworks(IkeTunUtils tunUtils) throws Exception { + // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. + mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V4, true /* isRestrictedToTestNetworks */); + assertNull(sVpnMgr.provisionVpnProfile(profile)); + + sVpnMgr.startProvisionedVpnProfile(); + + // Inject IKE negotiation + int expectedMsgId = 0; + tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, false /* isEncap */, + HexDump.hexStringToByteArray(SUCCESSFUL_IKE_INIT_RESP)); + tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, true /* isEncap */, + HexDump.hexStringToByteArray(SUCCESSFUL_IKE_AUTH_RESP)); + + // Verify the VPN network came up + final NetworkRequest nr = new NetworkRequest.Builder() + .clearCapabilities().addTransportType(TRANSPORT_VPN).build(); + + final TestNetworkCallback cb = new TestNetworkCallback(); + sCM.requestNetwork(nr, cb); + cb.waitForAvailable(); + final Network vpnNetwork = cb.currentNetwork; + assertNotNull(vpnNetwork); + + sVpnMgr.stopProvisionedVpnProfile(); + cb.waitForLost(); + assertEquals(vpnNetwork, cb.lastLostNetwork); + } + + private void doTestStartStopVpnProfile() throws Exception { + // Non-final; these variables ensure we clean up properly after our test if we have + // allocated test network resources + final TestNetworkManager tnm = sContext.getSystemService(TestNetworkManager.class); + TestNetworkInterface testIface = null; + TestNetworkCallback tunNetworkCallback = null; + + try { + // Build underlying test network + testIface = tnm.createTunInterface( + new LinkAddress[] { + new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), + new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)}); + + // Hold on to this callback to ensure network does not get reaped. + tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName()); + final IkeTunUtils tunUtils = new IkeTunUtils(testIface.getFileDescriptor()); + + checkStartStopVpnProfileBuildsNetworks(tunUtils); + } finally { + // Make sure to stop the VPN profile. This is safe to call multiple times. + sVpnMgr.stopProvisionedVpnProfile(); + + if (testIface != null) { + testIface.getFileDescriptor().close(); + } + + if (tunNetworkCallback != null) { + sCM.unregisterNetworkCallback(tunNetworkCallback); + } + + final Network testNetwork = tunNetworkCallback.currentNetwork; + if (testNetwork != null) { + tnm.teardownTestNetwork(testNetwork); + } + } + } + @Test public void testStartStopVpnProfile() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); - // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. + // Requires shell permission to update appops. runWithShellPermissionIdentity(() -> { - mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); - - final Ikev2VpnProfile profile = - buildIkev2VpnProfilePsk(true /* isRestrictedToTestNetworks */); - assertNull(sVpnMgr.provisionVpnProfile(profile)); - - sVpnMgr.startProvisionedVpnProfile(); - // TODO: When IKEv2 setup is injectable, verify network was set up properly. - - sVpnMgr.stopProvisionedVpnProfile(); - // TODO: When IKEv2 setup is injectable, verify network is lost. - }, Manifest.permission.MANAGE_TEST_NETWORKS); + doTestStartStopVpnProfile(); + }); } private static class CertificateAndKey { diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index a0307137a5..adaba9d398 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -21,8 +21,8 @@ import static android.net.cts.PacketUtils.IP6_HDRLEN; import static android.net.cts.PacketUtils.IPPROTO_ESP; import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_UDP; + import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; import android.os.ParcelFileDescriptor; @@ -39,19 +39,18 @@ import java.util.function.Predicate; public class TunUtils { private static final String TAG = TunUtils.class.getSimpleName(); + protected static final int IP4_ADDR_OFFSET = 12; + protected static final int IP4_ADDR_LEN = 4; + protected static final int IP6_ADDR_OFFSET = 8; + protected static final int IP6_ADDR_LEN = 16; + protected static final int IP4_PROTO_OFFSET = 9; + protected static final int IP6_PROTO_OFFSET = 6; + private static final int DATA_BUFFER_LEN = 4096; - private static final int TIMEOUT = 100; + private static final int TIMEOUT = 1000; - private static final int IP4_PROTO_OFFSET = 9; - private static final int IP6_PROTO_OFFSET = 6; - - private static final int IP4_ADDR_OFFSET = 12; - private static final int IP4_ADDR_LEN = 4; - private static final int IP6_ADDR_OFFSET = 8; - private static final int IP6_ADDR_LEN = 16; - - private final ParcelFileDescriptor mTunFd; private final List mPackets = new ArrayList<>(); + private final ParcelFileDescriptor mTunFd; private final Thread mReaderThread; public TunUtils(ParcelFileDescriptor tunFd) { @@ -112,46 +111,15 @@ public class TunUtils { return null; } - /** - * Checks if the specified bytes were ever sent in plaintext. - * - *

    Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like - * - * @param plaintext the plaintext bytes to check for - * @param startIndex the index in the list to check for - */ - public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { - Predicate verifier = - (pkt) -> { - return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) - != -1; - }; - return getFirstMatchingPacket(verifier, startIndex) != null; - } - - public byte[] getEspPacket(int spi, boolean encap, int startIndex) { - return getFirstMatchingPacket( - (pkt) -> { - return isEsp(pkt, spi, encap); - }, - startIndex); - } - - public byte[] awaitEspPacketNoPlaintext( - int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + protected byte[] awaitPacket(Predicate verifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; int startIndex = 0; synchronized (mPackets) { while (System.currentTimeMillis() < endTime) { - byte[] espPkt = getEspPacket(spi, useEncap, startIndex); - if (espPkt != null) { - // Validate packet size - assertEquals(expectedPacketSize, espPkt.length); - - // Always check plaintext from start - assertFalse(hasPlaintextPacket(plaintext, 0)); - return espPkt; // We've found the packet we're looking for. + final byte[] pkt = getFirstMatchingPacket(verifier, startIndex); + if (pkt != null) { + return pkt; // We've found the packet we're looking for. } startIndex = mPackets.size(); @@ -162,10 +130,21 @@ public class TunUtils { mPackets.wait(waitTimeout); } } - - fail("No such ESP packet found with SPI " + spi); } - return null; + + fail("No packet found matching verifier"); + throw new IllegalStateException("Impossible condition; should have thrown in fail()"); + } + + public byte[] awaitEspPacketNoPlaintext( + int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + final byte[] espPkt = awaitPacket( + (pkt) -> isEspFailIfSpecifiedPlaintextFound(pkt, spi, useEncap, plaintext)); + + // Validate packet size + assertEquals(expectedPacketSize, espPkt.length); + + return espPkt; // We've found the packet we're looking for. } private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { @@ -176,6 +155,24 @@ public class TunUtils { && pkt[espOffset + 3] == (byte) (spi & 0xff); } + /** + * Variant of isEsp that also fails the test if the provided plaintext is found + * + * @param pkt the packet bytes to verify + * @param spi the expected SPI to look for + * @param encap whether encap was enabled, and the packet has a UDP header + * @param plaintext the plaintext packet before outbound encryption, which MUST not appear in + * the provided packet. + */ + private static boolean isEspFailIfSpecifiedPlaintextFound( + byte[] pkt, int spi, boolean encap, byte[] plaintext) { + if (Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) != -1) { + fail("Banned plaintext packet found"); + } + + return isEsp(pkt, spi, encap); + } + private static boolean isEsp(byte[] pkt, int spi, boolean encap) { if (isIpv6(pkt)) { // IPv6 UDP encap not supported by kernels; assume non-encap. @@ -191,7 +188,7 @@ public class TunUtils { } } - private static boolean isIpv6(byte[] pkt) { + public static boolean isIpv6(byte[] pkt) { // First nibble shows IP version. 0x60 for IPv6 return (pkt[0] & (byte) 0xF0) == (byte) 0x60; } From 450854f8ba71a385a52ce4144cbb64d8fd9144af Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 12 May 2020 18:07:17 +0900 Subject: [PATCH 1152/1415] Add CTS test for the capport API The test relies on EthernetManager#setIncludeTestInterfaces to run validation on an "ethernet" network based on a tap interface, and simulates DHCP and HTTP servers so the device sees the capport DHCP option, and fetches the API contents. Bug: 156062304 Test: atest CaptivePortalApiTest (clean cherry-pick from aosp) Merged-In: I734dbd05c0f50b8dc4553102ab286f0d8807a7ac Change-Id: I734dbd05c0f50b8dc4553102ab286f0d8807a7ac --- tests/cts/net/Android.bp | 1 + .../android/net/cts/CaptivePortalApiTest.kt | 271 ++++++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 46fae33b9b..1f4b96e03b 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -39,6 +39,7 @@ java_defaults { static_libs: [ "FrameworksNetCommonTests", + "TestNetworkStackLib", "core-tests-support", "compatibility-device-util-axt", "cts-net-utils", diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt new file mode 100644 index 0000000000..40d0ca65c7 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt @@ -0,0 +1,271 @@ +/* + * 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 android.Manifest.permission.MANAGE_TEST_NETWORKS +import android.Manifest.permission.NETWORK_SETTINGS +import android.content.Context +import android.net.ConnectivityManager +import android.net.EthernetManager +import android.net.InetAddresses +import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL +import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED +import android.net.NetworkCapabilities.TRANSPORT_ETHERNET +import android.net.NetworkRequest +import android.net.TestNetworkInterface +import android.net.TestNetworkManager +import android.net.Uri +import android.net.dhcp.DhcpDiscoverPacket +import android.net.dhcp.DhcpPacket +import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE +import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_DISCOVER +import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_REQUEST +import android.net.dhcp.DhcpRequestPacket +import android.net.shared.Inet4AddressUtils.getBroadcastAddress +import android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address +import android.os.Build +import android.os.HandlerThread +import android.platform.test.annotations.AppModeFull +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import com.android.compatibility.common.util.ThrowingRunnable +import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DhcpClientPacketFilter +import com.android.testutils.DhcpOptionFilter +import com.android.testutils.RecorderCallback.CallbackEntry +import com.android.testutils.TapPacketReader +import com.android.testutils.TestableNetworkCallback +import fi.iki.elonen.NanoHTTPD +import org.junit.After +import org.junit.Assume.assumeFalse +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.net.Inet4Address +import java.util.concurrent.ArrayBlockingQueue +import java.util.concurrent.TimeUnit +import kotlin.reflect.KClass +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import kotlin.test.fail + +private const val MAX_PACKET_LENGTH = 1500 +private const val TEST_TIMEOUT_MS = 10_000L + +private const val TEST_LEASE_TIMEOUT_SECS = 3600 * 12 +private const val TEST_PREFIX_LENGTH = 24 + +private const val TEST_LOGIN_URL = "https://login.capport.android.com" +private const val TEST_VENUE_INFO_URL = "https://venueinfo.capport.android.com" +private const val TEST_DOMAIN_NAME = "lan" +private const val TEST_MTU = 1500.toShort() + +@AppModeFull(reason = "Instant apps cannot create test networks") +@RunWith(AndroidJUnit4::class) +class CaptivePortalApiTest { + @JvmField + @Rule + val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) + + private val context by lazy { InstrumentationRegistry.getInstrumentation().context } + private val tnm by lazy { context.assertHasService(TestNetworkManager::class.java) } + private val eth by lazy { context.assertHasService(EthernetManager::class.java) } + private val cm by lazy { context.assertHasService(ConnectivityManager::class.java) } + + private val handlerThread = HandlerThread(CaptivePortalApiTest::class.simpleName) + private val serverIpAddr = InetAddresses.parseNumericAddress("192.0.2.222") as Inet4Address + private val clientIpAddr = InetAddresses.parseNumericAddress("192.0.2.111") as Inet4Address + private val httpServer = HttpServer() + private val ethRequest = NetworkRequest.Builder() + // ETHERNET|TEST transport networks do not have NET_CAPABILITY_TRUSTED + .removeCapability(NET_CAPABILITY_TRUSTED) + .addTransportType(TRANSPORT_ETHERNET).build() + private val ethRequestCb = TestableNetworkCallback() + + private lateinit var iface: TestNetworkInterface + private lateinit var reader: TapPacketReader + private lateinit var capportUrl: Uri + + private var testSkipped = false + + @Before + fun setUp() { + // This test requires using a tap interface as the default ethernet interface: skip if there + // is already an ethernet interface connected. + testSkipped = eth.isAvailable() + assumeFalse(testSkipped) + + // Register a request so the network does not get torn down + cm.requestNetwork(ethRequest, ethRequestCb) + runAsShell(NETWORK_SETTINGS, MANAGE_TEST_NETWORKS) { + eth.setIncludeTestInterfaces(true) + // Keeping a reference to the test interface also makes sure the ParcelFileDescriptor + // does not go out of scope, which would cause it to close the underlying FileDescriptor + // in its finalizer. + iface = tnm.createTapInterface() + } + + handlerThread.start() + reader = TapPacketReader( + handlerThread.threadHandler, + iface.fileDescriptor.fileDescriptor, + MAX_PACKET_LENGTH) + handlerThread.threadHandler.post { reader.start() } + httpServer.start() + + // Pad the listening port to make sure it is always of length 5. This ensures the URL has + // always the same length so the test can use constant IP and UDP header lengths. + // The maximum port number is 65535 so a length of 5 is always enough. + capportUrl = Uri.parse("http://localhost:${httpServer.listeningPort}/testapi.html?par=val") + } + + @After + fun tearDown() { + if (testSkipped) return + cm.unregisterNetworkCallback(ethRequestCb) + + runAsShell(NETWORK_SETTINGS) { eth.setIncludeTestInterfaces(false) } + + httpServer.stop() + handlerThread.threadHandler.post { reader.stop() } + handlerThread.quitSafely() + + iface.fileDescriptor.close() + } + + @Test + fun testApiCallbacks() { + // Handle the DHCP handshake that includes the capport API URL + val discover = reader.assertDhcpPacketReceived( + DhcpDiscoverPacket::class, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER) + reader.sendResponse(makeOfferPacket(discover.clientMac, discover.transactionId)) + + val request = reader.assertDhcpPacketReceived( + DhcpRequestPacket::class, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_REQUEST) + assertEquals(discover.transactionId, request.transactionId) + assertEquals(clientIpAddr, request.mRequestedIp) + reader.sendResponse(makeAckPacket(request.clientMac, request.transactionId)) + + // Expect a request to the capport API + val capportReq = httpServer.recordedRequests.poll(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS) + assertNotNull(capportReq, "The device did not fetch captive portal API data within timeout") + assertEquals(capportUrl.path, capportReq.uri) + assertEquals(capportUrl.query, capportReq.queryParameterString) + + // Expect network callbacks with capport info + val testCb = TestableNetworkCallback(TEST_TIMEOUT_MS) + // LinkProperties do not contain captive portal info if the callback is registered without + // NETWORK_SETTINGS permissions. + val lp = runAsShell(NETWORK_SETTINGS) { + cm.registerNetworkCallback(ethRequest, testCb) + + try { + val ncCb = testCb.eventuallyExpect { + it.caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) + } + testCb.eventuallyExpect { + it.network == ncCb.network && it.lp.captivePortalData != null + }.lp + } finally { + cm.unregisterNetworkCallback(testCb) + } + } + + assertEquals(capportUrl, lp.captivePortalApiUrl) + with(lp.captivePortalData) { + assertNotNull(this) + assertTrue(isCaptive) + assertEquals(Uri.parse(TEST_LOGIN_URL), userPortalUrl) + assertEquals(Uri.parse(TEST_VENUE_INFO_URL), venueInfoUrl) + } + } + + private fun makeOfferPacket(clientMac: ByteArray, transactionId: Int) = + DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, transactionId, + false /* broadcast */, serverIpAddr, IPV4_ADDR_ANY /* relayIp */, clientIpAddr, + clientMac, TEST_LEASE_TIMEOUT_SECS, + getPrefixMaskAsInet4Address(TEST_PREFIX_LENGTH), + getBroadcastAddress(clientIpAddr, TEST_PREFIX_LENGTH), + listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */, + serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */, + TEST_MTU, capportUrl.toString()) + + private fun makeAckPacket(clientMac: ByteArray, transactionId: Int) = + DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, transactionId, + false /* broadcast */, serverIpAddr, IPV4_ADDR_ANY /* relayIp */, clientIpAddr, + clientIpAddr /* requestClientIp */, clientMac, TEST_LEASE_TIMEOUT_SECS, + getPrefixMaskAsInet4Address(TEST_PREFIX_LENGTH), + getBroadcastAddress(clientIpAddr, TEST_PREFIX_LENGTH), + listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */, + serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */, + TEST_MTU, false /* rapidCommit */, capportUrl.toString()) + + private fun parseDhcpPacket(bytes: ByteArray) = DhcpPacket.decodeFullPacket( + bytes, MAX_PACKET_LENGTH, DhcpPacket.ENCAP_L2) +} + +/** + * A minimal HTTP server running on localhost (loopback), on a random available port. + * + * The server records each request in [recordedRequests] and will not serve any further request + * until the last one is removed from the queue for verification. + */ +private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) { + val recordedRequests = ArrayBlockingQueue(1 /* capacity */) + + override fun serve(session: IHTTPSession): Response { + recordedRequests.offer(session) + return newFixedLengthResponse(""" + |{ + | "captive": true, + | "user-portal-url": "$TEST_LOGIN_URL", + | "venue-info-url": "$TEST_VENUE_INFO_URL" + |} + """.trimMargin()) + } +} + +private fun TapPacketReader.assertDhcpPacketReceived( + packetType: KClass, + timeoutMs: Long, + type: Byte +): T { + val packetBytes = popPacket(timeoutMs, DhcpClientPacketFilter() + .and(DhcpOptionFilter(DHCP_MESSAGE_TYPE, type))) + ?: fail("${packetType.simpleName} not received within timeout") + val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2) + assertTrue(packetType.isInstance(packet), + "Expected ${packetType.simpleName} but got ${packet.javaClass.simpleName}") + return packetType.java.cast(packet) +} + +private fun Context.assertHasService(manager: Class): T { + return getSystemService(manager) ?: fail("Service $manager not found") +} + +/** + * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. + */ +private fun runAsShell(vararg permissions: String, task: () -> T): T { + var ret: T? = null + runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) + return ret ?: fail("ThrowingRunnable was not run") +} From df503d4bd1fbb211efdfc82401c6309f28985806 Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 29 May 2020 10:46:30 +0800 Subject: [PATCH 1153/1415] Address comment from aosp/1232197 1. Call maybeRemoveDeprecatedUpstreams from Tethering rather than inside PrivateAddressCoordinator because the building logic of this method based on implementation details of Tethering. 2. Fix typo Bug: 130879722 Test: -build, flash, boot -atest TetheringTests Change-Id: I7584253b728bc17fc648fc19e492ca9f7ad2ff46 --- .../tethering/PrivateAddressCoordinator.java | 29 ++++++++++--------- .../networkstack/tethering/Tethering.java | 1 + .../PrivateAddressCoordinatorTest.java | 15 ++++++---- .../networkstack/tethering/TetheringTest.java | 6 ++-- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index 160a166b63..aa58a4b6a3 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -15,6 +15,8 @@ */ package com.android.networkstack.tethering; +import static java.util.Arrays.asList; + import android.content.Context; import android.net.ConnectivityManager; import android.net.IpPrefix; @@ -34,9 +36,10 @@ import com.android.internal.util.IndentingPrintWriter; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Random; +import java.util.Set; /** * This class coordinate IP addresses conflict problem. @@ -60,8 +63,8 @@ public class PrivateAddressCoordinator { // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream // address may be requested before coordinator get current upstream notification. To ensure // coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared - // when tethering is down. Instead coordinator would remove all depcreted upstreams from - // mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprectedUpstreams(). + // when tethering is down. Instead tethering would remove all deprecated upstreams from + // mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprecatedUpstreams(). private final ArrayMap> mUpstreamPrefixMap; private final ArraySet mDownstreams; // IANA has reserved the following three blocks of the IP address space for private intranets: @@ -124,15 +127,16 @@ public class PrivateAddressCoordinator { mUpstreamPrefixMap.remove(network); } - private void maybeRemoveDeprectedUpstreams() { - if (!mDownstreams.isEmpty() || mUpstreamPrefixMap.isEmpty()) return; + /** + * Maybe remove deprecated upstream records, this would be called once tethering started without + * any exiting tethered downstream. + */ + public void maybeRemoveDeprecatedUpstreams() { + if (mUpstreamPrefixMap.isEmpty()) return; - final ArrayList toBeRemoved = new ArrayList<>(); - List allNetworks = Arrays.asList(mConnectivityMgr.getAllNetworks()); - for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { - final Network network = mUpstreamPrefixMap.keyAt(i); - if (!allNetworks.contains(network)) toBeRemoved.add(network); - } + // Remove all upstreams that are no longer valid networks + final Set toBeRemoved = new HashSet<>(mUpstreamPrefixMap.keySet()); + toBeRemoved.removeAll(asList(mConnectivityMgr.getAllNetworks())); mUpstreamPrefixMap.removeAll(toBeRemoved); } @@ -143,8 +147,6 @@ public class PrivateAddressCoordinator { */ @Nullable public LinkAddress requestDownstreamAddress(final IpServer ipServer) { - maybeRemoveDeprectedUpstreams(); - // Address would be 192.168.[subAddress]/24. final byte[] bytes = mTetheringPrefix.getRawAddress(); final int subAddress = getRandomSubAddr(); @@ -237,7 +239,6 @@ public class PrivateAddressCoordinator { } void dump(final IndentingPrintWriter pw) { - pw.decreaseIndent(); pw.println("mUpstreamPrefixMap:"); pw.increaseIndent(); for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 6eb10129ef..ee482ff192 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -1695,6 +1695,7 @@ public class Tethering { return; } + mPrivateAddressCoordinator.maybeRemoveDeprecatedUpstreams(); mUpstreamNetworkMonitor.startObserveAllNetworks(); // TODO: De-duplicate with updateUpstreamWanted() below. diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 93efd49a6d..2c0df6fc63 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -127,10 +127,15 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } + private int getBluetoothSubAddress() { + final byte[] rawAddress = mBluetoothPrefix.getRawAddress(); + int bluetoothSubNet = rawAddress[2] & 0xff; + return (bluetoothSubNet << 8) + 0x5; + } + @Test public void testReserveBluetoothPrefix() throws Exception { - final int fakeSubAddr = 0x2c05; - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(getBluetoothSubAddress()); LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer); final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); @@ -146,7 +151,7 @@ public final class PrivateAddressCoordinatorTest { LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer); final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - assertEquals("Wrong wifi perfix: ", predefinedPrefix, hotspotPrefix); + assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); when(mHotspotIpServer.getAddress()).thenReturn(address); address = mPrivateAddressCoordinator.requestDownstreamAddress( @@ -159,7 +164,7 @@ public final class PrivateAddressCoordinatorTest { address = mPrivateAddressCoordinator.requestDownstreamAddress( mUsbIpServer); final IpPrefix allowUseFreePrefix = PrefixUtils.asIpPrefix(address); - assertEquals("Fail to reselect available perfix: ", predefinedPrefix, allowUseFreePrefix); + assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix); } private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6, @@ -202,7 +207,7 @@ public final class PrivateAddressCoordinatorTest { final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer); final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr); - assertEquals("Wrong wifi perfix: ", predefinedPrefix, hotspotPrefix); + assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); // 2. Update v6 only mobile network, hotspot prefix should not be removed. List testConflicts; diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 5fffaaedd8..1149604d85 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -1877,7 +1877,7 @@ public class TetheringTest { 0, upstreamNetwork); mLooper.dispatchAll(); - // verify trun off usb tethering + // verify turn off usb tethering verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); mTethering.interfaceRemoved(TEST_USB_IFNAME); mLooper.dispatchAll(); @@ -1915,9 +1915,9 @@ public class TetheringTest { 0, upstreamNetwork); mLooper.dispatchAll(); - // verify trun off usb tethering + // verify turn off usb tethering verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); - // verify trun off ethernet tethering + // verify turn off ethernet tethering verify(mockRequest).release(); mTethering.interfaceRemoved(TEST_USB_IFNAME); ethCallback.onUnavailable(); From f74fce0d0c5ad4b114b7c79c178bc43edffb8220 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 27 May 2020 23:22:27 +0800 Subject: [PATCH 1154/1415] Fix TetheringManagerTest failure when using entitlement required SIM If run tethering cts with entitlement required SIM, the test would failure due to no tethering upstream. Tethering would default start with UI base entitlement check which would have interfactive UI pop up. Tethering's upstream is blocked because entitlement UI is keep waiting for action till timeout. To avoid UI interaction, start tethering with silent entitlement check. Bug: 156714671 Test: atest CtsTetheringTest Change-Id: I85299841d60afba97ffcc4ae908a85e51139319b --- .../android/tethering/cts/TetheringManagerTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 10555312f7..f7160dd502 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -286,8 +286,9 @@ public class TetheringManagerTest { assertTrue(tetheredIfaces.length == 0); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), - c -> c.run() /* executor */, startTetheringCallback); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) + .setShouldShowEntitlementUi(false).build(); + mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.verifyTetheringStarted(); mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); @@ -529,8 +530,9 @@ public class TetheringManagerTest { assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), - c -> c.run() /* executor */, startTetheringCallback); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) + .setShouldShowEntitlementUi(false).build(); + mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.verifyTetheringStarted(); callback.expectTetheredInterfacesChanged(wifiRegexs); From 9e790873d9545889512daaeac9159b7dcefbb237 Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 29 May 2020 14:36:36 +0800 Subject: [PATCH 1155/1415] Gate exemptFromEentitlementCheck by Network_STACK permission Shell has TETHER_PRIVILEGED permission. To avoid any service to adopt shell identity by lunching service with Shell process, gate exemptFromEentitlementCheck by NETWORK_STACK. Bug: 157702014 Test: atest TetheringCoverageTests Change-Id: I6ddfda23d36ea9981e3e1eb5a87767f452a65852 --- .../tethering/TetheringService.java | 17 +++++++++++-- .../android/net/EthernetTetheringTest.java | 4 +-- .../tethering/TetheringServiceTest.java | 25 +++++++++++++------ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java index c11e86258d..613328d1c1 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -17,8 +17,10 @@ package com.android.networkstack.tethering; import static android.Manifest.permission.ACCESS_NETWORK_STATE; +import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.TETHER_PRIVILEGED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; @@ -253,15 +255,26 @@ public class TetheringService extends Service { return false; } + private boolean hasNetworkStackPermission() { + return checkCallingOrSelfPermission(NETWORK_STACK) + || checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK); + } + private boolean hasTetherPrivilegedPermission() { - return mService.checkCallingOrSelfPermission(TETHER_PRIVILEGED) == PERMISSION_GRANTED; + return checkCallingOrSelfPermission(TETHER_PRIVILEGED); + } + + private boolean checkCallingOrSelfPermission(final String permission) { + return mService.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED; } private boolean hasTetherChangePermission(final String callerPkg, final String callingAttributionTag, final boolean onlyAllowPrivileged) { + if (onlyAllowPrivileged && !hasNetworkStackPermission()) return false; + if (hasTetherPrivilegedPermission()) return true; - if (onlyAllowPrivileged || mTethering.isTetherProvisioningRequired()) return false; + if (mTethering.isTetherProvisioningRequired()) return false; int uid = Binder.getCallingUid(); diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index 2fb7e607d0..74df11370e 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -339,7 +339,7 @@ public class EthernetTetheringTest { private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception { return enableEthernetTethering(iface, new TetheringRequest.Builder(TETHERING_ETHERNET) - .setExemptFromEntitlementCheck(true).build()); + .setShouldShowEntitlementUi(false).build()); } private int getMTU(TestNetworkInterface iface) throws SocketException { @@ -510,7 +510,7 @@ public class EthernetTetheringTest { LinkAddress clientAddr = client == null ? null : new LinkAddress(client); return new TetheringRequest.Builder(TETHERING_ETHERNET) .setStaticIpv4Addresses(localAddr, clientAddr) - .setExemptFromEntitlementCheck(true).build(); + .setShouldShowEntitlementUi(false).build(); } private void assertInvalidStaticIpv4Request(String iface, String local, String client) diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index cf060ba95d..7bba67b05f 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -281,22 +281,33 @@ public final class TetheringServiceTest { }); } + private void runStartTetheringAndVerifyNoPermission(final TestTetheringResult result) + throws Exception { + final TetheringRequestParcel request = new TetheringRequestParcel(); + request.tetheringType = TETHERING_WIFI; + request.exemptFromEntitlementCheck = true; + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + } + @Test - public void testStartTetheringWithExemptFromEntitlementCheck() throws Exception { + public void testFailToBypassEntitlementWithoutNeworkStackPermission() throws Exception { final TetheringRequestParcel request = new TetheringRequestParcel(); request.tetheringType = TETHERING_WIFI; request.exemptFromEntitlementCheck = true; + runAsNoPermission((result) -> { + runStartTetheringAndVerifyNoPermission(result); + }); + runAsTetherPrivileged((result) -> { - runStartTethering(result, request); - verifyNoMoreInteractionsForTethering(); + runStartTetheringAndVerifyNoPermission(result); }); runAsWriteSettings((result) -> { - mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, - result); - result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); - verifyNoMoreInteractionsForTethering(); + runStartTetheringAndVerifyNoPermission(result); }); } From 3d95958d011dcecab29affce98d82198b50de61c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 20 May 2020 01:13:18 -0700 Subject: [PATCH 1156/1415] Add IPv6 testing for IKEv2 VPN tests This change adds tests for IPv6 IKEv2 VPN profiles. Bug: 148582947 Test: IPv6 tests passing Change-Id: Ic0f71df739bd9162653b5f2878e7ddc446ddde0e --- .../net/src/android/net/cts/Ikev2VpnTest.java | 81 ++++++++++++++----- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index ebce5135cf..5cc0cb4128 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -76,7 +76,7 @@ public class Ikev2VpnTest { private static final String TAG = Ikev2VpnTest.class.getSimpleName(); // Test vectors for IKE negotiation in test mode. - private static final String SUCCESSFUL_IKE_INIT_RESP = + private static final String SUCCESSFUL_IKE_INIT_RESP_V4 = "46b8eca1e0d72a18b2b5d9006d47a0022120222000000000000002d0220000300000002c01010004030000" + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800" + "100000b8070f159fe5141d8754ca86f72ecc28d66f514927e96cbe9eec0adb42bf2c276a0ab7" @@ -96,25 +96,53 @@ public class Ikev2VpnTest { + "297b6ad169bccce4f66c5399c6e0be9120166f2900001c0000400428b8df2e66f69c8584a186" + "c5eac66783551d49b72900001c000040054e7a622e802d5cbfb96d5f30a6e433994370173529" + "0000080000402e290000100000402f00020003000400050000000800004014"; - private static final String SUCCESSFUL_IKE_AUTH_RESP = + private static final String SUCCESSFUL_IKE_INIT_RESP_V6 = + "46b8eca1e0d72a1800d9ea1babce26bf2120222000000000000002d0220000300000002c01010004030000" + + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800" + + "100000ea0e6dd9ca5930a9a45c323a41f64bfd8cdef7730f5fbff37d7c377da427f489a42aa8" + + "c89233380e6e925990d49de35c2cdcf63a61302c731a4b3569df1ee1bf2457e55a6751838ede" + + "abb75cc63ba5c9e4355e8e784f383a5efe8a44727dc14aeaf8dacc2620fb1c8875416dc07739" + + "7fe4decc1bd514a9c7d270cf21fd734c63a25c34b30b68686e54e8a198f37f27cb491fe27235" + + "fab5476b036d875ccab9a68d65fbf3006197f9bebbf94de0d3802b4fafe1d48d931ce3a1a346" + + "2d65bd639e9bd7fa46299650a9dbaf9b324e40b466942d91a59f41ef8042f8474c4850ed0f63" + + "e9238949d41cd8bbaea9aefdb65443a6405792839563aa5dc5c36b5ce8326ccf8a94d9622b85" + + "038d390d5fc0299e14e1f022966d4ac66515f6108ca04faec44821fe5bbf2ed4f84ff5671219" + + "608cb4c36b44a31ba010c9088f8d5ff943bb9ff857f74be1755f57a5783874adc57f42bb174e" + + "4ad3215de628707014dbcb1707bd214658118fdd7a42b3e1638b991ce5b812a667f1145be811" + + "685e3cd3baf9b18d062657b64c206a4d19a531c252a6a51a04aeaf42c618620cdbab65baca23" + + "82c57ed888422aeaacf7f1bc3fe2247ff7e7eaca218b74d7b31d02f2b0afa123f802529e7e6c" + + "3259d418290740ddbf55686e26998d7edcbbf895664972fed666f2f20af40503aa2af436ec6d" + + "4ec981ab19b9088755d94ae7a7c2066ea331d4e56e290000243fefe5555fce552d57a84e682c" + + "d4a6dfb3f2f94a94464d5bec3d88b88e9559642900001c00004004eb4afff764e7b79bca78b1" + + "3a89100d36d678ae982900001c00004005d177216a3c26f782076e12570d40bfaaa148822929" + + "0000080000402e290000100000402f00020003000400050000000800004014"; + private static final String SUCCESSFUL_IKE_AUTH_RESP_V4 = "46b8eca1e0d72a18b2b5d9006d47a0022e20232000000001000000e0240000c420a2500a3da4c66fa6929e" + "600f36349ba0e38de14f78a3ad0416cba8c058735712a3d3f9a0a6ed36de09b5e9e02697e7c4" + "2d210ac86cfbd709503cfa51e2eab8cfdc6427d136313c072968f6506a546eb5927164200592" + "6e36a16ee994e63f029432a67bc7d37ca619e1bd6e1678df14853067ecf816b48b81e8746069" + "406363e5aa55f13cb2afda9dbebee94256c29d630b17dd7f1ee52351f92b6e1c3d8551c513f1" + "d74ac52a80b2041397e109fe0aeb3c105b0d4be0ae343a943398764281"; + private static final String SUCCESSFUL_IKE_AUTH_RESP_V6 = + "46b8eca1e0d72a1800d9ea1babce26bf2e20232000000001000000f0240000d4aaf6eaa6c06b50447e6f54" + + "827fd8a9d9d6ac8015c1ebb3e8cb03fc6e54b49a107441f50004027cc5021600828026367f03" + + "bc425821cd7772ee98637361300c9b76056e874fea2bd4a17212370b291894264d8c023a01d1" + + "c3b691fd4b7c0b534e8c95af4c4638e2d125cb21c6267e2507cd745d72e8da109c47b9259c6c" + + "57a26f6bc5b337b9b9496d54bdde0333d7a32e6e1335c9ee730c3ecd607a8689aa7b0577b74f" + + "3bf437696a9fd5fc0aee3ed346cd9e15d1dda293df89eb388a8719388a60ca7625754de12cdb" + + "efe4c886c5c401"; private static final long IKE_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); private static final InetAddress LOCAL_OUTER_6 = - InetAddress.parseNumericAddress("2001:db8:1::1"); + InetAddress.parseNumericAddress("2001:db8::1"); private static final int IP4_PREFIX_LEN = 32; private static final int IP6_PREFIX_LEN = 128; // TODO: Use IPv6 address when we can generate test vectors (GCE does not allow IPv6 yet). private static final String TEST_SERVER_ADDR_V4 = "192.0.2.2"; - private static final String TEST_SERVER_ADDR = "2001:db8::1"; + private static final String TEST_SERVER_ADDR_V6 = "2001:db8::2"; private static final String TEST_IDENTITY = "client.cts.android.com"; private static final List TEST_ALLOWED_ALGORITHMS = Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM); @@ -174,7 +202,7 @@ public class Ikev2VpnTest { private Ikev2VpnProfile buildIkev2VpnProfilePsk(boolean isRestrictedToTestNetworks) throws Exception { - return buildIkev2VpnProfilePsk(TEST_SERVER_ADDR, isRestrictedToTestNetworks); + return buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6, isRestrictedToTestNetworks); } private Ikev2VpnProfile buildIkev2VpnProfilePsk( @@ -188,7 +216,7 @@ public class Ikev2VpnTest { private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks) throws Exception { final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY) + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY) .setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa); return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); @@ -197,7 +225,7 @@ public class Ikev2VpnTest { private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks) throws Exception { final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY) + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY) .setAuthDigitalSignature( mUserCertKey.cert, mUserCertKey.key, mServerRootCa); @@ -205,7 +233,7 @@ public class Ikev2VpnTest { } private void checkBasicIkev2VpnProfile(@NonNull Ikev2VpnProfile profile) throws Exception { - assertEquals(TEST_SERVER_ADDR, profile.getServerAddr()); + assertEquals(TEST_SERVER_ADDR_V6, profile.getServerAddr()); assertEquals(TEST_IDENTITY, profile.getUserIdentity()); assertEquals(TEST_PROXY_INFO, profile.getProxyInfo()); assertEquals(TEST_ALLOWED_ALGORITHMS, profile.getAllowedAlgorithms()); @@ -355,12 +383,18 @@ public class Ikev2VpnTest { } } - private void checkStartStopVpnProfileBuildsNetworks(IkeTunUtils tunUtils) throws Exception { + private void checkStartStopVpnProfileBuildsNetworks(IkeTunUtils tunUtils, boolean testIpv6) + throws Exception { + String serverAddr = testIpv6 ? TEST_SERVER_ADDR_V6 : TEST_SERVER_ADDR_V4; + String initResp = testIpv6 ? SUCCESSFUL_IKE_INIT_RESP_V6 : SUCCESSFUL_IKE_INIT_RESP_V4; + String authResp = testIpv6 ? SUCCESSFUL_IKE_AUTH_RESP_V6 : SUCCESSFUL_IKE_AUTH_RESP_V4; + boolean hasNat = !testIpv6; + // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); final Ikev2VpnProfile profile = - buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V4, true /* isRestrictedToTestNetworks */); + buildIkev2VpnProfilePsk(serverAddr, true /* isRestrictedToTestNetworks */); assertNull(sVpnMgr.provisionVpnProfile(profile)); sVpnMgr.startProvisionedVpnProfile(); @@ -368,9 +402,9 @@ public class Ikev2VpnTest { // Inject IKE negotiation int expectedMsgId = 0; tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, false /* isEncap */, - HexDump.hexStringToByteArray(SUCCESSFUL_IKE_INIT_RESP)); - tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, true /* isEncap */, - HexDump.hexStringToByteArray(SUCCESSFUL_IKE_AUTH_RESP)); + HexDump.hexStringToByteArray(initResp)); + tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, hasNat /* isEncap */, + HexDump.hexStringToByteArray(authResp)); // Verify the VPN network came up final NetworkRequest nr = new NetworkRequest.Builder() @@ -387,7 +421,7 @@ public class Ikev2VpnTest { assertEquals(vpnNetwork, cb.lastLostNetwork); } - private void doTestStartStopVpnProfile() throws Exception { + private void doTestStartStopVpnProfile(boolean testIpv6) throws Exception { // Non-final; these variables ensure we clean up properly after our test if we have // allocated test network resources final TestNetworkManager tnm = sContext.getSystemService(TestNetworkManager.class); @@ -402,10 +436,11 @@ public class Ikev2VpnTest { new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)}); // Hold on to this callback to ensure network does not get reaped. - tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName()); + tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork( + testIface.getInterfaceName()); final IkeTunUtils tunUtils = new IkeTunUtils(testIface.getFileDescriptor()); - checkStartStopVpnProfileBuildsNetworks(tunUtils); + checkStartStopVpnProfileBuildsNetworks(tunUtils, testIpv6); } finally { // Make sure to stop the VPN profile. This is safe to call multiple times. sVpnMgr.stopProvisionedVpnProfile(); @@ -426,12 +461,22 @@ public class Ikev2VpnTest { } @Test - public void testStartStopVpnProfile() throws Exception { + public void testStartStopVpnProfileV4() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); // Requires shell permission to update appops. runWithShellPermissionIdentity(() -> { - doTestStartStopVpnProfile(); + doTestStartStopVpnProfile(false); + }); + } + + @Test + public void testStartStopVpnProfileV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + // Requires shell permission to update appops. + runWithShellPermissionIdentity(() -> { + doTestStartStopVpnProfile(true); }); } From d0216998a412130e7c161c64e9a1f06cdcfd616b Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Fri, 8 May 2020 17:50:53 +0800 Subject: [PATCH 1157/1415] [BOT.1] Add a class ForwardedStats in TetheringUtils Used to record offload transmitted/received forwarded bytes/packets. Bug: 150736748 Test: new test BpfTetheringCoordinatorTest Change-Id: Ie8725f95c3ddd5fb3811d479de32d2c1f7dcb493 --- .../src/android/net/util/TetheringUtils.java | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/Tethering/src/android/net/util/TetheringUtils.java b/Tethering/src/android/net/util/TetheringUtils.java index dd67dddae1..b17b4ba77c 100644 --- a/Tethering/src/android/net/util/TetheringUtils.java +++ b/Tethering/src/android/net/util/TetheringUtils.java @@ -15,18 +15,93 @@ */ package android.net.util; +import android.net.TetherStatsParcel; import android.net.TetheringRequestParcel; +import androidx.annotation.NonNull; + import java.io.FileDescriptor; import java.net.SocketException; import java.util.Objects; /** - * Native methods for tethering utilization. + * The classes and the methods for tethering utilization. * * {@hide} */ public class TetheringUtils { + /** + * The object which records offload Tx/Rx forwarded bytes/packets. + * TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with + * this class as well. + */ + public static class ForwardedStats { + public final long rxBytes; + public final long rxPackets; + public final long txBytes; + public final long txPackets; + + public ForwardedStats() { + rxBytes = 0; + rxPackets = 0; + txBytes = 0; + txPackets = 0; + } + + public ForwardedStats(long rxBytes, long txBytes) { + this.rxBytes = rxBytes; + this.rxPackets = 0; + this.txBytes = txBytes; + this.txPackets = 0; + } + + public ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets) { + this.rxBytes = rxBytes; + this.rxPackets = rxPackets; + this.txBytes = txBytes; + this.txPackets = txPackets; + } + + public ForwardedStats(@NonNull TetherStatsParcel tetherStats) { + rxBytes = tetherStats.rxBytes; + rxPackets = tetherStats.rxPackets; + txBytes = tetherStats.txBytes; + txPackets = tetherStats.txPackets; + } + + public ForwardedStats(@NonNull ForwardedStats other) { + rxBytes = other.rxBytes; + rxPackets = other.rxPackets; + txBytes = other.txBytes; + txPackets = other.txPackets; + } + + /** Add Tx/Rx bytes/packets and return the result as a new object. */ + @NonNull + public ForwardedStats add(@NonNull ForwardedStats other) { + return new ForwardedStats(rxBytes + other.rxBytes, rxPackets + other.rxPackets, + txBytes + other.txBytes, txPackets + other.txPackets); + } + + /** Subtract Tx/Rx bytes/packets and return the result as a new object. */ + @NonNull + public ForwardedStats subtract(@NonNull ForwardedStats other) { + // TODO: Perhaps throw an exception if any negative difference value just in case. + final long rxBytesDiff = Math.max(rxBytes - other.rxBytes, 0); + final long rxPacketsDiff = Math.max(rxPackets - other.rxPackets, 0); + final long txBytesDiff = Math.max(txBytes - other.txBytes, 0); + final long txPacketsDiff = Math.max(txPackets - other.txPackets, 0); + return new ForwardedStats(rxBytesDiff, rxPacketsDiff, txBytesDiff, txPacketsDiff); + } + + /** Returns the string representation of this object. */ + @NonNull + public String toString() { + return String.format("ForwardedStats(rxb: %d, rxp: %d, txb: %d, txp: %d)", rxBytes, + rxPackets, txBytes, txPackets); + } + } + /** * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. * @param fd the socket's {@link FileDescriptor}. From 68f1c2a63fb90366346cb0075dc8125ed082d406 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 12 Mar 2020 21:24:01 +0800 Subject: [PATCH 1158/1415] [BOT.2] Create a coordinator and stats provider to provide tether stats Make BPF tethering offload coordinator, BpfCoordinator, registers a network stats provider, BpfTetherStatsProvider, and provide the tethering stats from the BPF map. Bug: 150736748 Test: new test BpfCoordinatorTest Change-Id: I22e71f87b67668f7e733e4f215d93bf5b2c9380d --- Tethering/src/android/net/ip/IpServer.java | 15 +- .../tethering/BpfCoordinator.java | 280 ++++++++++++++++++ .../networkstack/tethering/Tethering.java | 9 +- .../tethering/TetheringDependencies.java | 11 + .../unit/src/android/net/ip/IpServerTest.java | 8 +- .../networkstack/tethering/TetheringTest.java | 7 + 6 files changed, 325 insertions(+), 5 deletions(-) create mode 100644 Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index f08429bb06..4d0287736c 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -65,6 +65,7 @@ import androidx.annotation.Nullable; import com.android.internal.util.MessageUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.networkstack.tethering.BpfCoordinator; import com.android.networkstack.tethering.PrivateAddressCoordinator; import java.io.IOException; @@ -225,6 +226,8 @@ public class IpServer extends StateMachine { private final SharedLog mLog; private final INetd mNetd; + @NonNull + private final BpfCoordinator mBpfCoordinator; private final Callback mCallback; private final InterfaceController mInterfaceCtrl; private final PrivateAddressCoordinator mPrivateAddressCoordinator; @@ -314,11 +317,13 @@ public class IpServer extends StateMachine { // object. It helps to reduce the arguments of the constructor. public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, - INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload, + INetd netd, @NonNull BpfCoordinator coordinator, Callback callback, + boolean usingLegacyDhcp, boolean usingBpfOffload, PrivateAddressCoordinator addressCoordinator, Dependencies deps) { super(ifaceName, looper); mLog = log.forSubComponent(ifaceName); mNetd = netd; + mBpfCoordinator = coordinator; mCallback = callback; mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog); mIfaceName = ifaceName; @@ -754,6 +759,14 @@ public class IpServer extends StateMachine { } upstreamIfindex = mDeps.getIfindex(upstreamIface); + + // Add upstream index to name mapping for the tether stats usage in the coordinator. + // Although this mapping could be added by both class Tethering and IpServer, adding + // mapping from IpServer guarantees that the mapping is added before the adding + // forwarding rules. That is because there are different state machines in both + // classes. It is hard to guarantee the link property update order between multiple + // state machines. + mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface); } // If v6only is null, we pass in null to setRaParams(), which handles diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java new file mode 100644 index 0000000000..0092eb7ee3 --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -0,0 +1,280 @@ +/* + * 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 com.android.networkstack.tethering; + +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; +import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkStats.UID_TETHERING; + +import android.app.usage.NetworkStatsManager; +import android.net.INetd; +import android.net.NetworkStats; +import android.net.NetworkStats.Entry; +import android.net.TetherStatsParcel; +import android.net.netstats.provider.NetworkStatsProvider; +import android.net.util.SharedLog; +import android.net.util.TetheringUtils.ForwardedStats; +import android.os.Handler; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.util.Log; +import android.util.SparseArray; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * This coordinator is responsible for providing BPF offload relevant functionality. + * - Get tethering stats. + * + * @hide + */ +public class BpfCoordinator { + private static final String TAG = BpfCoordinator.class.getSimpleName(); + // TODO: Make it customizable. + private static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; + + private enum StatsType { + STATS_PER_IFACE, + STATS_PER_UID, + } + + @NonNull + private final Handler mHandler; + @NonNull + private final INetd mNetd; + @NonNull + private final SharedLog mLog; + @NonNull + private final Dependencies mDeps; + @Nullable + private final BpfTetherStatsProvider mStatsProvider; + private boolean mStarted = false; + + // Maps upstream interface index to offloaded traffic statistics. + // Always contains the latest total bytes/packets, since each upstream was started, received + // from the BPF maps for each interface. + private SparseArray mStats = new SparseArray<>(); + + // Maps upstream interface index to interface names. + // Store all interface name since boot. Used for lookup what interface name it is from the + // tether stats got from netd because netd reports interface index to present an interface. + // TODO: Remove the unused interface name. + private SparseArray mInterfaceNames = new SparseArray<>(); + + // Runnable that used by scheduling next polling of stats. + private final Runnable mScheduledPollingTask = () -> { + updateForwardedStatsFromNetd(); + maybeSchedulePollingStats(); + }; + + static class Dependencies { + int getPerformPollInterval() { + // TODO: Consider make this configurable. + return DEFAULT_PERFORM_POLL_INTERVAL_MS; + } + } + + BpfCoordinator(@NonNull Handler handler, @NonNull INetd netd, + @NonNull NetworkStatsManager nsm, @NonNull SharedLog log, @NonNull Dependencies deps) { + mHandler = handler; + mNetd = netd; + mLog = log.forSubComponent(TAG); + BpfTetherStatsProvider provider = new BpfTetherStatsProvider(); + try { + nsm.registerNetworkStatsProvider(getClass().getSimpleName(), provider); + } catch (RuntimeException e) { + // TODO: Perhaps not allow to use BPF offload because the reregistration failure + // implied that no data limit could be applies on a metered upstream if any. + Log.wtf(TAG, "Cannot register offload stats provider: " + e); + provider = null; + } + mStatsProvider = provider; + mDeps = deps; + } + + /** + * Start BPF tethering offload stats polling when the first upstream is started. + * Note that this can be only called on handler thread. + * TODO: Perhaps check BPF support before starting. + * TODO: Start the stats polling only if there is any client on the downstream. + */ + public void start() { + if (mStarted) return; + + mStarted = true; + maybeSchedulePollingStats(); + + mLog.i("BPF tethering coordinator started"); + } + + /** + * Stop BPF tethering offload stats polling and cleanup upstream parameters. + * Note that this can be only called on handler thread. + */ + public void stop() { + if (!mStarted) return; + + // Stop scheduled polling tasks and poll the latest stats from BPF maps. + if (mHandler.hasCallbacks(mScheduledPollingTask)) { + mHandler.removeCallbacks(mScheduledPollingTask); + } + updateForwardedStatsFromNetd(); + + mStarted = false; + + mLog.i("BPF tethering coordinator stopped"); + } + + /** + * Add upstream name to lookup table. The lookup table is used for tether stats interface name + * lookup because the netd only reports interface index in BPF tether stats but the service + * expects the interface name in NetworkStats object. + * Note that this can be only called on handler thread. + */ + public void addUpstreamNameToLookupTable(int upstreamIfindex, String upstreamIface) { + if (upstreamIfindex == 0) return; + + // The same interface index to name mapping may be added by different IpServer objects or + // re-added by reconnection on the same upstream interface. Ignore the duplicate one. + final String iface = mInterfaceNames.get(upstreamIfindex); + if (iface == null) { + mInterfaceNames.put(upstreamIfindex, upstreamIface); + } else if (iface != upstreamIface) { + Log.wtf(TAG, "The upstream interface name " + upstreamIface + + " is different from the existing interface name " + + iface + " for index " + upstreamIfindex); + } + } + + /** + * A BPF tethering stats provider to provide network statistics to the system. + * Note that this class's data may only be accessed on the handler thread. + */ + private class BpfTetherStatsProvider extends NetworkStatsProvider { + // The offloaded traffic statistics per interface that has not been reported since the + // last call to pushTetherStats. Only the interfaces that were ever tethering upstreams + // and has pending tether stats delta are included in this NetworkStats object. + private NetworkStats mIfaceStats = new NetworkStats(0L, 0); + + // The same stats as above, but counts network stats per uid. + private NetworkStats mUidStats = new NetworkStats(0L, 0); + + @Override + public void onRequestStatsUpdate(int token) { + mHandler.post(() -> pushTetherStats()); + } + + @Override + public void onSetAlert(long quotaBytes) { + // no-op + } + + @Override + public void onSetLimit(@NonNull String iface, long quotaBytes) { + // no-op + } + + private void pushTetherStats() { + try { + // The token is not used for now. See b/153606961. + notifyStatsUpdated(0 /* token */, mIfaceStats, mUidStats); + + // Clear the accumulated tether stats delta after reported. Note that create a new + // empty object because NetworkStats#clear is @hide. + mIfaceStats = new NetworkStats(0L, 0); + mUidStats = new NetworkStats(0L, 0); + } catch (RuntimeException e) { + mLog.e("Cannot report network stats: ", e); + } + } + + private void accumulateDiff(@NonNull NetworkStats ifaceDiff, + @NonNull NetworkStats uidDiff) { + mIfaceStats = mIfaceStats.add(ifaceDiff); + mUidStats = mUidStats.add(uidDiff); + } + } + + @NonNull + private NetworkStats buildNetworkStats(@NonNull StatsType type, int ifIndex, + @NonNull ForwardedStats diff) { + NetworkStats stats = new NetworkStats(0L, 0); + final String iface = mInterfaceNames.get(ifIndex); + if (iface == null) { + // TODO: Use Log.wtf once the coordinator owns full control of tether stats from netd. + // For now, netd may add the empty stats for the upstream which is not monitored by + // the coordinator. Silently ignore it. + return stats; + } + final int uid = (type == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL; + // Note that the argument 'metered', 'roaming' and 'defaultNetwork' are not recorded for + // network stats snapshot. See NetworkStatsRecorder#recordSnapshotLocked. + return stats.addEntry(new Entry(iface, uid, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, diff.rxBytes, diff.rxPackets, + diff.txBytes, diff.txPackets, 0L /* operations */)); + } + + private void updateForwardedStatsFromNetd() { + final TetherStatsParcel[] tetherStatsList; + try { + // The reported tether stats are total data usage for all currently-active upstream + // interfaces since tethering start. + tetherStatsList = mNetd.tetherOffloadGetStats(); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Problem fetching tethering stats: ", e); + return; + } + + for (TetherStatsParcel tetherStats : tetherStatsList) { + final Integer ifIndex = tetherStats.ifIndex; + final ForwardedStats curr = new ForwardedStats(tetherStats); + final ForwardedStats base = mStats.get(ifIndex); + final ForwardedStats diff = (base != null) ? curr.subtract(base) : curr; + + // Update the local cache for counting tether stats delta. + mStats.put(ifIndex, curr); + + // Update the accumulated tether stats delta to the stats provider for the service + // querying. + if (mStatsProvider != null) { + try { + mStatsProvider.accumulateDiff( + buildNetworkStats(StatsType.STATS_PER_IFACE, ifIndex, diff), + buildNetworkStats(StatsType.STATS_PER_UID, ifIndex, diff)); + } catch (ArrayIndexOutOfBoundsException e) { + Log.wtf("Fail to update the accumulated stats delta for interface index " + + ifIndex + " : ", e); + } + } + } + } + + private void maybeSchedulePollingStats() { + if (!mStarted) return; + + if (mHandler.hasCallbacks(mScheduledPollingTask)) { + mHandler.removeCallbacks(mScheduledPollingTask); + } + + mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval()); + } +} diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 6eb10129ef..00723ac73b 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -232,6 +232,7 @@ public class Tethering { private final TetheringThreadExecutor mExecutor; private final TetheringNotificationUpdater mNotificationUpdater; private final UserManager mUserManager; + private final BpfCoordinator mBpfCoordinator; private final PrivateAddressCoordinator mPrivateAddressCoordinator; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; // All the usage of mTetheringEventCallback should run in the same thread. @@ -284,6 +285,8 @@ public class Tethering { mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new LinkedHashSet<>(); + mBpfCoordinator = mDeps.getBpfCoordinator( + mHandler, mNetd, mLog, new BpfCoordinator.Dependencies()); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); @@ -1704,6 +1707,9 @@ public class Tethering { chooseUpstreamType(true); mTryCell = false; } + + // TODO: Check the upstream interface if it is managed by BPF offload. + mBpfCoordinator.start(); } @Override @@ -1716,6 +1722,7 @@ public class Tethering { mTetherUpstream = null; reportUpstreamChanged(null); } + mBpfCoordinator.stop(); } private boolean updateUpstreamWanted() { @@ -2341,7 +2348,7 @@ public class Tethering { mLog.log("adding TetheringInterfaceStateMachine for: " + iface); final TetherState tetherState = new TetherState( - new IpServer(iface, mLooper, interfaceType, mLog, mNetd, + new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator, makeControlCallback(), mConfig.enableLegacyDhcpServer, mConfig.enableBpfOffload, mPrivateAddressCoordinator, mDeps.getIpServerDependencies())); diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index ce546c701a..d637c8646b 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -40,6 +40,17 @@ import java.util.ArrayList; * @hide */ public abstract class TetheringDependencies { + /** + * Get a reference to the BpfCoordinator to be used by tethering. + */ + public @NonNull BpfCoordinator getBpfCoordinator( + @NonNull Handler handler, @NonNull INetd netd, @NonNull SharedLog log, + @NonNull BpfCoordinator.Dependencies deps) { + final NetworkStatsManager statsManager = + (NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE); + return new BpfCoordinator(handler, netd, statsManager, log, deps); + } + /** * Get a reference to the offload hardware interface to be used by tethering. */ diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 0cda29a32f..433aacfaff 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -87,6 +87,7 @@ import android.text.TextUtils; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.networkstack.tethering.BpfCoordinator; import com.android.networkstack.tethering.PrivateAddressCoordinator; import org.junit.Before; @@ -126,6 +127,7 @@ public class IpServerTest { private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24"); @Mock private INetd mNetd; + @Mock private BpfCoordinator mBpfCoordinator; @Mock private IpServer.Callback mCallback; @Mock private SharedLog mSharedLog; @Mock private IDhcpServer mDhcpServer; @@ -179,7 +181,7 @@ public class IpServerTest { neighborCaptor.capture()); mIpServer = new IpServer( - IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, + IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mBpfCoordinator, mCallback, usingLegacyDhcp, usingBpfOffload, mAddressCoordinator, mDependencies); mIpServer.start(); mNeighborEventConsumer = neighborCaptor.getValue(); @@ -222,8 +224,8 @@ public class IpServerTest { when(mDependencies.getIpNeighborMonitor(any(), any(), any())) .thenReturn(mIpNeighborMonitor); mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, - mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD, - mAddressCoordinator, mDependencies); + mNetd, mBpfCoordinator, mCallback, false /* usingLegacyDhcp */, + DEFAULT_USING_BPF_OFFLOAD, mAddressCoordinator, mDependencies); mIpServer.start(); mLooper.dispatchAll(); verify(mCallback).updateInterfaceState( diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 5fffaaedd8..329d8a515c 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -203,6 +203,7 @@ public class TetheringTest { @Mock private ConnectivityManager mCm; @Mock private EthernetManager mEm; @Mock private TetheringNotificationUpdater mNotificationUpdater; + @Mock private BpfCoordinator mBpfCoordinator; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -336,6 +337,12 @@ public class TetheringTest { mIpv6CoordinatorNotifyList = null; } + @Override + public BpfCoordinator getBpfCoordinator(Handler handler, INetd netd, + SharedLog log, BpfCoordinator.Dependencies deps) { + return mBpfCoordinator; + } + @Override public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) { return mOffloadHardwareInterface; From 7997d691fe16971a0a05862614f759010cfe288f Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 7 May 2020 17:38:35 +0800 Subject: [PATCH 1159/1415] [BOT.3] Add unit test for polling network stats in the coordinator Verify that the coordinator could fetch tether stats from BPF maps and report the network stats to the service. Bug: 150736748 Test: atest BpfCoordinatorTest Change-Id: Ib1756159a2047c5db7d31359b0f288f840bd1bb1 --- .../tethering/BpfCoordinator.java | 16 +- .../tethering/BpfCoordinatorTest.java | 207 ++++++++++++++++++ 2 files changed, 218 insertions(+), 5 deletions(-) create mode 100644 Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index 0092eb7ee3..aded6cf73c 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -41,6 +41,8 @@ import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.annotations.VisibleForTesting; + /** * This coordinator is responsible for providing BPF offload relevant functionality. * - Get tethering stats. @@ -49,10 +51,11 @@ import androidx.annotation.Nullable; */ public class BpfCoordinator { private static final String TAG = BpfCoordinator.class.getSimpleName(); - // TODO: Make it customizable. - private static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; + @VisibleForTesting + static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; // TODO: Make it customizable. - private enum StatsType { + @VisibleForTesting + enum StatsType { STATS_PER_IFACE, STATS_PER_UID, } @@ -86,6 +89,7 @@ public class BpfCoordinator { maybeSchedulePollingStats(); }; + @VisibleForTesting static class Dependencies { int getPerformPollInterval() { // TODO: Consider make this configurable. @@ -169,7 +173,8 @@ public class BpfCoordinator { * A BPF tethering stats provider to provide network statistics to the system. * Note that this class's data may only be accessed on the handler thread. */ - private class BpfTetherStatsProvider extends NetworkStatsProvider { + @VisibleForTesting + class BpfTetherStatsProvider extends NetworkStatsProvider { // The offloaded traffic statistics per interface that has not been reported since the // last call to pushTetherStats. Only the interfaces that were ever tethering upstreams // and has pending tether stats delta are included in this NetworkStats object. @@ -193,7 +198,8 @@ public class BpfCoordinator { // no-op } - private void pushTetherStats() { + @VisibleForTesting + void pushTetherStats() { try { // The token is not used for now. See b/153606961. notifyStatsUpdated(0 /* token */, mIfaceStats, mUidStats); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java new file mode 100644 index 0000000000..b029b43d19 --- /dev/null +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -0,0 +1,207 @@ +/* + * 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 com.android.networkstack.tethering; + +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; +import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkStats.UID_TETHERING; + +import static com.android.networkstack.tethering.BpfCoordinator + .DEFAULT_PERFORM_POLL_INTERVAL_MS; +import static com.android.networkstack.tethering.BpfCoordinator.StatsType; +import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE; +import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID; + +import static junit.framework.Assert.assertNotNull; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.annotation.NonNull; +import android.app.usage.NetworkStatsManager; +import android.net.INetd; +import android.net.NetworkStats; +import android.net.TetherStatsParcel; +import android.net.util.SharedLog; +import android.os.Handler; +import android.os.test.TestLooper; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.TestableNetworkStatsProviderCbBinder; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class BpfCoordinatorTest { + @Mock private NetworkStatsManager mStatsManager; + @Mock private INetd mNetd; + // Late init since methods must be called by the thread that created this object. + private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb; + private BpfCoordinator.BpfTetherStatsProvider mTetherStatsProvider; + private final ArgumentCaptor mStringArrayCaptor = + ArgumentCaptor.forClass(ArrayList.class); + private final TestLooper mTestLooper = new TestLooper(); + private BpfCoordinator.Dependencies mDeps = + new BpfCoordinator.Dependencies() { + @Override + int getPerformPollInterval() { + return DEFAULT_PERFORM_POLL_INTERVAL_MS; + } + }; + + @Before public void setUp() { + MockitoAnnotations.initMocks(this); + } + + private void waitForIdle() { + mTestLooper.dispatchAll(); + } + + private void setupFunctioningNetdInterface() throws Exception { + when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]); + } + + @NonNull + private BpfCoordinator makeBpfCoordinator() throws Exception { + BpfCoordinator coordinator = new BpfCoordinator( + new Handler(mTestLooper.getLooper()), mNetd, mStatsManager, new SharedLog("test"), + mDeps); + final ArgumentCaptor + tetherStatsProviderCaptor = + ArgumentCaptor.forClass(BpfCoordinator.BpfTetherStatsProvider.class); + verify(mStatsManager).registerNetworkStatsProvider(anyString(), + tetherStatsProviderCaptor.capture()); + mTetherStatsProvider = tetherStatsProviderCaptor.getValue(); + assertNotNull(mTetherStatsProvider); + mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder(); + mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb); + return coordinator; + } + + @NonNull + private static NetworkStats.Entry buildTestEntry(@NonNull StatsType how, + @NonNull String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { + return new NetworkStats.Entry(iface, how == STATS_PER_IFACE ? UID_ALL : UID_TETHERING, + SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, + rxPackets, txBytes, txPackets, 0L); + } + + @NonNull + private static TetherStatsParcel buildTestTetherStatsParcel(@NonNull Integer ifIndex, + long rxBytes, long rxPackets, long txBytes, long txPackets) { + final TetherStatsParcel parcel = new TetherStatsParcel(); + parcel.ifIndex = ifIndex; + parcel.rxBytes = rxBytes; + parcel.rxPackets = rxPackets; + parcel.txBytes = txBytes; + parcel.txPackets = txPackets; + return parcel; + } + + private void setTetherOffloadStatsList(TetherStatsParcel[] tetherStatsList) throws Exception { + when(mNetd.tetherOffloadGetStats()).thenReturn(tetherStatsList); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + } + + @Test + public void testGetForwardedStats() throws Exception { + setupFunctioningNetdInterface(); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + coordinator.start(); + + final String wlanIface = "wlan0"; + final Integer wlanIfIndex = 100; + final String mobileIface = "rmnet_data0"; + final Integer mobileIfIndex = 101; + + // Add interface name to lookup table. In realistic case, the upstream interface name will + // be added by IpServer when IpServer has received with a new IPv6 upstream update event. + coordinator.addUpstreamNameToLookupTable(wlanIfIndex, wlanIface); + coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface); + + // [1] Both interface stats are changed. + // Setup the tether stats of wlan and mobile interface. Note that move forward the time of + // the looper to make sure the new tether stats has been updated by polling update thread. + setTetherOffloadStatsList(new TetherStatsParcel[] { + buildTestTetherStatsParcel(wlanIfIndex, 1000, 100, 2000, 200), + buildTestTetherStatsParcel(mobileIfIndex, 3000, 300, 4000, 400)}); + + final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_IFACE, wlanIface, 1000, 100, 2000, 200)) + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 3000, 300, 4000, 400)); + + final NetworkStats expectedUidStats = new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_UID, wlanIface, 1000, 100, 2000, 200)) + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 3000, 300, 4000, 400)); + + // Force pushing stats update to verify the stats reported. + // TODO: Perhaps make #expectNotifyStatsUpdated to use test TetherStatsParcel object for + // verifying the notification. + mTetherStatsProvider.pushTetherStats(); + mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStats, expectedUidStats); + + // [2] Only one interface stats is changed. + // The tether stats of mobile interface is accumulated and The tether stats of wlan + // interface is the same. + setTetherOffloadStatsList(new TetherStatsParcel[] { + buildTestTetherStatsParcel(wlanIfIndex, 1000, 100, 2000, 200), + buildTestTetherStatsParcel(mobileIfIndex, 3010, 320, 4030, 440)}); + + final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_IFACE, wlanIface, 0, 0, 0, 0)) + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 10, 20, 30, 40)); + + final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_UID, wlanIface, 0, 0, 0, 0)) + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 10, 20, 30, 40)); + + // Force pushing stats update to verify that only diff of stats is reported. + mTetherStatsProvider.pushTetherStats(); + mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStatsDiff, + expectedUidStatsDiff); + + // [3] Stop coordinator. + // Shutdown the coordinator and clear the invocation history, especially the + // tetherOffloadGetStats() calls. + coordinator.stop(); + clearInvocations(mNetd); + + // Verify the polling update thread stopped. + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + verify(mNetd, never()).tetherOffloadGetStats(); + } +} From b150b87fa95857814f6e1c37104acbbbd317f994 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Sat, 23 May 2020 22:54:49 +0800 Subject: [PATCH 1160/1415] [BOT.5] Move class Ipv6ForwardingRule from IpServer to the coordinator This is a preparation for moving adding/removing forwarding rules from IpServer to BpfCoordinator. Bug: 150736748 Test: atest IpServerTest Change-Id: I85316ef09ff3c9389ded11dcc384493d699da48e --- Tethering/src/android/net/ip/IpServer.java | 36 +--------------- .../tethering/BpfCoordinator.java | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 4d0287736c..088b88cb31 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -33,7 +33,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.RouteInfo; -import android.net.TetherOffloadRuleParcel; import android.net.TetheredClient; import android.net.TetheringManager; import android.net.TetheringRequestParcel; @@ -66,6 +65,7 @@ import com.android.internal.util.MessageUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.networkstack.tethering.BpfCoordinator; +import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule; import com.android.networkstack.tethering.PrivateAddressCoordinator; import java.io.IOException; @@ -272,40 +272,6 @@ public class IpServer extends StateMachine { } } - static class Ipv6ForwardingRule { - public final int upstreamIfindex; - public final int downstreamIfindex; - public final Inet6Address address; - public final MacAddress srcMac; - public final MacAddress dstMac; - - Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, Inet6Address address, - MacAddress srcMac, MacAddress dstMac) { - this.upstreamIfindex = upstreamIfindex; - this.downstreamIfindex = downstreamIfIndex; - this.address = address; - this.srcMac = srcMac; - this.dstMac = dstMac; - } - - public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) { - return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac, - dstMac); - } - - // Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream() - // would be error-prone due to generated stable AIDL classes not having a copy constructor. - public TetherOffloadRuleParcel toTetherOffloadRuleParcel() { - final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel(); - parcel.inputInterfaceIndex = upstreamIfindex; - parcel.outputInterfaceIndex = downstreamIfindex; - parcel.destination = address.getAddress(); - parcel.prefixLength = 128; - parcel.srcL2Address = srcMac.toByteArray(); - parcel.dstL2Address = dstMac.toByteArray(); - return parcel; - } - } private final LinkedHashMap mIpv6ForwardingRules = new LinkedHashMap<>(); diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index aded6cf73c..6b854f2ac9 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -26,8 +26,10 @@ import static android.net.NetworkStats.UID_TETHERING; import android.app.usage.NetworkStatsManager; import android.net.INetd; +import android.net.MacAddress; import android.net.NetworkStats; import android.net.NetworkStats.Entry; +import android.net.TetherOffloadRuleParcel; import android.net.TetherStatsParcel; import android.net.netstats.provider.NetworkStatsProvider; import android.net.util.SharedLog; @@ -43,6 +45,8 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import java.net.Inet6Address; + /** * This coordinator is responsible for providing BPF offload relevant functionality. * - Get tethering stats. @@ -169,6 +173,45 @@ public class BpfCoordinator { } } + /** IPv6 forwarding rule class. */ + public static class Ipv6ForwardingRule { + public final int upstreamIfindex; + public final int downstreamIfindex; + public final Inet6Address address; + public final MacAddress srcMac; + public final MacAddress dstMac; + + public Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, Inet6Address address, + MacAddress srcMac, MacAddress dstMac) { + this.upstreamIfindex = upstreamIfindex; + this.downstreamIfindex = downstreamIfIndex; + this.address = address; + this.srcMac = srcMac; + this.dstMac = dstMac; + } + + /** Return a new rule object which updates with new upstream index. */ + public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) { + return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac, + dstMac); + } + + /** + * Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream() + * would be error-prone due to generated stable AIDL classes not having a copy constructor. + */ + public TetherOffloadRuleParcel toTetherOffloadRuleParcel() { + final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel(); + parcel.inputInterfaceIndex = upstreamIfindex; + parcel.outputInterfaceIndex = downstreamIfindex; + parcel.destination = address.getAddress(); + parcel.prefixLength = 128; + parcel.srcL2Address = srcMac.toByteArray(); + parcel.dstL2Address = dstMac.toByteArray(); + return parcel; + } + } + /** * A BPF tethering stats provider to provide network statistics to the system. * Note that this class's data may only be accessed on the handler thread. From 140042db6fe1a247fc2e890cbceaadd055ecf53b Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Fri, 29 May 2020 19:30:01 +0800 Subject: [PATCH 1161/1415] Make tethering module to use netd_aidl_interface-unstable-java Use unstable aidl for new api tetherOffload* and modified parcel TetherStatsParcel in BpfCoordinator{, Test}. Bug: 150736748 Test: m Change-Id: I2d2cedf560319653f67f6b06f7abb0bf66eba91a --- Tethering/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 33c2b5828d..4116afca98 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -25,7 +25,7 @@ java_defaults { ], static_libs: [ "androidx.annotation_annotation", - "netd_aidl_interface-V3-java", + "netd_aidl_interface-unstable-java", "netlink-client", "networkstack-aidl-interfaces-java", "android.hardware.tetheroffload.config-V1.0-java", From caf797ef34475f49742e61ac2b0439f0f2c0b6ff Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 5 Feb 2020 11:02:02 -0800 Subject: [PATCH 1162/1415] Add CTS tests for ConnectivityDiagnostics callbacks. Verify that the callbacks onConnectivityReport() and onNetworkConnectivityReported() are invoked by the System when expected. ConnectivityDiagnosticsManager provides an API for registering callbacks with the System. These callbacks allow the System to notify registered and permissioned callbacks on Network validation, suspected data stalls, and Network connectivity reported. Bug: 148032944 Test: android.net.cts.ConnectivityDiagnosticsManagerTest Change-Id: I748229d41c16adf1561e03aa597d5aac00f12912 Merged-In: I748229d41c16adf1561e03aa597d5aac00f12912 (cherry picked from commit fa23ec3b252c33e4cdc3e1463d77ba279d7da144) --- .../ConnectivityDiagnosticsManagerTest.java | 232 +++++++++++++++++- 1 file changed, 221 insertions(+), 11 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 9d357055d1..6687fdcbfb 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -17,19 +17,49 @@ package android.net.cts; import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityDiagnosticsManager; +import android.net.ConnectivityManager; +import android.net.LinkAddress; +import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.os.Binder; import android.os.Build; +import android.os.IBinder; +import android.os.PersistableBundle; +import android.os.Process; +import android.util.Pair; import androidx.test.InstrumentationRegistry; +import com.android.testutils.ArrayTrackRecord; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,33 +69,71 @@ import java.util.concurrent.Executor; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q public class ConnectivityDiagnosticsManagerTest { + private static final int CALLBACK_TIMEOUT_MILLIS = 5000; + private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500; + private static final Executor INLINE_EXECUTOR = x -> x.run(); - private static final NetworkRequest DEFAULT_REQUEST = new NetworkRequest.Builder().build(); + + private static final NetworkRequest TEST_NETWORK_REQUEST = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_TEST) + .removeCapability(NET_CAPABILITY_TRUSTED) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .build(); + + // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests + // for it. + private static final TestNetworkCallback TEST_NETWORK_CALLBACK = new TestNetworkCallback(); + + private static final IBinder BINDER = new Binder(); private Context mContext; + private ConnectivityManager mConnectivityManager; private ConnectivityDiagnosticsManager mCdm; - private ConnectivityDiagnosticsCallback mCallback; + private Network mTestNetwork; @Before public void setUp() throws Exception { mContext = InstrumentationRegistry.getContext(); + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class); - mCallback = new ConnectivityDiagnosticsCallback() {}; + mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, TEST_NETWORK_CALLBACK); + } + + @After + public void tearDown() throws Exception { + mConnectivityManager.unregisterNetworkCallback(TEST_NETWORK_CALLBACK); + + if (mTestNetwork != null) { + runWithShellPermissionIdentity(() -> { + final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); + tnm.teardownTestNetwork(mTestNetwork); + }); + } } @Test - public void testRegisterConnectivityDiagnosticsCallback() { - mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback); + public void testRegisterConnectivityDiagnosticsCallback() throws Exception { + mTestNetwork = setUpTestNetwork(); + + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); } @Test public void testRegisterDuplicateConnectivityDiagnosticsCallback() { - mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback); + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); try { - mCdm.registerConnectivityDiagnosticsCallback( - DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); fail("Registering the same callback twice should throw an IllegalArgumentException"); } catch (IllegalArgumentException expected) { } @@ -73,13 +141,155 @@ public class ConnectivityDiagnosticsManagerTest { @Test public void testUnregisterConnectivityDiagnosticsCallback() { - mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback); - mCdm.unregisterConnectivityDiagnosticsCallback(mCallback); + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + mCdm.unregisterConnectivityDiagnosticsCallback(cb); } @Test public void testUnregisterUnknownConnectivityDiagnosticsCallback() { // Expected to silently ignore the unregister() call - mCdm.unregisterConnectivityDiagnosticsCallback(mCallback); + mCdm.unregisterConnectivityDiagnosticsCallback(new TestConnectivityDiagnosticsCallback()); + } + + @Test + public void testOnConnectivityReportAvailable() throws Exception { + mTestNetwork = setUpTestNetwork(); + + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); + } + + @Test + public void testOnNetworkConnectivityReportedTrue() throws Exception { + verifyOnNetworkConnectivityReported(true /* hasConnectivity */); + } + + @Test + public void testOnNetworkConnectivityReportedFalse() throws Exception { + verifyOnNetworkConnectivityReported(false /* hasConnectivity */); + } + + private void verifyOnNetworkConnectivityReported(boolean hasConnectivity) throws Exception { + mTestNetwork = setUpTestNetwork(); + + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + + // onConnectivityReportAvailable always invoked when the test network is established + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); + + mConnectivityManager.reportNetworkConnectivity(mTestNetwork, hasConnectivity); + + cb.expectOnNetworkConnectivityReported(mTestNetwork, hasConnectivity); + + // if hasConnectivity does not match the network's known connectivity, it will be + // revalidated which will trigger another onConnectivityReportAvailable callback. + if (!hasConnectivity) { + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + } + + cb.assertNoCallback(); + } + + @NonNull + private Network waitForConnectivityServiceIdleAndGetNetwork() throws InterruptedException { + // Get a new Network. This requires going through the ConnectivityService thread. Once it + // completes, all previously enqueued messages on the ConnectivityService main Handler have + // completed. + final TestNetworkCallback callback = new TestNetworkCallback(); + mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, callback); + final Network network = callback.waitForAvailable(); + mConnectivityManager.unregisterNetworkCallback(callback); + assertNotNull(network); + return network; + } + + /** + * Registers a test NetworkAgent with ConnectivityService with limited capabilities, which leads + * to the Network being validated. + */ + @NonNull + private Network setUpTestNetwork() throws Exception { + final int[] administratorUids = new int[] {Process.myUid()}; + runWithShellPermissionIdentity( + () -> { + final TestNetworkManager tnm = + mContext.getSystemService(TestNetworkManager.class); + final TestNetworkInterface tni = tnm.createTunInterface(new LinkAddress[0]); + tnm.setupTestNetwork(tni.getInterfaceName(), administratorUids, BINDER); + }); + return waitForConnectivityServiceIdleAndGetNetwork(); + } + + private static class TestConnectivityDiagnosticsCallback + extends ConnectivityDiagnosticsCallback { + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + + @Override + public void onConnectivityReportAvailable(ConnectivityReport report) { + mHistory.add(report); + } + + @Override + public void onDataStallSuspected(DataStallReport report) { + mHistory.add(report); + } + + @Override + public void onNetworkConnectivityReported(Network network, boolean hasConnectivity) { + mHistory.add(new Pair(network, hasConnectivity)); + } + + public void expectOnConnectivityReportAvailable( + @NonNull Network network, @NonNull String interfaceName) { + final ConnectivityReport result = + (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.getNetwork()); + + final NetworkCapabilities nc = result.getNetworkCapabilities(); + assertNotNull(nc); + assertTrue(nc.hasTransport(TRANSPORT_TEST)); + assertNotNull(result.getLinkProperties()); + assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); + + final PersistableBundle extras = result.getAdditionalInfo(); + assertTrue(extras.containsKey(KEY_NETWORK_VALIDATION_RESULT)); + final int validationResult = extras.getInt(KEY_NETWORK_VALIDATION_RESULT); + assertEquals("Network validation result is not 'valid'", + NETWORK_VALIDATION_RESULT_VALID, validationResult); + + assertTrue(extras.containsKey(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK)); + final int probesSucceeded = extras.getInt(KEY_NETWORK_VALIDATION_RESULT); + assertTrue("PROBES_SUCCEEDED mask not in expected range", probesSucceeded >= 0); + + assertTrue(extras.containsKey(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK)); + final int probesAttempted = extras.getInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK); + assertTrue("PROBES_ATTEMPTED mask not in expected range", probesAttempted >= 0); + } + + public void expectOnNetworkConnectivityReported( + @NonNull Network network, boolean hasConnectivity) { + final Pair result = + (Pair) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.first /* network */); + assertEquals(hasConnectivity, result.second /* hasConnectivity */); + } + + public void assertNoCallback() { + // If no more callbacks exist, there should be nothing left in the ReadHead + assertNull("Unexpected event in history", + mHistory.poll(NO_CALLBACK_INVOKED_TIMEOUT, x -> true)); + } } } From a4107118ff89217a2ffad42537797b9248daff89 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 15 Apr 2020 13:43:45 -0700 Subject: [PATCH 1163/1415] Add CTS testing for ConnectivityDiagnostics Data Stall callback. Verify that onDataStallSuspected() is invoked by the System when expected. ConnectivityDiagnosticsManager provides an API for registering callbacks with the System. These callbacks allow the System to notify registered and permissioned callbacks on Network validation, suspected data stalls, and Network connectivity reported. Bug: 148032944 Test: atest ConnectivityDiagnosticsManagerTest Change-Id: If6ceae9d2bbcabf88298d2d8c39cad5275fbd1ef Merged-In: If6ceae9d2bbcabf88298d2d8c39cad5275fbd1ef (cherry picked from commit dfcee1ac4a2843884034623601deb78b1a2d84df) --- .../ConnectivityDiagnosticsManagerTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 6687fdcbfb..8cacb4351d 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -23,6 +23,12 @@ import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_ import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID; import static android.net.ConnectivityDiagnosticsManager.DataStallReport; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_TCP_METRICS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE; +import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; import static android.net.NetworkCapabilities.TRANSPORT_TEST; @@ -71,6 +77,10 @@ import java.util.concurrent.Executor; public class ConnectivityDiagnosticsManagerTest { private static final int CALLBACK_TIMEOUT_MILLIS = 5000; private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500; + private static final long TIMESTAMP = 123456789L; + private static final int DNS_CONSECUTIVE_TIMEOUTS = 5; + private static final int COLLECTION_PERIOD_MILLIS = 5000; + private static final int FAIL_RATE_PERCENTAGE = 100; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -166,6 +176,46 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } + @Test + public void testOnDataStallSuspected_DnsEvents() throws Exception { + final PersistableBundle extras = new PersistableBundle(); + extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, DNS_CONSECUTIVE_TIMEOUTS); + + verifyOnDataStallSuspected(DETECTION_METHOD_DNS_EVENTS, TIMESTAMP, extras); + } + + @Test + public void testOnDataStallSuspected_TcpMetrics() throws Exception { + final PersistableBundle extras = new PersistableBundle(); + extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS, COLLECTION_PERIOD_MILLIS); + extras.putInt(KEY_TCP_PACKET_FAIL_RATE, FAIL_RATE_PERCENTAGE); + + verifyOnDataStallSuspected(DETECTION_METHOD_TCP_METRICS, TIMESTAMP, extras); + } + + private void verifyOnDataStallSuspected( + int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras) + throws Exception { + mTestNetwork = setUpTestNetwork(); + + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + + runWithShellPermissionIdentity( + () -> mConnectivityManager.simulateDataStall( + detectionMethod, timestampMillis, mTestNetwork, extras), + android.Manifest.permission.MANAGE_TEST_NETWORKS); + + cb.expectOnDataStallSuspected( + mTestNetwork, interfaceName, detectionMethod, timestampMillis, extras); + cb.assertNoCallback(); + } + @Test public void testOnNetworkConnectivityReportedTrue() throws Exception { verifyOnNetworkConnectivityReported(true /* hasConnectivity */); @@ -278,6 +328,27 @@ public class ConnectivityDiagnosticsManagerTest { assertTrue("PROBES_ATTEMPTED mask not in expected range", probesAttempted >= 0); } + public void expectOnDataStallSuspected( + @NonNull Network network, + @NonNull String interfaceName, + int detectionMethod, + long timestampMillis, + @NonNull PersistableBundle extras) { + final DataStallReport result = + (DataStallReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.getNetwork()); + assertEquals(detectionMethod, result.getDetectionMethod()); + assertEquals(timestampMillis, result.getReportTimestamp()); + + final NetworkCapabilities nc = result.getNetworkCapabilities(); + assertNotNull(nc); + assertTrue(nc.hasTransport(TRANSPORT_TEST)); + assertNotNull(result.getLinkProperties()); + assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); + + assertTrue(persistableBundleEquals(extras, result.getStallDetails())); + } + public void expectOnNetworkConnectivityReported( @NonNull Network network, boolean hasConnectivity) { final Pair result = From 6609fbbfe194cd81c1d409cac13c94b49ee6a902 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 15 May 2020 11:27:22 -0700 Subject: [PATCH 1164/1415] Test Data Stall with unknown detection type. This CL adds a CTS test for Data Stall events to ConnectivityDiagnostics. This makes sure that new DataStall detection methods are passed to ConnectivityDiagnostics callbacks with the appropriate detection method bit mask. Bug: 156294356 Bug: 148032944 Test: atest ConnectivityDiagnosticsManagerTest Change-Id: Id6f1bff59b08192f09ebcc4578a3c233fd1c2768 Merged-In: Id6f1bff59b08192f09ebcc4578a3c233fd1c2768 (cherry picked from commit 03278ff4593ba697acc97097d458d752f33228b3) --- .../ConnectivityDiagnosticsManagerTest.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 8cacb4351d..0248f971dc 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -81,6 +81,8 @@ public class ConnectivityDiagnosticsManagerTest { private static final int DNS_CONSECUTIVE_TIMEOUTS = 5; private static final int COLLECTION_PERIOD_MILLIS = 5000; private static final int FAIL_RATE_PERCENTAGE = 100; + private static final int UNKNOWN_DETECTION_METHOD = 4; + private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -193,9 +195,28 @@ public class ConnectivityDiagnosticsManagerTest { verifyOnDataStallSuspected(DETECTION_METHOD_TCP_METRICS, TIMESTAMP, extras); } + @Test + public void testOnDataStallSuspected_UnknownDetectionMethod() throws Exception { + verifyOnDataStallSuspected( + UNKNOWN_DETECTION_METHOD, + FILTERED_UNKNOWN_DETECTION_METHOD, + TIMESTAMP, + PersistableBundle.EMPTY); + } + private void verifyOnDataStallSuspected( int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras) throws Exception { + // Input detection method is expected to match received detection method + verifyOnDataStallSuspected(detectionMethod, detectionMethod, timestampMillis, extras); + } + + private void verifyOnDataStallSuspected( + int inputDetectionMethod, + int expectedDetectionMethod, + long timestampMillis, + @NonNull PersistableBundle extras) + throws Exception { mTestNetwork = setUpTestNetwork(); final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); @@ -208,11 +229,11 @@ public class ConnectivityDiagnosticsManagerTest { runWithShellPermissionIdentity( () -> mConnectivityManager.simulateDataStall( - detectionMethod, timestampMillis, mTestNetwork, extras), + inputDetectionMethod, timestampMillis, mTestNetwork, extras), android.Manifest.permission.MANAGE_TEST_NETWORKS); cb.expectOnDataStallSuspected( - mTestNetwork, interfaceName, detectionMethod, timestampMillis, extras); + mTestNetwork, interfaceName, expectedDetectionMethod, timestampMillis, extras); cb.assertNoCallback(); } From fec419cdd6e511525e25802395992c39b00f0c1e Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 19 May 2020 21:01:32 -0700 Subject: [PATCH 1165/1415] Extract IPsec and test network utility methods This patch moves some test setup functions to util classes in preparation for IKEv2 VPN tests which will use those same utilities. Bug: 148582947 Test: atest IpSecManagerTunnelTest; passing Change-Id: I9aeafa45ab515ce72a72c3de6f70fb26e32e7fd4 Merged-In: I9aeafa45ab515ce72a72c3de6f70fb26e32e7fd4 (cherry picked from commit 30432fa7640603c1e746b7d8c83e2e6052d8f967) --- .../net/cts/IpSecManagerTunnelTest.java | 137 ++++++------------ .../net/src/android/net/cts/PacketUtils.java | 14 ++ .../android/net/cts/util/CtsNetUtils.java | 54 +++++++ 3 files changed, 110 insertions(+), 95 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 1d83dda33c..ae38faa124 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -18,20 +18,17 @@ package android.net.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import static android.net.IpSecManager.UdpEncapsulationSocket; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; -import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; -import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; import static android.net.cts.PacketUtils.BytePayload; import static android.net.cts.PacketUtils.EspHeader; import static android.net.cts.PacketUtils.IP4_HDRLEN; import static android.net.cts.PacketUtils.IP6_HDRLEN; -import static android.net.cts.PacketUtils.Ip4Header; -import static android.net.cts.PacketUtils.Ip6Header; import static android.net.cts.PacketUtils.IpHeader; import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.net.cts.PacketUtils.UdpHeader; +import static android.net.cts.PacketUtils.getIpHeader; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; @@ -40,38 +37,28 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; -import android.app.AppOpsManager; import android.content.Context; -import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecTransform; import android.net.LinkAddress; import android.net.Network; -import android.net.NetworkRequest; import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.cts.PacketUtils.Payload; -import android.os.Binder; -import android.os.Build; -import android.os.IBinder; +import android.net.cts.util.CtsNetUtils; import android.os.ParcelFileDescriptor; -import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; -import com.android.compatibility.common.util.SystemUtil; - -import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import org.junit.AfterClass; import org.junit.Before; @@ -114,7 +101,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { private static TunUtils sTunUtils; private static Context sContext = InstrumentationRegistry.getContext(); - private static IBinder sBinder = new Binder(); + private static final CtsNetUtils mCtsNetUtils = new CtsNetUtils(sContext); @BeforeClass public static void setUpBeforeClass() throws Exception { @@ -127,7 +114,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and // a standard permission is insufficient. So we shell out the appop, to give us the // right appop permissions. - setAppop(OP_MANAGE_IPSEC_TUNNELS, true); + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, true); TestNetworkInterface testIface = sTNM.createTunInterface( @@ -137,8 +124,9 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { }); sTunFd = testIface.getFileDescriptor(); - sTunNetworkCallback = setupAndGetTestNetwork(testIface.getInterfaceName()); - sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); + sTunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName()); + sTunNetworkCallback.waitForAvailable(); + sTunNetwork = sTunNetworkCallback.currentNetwork; sTunUtils = new TunUtils(sTunFd); } @@ -149,7 +137,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { super.setUp(); // Set to true before every run; some tests flip this. - setAppop(OP_MANAGE_IPSEC_TUNNELS, true); + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, true); // Clear sTunUtils state sTunUtils.reset(); @@ -157,7 +145,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { @AfterClass public static void tearDownAfterClass() throws Exception { - setAppop(OP_MANAGE_IPSEC_TUNNELS, false); + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false); sCM.unregisterNetworkCallback(sTunNetworkCallback); @@ -169,50 +157,12 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { .dropShellPermissionIdentity(); } - private static boolean hasTunnelsFeature() { - return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - || SystemProperties.getInt("ro.product.first_api_level", 0) - >= Build.VERSION_CODES.Q; - } - - private static void setAppop(int appop, boolean allow) { - String opName = AppOpsManager.opToName(appop); - for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { - String cmd = - String.format( - "appops set %s %s %s", - pkg, // Package name - opName, // Appop - (allow ? "allow" : "deny")); // Action - SystemUtil.runShellCommand(cmd); - } - } - - private static TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception { - // Build a network request - NetworkRequest nr = - new NetworkRequest.Builder() - .clearCapabilities() - .addTransportType(TRANSPORT_TEST) - .setNetworkSpecifier(ifname) - .build(); - - TestNetworkCallback cb = new TestNetworkCallback(); - sCM.requestNetwork(nr, cb); - - // Setup the test network after network request is filed to prevent Network from being - // reaped due to no requests matching it. - sTNM.setupTestNetwork(ifname, sBinder); - - return cb; - } - @Test public void testSecurityExceptionCreateTunnelInterfaceWithoutAppop() throws Exception { - if (!hasTunnelsFeature()) return; + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); // Ensure we don't have the appop. Permission is not requested in the Manifest - setAppop(OP_MANAGE_IPSEC_TUNNELS, false); + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false); // Security exceptions are thrown regardless of IPv4/IPv6. Just test one try { @@ -224,10 +174,10 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { @Test public void testSecurityExceptionBuildTunnelTransformWithoutAppop() throws Exception { - if (!hasTunnelsFeature()) return; + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); // Ensure we don't have the appop. Permission is not requested in the Manifest - setAppop(OP_MANAGE_IPSEC_TUNNELS, false); + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false); // Security exceptions are thrown regardless of IPv4/IPv6. Just test one try (IpSecManager.SecurityParameterIndex spi = @@ -253,19 +203,6 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { public abstract int run(Network ipsecNetwork) throws Exception; } - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CompletableFuture futureNetwork = new CompletableFuture<>(); - - @Override - public void onAvailable(Network network) { - futureNetwork.complete(network); - } - - public Network getNetworkBlocking() throws Exception { - return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - } - private int getPacketSize( int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) { int expectedPacketSize = TEST_DATA.length + UDP_HDRLEN; @@ -499,8 +436,6 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { public void checkTunnelReflected( int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) throws Exception { - if (!hasTunnelsFeature()) return; - InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; @@ -580,7 +515,6 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { boolean transportInTunnelMode, IpSecTunnelTestRunnableFactory factory) throws Exception { - if (!hasTunnelsFeature()) return; InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; @@ -648,8 +582,9 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) { // Build the test network tunnelIface.addAddress(localInner, innerPrefixLen); - testNetworkCb = setupAndGetTestNetwork(tunnelIface.getInterfaceName()); - Network testNetwork = testNetworkCb.getNetworkBlocking(); + testNetworkCb = mCtsNetUtils.setupAndGetTestNetwork(tunnelIface.getInterfaceName()); + testNetworkCb.waitForAvailable(); + Network testNetwork = testNetworkCb.currentNetwork; // Check interface was created assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); @@ -718,18 +653,6 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } } - private IpHeader getIpHeader(int protocol, InetAddress src, InetAddress dst, Payload payload) { - if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { - throw new IllegalArgumentException("Invalid src/dst address combination"); - } - - if (src instanceof Inet6Address) { - return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); - } else { - return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); - } - } - private EspHeader buildTransportModeEspPacket( int spi, InetAddress src, InetAddress dst, int port, Payload payload) throws Exception { IpHeader preEspIpHeader = getIpHeader(payload.getProtocolId(), src, dst, payload); @@ -819,134 +742,158 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Transport-in-Tunnel mode tests @Test public void testTransportInTunnelModeV4InV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET, AF_INET, false, true); checkTunnelInput(AF_INET, AF_INET, false, true); } @Test public void testTransportInTunnelModeV4InV4Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET, false, true); } @Test public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET, AF_INET, true, true); checkTunnelInput(AF_INET, AF_INET, true, true); } @Test public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET, false, true); } @Test public void testTransportInTunnelModeV4InV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } @Test public void testTransportInTunnelModeV4InV6Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET, false, true); } @Test public void testTransportInTunnelModeV6InV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET6, AF_INET, false, true); checkTunnelInput(AF_INET6, AF_INET, false, true); } @Test public void testTransportInTunnelModeV6InV4Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET, false, true); } @Test public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET6, AF_INET, true, true); checkTunnelInput(AF_INET6, AF_INET, true, true); } @Test public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET, false, true); } @Test public void testTransportInTunnelModeV6InV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } @Test public void testTransportInTunnelModeV6InV6Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET, false, true); } // Tunnel mode tests @Test public void testTunnelV4InV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET, AF_INET, false, false); checkTunnelInput(AF_INET, AF_INET, false, false); } @Test public void testTunnelV4InV4Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET, false, false); } @Test public void testTunnelV4InV4UdpEncap() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET, AF_INET, true, false); checkTunnelInput(AF_INET, AF_INET, true, false); } @Test public void testTunnelV4InV4UdpEncapReflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET, true, false); } @Test public void testTunnelV4InV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET, AF_INET6, false, false); checkTunnelInput(AF_INET, AF_INET6, false, false); } @Test public void testTunnelV4InV6Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET, AF_INET6, false, false); } @Test public void testTunnelV6InV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET6, AF_INET, false, false); checkTunnelInput(AF_INET6, AF_INET, false, false); } @Test public void testTunnelV6InV4Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET6, AF_INET, false, false); } @Test public void testTunnelV6InV4UdpEncap() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET6, AF_INET, true, false); checkTunnelInput(AF_INET6, AF_INET, true, false); } @Test public void testTunnelV6InV4UdpEncapReflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET6, AF_INET, true, false); } @Test public void testTunnelV6InV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelOutput(AF_INET6, AF_INET6, false, false); checkTunnelInput(AF_INET6, AF_INET6, false, false); } @Test public void testTunnelV6InV6Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET6, AF_INET6, false, false); } } diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java index 6177827ba6..0aedecb5ad 100644 --- a/tests/cts/net/src/android/net/cts/PacketUtils.java +++ b/tests/cts/net/src/android/net/cts/PacketUtils.java @@ -27,6 +27,7 @@ import java.nio.ShortBuffer; import java.security.GeneralSecurityException; import java.security.SecureRandom; import java.util.Arrays; + import javax.crypto.Cipher; import javax.crypto.Mac; import javax.crypto.spec.IvParameterSpec; @@ -443,6 +444,19 @@ public class PacketUtils { return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); } + public static IpHeader getIpHeader( + int protocol, InetAddress src, InetAddress dst, Payload payload) { + if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { + throw new IllegalArgumentException("Invalid src/dst address combination"); + } + + if (src instanceof Inet6Address) { + return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); + } else { + return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); + } + } + /* * Debug printing */ 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 f39b184914..32cdf92144 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 @@ -20,6 +20,7 @@ import static android.Manifest.permission.NETWORK_SETTINGS; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -27,11 +28,13 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.annotation.NonNull; +import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.LinkProperties; @@ -40,7 +43,12 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; +import android.net.TestNetworkManager; import android.net.wifi.WifiManager; +import android.os.Binder; +import android.os.Build; +import android.os.IBinder; +import android.os.SystemProperties; import android.provider.Settings; import android.system.Os; import android.system.OsConstants; @@ -73,6 +81,7 @@ public final class CtsNetUtils { public static final String NETWORK_CALLBACK_ACTION = "ConnectivityManagerTest.NetworkCallbackAction"; + private final IBinder mBinder = new Binder(); private final Context mContext; private final ConnectivityManager mCm; private final ContentResolver mCR; @@ -88,6 +97,51 @@ public final class CtsNetUtils { mCR = context.getContentResolver(); } + /** Checks if FEATURE_IPSEC_TUNNELS is enabled on the device */ + public boolean hasIpsecTunnelsFeature() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + || SystemProperties.getInt("ro.product.first_api_level", 0) + >= Build.VERSION_CODES.Q; + } + + /** + * Sets the given appop using shell commands + * + *

    Expects caller to hold the shell permission identity. + */ + public void setAppopPrivileged(int appop, boolean allow) { + final String opName = AppOpsManager.opToName(appop); + for (final String pkg : new String[] {"com.android.shell", mContext.getPackageName()}) { + final String cmd = + String.format( + "appops set %s %s %s", + pkg, // Package name + opName, // Appop + (allow ? "allow" : "deny")); // Action + SystemUtil.runShellCommand(cmd); + } + } + + /** Sets up a test network using the provided interface name */ + public TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception { + // Build a network request + final NetworkRequest nr = + new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(TRANSPORT_TEST) + .setNetworkSpecifier(ifname) + .build(); + + final TestNetworkCallback cb = new TestNetworkCallback(); + mCm.requestNetwork(nr, cb); + + // Setup the test network after network request is filed to prevent Network from being + // reaped due to no requests matching it. + mContext.getSystemService(TestNetworkManager.class).setupTestNetwork(ifname, mBinder); + + return cb; + } + // Toggle WiFi twice, leaving it in the state it started in public void toggleWifi() { if (mWifiManager.isWifiEnabled()) { From bfc3ee8559a109c7f90a03468564dca07c5398f7 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 21 Apr 2020 17:01:28 -0700 Subject: [PATCH 1166/1415] Add basic tests for IKEv2/IPsec VPNs This change adds basic tests for all IKEv2/IPsec VPN public APIs. Additional testing for ensuring IKEv2 setup completes will be done in a subsequent CL. Bug: 148582947 Test: Ikev2VpnTest added Change-Id: Ia5d35c32525b32be4a0dc0584630f5bb9e7f1bcb Merged-In: Ia5d35c32525b32be4a0dc0584630f5bb9e7f1bcb (cherry picked from commit 12f571feaea736de875aebef8ad0cc70630ad6ab) --- .../net/src/android/net/cts/Ikev2VpnTest.java | 357 ++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 tests/cts/net/src/android/net/cts/Ikev2VpnTest.java diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java new file mode 100644 index 0000000000..8c1cbbb6d9 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -0,0 +1,357 @@ +/* + * 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 com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.Manifest; +import android.annotation.NonNull; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.Ikev2VpnProfile; +import android.net.IpSecAlgorithm; +import android.net.ProxyInfo; +import android.net.VpnManager; +import android.net.cts.util.CtsNetUtils; +import android.platform.test.annotations.AppModeFull; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.security.auth.x500.X500Principal; + +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "Appops state changes disallowed for instant apps (OP_ACTIVATE_PLATFORM_VPN)") +public class Ikev2VpnTest { + private static final String TAG = Ikev2VpnTest.class.getSimpleName(); + + private static final String TEST_SERVER_ADDR = "2001:db8::1"; + private static final String TEST_IDENTITY = "client.cts.android.com"; + private static final List TEST_ALLOWED_ALGORITHMS = + Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM); + + private static final ProxyInfo TEST_PROXY_INFO = + ProxyInfo.buildDirectProxy("proxy.cts.android.com", 1234); + private static final int TEST_MTU = 1300; + + private static final byte[] TEST_PSK = "ikev2".getBytes(); + private static final String TEST_USER = "username"; + private static final String TEST_PASSWORD = "pa55w0rd"; + + // Static state to reduce setup/teardown + private static final Context sContext = InstrumentationRegistry.getContext(); + private static final ConnectivityManager sCM = + (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + private static final VpnManager sVpnMgr = + (VpnManager) sContext.getSystemService(Context.VPN_MANAGEMENT_SERVICE); + private static final CtsNetUtils mCtsNetUtils = new CtsNetUtils(sContext); + + private final X509Certificate mServerRootCa; + private final CertificateAndKey mUserCertKey; + + public Ikev2VpnTest() throws Exception { + // Build certificates + mServerRootCa = generateRandomCertAndKeyPair().cert; + mUserCertKey = generateRandomCertAndKeyPair(); + } + + /** + * Sets the given appop using shell commands + * + *

    This method must NEVER be called from within a shell permission, as it will attempt to + * acquire, and then drop the shell permission identity. This results in the caller losing the + * shell permission identity due to these calls not being reference counted. + */ + public void setAppop(int appop, boolean allow) { + // Requires shell permission to update appops. + runWithShellPermissionIdentity(() -> { + mCtsNetUtils.setAppopPrivileged(appop, allow); + }, Manifest.permission.MANAGE_TEST_NETWORKS); + } + + private Ikev2VpnProfile buildIkev2VpnProfileCommon( + Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks) throws Exception { + if (isRestrictedToTestNetworks) { + builder.restrictToTestNetworks(); + } + + return builder.setBypassable(true) + .setProxy(TEST_PROXY_INFO) + .setMaxMtu(TEST_MTU) + .setMetered(false) + .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS) + .build(); + } + + private Ikev2VpnProfile buildIkev2VpnProfilePsk(boolean isRestrictedToTestNetworks) + throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY).setAuthPsk(TEST_PSK); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks) + throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY) + .setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks) + throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY) + .setAuthDigitalSignature( + mUserCertKey.cert, mUserCertKey.key, mServerRootCa); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private void checkBasicIkev2VpnProfile(@NonNull Ikev2VpnProfile profile) throws Exception { + assertEquals(TEST_SERVER_ADDR, profile.getServerAddr()); + assertEquals(TEST_IDENTITY, profile.getUserIdentity()); + assertEquals(TEST_PROXY_INFO, profile.getProxyInfo()); + assertEquals(TEST_ALLOWED_ALGORITHMS, profile.getAllowedAlgorithms()); + assertTrue(profile.isBypassable()); + assertFalse(profile.isMetered()); + assertEquals(TEST_MTU, profile.getMaxMtu()); + assertFalse(profile.isRestrictedToTestNetworks()); + } + + @Test + public void testBuildIkev2VpnProfilePsk() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertArrayEquals(TEST_PSK, profile.getPresharedKey()); + + // Verify nothing else is set. + assertNull(profile.getUsername()); + assertNull(profile.getPassword()); + assertNull(profile.getServerRootCaCert()); + assertNull(profile.getRsaPrivateKey()); + assertNull(profile.getUserCert()); + } + + @Test + public void testBuildIkev2VpnProfileUsernamePassword() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfileUsernamePassword(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertEquals(TEST_USER, profile.getUsername()); + assertEquals(TEST_PASSWORD, profile.getPassword()); + assertEquals(mServerRootCa, profile.getServerRootCaCert()); + + // Verify nothing else is set. + assertNull(profile.getPresharedKey()); + assertNull(profile.getRsaPrivateKey()); + assertNull(profile.getUserCert()); + } + + @Test + public void testBuildIkev2VpnProfileDigitalSignature() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfileDigitalSignature(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertEquals(mUserCertKey.cert, profile.getUserCert()); + assertEquals(mUserCertKey.key, profile.getRsaPrivateKey()); + assertEquals(mServerRootCa, profile.getServerRootCaCert()); + + // Verify nothing else is set. + assertNull(profile.getUsername()); + assertNull(profile.getPassword()); + assertNull(profile.getPresharedKey()); + } + + private void verifyProvisionVpnProfile( + boolean hasActivateVpn, boolean hasActivatePlatformVpn, boolean expectIntent) + throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_VPN, hasActivateVpn); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, hasActivatePlatformVpn); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + final Intent intent = sVpnMgr.provisionVpnProfile(profile); + assertEquals(expectIntent, intent != null); + } + + @Test + public void testProvisionVpnProfileNoPreviousConsent() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(false /* hasActivateVpn */, + false /* hasActivatePlatformVpn */, true /* expectIntent */); + } + + @Test + public void testProvisionVpnProfilePlatformVpnConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(false /* hasActivateVpn */, + true /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testProvisionVpnProfileVpnServiceConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(true /* hasActivateVpn */, + false /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testProvisionVpnProfileAllPreConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(true /* hasActivateVpn */, + true /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testDeleteVpnProfile() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + assertNull(sVpnMgr.provisionVpnProfile(profile)); + + // Verify that deleting the profile works (even without the appop) + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + sVpnMgr.deleteProvisionedVpnProfile(); + + // Test that the profile was deleted - starting it should throw an IAE. + try { + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + sVpnMgr.startProvisionedVpnProfile(); + fail("Expected IllegalArgumentException due to missing profile"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testStartVpnProfileNoPreviousConsent() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_VPN, false); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + + // Make sure the VpnProfile is not provisioned already. + sVpnMgr.stopProvisionedVpnProfile(); + + try { + sVpnMgr.startProvisionedVpnProfile(); + fail("Expected SecurityException for missing consent"); + } catch (SecurityException expected) { + } + } + + @Test + public void testStartStopVpnProfile() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. + runWithShellPermissionIdentity(() -> { + mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(true /* isRestrictedToTestNetworks */); + assertNull(sVpnMgr.provisionVpnProfile(profile)); + + sVpnMgr.startProvisionedVpnProfile(); + // TODO: When IKEv2 setup is injectable, verify network was set up properly. + + sVpnMgr.stopProvisionedVpnProfile(); + // TODO: When IKEv2 setup is injectable, verify network is lost. + }, Manifest.permission.MANAGE_TEST_NETWORKS); + } + + private static class CertificateAndKey { + public final X509Certificate cert; + public final PrivateKey key; + + CertificateAndKey(X509Certificate cert, PrivateKey key) { + this.cert = cert; + this.key = key; + } + } + + private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception { + final Date validityBeginDate = + new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L)); + final Date validityEndDate = + new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L)); + + // Generate a keypair + final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(512); + final KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + final X500Principal dnName = new X500Principal("CN=test.android.com"); + final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator(); + certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis())); + certGen.setSubjectDN(dnName); + certGen.setIssuerDN(dnName); + certGen.setNotBefore(validityBeginDate); + certGen.setNotAfter(validityEndDate); + certGen.setPublicKey(keyPair.getPublic()); + certGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); + + final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL"); + return new CertificateAndKey(cert, keyPair.getPrivate()); + } +} From a68fbd80f6d0d8e27870b31f8a020f1d0de0fdd3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 4 May 2020 16:13:54 -0700 Subject: [PATCH 1167/1415] Add Ikev2VpnTests including IKE negotiation. This commit expands IKEv2 VPN CTS testing to ensure that given a successful IKEv2 negotiation, the VPN network will be correctly set up. Additionally, it verifies that the stopProvisionedVpnProfile will teardown the VPN network. Bug: 148582947 Test: atest CtsNetTestCases:Ikev2VpnTest Change-Id: Ib6635f0068200ac0172515989fbdee5c3d49e231 Merged-In: Ib6635f0068200ac0172515989fbdee5c3d49e231 (cherry picked from commit 0ef85ff5a391fe81fb7d06959566d869f805f8b5) --- .../net/src/android/net/cts/IkeTunUtils.java | 188 ++++++++++++++++++ .../net/src/android/net/cts/Ikev2VpnTest.java | 147 ++++++++++++-- .../cts/net/src/android/net/cts/TunUtils.java | 97 +++++---- 3 files changed, 366 insertions(+), 66 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/IkeTunUtils.java diff --git a/tests/cts/net/src/android/net/cts/IkeTunUtils.java b/tests/cts/net/src/android/net/cts/IkeTunUtils.java new file mode 100644 index 0000000000..fc25292b27 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IkeTunUtils.java @@ -0,0 +1,188 @@ +/* + * 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.net.cts.PacketUtils.BytePayload; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.IpHeader; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.net.cts.PacketUtils.UdpHeader; +import static android.net.cts.PacketUtils.getIpHeader; +import static android.system.OsConstants.IPPROTO_UDP; + +import android.os.ParcelFileDescriptor; + +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.Arrays; + +// TODO: Merge this with the version in the IPsec module (IKEv2 library) CTS tests. +/** An extension of the TunUtils class with IKE-specific packet handling. */ +public class IkeTunUtils extends TunUtils { + private static final int PORT_LEN = 2; + + private static final byte[] NON_ESP_MARKER = new byte[] {0, 0, 0, 0}; + + private static final int IKE_HEADER_LEN = 28; + private static final int IKE_SPI_LEN = 8; + private static final int IKE_IS_RESP_BYTE_OFFSET = 19; + private static final int IKE_MSG_ID_OFFSET = 20; + private static final int IKE_MSG_ID_LEN = 4; + + public IkeTunUtils(ParcelFileDescriptor tunFd) { + super(tunFd); + } + + /** + * Await an expected IKE request and inject an IKE response. + * + * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER. + */ + public byte[] awaitReqAndInjectResp(long expectedInitIkeSpi, int expectedMsgId, + boolean encapExpected, byte[] respIkePkt) throws Exception { + final byte[] request = awaitIkePacket(expectedInitIkeSpi, expectedMsgId, encapExpected); + + // Build response header by flipping address and port + final InetAddress srcAddr = getDstAddress(request); + final InetAddress dstAddr = getSrcAddress(request); + final int srcPort = getDstPort(request); + final int dstPort = getSrcPort(request); + + final byte[] response = + buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, encapExpected, respIkePkt); + injectPacket(response); + return request; + } + + private byte[] awaitIkePacket(long expectedInitIkeSpi, int expectedMsgId, boolean expectEncap) + throws Exception { + return super.awaitPacket(pkt -> isIke(pkt, expectedInitIkeSpi, expectedMsgId, expectEncap)); + } + + private static boolean isIke( + byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, boolean encapExpected) { + final int ipProtocolOffset; + final int ikeOffset; + + if (isIpv6(pkt)) { + ipProtocolOffset = IP6_PROTO_OFFSET; + ikeOffset = IP6_HDRLEN + UDP_HDRLEN; + } else { + if (encapExpected && !hasNonEspMarkerv4(pkt)) { + return false; + } + + // Use default IPv4 header length (assuming no options) + final int encapMarkerLen = encapExpected ? NON_ESP_MARKER.length : 0; + ipProtocolOffset = IP4_PROTO_OFFSET; + ikeOffset = IP4_HDRLEN + UDP_HDRLEN + encapMarkerLen; + } + + return pkt[ipProtocolOffset] == IPPROTO_UDP + && areSpiAndMsgIdEqual(pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId); + } + + /** Checks if the provided IPv4 packet has a UDP-encapsulation NON-ESP marker */ + private static boolean hasNonEspMarkerv4(byte[] ipv4Pkt) { + final int nonEspMarkerOffset = IP4_HDRLEN + UDP_HDRLEN; + if (ipv4Pkt.length < nonEspMarkerOffset + NON_ESP_MARKER.length) { + return false; + } + + final byte[] nonEspMarker = Arrays.copyOfRange( + ipv4Pkt, nonEspMarkerOffset, nonEspMarkerOffset + NON_ESP_MARKER.length); + return Arrays.equals(NON_ESP_MARKER, nonEspMarker); + } + + private static boolean areSpiAndMsgIdEqual( + byte[] pkt, int ikeOffset, long expectedIkeInitSpi, int expectedMsgId) { + if (pkt.length <= ikeOffset + IKE_HEADER_LEN) { + return false; + } + + final ByteBuffer buffer = ByteBuffer.wrap(pkt); + final long spi = buffer.getLong(ikeOffset); + final int msgId = buffer.getInt(ikeOffset + IKE_MSG_ID_OFFSET); + + return expectedIkeInitSpi == spi && expectedMsgId == msgId; + } + + private static InetAddress getSrcAddress(byte[] pkt) throws Exception { + return getAddress(pkt, true); + } + + private static InetAddress getDstAddress(byte[] pkt) throws Exception { + return getAddress(pkt, false); + } + + private static InetAddress getAddress(byte[] pkt, boolean getSrcAddr) throws Exception { + final int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; + final int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; + final int ipOffset = getSrcAddr ? srcIpOffset : srcIpOffset + ipLen; + + if (pkt.length < ipOffset + ipLen) { + // Should be impossible; getAddress() is only called with a full IKE request including + // the IP and UDP headers. + throw new IllegalArgumentException("Packet was too short to contain IP address"); + } + + return InetAddress.getByAddress(Arrays.copyOfRange(pkt, ipOffset, ipOffset + ipLen)); + } + + private static int getSrcPort(byte[] pkt) throws Exception { + return getPort(pkt, true); + } + + private static int getDstPort(byte[] pkt) throws Exception { + return getPort(pkt, false); + } + + private static int getPort(byte[] pkt, boolean getSrcPort) { + final int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; + final int portOffset = getSrcPort ? srcPortOffset : srcPortOffset + PORT_LEN; + + if (pkt.length < portOffset + PORT_LEN) { + // Should be impossible; getPort() is only called with a full IKE request including the + // IP and UDP headers. + throw new IllegalArgumentException("Packet was too short to contain port"); + } + + final ByteBuffer buffer = ByteBuffer.wrap(pkt); + return Short.toUnsignedInt(buffer.getShort(portOffset)); + } + + private static byte[] buildIkePacket( + InetAddress srcAddr, + InetAddress dstAddr, + int srcPort, + int dstPort, + boolean useEncap, + byte[] payload) + throws Exception { + // Append non-ESP marker if encap is enabled + if (useEncap) { + final ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER.length + payload.length); + buffer.put(NON_ESP_MARKER); + buffer.put(payload); + payload = buffer.array(); + } + + final UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(payload)); + final IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt); + return ipPkt.getPacketBytes(); + } +} diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index 8c1cbbb6d9..ebce5135cf 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -16,11 +16,15 @@ package android.net.cts; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; + import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -34,7 +38,12 @@ import android.content.Intent; import android.net.ConnectivityManager; import android.net.Ikev2VpnProfile; import android.net.IpSecAlgorithm; +import android.net.LinkAddress; +import android.net.Network; +import android.net.NetworkRequest; import android.net.ProxyInfo; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; import android.net.VpnManager; import android.net.cts.util.CtsNetUtils; import android.platform.test.annotations.AppModeFull; @@ -42,12 +51,14 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.HexDump; import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; import org.junit.Test; import org.junit.runner.RunWith; import java.math.BigInteger; +import java.net.InetAddress; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; @@ -64,6 +75,45 @@ import javax.security.auth.x500.X500Principal; public class Ikev2VpnTest { private static final String TAG = Ikev2VpnTest.class.getSimpleName(); + // Test vectors for IKE negotiation in test mode. + private static final String SUCCESSFUL_IKE_INIT_RESP = + "46b8eca1e0d72a18b2b5d9006d47a0022120222000000000000002d0220000300000002c01010004030000" + + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800" + + "100000b8070f159fe5141d8754ca86f72ecc28d66f514927e96cbe9eec0adb42bf2c276a0ab7" + + "a97fa93555f4be9218c14e7f286bb28c6b4fb13825a420f2ffc165854f200bab37d69c8963d4" + + "0acb831d983163aa50622fd35c182efe882cf54d6106222abcfaa597255d302f1b95ab71c142" + + "c279ea5839a180070bff73f9d03fab815f0d5ee2adec7e409d1e35979f8bd92ffd8aab13d1a0" + + "0657d816643ae767e9ae84d2ccfa2bcce1a50572be8d3748ae4863c41ae90da16271e014270f" + + "77edd5cd2e3299f3ab27d7203f93d770bacf816041cdcecd0f9af249033979da4369cb242dd9" + + "6d172e60513ff3db02de63e50eb7d7f596ada55d7946cad0af0669d1f3e2804846ab3f2a930d" + + "df56f7f025f25c25ada694e6231abbb87ee8cfd072c8481dc0b0f6b083fdc3bd89b080e49feb" + + "0288eef6fdf8a26ee2fc564a11e7385215cf2deaf2a9965638fc279c908ccdf04094988d91a2" + + "464b4a8c0326533aff5119ed79ecbd9d99a218b44f506a5eb09351e67da86698b4c58718db25" + + "d55f426fb4c76471b27a41fbce00777bc233c7f6e842e39146f466826de94f564cad8b92bfbe" + + "87c99c4c7973ec5f1eea8795e7da82819753aa7c4fcfdab77066c56b939330c4b0d354c23f83" + + "ea82fa7a64c4b108f1188379ea0eb4918ee009d804100e6bf118771b9058d42141c847d5ec37" + + "6e5ec591c71fc9dac01063c2bd31f9c783b28bf1182900002430f3d5de3449462b31dd28bc27" + + "297b6ad169bccce4f66c5399c6e0be9120166f2900001c0000400428b8df2e66f69c8584a186" + + "c5eac66783551d49b72900001c000040054e7a622e802d5cbfb96d5f30a6e433994370173529" + + "0000080000402e290000100000402f00020003000400050000000800004014"; + private static final String SUCCESSFUL_IKE_AUTH_RESP = + "46b8eca1e0d72a18b2b5d9006d47a0022e20232000000001000000e0240000c420a2500a3da4c66fa6929e" + + "600f36349ba0e38de14f78a3ad0416cba8c058735712a3d3f9a0a6ed36de09b5e9e02697e7c4" + + "2d210ac86cfbd709503cfa51e2eab8cfdc6427d136313c072968f6506a546eb5927164200592" + + "6e36a16ee994e63f029432a67bc7d37ca619e1bd6e1678df14853067ecf816b48b81e8746069" + + "406363e5aa55f13cb2afda9dbebee94256c29d630b17dd7f1ee52351f92b6e1c3d8551c513f1" + + "d74ac52a80b2041397e109fe0aeb3c105b0d4be0ae343a943398764281"; + private static final long IKE_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); + + private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); + private static final InetAddress LOCAL_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::1"); + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 128; + + // TODO: Use IPv6 address when we can generate test vectors (GCE does not allow IPv6 yet). + private static final String TEST_SERVER_ADDR_V4 = "192.0.2.2"; private static final String TEST_SERVER_ADDR = "2001:db8::1"; private static final String TEST_IDENTITY = "client.cts.android.com"; private static final List TEST_ALLOWED_ALGORITHMS = @@ -73,7 +123,7 @@ public class Ikev2VpnTest { ProxyInfo.buildDirectProxy("proxy.cts.android.com", 1234); private static final int TEST_MTU = 1300; - private static final byte[] TEST_PSK = "ikev2".getBytes(); + private static final byte[] TEST_PSK = "ikeAndroidPsk".getBytes(); private static final String TEST_USER = "username"; private static final String TEST_PASSWORD = "pa55w0rd"; @@ -115,17 +165,22 @@ public class Ikev2VpnTest { } return builder.setBypassable(true) + .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS) .setProxy(TEST_PROXY_INFO) .setMaxMtu(TEST_MTU) .setMetered(false) - .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS) .build(); } private Ikev2VpnProfile buildIkev2VpnProfilePsk(boolean isRestrictedToTestNetworks) throws Exception { + return buildIkev2VpnProfilePsk(TEST_SERVER_ADDR, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfilePsk( + String remote, boolean isRestrictedToTestNetworks) throws Exception { final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY).setAuthPsk(TEST_PSK); + new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY).setAuthPsk(TEST_PSK); return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); } @@ -300,24 +355,84 @@ public class Ikev2VpnTest { } } + private void checkStartStopVpnProfileBuildsNetworks(IkeTunUtils tunUtils) throws Exception { + // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. + mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V4, true /* isRestrictedToTestNetworks */); + assertNull(sVpnMgr.provisionVpnProfile(profile)); + + sVpnMgr.startProvisionedVpnProfile(); + + // Inject IKE negotiation + int expectedMsgId = 0; + tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, false /* isEncap */, + HexDump.hexStringToByteArray(SUCCESSFUL_IKE_INIT_RESP)); + tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, true /* isEncap */, + HexDump.hexStringToByteArray(SUCCESSFUL_IKE_AUTH_RESP)); + + // Verify the VPN network came up + final NetworkRequest nr = new NetworkRequest.Builder() + .clearCapabilities().addTransportType(TRANSPORT_VPN).build(); + + final TestNetworkCallback cb = new TestNetworkCallback(); + sCM.requestNetwork(nr, cb); + cb.waitForAvailable(); + final Network vpnNetwork = cb.currentNetwork; + assertNotNull(vpnNetwork); + + sVpnMgr.stopProvisionedVpnProfile(); + cb.waitForLost(); + assertEquals(vpnNetwork, cb.lastLostNetwork); + } + + private void doTestStartStopVpnProfile() throws Exception { + // Non-final; these variables ensure we clean up properly after our test if we have + // allocated test network resources + final TestNetworkManager tnm = sContext.getSystemService(TestNetworkManager.class); + TestNetworkInterface testIface = null; + TestNetworkCallback tunNetworkCallback = null; + + try { + // Build underlying test network + testIface = tnm.createTunInterface( + new LinkAddress[] { + new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), + new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)}); + + // Hold on to this callback to ensure network does not get reaped. + tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName()); + final IkeTunUtils tunUtils = new IkeTunUtils(testIface.getFileDescriptor()); + + checkStartStopVpnProfileBuildsNetworks(tunUtils); + } finally { + // Make sure to stop the VPN profile. This is safe to call multiple times. + sVpnMgr.stopProvisionedVpnProfile(); + + if (testIface != null) { + testIface.getFileDescriptor().close(); + } + + if (tunNetworkCallback != null) { + sCM.unregisterNetworkCallback(tunNetworkCallback); + } + + final Network testNetwork = tunNetworkCallback.currentNetwork; + if (testNetwork != null) { + tnm.teardownTestNetwork(testNetwork); + } + } + } + @Test public void testStartStopVpnProfile() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); - // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. + // Requires shell permission to update appops. runWithShellPermissionIdentity(() -> { - mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); - - final Ikev2VpnProfile profile = - buildIkev2VpnProfilePsk(true /* isRestrictedToTestNetworks */); - assertNull(sVpnMgr.provisionVpnProfile(profile)); - - sVpnMgr.startProvisionedVpnProfile(); - // TODO: When IKEv2 setup is injectable, verify network was set up properly. - - sVpnMgr.stopProvisionedVpnProfile(); - // TODO: When IKEv2 setup is injectable, verify network is lost. - }, Manifest.permission.MANAGE_TEST_NETWORKS); + doTestStartStopVpnProfile(); + }); } private static class CertificateAndKey { diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index a0307137a5..adaba9d398 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -21,8 +21,8 @@ import static android.net.cts.PacketUtils.IP6_HDRLEN; import static android.net.cts.PacketUtils.IPPROTO_ESP; import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_UDP; + import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; import android.os.ParcelFileDescriptor; @@ -39,19 +39,18 @@ import java.util.function.Predicate; public class TunUtils { private static final String TAG = TunUtils.class.getSimpleName(); + protected static final int IP4_ADDR_OFFSET = 12; + protected static final int IP4_ADDR_LEN = 4; + protected static final int IP6_ADDR_OFFSET = 8; + protected static final int IP6_ADDR_LEN = 16; + protected static final int IP4_PROTO_OFFSET = 9; + protected static final int IP6_PROTO_OFFSET = 6; + private static final int DATA_BUFFER_LEN = 4096; - private static final int TIMEOUT = 100; + private static final int TIMEOUT = 1000; - private static final int IP4_PROTO_OFFSET = 9; - private static final int IP6_PROTO_OFFSET = 6; - - private static final int IP4_ADDR_OFFSET = 12; - private static final int IP4_ADDR_LEN = 4; - private static final int IP6_ADDR_OFFSET = 8; - private static final int IP6_ADDR_LEN = 16; - - private final ParcelFileDescriptor mTunFd; private final List mPackets = new ArrayList<>(); + private final ParcelFileDescriptor mTunFd; private final Thread mReaderThread; public TunUtils(ParcelFileDescriptor tunFd) { @@ -112,46 +111,15 @@ public class TunUtils { return null; } - /** - * Checks if the specified bytes were ever sent in plaintext. - * - *

    Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like - * - * @param plaintext the plaintext bytes to check for - * @param startIndex the index in the list to check for - */ - public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { - Predicate verifier = - (pkt) -> { - return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) - != -1; - }; - return getFirstMatchingPacket(verifier, startIndex) != null; - } - - public byte[] getEspPacket(int spi, boolean encap, int startIndex) { - return getFirstMatchingPacket( - (pkt) -> { - return isEsp(pkt, spi, encap); - }, - startIndex); - } - - public byte[] awaitEspPacketNoPlaintext( - int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + protected byte[] awaitPacket(Predicate verifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; int startIndex = 0; synchronized (mPackets) { while (System.currentTimeMillis() < endTime) { - byte[] espPkt = getEspPacket(spi, useEncap, startIndex); - if (espPkt != null) { - // Validate packet size - assertEquals(expectedPacketSize, espPkt.length); - - // Always check plaintext from start - assertFalse(hasPlaintextPacket(plaintext, 0)); - return espPkt; // We've found the packet we're looking for. + final byte[] pkt = getFirstMatchingPacket(verifier, startIndex); + if (pkt != null) { + return pkt; // We've found the packet we're looking for. } startIndex = mPackets.size(); @@ -162,10 +130,21 @@ public class TunUtils { mPackets.wait(waitTimeout); } } - - fail("No such ESP packet found with SPI " + spi); } - return null; + + fail("No packet found matching verifier"); + throw new IllegalStateException("Impossible condition; should have thrown in fail()"); + } + + public byte[] awaitEspPacketNoPlaintext( + int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + final byte[] espPkt = awaitPacket( + (pkt) -> isEspFailIfSpecifiedPlaintextFound(pkt, spi, useEncap, plaintext)); + + // Validate packet size + assertEquals(expectedPacketSize, espPkt.length); + + return espPkt; // We've found the packet we're looking for. } private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { @@ -176,6 +155,24 @@ public class TunUtils { && pkt[espOffset + 3] == (byte) (spi & 0xff); } + /** + * Variant of isEsp that also fails the test if the provided plaintext is found + * + * @param pkt the packet bytes to verify + * @param spi the expected SPI to look for + * @param encap whether encap was enabled, and the packet has a UDP header + * @param plaintext the plaintext packet before outbound encryption, which MUST not appear in + * the provided packet. + */ + private static boolean isEspFailIfSpecifiedPlaintextFound( + byte[] pkt, int spi, boolean encap, byte[] plaintext) { + if (Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) != -1) { + fail("Banned plaintext packet found"); + } + + return isEsp(pkt, spi, encap); + } + private static boolean isEsp(byte[] pkt, int spi, boolean encap) { if (isIpv6(pkt)) { // IPv6 UDP encap not supported by kernels; assume non-encap. @@ -191,7 +188,7 @@ public class TunUtils { } } - private static boolean isIpv6(byte[] pkt) { + public static boolean isIpv6(byte[] pkt) { // First nibble shows IP version. 0x60 for IPv6 return (pkt[0] & (byte) 0xF0) == (byte) 0x60; } From 1f0bdd40bd360bcb3af85cef6dcffd77a4ffe331 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 20 May 2020 01:13:18 -0700 Subject: [PATCH 1168/1415] Add IPv6 testing for IKEv2 VPN tests This change adds tests for IPv6 IKEv2 VPN profiles. Bug: 148582947 Test: IPv6 tests passing Change-Id: Ic0f71df739bd9162653b5f2878e7ddc446ddde0e Merged-In: Ic0f71df739bd9162653b5f2878e7ddc446ddde0e (cherry picked from commit e19a04da9d2ff0993af8884888bb4a327c546098) --- .../net/src/android/net/cts/Ikev2VpnTest.java | 81 ++++++++++++++----- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index ebce5135cf..5cc0cb4128 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -76,7 +76,7 @@ public class Ikev2VpnTest { private static final String TAG = Ikev2VpnTest.class.getSimpleName(); // Test vectors for IKE negotiation in test mode. - private static final String SUCCESSFUL_IKE_INIT_RESP = + private static final String SUCCESSFUL_IKE_INIT_RESP_V4 = "46b8eca1e0d72a18b2b5d9006d47a0022120222000000000000002d0220000300000002c01010004030000" + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800" + "100000b8070f159fe5141d8754ca86f72ecc28d66f514927e96cbe9eec0adb42bf2c276a0ab7" @@ -96,25 +96,53 @@ public class Ikev2VpnTest { + "297b6ad169bccce4f66c5399c6e0be9120166f2900001c0000400428b8df2e66f69c8584a186" + "c5eac66783551d49b72900001c000040054e7a622e802d5cbfb96d5f30a6e433994370173529" + "0000080000402e290000100000402f00020003000400050000000800004014"; - private static final String SUCCESSFUL_IKE_AUTH_RESP = + private static final String SUCCESSFUL_IKE_INIT_RESP_V6 = + "46b8eca1e0d72a1800d9ea1babce26bf2120222000000000000002d0220000300000002c01010004030000" + + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800" + + "100000ea0e6dd9ca5930a9a45c323a41f64bfd8cdef7730f5fbff37d7c377da427f489a42aa8" + + "c89233380e6e925990d49de35c2cdcf63a61302c731a4b3569df1ee1bf2457e55a6751838ede" + + "abb75cc63ba5c9e4355e8e784f383a5efe8a44727dc14aeaf8dacc2620fb1c8875416dc07739" + + "7fe4decc1bd514a9c7d270cf21fd734c63a25c34b30b68686e54e8a198f37f27cb491fe27235" + + "fab5476b036d875ccab9a68d65fbf3006197f9bebbf94de0d3802b4fafe1d48d931ce3a1a346" + + "2d65bd639e9bd7fa46299650a9dbaf9b324e40b466942d91a59f41ef8042f8474c4850ed0f63" + + "e9238949d41cd8bbaea9aefdb65443a6405792839563aa5dc5c36b5ce8326ccf8a94d9622b85" + + "038d390d5fc0299e14e1f022966d4ac66515f6108ca04faec44821fe5bbf2ed4f84ff5671219" + + "608cb4c36b44a31ba010c9088f8d5ff943bb9ff857f74be1755f57a5783874adc57f42bb174e" + + "4ad3215de628707014dbcb1707bd214658118fdd7a42b3e1638b991ce5b812a667f1145be811" + + "685e3cd3baf9b18d062657b64c206a4d19a531c252a6a51a04aeaf42c618620cdbab65baca23" + + "82c57ed888422aeaacf7f1bc3fe2247ff7e7eaca218b74d7b31d02f2b0afa123f802529e7e6c" + + "3259d418290740ddbf55686e26998d7edcbbf895664972fed666f2f20af40503aa2af436ec6d" + + "4ec981ab19b9088755d94ae7a7c2066ea331d4e56e290000243fefe5555fce552d57a84e682c" + + "d4a6dfb3f2f94a94464d5bec3d88b88e9559642900001c00004004eb4afff764e7b79bca78b1" + + "3a89100d36d678ae982900001c00004005d177216a3c26f782076e12570d40bfaaa148822929" + + "0000080000402e290000100000402f00020003000400050000000800004014"; + private static final String SUCCESSFUL_IKE_AUTH_RESP_V4 = "46b8eca1e0d72a18b2b5d9006d47a0022e20232000000001000000e0240000c420a2500a3da4c66fa6929e" + "600f36349ba0e38de14f78a3ad0416cba8c058735712a3d3f9a0a6ed36de09b5e9e02697e7c4" + "2d210ac86cfbd709503cfa51e2eab8cfdc6427d136313c072968f6506a546eb5927164200592" + "6e36a16ee994e63f029432a67bc7d37ca619e1bd6e1678df14853067ecf816b48b81e8746069" + "406363e5aa55f13cb2afda9dbebee94256c29d630b17dd7f1ee52351f92b6e1c3d8551c513f1" + "d74ac52a80b2041397e109fe0aeb3c105b0d4be0ae343a943398764281"; + private static final String SUCCESSFUL_IKE_AUTH_RESP_V6 = + "46b8eca1e0d72a1800d9ea1babce26bf2e20232000000001000000f0240000d4aaf6eaa6c06b50447e6f54" + + "827fd8a9d9d6ac8015c1ebb3e8cb03fc6e54b49a107441f50004027cc5021600828026367f03" + + "bc425821cd7772ee98637361300c9b76056e874fea2bd4a17212370b291894264d8c023a01d1" + + "c3b691fd4b7c0b534e8c95af4c4638e2d125cb21c6267e2507cd745d72e8da109c47b9259c6c" + + "57a26f6bc5b337b9b9496d54bdde0333d7a32e6e1335c9ee730c3ecd607a8689aa7b0577b74f" + + "3bf437696a9fd5fc0aee3ed346cd9e15d1dda293df89eb388a8719388a60ca7625754de12cdb" + + "efe4c886c5c401"; private static final long IKE_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); private static final InetAddress LOCAL_OUTER_6 = - InetAddress.parseNumericAddress("2001:db8:1::1"); + InetAddress.parseNumericAddress("2001:db8::1"); private static final int IP4_PREFIX_LEN = 32; private static final int IP6_PREFIX_LEN = 128; // TODO: Use IPv6 address when we can generate test vectors (GCE does not allow IPv6 yet). private static final String TEST_SERVER_ADDR_V4 = "192.0.2.2"; - private static final String TEST_SERVER_ADDR = "2001:db8::1"; + private static final String TEST_SERVER_ADDR_V6 = "2001:db8::2"; private static final String TEST_IDENTITY = "client.cts.android.com"; private static final List TEST_ALLOWED_ALGORITHMS = Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM); @@ -174,7 +202,7 @@ public class Ikev2VpnTest { private Ikev2VpnProfile buildIkev2VpnProfilePsk(boolean isRestrictedToTestNetworks) throws Exception { - return buildIkev2VpnProfilePsk(TEST_SERVER_ADDR, isRestrictedToTestNetworks); + return buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6, isRestrictedToTestNetworks); } private Ikev2VpnProfile buildIkev2VpnProfilePsk( @@ -188,7 +216,7 @@ public class Ikev2VpnTest { private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks) throws Exception { final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY) + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY) .setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa); return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); @@ -197,7 +225,7 @@ public class Ikev2VpnTest { private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks) throws Exception { final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR, TEST_IDENTITY) + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY) .setAuthDigitalSignature( mUserCertKey.cert, mUserCertKey.key, mServerRootCa); @@ -205,7 +233,7 @@ public class Ikev2VpnTest { } private void checkBasicIkev2VpnProfile(@NonNull Ikev2VpnProfile profile) throws Exception { - assertEquals(TEST_SERVER_ADDR, profile.getServerAddr()); + assertEquals(TEST_SERVER_ADDR_V6, profile.getServerAddr()); assertEquals(TEST_IDENTITY, profile.getUserIdentity()); assertEquals(TEST_PROXY_INFO, profile.getProxyInfo()); assertEquals(TEST_ALLOWED_ALGORITHMS, profile.getAllowedAlgorithms()); @@ -355,12 +383,18 @@ public class Ikev2VpnTest { } } - private void checkStartStopVpnProfileBuildsNetworks(IkeTunUtils tunUtils) throws Exception { + private void checkStartStopVpnProfileBuildsNetworks(IkeTunUtils tunUtils, boolean testIpv6) + throws Exception { + String serverAddr = testIpv6 ? TEST_SERVER_ADDR_V6 : TEST_SERVER_ADDR_V4; + String initResp = testIpv6 ? SUCCESSFUL_IKE_INIT_RESP_V6 : SUCCESSFUL_IKE_INIT_RESP_V4; + String authResp = testIpv6 ? SUCCESSFUL_IKE_AUTH_RESP_V6 : SUCCESSFUL_IKE_AUTH_RESP_V4; + boolean hasNat = !testIpv6; + // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); final Ikev2VpnProfile profile = - buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V4, true /* isRestrictedToTestNetworks */); + buildIkev2VpnProfilePsk(serverAddr, true /* isRestrictedToTestNetworks */); assertNull(sVpnMgr.provisionVpnProfile(profile)); sVpnMgr.startProvisionedVpnProfile(); @@ -368,9 +402,9 @@ public class Ikev2VpnTest { // Inject IKE negotiation int expectedMsgId = 0; tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, false /* isEncap */, - HexDump.hexStringToByteArray(SUCCESSFUL_IKE_INIT_RESP)); - tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, true /* isEncap */, - HexDump.hexStringToByteArray(SUCCESSFUL_IKE_AUTH_RESP)); + HexDump.hexStringToByteArray(initResp)); + tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, hasNat /* isEncap */, + HexDump.hexStringToByteArray(authResp)); // Verify the VPN network came up final NetworkRequest nr = new NetworkRequest.Builder() @@ -387,7 +421,7 @@ public class Ikev2VpnTest { assertEquals(vpnNetwork, cb.lastLostNetwork); } - private void doTestStartStopVpnProfile() throws Exception { + private void doTestStartStopVpnProfile(boolean testIpv6) throws Exception { // Non-final; these variables ensure we clean up properly after our test if we have // allocated test network resources final TestNetworkManager tnm = sContext.getSystemService(TestNetworkManager.class); @@ -402,10 +436,11 @@ public class Ikev2VpnTest { new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)}); // Hold on to this callback to ensure network does not get reaped. - tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName()); + tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork( + testIface.getInterfaceName()); final IkeTunUtils tunUtils = new IkeTunUtils(testIface.getFileDescriptor()); - checkStartStopVpnProfileBuildsNetworks(tunUtils); + checkStartStopVpnProfileBuildsNetworks(tunUtils, testIpv6); } finally { // Make sure to stop the VPN profile. This is safe to call multiple times. sVpnMgr.stopProvisionedVpnProfile(); @@ -426,12 +461,22 @@ public class Ikev2VpnTest { } @Test - public void testStartStopVpnProfile() throws Exception { + public void testStartStopVpnProfileV4() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); // Requires shell permission to update appops. runWithShellPermissionIdentity(() -> { - doTestStartStopVpnProfile(); + doTestStartStopVpnProfile(false); + }); + } + + @Test + public void testStartStopVpnProfileV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + // Requires shell permission to update appops. + runWithShellPermissionIdentity(() -> { + doTestStartStopVpnProfile(true); }); } From adac7d2cc3dd66e7293814e16b6e9a952d742cac Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Sun, 31 May 2020 11:35:50 +0100 Subject: [PATCH 1169/1415] Switch to standard naming scheme Removes use of the special framework-modules naming scheme. Bug: 155164730 Test: m java Exempt-From-Owner-Approval: Build cleanup. Change-Id: I0c31e2183353dfb5bd49f04f3455cb7b10be6866 --- Tethering/Android.bp | 2 +- Tethering/common/TetheringLib/Android.bp | 5 ----- Tethering/tests/unit/Android.bp | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index ad903e0023..93e41a3a4a 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -35,7 +35,7 @@ java_defaults { libs: [ "framework-tethering.impl", "framework-telephony-stubs", - "framework-wifi-stubs-systemapi", + "framework-wifi", "unsupportedappusage", ], plugins: ["java_api_finder"], diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 408725c865..a631a88e6f 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -20,11 +20,6 @@ java_sdk_library { ":framework-tethering-srcs", ], - // TODO(b/155480189) - Remove naming_scheme once references have been resolved. - // Temporary java_sdk_library component naming scheme to use to ease the transition from separate - // modules to java_sdk_library. - naming_scheme: "framework-modules", - jarjar_rules: "jarjar-rules.txt", installable: true, diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp index 4e3048ef06..04137145a2 100644 --- a/Tethering/tests/unit/Android.bp +++ b/Tethering/tests/unit/Android.bp @@ -61,7 +61,7 @@ java_defaults { "framework-res", "framework-telephony-stubs", "framework-tethering.impl", - "framework-wifi-stubs-module_libs_api", + "framework-wifi.stubs.module_lib", ], jni_libs: [ // For mockito extended From 539bfc16eea52a55de76ad21059153e8a725634a Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 2 Jun 2020 10:51:55 +0900 Subject: [PATCH 1170/1415] Skip Ikev2VpnTest on Q The Ikev2 VPN feature was introduced in R. Bug: 150904735 Test: atest CtsNetTestCasesLatestSdk:Ikev2VpnTest Change-Id: I51ded6e967291c110ff0bbd18a3631ab9a742e74 --- tests/cts/net/src/android/net/cts/Ikev2VpnTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index 5cc0cb4128..dff2581118 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -46,13 +46,15 @@ import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.VpnManager; import android.net.cts.util.CtsNetUtils; +import android.os.Build; import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -70,7 +72,8 @@ import java.util.concurrent.TimeUnit; import javax.security.auth.x500.X500Principal; -@RunWith(AndroidJUnit4.class) +@RunWith(DevSdkIgnoreRunner.class) +@IgnoreUpTo(Build.VERSION_CODES.Q) @AppModeFull(reason = "Appops state changes disallowed for instant apps (OP_ACTIVATE_PLATFORM_VPN)") public class Ikev2VpnTest { private static final String TAG = Ikev2VpnTest.class.getSimpleName(); From eef04c75cecbfd8ad8f40a66faa8947ce0d4afff Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 2 Jun 2020 11:01:58 +0900 Subject: [PATCH 1171/1415] Remove dependency on kotlin-reflect While local runs pass, kotlin-reflect.jar is not found on the test infrastructure. Depending on that library does not make the test much more simple. Bug: 156062304 Test: atest CtsNetTestCasesLatestSdk:CaptivePortalApiTest Change-Id: I6691a07ef8d6c63e68cb78813a5e3e499ef897df --- .../net/src/android/net/cts/CaptivePortalApiTest.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt index 40d0ca65c7..68d5281650 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt @@ -61,7 +61,6 @@ import org.junit.runner.RunWith import java.net.Inet4Address import java.util.concurrent.ArrayBlockingQueue import java.util.concurrent.TimeUnit -import kotlin.reflect.KClass import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -90,7 +89,7 @@ class CaptivePortalApiTest { private val eth by lazy { context.assertHasService(EthernetManager::class.java) } private val cm by lazy { context.assertHasService(ConnectivityManager::class.java) } - private val handlerThread = HandlerThread(CaptivePortalApiTest::class.simpleName) + private val handlerThread = HandlerThread(CaptivePortalApiTest::class.java.simpleName) private val serverIpAddr = InetAddresses.parseNumericAddress("192.0.2.222") as Inet4Address private val clientIpAddr = InetAddresses.parseNumericAddress("192.0.2.111") as Inet4Address private val httpServer = HttpServer() @@ -155,11 +154,11 @@ class CaptivePortalApiTest { fun testApiCallbacks() { // Handle the DHCP handshake that includes the capport API URL val discover = reader.assertDhcpPacketReceived( - DhcpDiscoverPacket::class, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER) + DhcpDiscoverPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER) reader.sendResponse(makeOfferPacket(discover.clientMac, discover.transactionId)) val request = reader.assertDhcpPacketReceived( - DhcpRequestPacket::class, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_REQUEST) + DhcpRequestPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_REQUEST) assertEquals(discover.transactionId, request.transactionId) assertEquals(clientIpAddr, request.mRequestedIp) reader.sendResponse(makeAckPacket(request.clientMac, request.transactionId)) @@ -244,7 +243,7 @@ private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) } private fun TapPacketReader.assertDhcpPacketReceived( - packetType: KClass, + packetType: Class, timeoutMs: Long, type: Byte ): T { @@ -254,7 +253,7 @@ private fun TapPacketReader.assertDhcpPacketReceived( val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2) assertTrue(packetType.isInstance(packet), "Expected ${packetType.simpleName} but got ${packet.javaClass.simpleName}") - return packetType.java.cast(packet) + return packetType.cast(packet) } private fun Context.assertHasService(manager: Class): T { From caee6ff9cb138e42c924ca4608c4552e4aef251a Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 2 Jun 2020 03:07:47 +0000 Subject: [PATCH 1172/1415] Fix TetheringManagerTest failure when using entitlement required SIM If run tethering cts with entitlement required SIM, the test would failure due to no tethering upstream. Tethering would default start with UI base entitlement check which would have interfactive UI pop up. Tethering's upstream is blocked because entitlement UI is keep waiting for action till timeout. To avoid UI interaction, start tethering with silent entitlement check. Bug: 156714671 Test: atest CtsTetheringTest Merged-In: I85299841d60afba97ffcc4ae908a85e51139319b Change-Id: I85299841d60afba97ffcc4ae908a85e51139319b --- .../android/tethering/cts/TetheringManagerTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 10555312f7..f7160dd502 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -286,8 +286,9 @@ public class TetheringManagerTest { assertTrue(tetheredIfaces.length == 0); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), - c -> c.run() /* executor */, startTetheringCallback); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) + .setShouldShowEntitlementUi(false).build(); + mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.verifyTetheringStarted(); mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); @@ -529,8 +530,9 @@ public class TetheringManagerTest { assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), - c -> c.run() /* executor */, startTetheringCallback); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) + .setShouldShowEntitlementUi(false).build(); + mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.verifyTetheringStarted(); callback.expectTetheredInterfacesChanged(wifiRegexs); From 2a8d380f404223926e4ebf7f455a71ded13b2ed3 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Tue, 2 Jun 2020 11:36:56 +0100 Subject: [PATCH 1173/1415] Clean up the visibility rules for framework modules Switching from java_library to java_sdk_library switched the meaning of the module name from referring to the implementation library to referring to the stubs. This change updates the visibility rules to reflect that new meaning. Visibility rules that were previously set for the java_library have been moved to the impl_library_visibility property and the special //visibility:override value has been prepended to prevent it from inheriting the values from the visibility property. Visibility rules set for the stubs (via stubs_library_visibility) property have been moved to the visibility property. Bug: 155164730 Test: m nothing Exempt-From-Owner-Approval: Build cleanup Change-Id: Icc9bc5a9ef86cf7ba0f15c2b2a4abd596ec9f640 Merged-In: Icc9bc5a9ef86cf7ba0f15c2b2a4abd596ec9f640 (cherry picked from a17cf677b5fe58ddec610ffd92f7b1b378785232) --- Tethering/common/TetheringLib/Android.bp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 408725c865..6c05b11258 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -16,6 +16,16 @@ java_sdk_library { name: "framework-tethering", defaults: ["framework-module-defaults"], + + // Allow access to the stubs from anywhere. + visibility: ["//visibility:public"], + + // Restrict access to implementation library. + impl_library_visibility: [ + "//visibility:override", // Ignore the visibility property. + "//frameworks/base/packages/Tethering:__subpackages__", + ], + srcs: [ ":framework-tethering-srcs", ], @@ -29,8 +39,6 @@ java_sdk_library { installable: true, hostdex: true, // for hiddenapi check - visibility: ["//frameworks/base/packages/Tethering:__subpackages__"], - stubs_library_visibility: ["//visibility:public"], apex_available: ["com.android.tethering"], permitted_packages: ["android.net"], } From dfc7fb7f758c4799966b89a3827f56db6388bcbb Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Tue, 2 Jun 2020 11:41:13 +0100 Subject: [PATCH 1174/1415] Switch to standard naming scheme Removes use of the special framework-modules naming scheme. Bug: 155164730 Test: m java Exempt-From-Owner-Approval: Build cleanup. Change-Id: I3896d7c91e937f503b49f5df011c21ee51219652 Merged-In: I0c31e2183353dfb5bd49f04f3455cb7b10be6866 Merged-In: I3b78fcbcacc3df787e171d6eedeef1e51b087615 (cherry picked from adac7d2cc3dd66e7293814e16b6e9a952d742cac) --- Tethering/common/TetheringLib/Android.bp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 6c05b11258..c8becce7be 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -30,11 +30,6 @@ java_sdk_library { ":framework-tethering-srcs", ], - // TODO(b/155480189) - Remove naming_scheme once references have been resolved. - // Temporary java_sdk_library component naming scheme to use to ease the transition from separate - // modules to java_sdk_library. - naming_scheme: "framework-modules", - jarjar_rules: "jarjar-rules.txt", installable: true, From 2bc22844e8c8deab8d956be1c1bc6395dbd733b7 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 3 Jun 2020 00:38:34 +0000 Subject: [PATCH 1175/1415] Skip Ikev2VpnTest on Q The Ikev2 VPN feature was introduced in R. Bug: 150904735 Test: atest CtsNetTestCasesLatestSdk:Ikev2VpnTest Original-Change: https://android-review.googlesource.com/1322414 Merged-In: I51ded6e967291c110ff0bbd18a3631ab9a742e74 Change-Id: I51ded6e967291c110ff0bbd18a3631ab9a742e74 --- tests/cts/net/src/android/net/cts/Ikev2VpnTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index 5cc0cb4128..dff2581118 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -46,13 +46,15 @@ import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.VpnManager; import android.net.cts.util.CtsNetUtils; +import android.os.Build; import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -70,7 +72,8 @@ import java.util.concurrent.TimeUnit; import javax.security.auth.x500.X500Principal; -@RunWith(AndroidJUnit4.class) +@RunWith(DevSdkIgnoreRunner.class) +@IgnoreUpTo(Build.VERSION_CODES.Q) @AppModeFull(reason = "Appops state changes disallowed for instant apps (OP_ACTIVATE_PLATFORM_VPN)") public class Ikev2VpnTest { private static final String TAG = Ikev2VpnTest.class.getSimpleName(); From 6566ca3d0aed16d54eb531255b81de298870cd99 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Wed, 3 Jun 2020 00:38:46 +0000 Subject: [PATCH 1176/1415] Remove dependency on kotlin-reflect While local runs pass, kotlin-reflect.jar is not found on the test infrastructure. Depending on that library does not make the test much more simple. Bug: 156062304 Test: atest CtsNetTestCasesLatestSdk:CaptivePortalApiTest Original-Change: https://android-review.googlesource.com/1322415 Merged-In: I6691a07ef8d6c63e68cb78813a5e3e499ef897df Change-Id: I6691a07ef8d6c63e68cb78813a5e3e499ef897df --- .../net/src/android/net/cts/CaptivePortalApiTest.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt index 40d0ca65c7..68d5281650 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt @@ -61,7 +61,6 @@ import org.junit.runner.RunWith import java.net.Inet4Address import java.util.concurrent.ArrayBlockingQueue import java.util.concurrent.TimeUnit -import kotlin.reflect.KClass import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -90,7 +89,7 @@ class CaptivePortalApiTest { private val eth by lazy { context.assertHasService(EthernetManager::class.java) } private val cm by lazy { context.assertHasService(ConnectivityManager::class.java) } - private val handlerThread = HandlerThread(CaptivePortalApiTest::class.simpleName) + private val handlerThread = HandlerThread(CaptivePortalApiTest::class.java.simpleName) private val serverIpAddr = InetAddresses.parseNumericAddress("192.0.2.222") as Inet4Address private val clientIpAddr = InetAddresses.parseNumericAddress("192.0.2.111") as Inet4Address private val httpServer = HttpServer() @@ -155,11 +154,11 @@ class CaptivePortalApiTest { fun testApiCallbacks() { // Handle the DHCP handshake that includes the capport API URL val discover = reader.assertDhcpPacketReceived( - DhcpDiscoverPacket::class, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER) + DhcpDiscoverPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER) reader.sendResponse(makeOfferPacket(discover.clientMac, discover.transactionId)) val request = reader.assertDhcpPacketReceived( - DhcpRequestPacket::class, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_REQUEST) + DhcpRequestPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_REQUEST) assertEquals(discover.transactionId, request.transactionId) assertEquals(clientIpAddr, request.mRequestedIp) reader.sendResponse(makeAckPacket(request.clientMac, request.transactionId)) @@ -244,7 +243,7 @@ private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) } private fun TapPacketReader.assertDhcpPacketReceived( - packetType: KClass, + packetType: Class, timeoutMs: Long, type: Byte ): T { @@ -254,7 +253,7 @@ private fun TapPacketReader.assertDhcpPacketReceived( val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2) assertTrue(packetType.isInstance(packet), "Expected ${packetType.simpleName} but got ${packet.javaClass.simpleName}") - return packetType.java.cast(packet) + return packetType.cast(packet) } private fun Context.assertHasService(manager: Class): T { From f99d2a103d5bc971ede2b233f33e46dd1c3a603c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 03:21:31 -0700 Subject: [PATCH 1177/1415] Stop reducing RA advertised ipv6 mtu by 16 - not needed. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This effectively reverts: commit da0fb1bca8eda1ce8159289a2ea9e4f6933ce517 Author: Maciej Żenczykowski Date: Wed Feb 19 01:24:39 2020 -0800 Reduce advertised ipv6 mtu by 16 to fit ethernet header This is a temporary hack to workaround the inability of current kernel's ebpf bpf_skb_change_mode() function to prefix a 14-byte ethernet header on to a packet without going over the upstream (source, rawip) interface's mtu *before* we bpf_redirect() to the downstream (destination, ethernet) interface. Test: build, atest, atest TetheringTests Bug: 149816401 Test: flashed a flame with new kernel and it works at 1500 mtu Bug: 149816401 Signed-off-by: Maciej Żenczykowski Change-Id: I76a75a16fa27b47d78816b2f9379ef4bb68beb00 Merged-In: I76a75a16fa27b47d78816b2f9379ef4bb68beb00 --- Tethering/src/android/net/ip/IpServer.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index f08429bb06..3fd9ee9a33 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -730,12 +730,7 @@ public class IpServer extends StateMachine { final String upstreamIface = v6only.getInterfaceName(); params = new RaParams(); - // When BPF offload is enabled, we advertise an mtu lower by 16, which is the closest - // multiple of 8 >= 14, the ethernet header size. This makes kernel ebpf tethering - // offload happy. This hack should be reverted once we have the kernel fixed up. - // Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu) - // see RouterAdvertisementDaemon.java putMtu() - params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu(); + params.mtu = v6only.getMtu(); params.hasDefaultRoute = v6only.hasIpv6DefaultRoute(); if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment); From 7deca3e618b0395f91840ce5f1a438982098c967 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 3 Jun 2020 11:01:13 +0900 Subject: [PATCH 1178/1415] Fix CtsNetUtils connectTo/disconnectFromWifi connectToWifi needs to clear the wifi networks blacklist before calling reconnect(), otherwise wifi may not reconnect if the previous network was blacklisted. disconnectFromWifi should not wait for a onLost callback if wifi was already disconnected. Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest Test: atest CtsNetApi23TestCases Bug: 150949391 Change-Id: I244b91bdd8708694fce9f10d92b8b6646d28188f --- tests/cts/net/api23Test/AndroidManifest.xml | 3 ++ .../android/net/cts/util/CtsNetUtils.java | 38 ++++++++++++++----- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/api23Test/AndroidManifest.xml b/tests/cts/net/api23Test/AndroidManifest.xml index 8af87f6011..4889660b97 100644 --- a/tests/cts/net/api23Test/AndroidManifest.xml +++ b/tests/cts/net/api23Test/AndroidManifest.xml @@ -18,8 +18,11 @@ + + + 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 32cdf92144..b1f3602950 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 @@ -30,8 +30,8 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.BroadcastReceiver; -import android.content.Context; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; @@ -44,6 +44,8 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.TestNetworkManager; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Build; @@ -169,6 +171,7 @@ public final class CtsNetUtils { boolean connected = false; try { + clearWifiBlacklist(); SystemUtil.runShellCommand("svc wifi enable"); SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(), NETWORK_SETTINGS); @@ -188,11 +191,23 @@ public final class CtsNetUtils { return wifiNetwork; } + /** + * Re-enable wifi networks that were blacklisted, typically because no internet connection was + * detected the last time they were connected. This is necessary to make sure wifi can reconnect + * to them. + */ + private void clearWifiBlacklist() { + SystemUtil.runWithShellPermissionIdentity(() -> { + for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) { + mWifiManager.enableNetwork(config.networkId, false /* attemptConnect */); + } + }); + } + /** Disable WiFi and wait for it to become disconnected from the network. */ public void disconnectFromWifi(Network wifiNetworkToCheck) { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network lostWifiNetwork = null; ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); @@ -200,9 +215,15 @@ public final class CtsNetUtils { filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(receiver, filter); + final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + final boolean wasWifiConnected = wifiInfo != null && wifiInfo.getNetworkId() != -1; // Assert that we can establish a TCP connection on wifi. Socket wifiBoundSocket = null; if (wifiNetworkToCheck != null) { + assertTrue("Cannot check network " + wifiNetworkToCheck + ": wifi is not connected", + wasWifiConnected); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(wifiNetworkToCheck); + assertNotNull("Network " + wifiNetworkToCheck + " is not connected", nc); try { wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); testHttpRequest(wifiBoundSocket); @@ -211,13 +232,14 @@ public final class CtsNetUtils { } } - boolean disconnected = false; try { SystemUtil.runShellCommand("svc wifi disable"); - // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. - lostWifiNetwork = callback.waitForLost(); - assertNotNull(lostWifiNetwork); - disconnected = receiver.waitForState(); + if (wasWifiConnected) { + // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. + assertNotNull("Did not receive onLost callback after disabling wifi", + callback.waitForLost()); + assertTrue("Wifi failed to reach DISCONNECTED state.", receiver.waitForState()); + } } catch (InterruptedException ex) { fail("disconnectFromWifi was interrupted"); } finally { @@ -225,8 +247,6 @@ public final class CtsNetUtils { mContext.unregisterReceiver(receiver); } - assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); - // Check that the socket is closed when wifi disconnects. if (wifiBoundSocket != null) { try { From 9503eb2065b1915663d5ea931daf6a032b73060f Mon Sep 17 00:00:00 2001 From: Ashwini Oruganti Date: Fri, 29 May 2020 16:14:30 -0700 Subject: [PATCH 1179/1415] Add an exported flag in manifest With b/150232615, we will need an explicit value set for the exported flag when intent filters are present, as the default behavior is changing for future versions. This change adds the value reflecting the previous default to the manifest. These changes were made using an automated tool, the xml file may be reformatted slightly creating a larger diff. The only "real" change is the addition of "android:exported" to activities, services, and receivers that have one or more intent-filters. Bug: 150232615 Test: TH Exempt-From-Owner-Approval: mechanical refactoring Change-Id: Id54ddf286cf8a2b002ead8e555d0a4aaee29cf1a --- tests/cts/hostside/app/AndroidManifest.xml | 40 +++++++-------- tests/cts/hostside/app2/AndroidManifest.xml | 51 ++++++++++--------- tests/cts/net/api23Test/AndroidManifest.xml | 16 +++--- tests/cts/net/appForApi23/AndroidManifest.xml | 24 ++++----- 4 files changed, 68 insertions(+), 63 deletions(-) diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index 3940de4240..e5bae5fdc0 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -15,42 +15,42 @@ --> + package="com.android.cts.net.hostside"> - - - - - - - + + + + + + + - - - + + + + android:permission="android.permission.BIND_VPN_SERVICE" + android:exported="true"> - + - + - + diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml index ad270b3170..eb777f2e31 100644 --- a/tests/cts/hostside/app2/AndroidManifest.xml +++ b/tests/cts/hostside/app2/AndroidManifest.xml @@ -16,38 +16,43 @@ --> + package="com.android.cts.net.hostside.app2"> - + - + + This application also provides a service, RemoteSocketFactoryService, that the test app can + use to open sockets to remote hosts as a different user ID. + --> - - - - + + + + - + - - - - - - + + + + + + diff --git a/tests/cts/net/api23Test/AndroidManifest.xml b/tests/cts/net/api23Test/AndroidManifest.xml index 4889660b97..69ee0dd87b 100644 --- a/tests/cts/net/api23Test/AndroidManifest.xml +++ b/tests/cts/net/api23Test/AndroidManifest.xml @@ -16,7 +16,7 @@ --> + package="android.net.cts.api23test"> @@ -26,20 +26,20 @@ - + - + - + + android:targetPackage="android.net.cts.api23test" + android:label="CTS tests of android.net"> + android:value="com.android.cts.runner.CtsTestRunListener"/> - diff --git a/tests/cts/net/appForApi23/AndroidManifest.xml b/tests/cts/net/appForApi23/AndroidManifest.xml index ed4cedbc1d..158b9c41f1 100644 --- a/tests/cts/net/appForApi23/AndroidManifest.xml +++ b/tests/cts/net/appForApi23/AndroidManifest.xml @@ -16,32 +16,32 @@ --> + package="android.net.cts.appForApi23"> - - - + + + - + - + - + + android:label="ConnectivityListeningActivity" + android:exported="true"> - - + + - From d1c80d7e2096f14909c9f383a7927e7467657529 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Wed, 3 Jun 2020 07:54:49 +0000 Subject: [PATCH 1180/1415] Fix CtsNetUtils connectTo/disconnectFromWifi connectToWifi needs to clear the wifi networks blacklist before calling reconnect(), otherwise wifi may not reconnect if the previous network was blacklisted. disconnectFromWifi should not wait for a onLost callback if wifi was already disconnected. Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest Test: atest CtsNetApi23TestCases Bug: 150949391 Original-Change: https://android-review.googlesource.com/1322428 Merged-In: I244b91bdd8708694fce9f10d92b8b6646d28188f Change-Id: I244b91bdd8708694fce9f10d92b8b6646d28188f --- tests/cts/net/api23Test/AndroidManifest.xml | 3 ++ .../android/net/cts/util/CtsNetUtils.java | 38 ++++++++++++++----- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/api23Test/AndroidManifest.xml b/tests/cts/net/api23Test/AndroidManifest.xml index 8af87f6011..4889660b97 100644 --- a/tests/cts/net/api23Test/AndroidManifest.xml +++ b/tests/cts/net/api23Test/AndroidManifest.xml @@ -18,8 +18,11 @@ + + + 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 32cdf92144..b1f3602950 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 @@ -30,8 +30,8 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.BroadcastReceiver; -import android.content.Context; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; @@ -44,6 +44,8 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.TestNetworkManager; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Build; @@ -169,6 +171,7 @@ public final class CtsNetUtils { boolean connected = false; try { + clearWifiBlacklist(); SystemUtil.runShellCommand("svc wifi enable"); SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(), NETWORK_SETTINGS); @@ -188,11 +191,23 @@ public final class CtsNetUtils { return wifiNetwork; } + /** + * Re-enable wifi networks that were blacklisted, typically because no internet connection was + * detected the last time they were connected. This is necessary to make sure wifi can reconnect + * to them. + */ + private void clearWifiBlacklist() { + SystemUtil.runWithShellPermissionIdentity(() -> { + for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) { + mWifiManager.enableNetwork(config.networkId, false /* attemptConnect */); + } + }); + } + /** Disable WiFi and wait for it to become disconnected from the network. */ public void disconnectFromWifi(Network wifiNetworkToCheck) { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network lostWifiNetwork = null; ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); @@ -200,9 +215,15 @@ public final class CtsNetUtils { filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(receiver, filter); + final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + final boolean wasWifiConnected = wifiInfo != null && wifiInfo.getNetworkId() != -1; // Assert that we can establish a TCP connection on wifi. Socket wifiBoundSocket = null; if (wifiNetworkToCheck != null) { + assertTrue("Cannot check network " + wifiNetworkToCheck + ": wifi is not connected", + wasWifiConnected); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(wifiNetworkToCheck); + assertNotNull("Network " + wifiNetworkToCheck + " is not connected", nc); try { wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); testHttpRequest(wifiBoundSocket); @@ -211,13 +232,14 @@ public final class CtsNetUtils { } } - boolean disconnected = false; try { SystemUtil.runShellCommand("svc wifi disable"); - // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. - lostWifiNetwork = callback.waitForLost(); - assertNotNull(lostWifiNetwork); - disconnected = receiver.waitForState(); + if (wasWifiConnected) { + // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. + assertNotNull("Did not receive onLost callback after disabling wifi", + callback.waitForLost()); + assertTrue("Wifi failed to reach DISCONNECTED state.", receiver.waitForState()); + } } catch (InterruptedException ex) { fail("disconnectFromWifi was interrupted"); } finally { @@ -225,8 +247,6 @@ public final class CtsNetUtils { mContext.unregisterReceiver(receiver); } - assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); - // Check that the socket is closed when wifi disconnects. if (wifiBoundSocket != null) { try { From abf0c1d1e68e1e92d4c3a566ff7744e0c7a0c3a0 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 4 Jun 2020 12:52:31 +0800 Subject: [PATCH 1181/1415] Reset vpn provision status The vpn status of cts app is updated to be consented in this tests which will impact the following test related to vpn. Thus, reset the status after finishing the test. Bug: 153760253 Test: atest CtsNetTestCasesLatestSdk Change-Id: I4856cfc7ddfd70125c513a4201132256704d1a66 --- tests/cts/net/src/android/net/cts/Ikev2VpnTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index 5cc0cb4128..2fa51233d1 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -54,6 +54,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; +import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -172,6 +173,12 @@ public class Ikev2VpnTest { mUserCertKey = generateRandomCertAndKeyPair(); } + @After + public void tearDown() { + setAppop(AppOpsManager.OP_ACTIVATE_VPN, false); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + } + /** * Sets the given appop using shell commands * From f33b6ea26108fcd1fca02d13318907c53ebc8c52 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 3 Jun 2020 16:10:43 +0900 Subject: [PATCH 1182/1415] Add CtsNetTestCasesLatestSdk to postsubmit Also exclude some tests that cannot run on cuttlefish. This is a first step to add the suite to presubmit. Having the test in presubmit is essential to avoid regressions and keep it passing. Bug: 158153057 Test: m CtsNetTestCases; this patch will provide postsubmit results Change-Id: I48b2b5490d3fd5eb6f9456825c11f3fee0ec5b67 --- tests/cts/net/Android.bp | 1 + tests/cts/net/TEST_MAPPING | 13 +++++++++++++ .../android/net/cts/ConnectivityManagerTest.java | 6 ++++++ tests/cts/net/src/android/net/cts/DnsTest.java | 3 +++ 4 files changed, 23 insertions(+) create mode 100644 tests/cts/net/TEST_MAPPING diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 82b7413fbf..052ab263d2 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -82,6 +82,7 @@ android_test { min_sdk_version: "29", target_sdk_version: "29", test_suites: [ + "device-tests", "mts", ], test_config_template: "AndroidTestTemplate.xml", diff --git a/tests/cts/net/TEST_MAPPING b/tests/cts/net/TEST_MAPPING new file mode 100644 index 0000000000..e2a9c75778 --- /dev/null +++ b/tests/cts/net/TEST_MAPPING @@ -0,0 +1,13 @@ +{ + // TODO: move to mainline-presubmit once supported + "postsubmit": [ + { + "name": "CtsNetTestCasesLatestSdk", + "options": [ + { + "exclude-annotation": "com.android.testutils.SkipPresubmit" + } + ] + } + ] +} diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index d498ed9885..3880664827 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -96,6 +96,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.ArrayUtils; +import com.android.testutils.SkipPresubmit; import libcore.io.Streams; @@ -325,6 +326,7 @@ public class ConnectivityManagerTest { */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + @SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks") public void testOpenConnection() throws Exception { boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); @@ -990,6 +992,7 @@ public class ConnectivityManagerTest { @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") public void testCreateTcpKeepalive() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi"); @@ -1199,6 +1202,7 @@ public class ConnectivityManagerTest { */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") public void testSocketKeepaliveLimitWifi() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device" @@ -1252,6 +1256,7 @@ public class ConnectivityManagerTest { */ @AppModeFull(reason = "Cannot request network in instant app mode") @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") public void testSocketKeepaliveLimitTelephony() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" @@ -1294,6 +1299,7 @@ public class ConnectivityManagerTest { */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") public void testSocketKeepaliveUnprivileged() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device" diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index 746dcb0a1c..fde27e9f12 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -27,6 +27,8 @@ import android.os.SystemClock; import android.test.AndroidTestCase; import android.util.Log; +import com.android.testutils.SkipPresubmit; + import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -68,6 +70,7 @@ public class DnsTest extends AndroidTestCase { * Perf - measure size of first and second tier caches and their effect * Assert requires network permission */ + @SkipPresubmit(reason = "IPv6 support may be missing on presubmit virtual hardware") public void testDnsWorks() throws Exception { ensureIpv6Connectivity(); From 072e96ebdfcf8870dcc95d8abc5284cdd8d86886 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 5 Jun 2020 10:25:38 +0800 Subject: [PATCH 1183/1415] Enlarge the onAvailable callback timeout to 30 seconds Sometimes the device may take a long time to connect to the wifi, try to enlarge the timeout to lower the fail rate of test. Bug: 157391946 Test: atest CtsHostsideNetworkTests:com.android.cts.net.HostsideNetworkCallbackTests Change-Id: Ie89936ecc2d70ee22dd312067ccedd2523e81855 --- .../src/com/android/cts/net/hostside/NetworkCallbackTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index f3cd8a9772..aa59959994 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -83,6 +83,7 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } private class TestNetworkCallback extends INetworkCallback.Stub { + private static final int TEST_CONNECT_TIMEOUT_MS = 30_000; private static final int TEST_CALLBACK_TIMEOUT_MS = 5_000; private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); @@ -131,7 +132,7 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } public Network expectAvailableCallbackAndGetNetwork() { - final CallbackInfo cb = nextCallback(TEST_CALLBACK_TIMEOUT_MS); + final CallbackInfo cb = nextCallback(TEST_CONNECT_TIMEOUT_MS); if (cb.state != CallbackState.AVAILABLE) { fail("Network is not available. Instead obtained the following callback :" + cb); From f0a78c385d25190b064b69fdee84e94fef085174 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Fri, 5 Jun 2020 05:00:18 +0000 Subject: [PATCH 1184/1415] Add CtsNetTestCasesLatestSdk to postsubmit Also exclude some tests that cannot run on cuttlefish. This is a first step to add the suite to presubmit. Having the test in presubmit is essential to avoid regressions and keep it passing. Bug: 158153057 Test: m CtsNetTestCases; this patch will provide postsubmit results Original-Change: https://android-review.googlesource.com/1322430 Merged-In: I48b2b5490d3fd5eb6f9456825c11f3fee0ec5b67 Change-Id: I48b2b5490d3fd5eb6f9456825c11f3fee0ec5b67 --- tests/cts/net/Android.bp | 1 + tests/cts/net/TEST_MAPPING | 13 +++++++++++++ .../android/net/cts/ConnectivityManagerTest.java | 6 ++++++ tests/cts/net/src/android/net/cts/DnsTest.java | 3 +++ 4 files changed, 23 insertions(+) create mode 100644 tests/cts/net/TEST_MAPPING diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 82b7413fbf..052ab263d2 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -82,6 +82,7 @@ android_test { min_sdk_version: "29", target_sdk_version: "29", test_suites: [ + "device-tests", "mts", ], test_config_template: "AndroidTestTemplate.xml", diff --git a/tests/cts/net/TEST_MAPPING b/tests/cts/net/TEST_MAPPING new file mode 100644 index 0000000000..e2a9c75778 --- /dev/null +++ b/tests/cts/net/TEST_MAPPING @@ -0,0 +1,13 @@ +{ + // TODO: move to mainline-presubmit once supported + "postsubmit": [ + { + "name": "CtsNetTestCasesLatestSdk", + "options": [ + { + "exclude-annotation": "com.android.testutils.SkipPresubmit" + } + ] + } + ] +} diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index d498ed9885..3880664827 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -96,6 +96,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.ArrayUtils; +import com.android.testutils.SkipPresubmit; import libcore.io.Streams; @@ -325,6 +326,7 @@ public class ConnectivityManagerTest { */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + @SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks") public void testOpenConnection() throws Exception { boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); @@ -990,6 +992,7 @@ public class ConnectivityManagerTest { @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") public void testCreateTcpKeepalive() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi"); @@ -1199,6 +1202,7 @@ public class ConnectivityManagerTest { */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") public void testSocketKeepaliveLimitWifi() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device" @@ -1252,6 +1256,7 @@ public class ConnectivityManagerTest { */ @AppModeFull(reason = "Cannot request network in instant app mode") @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") public void testSocketKeepaliveLimitTelephony() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" @@ -1294,6 +1299,7 @@ public class ConnectivityManagerTest { */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") public void testSocketKeepaliveUnprivileged() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device" diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index 746dcb0a1c..fde27e9f12 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -27,6 +27,8 @@ import android.os.SystemClock; import android.test.AndroidTestCase; import android.util.Log; +import com.android.testutils.SkipPresubmit; + import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -68,6 +70,7 @@ public class DnsTest extends AndroidTestCase { * Perf - measure size of first and second tier caches and their effect * Assert requires network permission */ + @SkipPresubmit(reason = "IPv6 support may be missing on presubmit virtual hardware") public void testDnsWorks() throws Exception { ensureIpv6Connectivity(); From bac55b7eeba056ce614a292a4e1c3b121b77a77a Mon Sep 17 00:00:00 2001 From: Lucas Lin Date: Fri, 5 Jun 2020 09:19:38 +0000 Subject: [PATCH 1185/1415] Enlarge the onAvailable callback timeout to 30 seconds Sometimes the device may take a long time to connect to the wifi, try to enlarge the timeout to lower the fail rate of test. Bug: 157391946 Test: atest CtsHostsideNetworkTests:com.android.cts.net.HostsideNetworkCallbackTests Original-Change: https://android-review.googlesource.com/1324092 Merged-In: Ie89936ecc2d70ee22dd312067ccedd2523e81855 Change-Id: Ie89936ecc2d70ee22dd312067ccedd2523e81855 --- .../src/com/android/cts/net/hostside/NetworkCallbackTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index f3cd8a9772..aa59959994 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -83,6 +83,7 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } private class TestNetworkCallback extends INetworkCallback.Stub { + private static final int TEST_CONNECT_TIMEOUT_MS = 30_000; private static final int TEST_CALLBACK_TIMEOUT_MS = 5_000; private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); @@ -131,7 +132,7 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } public Network expectAvailableCallbackAndGetNetwork() { - final CallbackInfo cb = nextCallback(TEST_CALLBACK_TIMEOUT_MS); + final CallbackInfo cb = nextCallback(TEST_CONNECT_TIMEOUT_MS); if (cb.state != CallbackState.AVAILABLE) { fail("Network is not available. Instead obtained the following callback :" + cb); From 3fe5434d190347547b8a45a97f7272db442fc4ed Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 29 May 2020 00:43:36 +0800 Subject: [PATCH 1186/1415] Make tether settings intent explicit Currently tethering notification is sending a pending intent for redirecting user to tether settings page. However, this intent is implicit that only create with Settings.ACTION_TETHER_SETTINGS. For security reasons, this intetnt should specify an explicit component to be delivered to. Thus, specify the settings package name to this intent. Test: atest TetheringTests Bug: 156353008 Change-Id: I49187aee8a004caa890e2a73c0a28d280215c7d4 --- .../TetheringNotificationUpdater.java | 22 +++++++++++---- .../TetheringNotificationUpdaterTest.kt | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index d03deda37f..593d04a06b 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -24,8 +24,10 @@ import android.app.Notification.Action; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.net.NetworkCapabilities; @@ -252,6 +254,14 @@ public class TetheringNotificationUpdater { mNotificationManager.cancel(null /* tag */, id); } + @VisibleForTesting + static String getSettingsPackageName(@NonNull final PackageManager pm) { + final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS); + final ComponentName settingsComponent = settingsIntent.resolveActivity(pm); + return settingsComponent != null + ? settingsComponent.getPackageName() : "com.android.settings"; + } + @VisibleForTesting void notifyTetheringDisabledByRestriction() { final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); @@ -262,8 +272,9 @@ public class TetheringNotificationUpdater { final PendingIntent pi = PendingIntent.getActivity( mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), 0 /* requestCode */, - new Intent(Settings.ACTION_TETHER_SETTINGS), - Intent.FLAG_ACTIVITY_NEW_TASK, + new Intent(Settings.ACTION_TETHER_SETTINGS) + .setPackage(getSettingsPackageName(mContext.getPackageManager())), + Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE, null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, @@ -284,7 +295,7 @@ public class TetheringNotificationUpdater { mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), 0 /* requestCode */, intent, - 0 /* flags */); + PendingIntent.FLAG_IMMUTABLE); final Action action = new Action.Builder(NO_ICON_ID, disableButton, pi).build(); showNotification(R.drawable.stat_sys_tether_general, title, message, @@ -305,8 +316,9 @@ public class TetheringNotificationUpdater { final PendingIntent pi = PendingIntent.getActivity( mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), 0 /* requestCode */, - new Intent(Settings.ACTION_TETHER_SETTINGS), - Intent.FLAG_ACTIVITY_NEW_TASK, + new Intent(Settings.ACTION_TETHER_SETTINGS) + .setPackage(getSettingsPackageName(mContext.getPackageManager())), + Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE, null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 745468fdf3..d88f39ec45 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -19,6 +19,10 @@ package com.android.networkstack.tethering import android.app.Notification import android.app.NotificationManager import android.content.Context +import android.content.pm.ActivityInfo +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo import android.content.res.Resources import android.net.ConnectivityManager.TETHERING_WIFI import android.os.Handler @@ -51,6 +55,7 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.times @@ -351,4 +356,26 @@ class TetheringNotificationUpdaterTest { notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) } + + @Test + fun testGetSettingsPackageName() { + val defaultSettingsPackageName = "com.android.settings" + val testSettingsPackageName = "com.android.test.settings" + val pm = mock(PackageManager::class.java) + doReturn(null).`when`(pm).resolveActivity(any(), anyInt()) + assertEquals(defaultSettingsPackageName, + TetheringNotificationUpdater.getSettingsPackageName(pm)) + + val resolveInfo = ResolveInfo().apply { + activityInfo = ActivityInfo().apply { + name = "test" + applicationInfo = ApplicationInfo().apply { + packageName = testSettingsPackageName + } + } + } + doReturn(resolveInfo).`when`(pm).resolveActivity(any(), anyInt()) + assertEquals(testSettingsPackageName, + TetheringNotificationUpdater.getSettingsPackageName(pm)) + } } From c42a0ffc0d1af882f20e3ac1329d09271ab5a94e Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 6 May 2020 14:34:47 +0800 Subject: [PATCH 1187/1415] [BOT.4] Make BpfCoordinator to support data warning Invoke the existing polling thread to update data alert statistics. Once the data alert limit has reached, trigger the notification. Bug: 150736748 Test: BpfCoordinatorTest Change-Id: Ibf25560ca2e9f003d8eba01361dc7d35ec1b1627 --- .../tethering/BpfCoordinator.java | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index 6b854f2ac9..089b12aa39 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -23,6 +23,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStats.UID_TETHERING; +import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; import android.app.usage.NetworkStatsManager; import android.net.INetd; @@ -37,6 +38,7 @@ import android.net.util.TetheringUtils.ForwardedStats; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceSpecificException; +import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; @@ -50,6 +52,7 @@ import java.net.Inet6Address; /** * This coordinator is responsible for providing BPF offload relevant functionality. * - Get tethering stats. + * - Set global alert. * * @hide */ @@ -76,6 +79,10 @@ public class BpfCoordinator { private final BpfTetherStatsProvider mStatsProvider; private boolean mStarted = false; + // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert + // quota is interface independent and global for tether offload. + private long mRemainingAlertQuota = QUOTA_UNLIMITED; + // Maps upstream interface index to offloaded traffic statistics. // Always contains the latest total bytes/packets, since each upstream was started, received // from the BPF maps for each interface. @@ -158,15 +165,15 @@ public class BpfCoordinator { * expects the interface name in NetworkStats object. * Note that this can be only called on handler thread. */ - public void addUpstreamNameToLookupTable(int upstreamIfindex, String upstreamIface) { - if (upstreamIfindex == 0) return; + public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) { + if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return; // The same interface index to name mapping may be added by different IpServer objects or // re-added by reconnection on the same upstream interface. Ignore the duplicate one. final String iface = mInterfaceNames.get(upstreamIfindex); if (iface == null) { mInterfaceNames.put(upstreamIfindex, upstreamIface); - } else if (iface != upstreamIface) { + } else if (!TextUtils.equals(iface, upstreamIface)) { Log.wtf(TAG, "The upstream interface name " + upstreamIface + " is different from the existing interface name " + iface + " for index " + upstreamIfindex); @@ -214,7 +221,7 @@ public class BpfCoordinator { /** * A BPF tethering stats provider to provide network statistics to the system. - * Note that this class's data may only be accessed on the handler thread. + * Note that this class' data may only be accessed on the handler thread. */ @VisibleForTesting class BpfTetherStatsProvider extends NetworkStatsProvider { @@ -233,7 +240,7 @@ public class BpfCoordinator { @Override public void onSetAlert(long quotaBytes) { - // no-op + mHandler.post(() -> updateAlertQuota(quotaBytes)); } @Override @@ -282,6 +289,19 @@ public class BpfCoordinator { diff.txBytes, diff.txPackets, 0L /* operations */)); } + private void updateAlertQuota(long newQuota) { + if (newQuota < QUOTA_UNLIMITED) { + throw new IllegalArgumentException("invalid quota value " + newQuota); + } + if (mRemainingAlertQuota == newQuota) return; + + mRemainingAlertQuota = newQuota; + if (mRemainingAlertQuota == 0) { + mLog.i("onAlertReached"); + if (mStatsProvider != null) mStatsProvider.notifyAlertReached(); + } + } + private void updateForwardedStatsFromNetd() { final TetherStatsParcel[] tetherStatsList; try { @@ -293,11 +313,13 @@ public class BpfCoordinator { return; } + long usedAlertQuota = 0; for (TetherStatsParcel tetherStats : tetherStatsList) { final Integer ifIndex = tetherStats.ifIndex; final ForwardedStats curr = new ForwardedStats(tetherStats); final ForwardedStats base = mStats.get(ifIndex); final ForwardedStats diff = (base != null) ? curr.subtract(base) : curr; + usedAlertQuota += diff.rxBytes + diff.txBytes; // Update the local cache for counting tether stats delta. mStats.put(ifIndex, curr); @@ -315,6 +337,13 @@ public class BpfCoordinator { } } } + + if (mRemainingAlertQuota > 0 && usedAlertQuota > 0) { + // Trim to zero if overshoot. + final long newQuota = Math.max(mRemainingAlertQuota - usedAlertQuota, 0); + updateAlertQuota(newQuota); + } + } private void maybeSchedulePollingStats() { From b1406cf0d6bbc6b93cdc2e7bf64fb85e96a590e7 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Sat, 16 May 2020 20:02:48 +0800 Subject: [PATCH 1188/1415] [BOT.9] Add unit test for data warning in BpfCoordinator Bug: 150736748 Test: atest BpfCoordinatorTest Change-Id: Ic1f37de75b064d7c8717e1b496e13174bb8693ec --- .../tethering/BpfCoordinatorTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java index b029b43d19..3e19ddfc0b 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -23,6 +23,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStats.UID_TETHERING; +import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; import static com.android.networkstack.tethering.BpfCoordinator .DEFAULT_PERFORM_POLL_INTERVAL_MS; @@ -204,4 +205,42 @@ public class BpfCoordinatorTest { waitForIdle(); verify(mNetd, never()).tetherOffloadGetStats(); } + + @Test + public void testOnSetAlert() throws Exception { + setupFunctioningNetdInterface(); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + coordinator.start(); + + final String mobileIface = "rmnet_data0"; + final Integer mobileIfIndex = 100; + coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface); + + // Verify that set quota to 0 will immediately triggers a callback. + mTetherStatsProvider.onSetAlert(0); + waitForIdle(); + mTetherStatsProviderCb.expectNotifyAlertReached(); + + // Verify that notifyAlertReached never fired if quota is not yet reached. + when(mNetd.tetherOffloadGetStats()).thenReturn( + new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 0, 0, 0, 0)}); + mTetherStatsProvider.onSetAlert(100); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.assertNoCallback(); + + // Verify that notifyAlertReached fired when quota is reached. + when(mNetd.tetherOffloadGetStats()).thenReturn( + new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 50, 0, 50, 0)}); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.expectNotifyAlertReached(); + + // Verify that set quota with UNLIMITED won't trigger any callback. + mTetherStatsProvider.onSetAlert(QUOTA_UNLIMITED); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.assertNoCallback(); + } } From ce3c9ae27890c9df4fcc96c4d3b0d97373161d08 Mon Sep 17 00:00:00 2001 From: evitayan Date: Mon, 1 Jun 2020 17:50:51 -0700 Subject: [PATCH 1189/1415] Fix tests that failed on devices without IPsec tunnel feature Three tests failed when they try to set up IKE Session with a tunnel mode Child SA and the device does not have ipsec tunnel feature. This commit changed these tests to set up IKE Session with a transport mode SA because 1) the logic these tests are verifying is unrelated to the Child SA type and 2) using transport mode make sure these tests run on all the devices. Bug: 158268209 Test: CtsIkeTestCases, verified on taimen Change-Id: I9a8c7f631f0e6e02492816e3fbf0d751017dc2b3 --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 62 +++++++++++-------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 7 +++ 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 0509fc0c92..13f953a50d 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -18,13 +18,14 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; -import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.net.LinkAddress; +import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionParams; @@ -84,7 +85,15 @@ public class IkeSessionPskTest extends IkeSessionTestBase { + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" + "6743A7CEB2BE34AC00095A5B8"; - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + private IkeSession openIkeSessionWithTunnelModeChild(InetAddress remoteAddress) { + return openIkeSession(remoteAddress, buildTunnelModeChildSessionParams()); + } + + private IkeSession openIkeSessionWithTransportModeChild(InetAddress remoteAddress) { + return openIkeSession(remoteAddress, buildTransportModeChildParamsWithDefaultTs()); + } + + private IkeSession openIkeSession(InetAddress remoteAddress, ChildSessionParams childParams) { IkeSessionParams ikeParams = new IkeSessionParams.Builder(sContext) .setNetwork(mTunNetwork) @@ -98,7 +107,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { return new IkeSession( sContext, ikeParams, - buildTunnelModeChildSessionParams(), + childParams, mUserCbExecutor, mIkeSessionCallback, mFirstChildSessionCallback); @@ -124,7 +133,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { if (!hasTunnelsFeature()) return; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 @@ -222,7 +231,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { setUpTestNetwork(mLocalAddress); // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking( ikeInitResp, 1 /* expectedAuthReqPktCnt */, @@ -258,7 +267,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { if (!hasTunnelsFeature()) return; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); ikeSession.kill(); @@ -272,7 +281,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( IKE_DETERMINISTIC_INITIATOR_SPI, @@ -309,7 +318,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { + "AB6E4808BAC0CA1DAD6ADD0A126A41BD"; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthFailRespHex); mFirstChildSessionCallback.awaitOnClosed(); @@ -322,27 +331,28 @@ public class IkeSessionPskTest extends IkeSessionTestBase { @Test public void testIkeAuthHandlesFirstChildCreationFail() throws Exception { final String ikeInitRespHex = - "46B8ECA1E0D72A182B300285DA19E6452120222000000000000001502200" - + "00300000002C010100040300000C0100000C800E01000300000803000005" - + "0300000802000004000000080400000228000088000200005C9DE629981F" - + "DB1FC45DB6CCF15D076C1F51BD9F63C771DC089F05CCDE6247965D15C616" - + "C7B5A62342491715E4D1FEA19326477D24143E8E56AB6AD93F54B19BC32A" - + "44BC0A5B5632E57D0A3C43E466E1547D8E4EF65EA4B864A348161666E229" - + "84975A486251A17C4F096A6D5CF3DB83874B70324A31AA7ADDE2D73BADD8" - + "238029000024CF06260F7C4923295E7C91F2B8479212892DA7A519A0322F" - + "F5B2BF570B92972B2900001C00004004C7ACC2C7D58CF8C9F5E953993AF4" - + "6CAC976635B42900001C00004005B64B190DFE7BDE8B9B1475EDE67B63D6" - + "F1DBBF44290000080000402E290000100000402F00020003000400050000" + "46B8ECA1E0D72A18F5ABBF896A1240BE2120222000000000000001502200" + + "00300000002C010100040300000C0100000C800E0100030000080300000C" + + "03000008020000050000000804000002280000880002000074950F016B85" + + "605E57E24651843AB70E41B552EDEE227DFE51E6CBEC00E75FFEFC7D5453" + + "109B15F721FCD811FC9F113BE06050882F2FC5F5FF25857E555CCFB5AB64" + + "8B0D1D7A819A3B05DE1FE89A4A627C60D5AA06CD0F66ACD3748722F9CD4F" + + "F30AE7477CBC12049821F07AD6C9F0ED732321A6A36FA817722E025AC34B" + + "ABE62900002432E3807F595070E95EDA341A787599B24B1151B535B0222B" + + "65C003401B9B38F82900001C000040043BB760DB3037B51768DFFAB4B21D" + + "B1716EA1C1382900001C0000400531098EB04DF1BE3F304606BD59B454A8" + + "CC7E7311290000080000402E290000100000402F00020003000400050000" + "000800004014"; final String ikeAuthCreateChildFailHex = - "46B8ECA1E0D72A182B300285DA19E6452E202320000000010000008C2400" - + "0070386FC9CCC67495A17915D0544390A2963A769F4A42C6FA668CEEC07F" - + "EC0C87D681DE34267023DD394F1401B5A563E71002C0CE0928D0ABC0C4570" - + "E39C2EDEF820F870AB71BD70A3F3EB5C96CA294B6D3F01677690DCF9F8CFC" - + "9584650957573502BA83E32F18207A9ADEB1FA"; + "46B8ECA1E0D72A18F5ABBF896A1240BE2E20232000000001000000B02400" + + "009400B0861242E0C88ECB3848D772B560CAD65B6AC9DFFDC8622A394B8E" + + "64E550BDD69FCD7E768129787ED9062992C1D6DB0F0631C2E05765B403CF" + + "EF1D0A055B32F6698FF7DB5B8FB1B6A83A81634D00E22C86E35B3BFBEC73" + + "EAC6806678926945BC7A57003DC1A3528A1EC423EE56C1075B36C0B57A6B" + + "C6DD990182F6FABFFA167D199C7D629E5B830AAD2AFBD31CEBA6"; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthCreateChildFailHex); // Even though the child creation failed, the authentication succeeded, so the IKE Session's @@ -352,7 +362,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Verify Child Creation failed IkeProtocolException protocolException = (IkeProtocolException) mFirstChildSessionCallback.awaitOnClosedException(); - assertEquals(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE, protocolException.getErrorType()); + assertEquals(ERROR_TYPE_TS_UNACCEPTABLE, protocolException.getErrorType()); assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); ikeSession.kill(); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 2458b25e33..a81063b30a 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -276,6 +276,13 @@ abstract class IkeSessionTestBase extends IkeTestBase { .build(); } + TransportModeChildSessionParams buildTransportModeChildParamsWithDefaultTs() { + return new TransportModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .build(); + } + TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { return new TunnelModeChildSessionParams.Builder() .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) From 9d1f86f3a8f6fa785f8f086a7d7373c77d0e883a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Jun 2020 14:16:25 -0700 Subject: [PATCH 1190/1415] Verify owner of IKEv2 VPNs This change adds assertions to ensure that the owner UIDs of IKEv2 VPNs are correctly set. Bug: 150135470 Test: This Change-Id: Iabf2859c289aa86ec38aea1edcc1fb248b9d0d26 --- tests/cts/net/src/android/net/cts/Ikev2VpnTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index dff2581118..0bdd1d49f1 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -16,6 +16,7 @@ package android.net.cts; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; @@ -40,6 +41,7 @@ import android.net.Ikev2VpnProfile; import android.net.IpSecAlgorithm; import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.ProxyInfo; import android.net.TestNetworkInterface; @@ -47,6 +49,7 @@ import android.net.TestNetworkManager; import android.net.VpnManager; import android.net.cts.util.CtsNetUtils; import android.os.Build; +import android.os.Process; import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; @@ -419,6 +422,11 @@ public class Ikev2VpnTest { final Network vpnNetwork = cb.currentNetwork; assertNotNull(vpnNetwork); + final NetworkCapabilities caps = sCM.getNetworkCapabilities(vpnNetwork); + assertTrue(caps.hasTransport(TRANSPORT_VPN)); + assertTrue(caps.hasCapability(NET_CAPABILITY_INTERNET)); + assertEquals(Process.myUid(), caps.getOwnerUid()); + sVpnMgr.stopProvisionedVpnProfile(); cb.waitForLost(); assertEquals(vpnNetwork, cb.lastLostNetwork); From c5bad6f58c7414ecffde4d6a43228fba958ee4f8 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 9 Jun 2020 04:26:48 +0000 Subject: [PATCH 1191/1415] Reset vpn provision status The vpn status of cts app is updated to be consented in this tests which will impact the following test related to vpn. Thus, reset the status after finishing the test. Bug: 153760253 Test: atest CtsNetTestCasesLatestSdk Merged-In: I4856cfc7ddfd70125c513a4201132256704d1a66 Change-Id: I4856cfc7ddfd70125c513a4201132256704d1a66 --- tests/cts/net/src/android/net/cts/Ikev2VpnTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index dff2581118..81dfed507a 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -56,6 +56,7 @@ import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; +import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -175,6 +176,12 @@ public class Ikev2VpnTest { mUserCertKey = generateRandomCertAndKeyPair(); } + @After + public void tearDown() { + setAppop(AppOpsManager.OP_ACTIVATE_VPN, false); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + } + /** * Sets the given appop using shell commands * From 269c0886eda695c200a09d17bd2de2a657eaf1c2 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 6 May 2020 14:57:35 +0800 Subject: [PATCH 1192/1415] [BOT.6] Make BpfCoordinator to support data limit The BPF tethering coordinator listens to the forwarding rule changes for updating data limit which is applied in the following conditions. - After adding the first rule on a given upstream, add data limit. - After removing the last rule on a given upstream, clear data limit. - The service applies a new data limit on current upstream. The reason for relying on rule changes is because the Tethering and IpServer objects have multi-internal state machines. It is hard to synchronize all of their states. Note that the data limit cleanup for stopping or switching upstream relies on offload rules are all removed as well. Bug: 150736748 Test: manual Change-Id: I829d36339973f9473fe6b616c48aa288f18d1c46 --- Tethering/src/android/net/ip/IpServer.java | 50 +-- .../tethering/BpfCoordinator.java | 341 ++++++++++++++++-- .../networkstack/tethering/Tethering.java | 4 +- .../unit/src/android/net/ip/IpServerTest.java | 166 ++++++--- .../tethering/BpfCoordinatorTest.java | 6 +- 5 files changed, 452 insertions(+), 115 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 830f6a0fec..1671dda4bd 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -77,7 +77,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; import java.util.Random; @@ -272,9 +271,6 @@ public class IpServer extends StateMachine { } } - private final LinkedHashMap mIpv6ForwardingRules = - new LinkedHashMap<>(); - private final IpNeighborMonitor mIpNeighborMonitor; private LinkAddress mIpv4Address; @@ -843,43 +839,29 @@ public class IpServer extends StateMachine { // TODO: Perhaps remove this protection check. if (!mUsingBpfOffload) return; - try { - mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel()); - mIpv6ForwardingRules.put(rule.address, rule); - } catch (RemoteException | ServiceSpecificException e) { - mLog.e("Could not add IPv6 downstream rule: ", e); - } + mBpfCoordinator.tetherOffloadRuleAdd(this, rule); } - private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) { - // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF - // offload is disabled. Add this check just in case. + private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule) { // TODO: Perhaps remove this protection check. + // See the related comment in #addIpv6ForwardingRule. if (!mUsingBpfOffload) return; - try { - mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel()); - if (removeFromMap) { - mIpv6ForwardingRules.remove(rule.address); - } - } catch (RemoteException | ServiceSpecificException e) { - mLog.e("Could not remove IPv6 downstream rule: ", e); - } + mBpfCoordinator.tetherOffloadRuleRemove(this, rule); } private void clearIpv6ForwardingRules() { - for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) { - removeIpv6ForwardingRule(rule, false /*removeFromMap*/); - } - mIpv6ForwardingRules.clear(); + if (!mUsingBpfOffload) return; + + mBpfCoordinator.tetherOffloadRuleClear(this); } - // Convenience method to replace a rule with the same rule on a new upstream interface. - // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions. - // Relies on the fact that rules are in a map indexed by IP address. - private void updateIpv6ForwardingRule(Ipv6ForwardingRule rule, int newIfindex) { - addIpv6ForwardingRule(rule.onNewUpstream(newIfindex)); - removeIpv6ForwardingRule(rule, false /*removeFromMap*/); + private void updateIpv6ForwardingRule(int newIfindex) { + // TODO: Perhaps remove this protection check. + // See the related comment in #addIpv6ForwardingRule. + if (!mUsingBpfOffload) return; + + mBpfCoordinator.tetherOffloadRuleUpdate(this, newIfindex); } // Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream @@ -895,9 +877,7 @@ public class IpServer extends StateMachine { // If the upstream interface has changed, remove all rules and re-add them with the new // upstream interface. if (prevUpstreamIfindex != upstreamIfindex) { - for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) { - updateIpv6ForwardingRule(rule, upstreamIfindex); - } + updateIpv6ForwardingRule(upstreamIfindex); } // If we're here to process a NeighborEvent, do so now. @@ -917,7 +897,7 @@ public class IpServer extends StateMachine { if (e.isValid()) { addIpv6ForwardingRule(rule); } else { - removeIpv6ForwardingRule(rule, true /*removeFromMap*/); + removeIpv6ForwardingRule(rule); } } diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index 089b12aa39..fc27b6add0 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -32,6 +32,7 @@ import android.net.NetworkStats; import android.net.NetworkStats.Entry; import android.net.TetherOffloadRuleParcel; import android.net.TetherStatsParcel; +import android.net.ip.IpServer; import android.net.netstats.provider.NetworkStatsProvider; import android.net.util.SharedLog; import android.net.util.TetheringUtils.ForwardedStats; @@ -48,11 +49,17 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import java.net.Inet6Address; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Objects; /** * This coordinator is responsible for providing BPF offload relevant functionality. * - Get tethering stats. + * - Set data limit. * - Set global alert. + * - Add/remove forwarding rules. * * @hide */ @@ -77,7 +84,14 @@ public class BpfCoordinator { private final Dependencies mDeps; @Nullable private final BpfTetherStatsProvider mStatsProvider; - private boolean mStarted = false; + + // Tracks whether BPF tethering is started or not. This is set by tethering before it + // starts the first IpServer and is cleared by tethering shortly before the last IpServer + // is stopped. Note that rule updates (especially deletions, but sometimes additions as + // well) may arrive when this is false. If they do, they must be communicated to netd. + // Changes in data limits may also arrive when this is false, and if they do, they must + // also be communicated to netd. + private boolean mPollingStarted = false; // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert // quota is interface independent and global for tether offload. @@ -86,13 +100,40 @@ public class BpfCoordinator { // Maps upstream interface index to offloaded traffic statistics. // Always contains the latest total bytes/packets, since each upstream was started, received // from the BPF maps for each interface. - private SparseArray mStats = new SparseArray<>(); + private final SparseArray mStats = new SparseArray<>(); + + // Maps upstream interface names to interface quotas. + // Always contains the latest value received from the framework for each interface, regardless + // of whether offload is currently running (or is even supported) on that interface. Only + // includes interfaces that have a quota set. Note that this map is used for storing the quota + // which is set from the service. Because the service uses the interface name to present the + // interface, this map uses the interface name to be the mapping index. + private final HashMap mInterfaceQuotas = new HashMap<>(); // Maps upstream interface index to interface names. // Store all interface name since boot. Used for lookup what interface name it is from the // tether stats got from netd because netd reports interface index to present an interface. // TODO: Remove the unused interface name. - private SparseArray mInterfaceNames = new SparseArray<>(); + private final SparseArray mInterfaceNames = new SparseArray<>(); + + // Map of downstream rule maps. Each of these maps represents the IPv6 forwarding rules for a + // given downstream. Each map: + // - Is owned by the IpServer that is responsible for that downstream. + // - Must only be modified by that IpServer. + // - Is created when the IpServer adds its first rule, and deleted when the IpServer deletes + // its last rule (or clears its rules). + // TODO: Perhaps seal the map and rule operations which communicates with netd into a class. + // TODO: Does this need to be a LinkedHashMap or can it just be a HashMap? Also, could it be + // a ConcurrentHashMap, in order to avoid the copies in tetherOffloadRuleClear + // and tetherOffloadRuleUpdate? + // TODO: Perhaps use one-dimensional map and access specific downstream rules via downstream + // index. For doing that, IpServer must guarantee that it always has a valid IPv6 downstream + // interface index while calling function to clear all rules. IpServer may be calling clear + // rules function without a valid IPv6 downstream interface index even if it may have one + // before. IpServer would need to call getInterfaceParams() in the constructor instead of when + // startIpv6() is called, and make mInterfaceParams final. + private final HashMap> + mIpv6ForwardingRules = new LinkedHashMap<>(); // Runnable that used by scheduling next polling of stats. private final Runnable mScheduledPollingTask = () -> { @@ -101,14 +142,15 @@ public class BpfCoordinator { }; @VisibleForTesting - static class Dependencies { + public static class Dependencies { int getPerformPollInterval() { // TODO: Consider make this configurable. return DEFAULT_PERFORM_POLL_INTERVAL_MS; } } - BpfCoordinator(@NonNull Handler handler, @NonNull INetd netd, + @VisibleForTesting + public BpfCoordinator(@NonNull Handler handler, @NonNull INetd netd, @NonNull NetworkStatsManager nsm, @NonNull SharedLog log, @NonNull Dependencies deps) { mHandler = handler; mNetd = netd; @@ -132,31 +174,153 @@ public class BpfCoordinator { * TODO: Perhaps check BPF support before starting. * TODO: Start the stats polling only if there is any client on the downstream. */ - public void start() { - if (mStarted) return; + public void startPolling() { + if (mPollingStarted) return; - mStarted = true; + mPollingStarted = true; maybeSchedulePollingStats(); - mLog.i("BPF tethering coordinator started"); + mLog.i("Polling started"); } /** - * Stop BPF tethering offload stats polling and cleanup upstream parameters. + * Stop BPF tethering offload stats polling. + * The data limit cleanup and the tether stats maps cleanup are not implemented here. + * These cleanups rely on all IpServers calling #tetherOffloadRuleRemove. After the + * last rule is removed from the upstream, #tetherOffloadRuleRemove does the cleanup + * functionality. * Note that this can be only called on handler thread. */ - public void stop() { - if (!mStarted) return; + public void stopPolling() { + if (!mPollingStarted) return; // Stop scheduled polling tasks and poll the latest stats from BPF maps. if (mHandler.hasCallbacks(mScheduledPollingTask)) { mHandler.removeCallbacks(mScheduledPollingTask); } updateForwardedStatsFromNetd(); + mPollingStarted = false; - mStarted = false; + mLog.i("Polling stopped"); + } - mLog.i("BPF tethering coordinator stopped"); + /** + * Add forwarding rule. After adding the first rule on a given upstream, must add the data + * limit on the given upstream. + * Note that this can be only called on handler thread. + */ + public void tetherOffloadRuleAdd( + @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) { + try { + // TODO: Perhaps avoid to add a duplicate rule. + mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel()); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Could not add IPv6 forwarding rule: ", e); + return; + } + + if (!mIpv6ForwardingRules.containsKey(ipServer)) { + mIpv6ForwardingRules.put(ipServer, new LinkedHashMap()); + } + LinkedHashMap rules = mIpv6ForwardingRules.get(ipServer); + + // Setup the data limit on the given upstream if the first rule is added. + final int upstreamIfindex = rule.upstreamIfindex; + if (!isAnyRuleOnUpstream(upstreamIfindex)) { + // If failed to set a data limit, probably should not use this upstream, because + // the upstream may not want to blow through the data limit that was told to apply. + // TODO: Perhaps stop the coordinator. + boolean success = updateDataLimit(upstreamIfindex); + if (!success) { + final String iface = mInterfaceNames.get(upstreamIfindex); + mLog.e("Setting data limit for " + iface + " failed."); + } + } + + // Must update the adding rule after calling #isAnyRuleOnUpstream because it needs to + // check if it is about adding a first rule for a given upstream. + rules.put(rule.address, rule); + } + + /** + * Remove forwarding rule. After removing the last rule on a given upstream, must clear + * data limit, update the last tether stats and remove the tether stats in the BPF maps. + * Note that this can be only called on handler thread. + */ + public void tetherOffloadRuleRemove( + @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) { + try { + // TODO: Perhaps avoid to remove a non-existent rule. + mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel()); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Could not remove IPv6 forwarding rule: ", e); + return; + } + + LinkedHashMap rules = mIpv6ForwardingRules.get(ipServer); + if (rules == null) return; + + // Must remove rules before calling #isAnyRuleOnUpstream because it needs to check if + // the last rule is removed for a given upstream. If no rule is removed, return early. + // Avoid unnecessary work on a non-existent rule which may have never been added or + // removed already. + if (rules.remove(rule.address) == null) return; + + // Remove the downstream entry if it has no more rule. + if (rules.isEmpty()) { + mIpv6ForwardingRules.remove(ipServer); + } + + // Do cleanup functionality if there is no more rule on the given upstream. + final int upstreamIfindex = rule.upstreamIfindex; + if (!isAnyRuleOnUpstream(upstreamIfindex)) { + try { + final TetherStatsParcel stats = + mNetd.tetherOffloadGetAndClearStats(upstreamIfindex); + // Update the last stats delta and delete the local cache for a given upstream. + updateQuotaAndStatsFromSnapshot(new TetherStatsParcel[] {stats}); + mStats.remove(upstreamIfindex); + } catch (RemoteException | ServiceSpecificException e) { + Log.wtf(TAG, "Exception when cleanup tether stats for upstream index " + + upstreamIfindex + ": ", e); + } + } + } + + /** + * Clear all forwarding rules for a given downstream. + * Note that this can be only called on handler thread. + */ + public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) { + final LinkedHashMap rules = mIpv6ForwardingRules.get( + ipServer); + if (rules == null) return; + + // Need to build a rule list because the rule map may be changed in the iteration. + for (final Ipv6ForwardingRule rule : new ArrayList(rules.values())) { + tetherOffloadRuleRemove(ipServer, rule); + } + } + + /** + * Update existing forwarding rules to new upstream for a given downstream. + * Note that this can be only called on handler thread. + */ + public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) { + final LinkedHashMap rules = mIpv6ForwardingRules.get( + ipServer); + if (rules == null) return; + + // Need to build a rule list because the rule map may be changed in the iteration. + for (final Ipv6ForwardingRule rule : new ArrayList(rules.values())) { + // Remove the old rule before adding the new one because the map uses the same key for + // both rules. Reversing the processing order causes that the new rule is removed as + // unexpected. + // TODO: Add new rule first to reduce the latency which has no rule. + tetherOffloadRuleRemove(ipServer, rule); + tetherOffloadRuleAdd(ipServer, rule.onNewUpstream(newUpstreamIfindex)); + } } /** @@ -184,12 +348,17 @@ public class BpfCoordinator { public static class Ipv6ForwardingRule { public final int upstreamIfindex; public final int downstreamIfindex; + + @NonNull public final Inet6Address address; + @NonNull public final MacAddress srcMac; + @NonNull public final MacAddress dstMac; - public Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, Inet6Address address, - MacAddress srcMac, MacAddress dstMac) { + public Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, + @NonNull Inet6Address address, @NonNull MacAddress srcMac, + @NonNull MacAddress dstMac) { this.upstreamIfindex = upstreamIfindex; this.downstreamIfindex = downstreamIfIndex; this.address = address; @@ -198,6 +367,7 @@ public class BpfCoordinator { } /** Return a new rule object which updates with new upstream index. */ + @NonNull public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) { return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac, dstMac); @@ -207,6 +377,7 @@ public class BpfCoordinator { * Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream() * would be error-prone due to generated stable AIDL classes not having a copy constructor. */ + @NonNull public TetherOffloadRuleParcel toTetherOffloadRuleParcel() { final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel(); parcel.inputInterfaceIndex = upstreamIfindex; @@ -217,6 +388,24 @@ public class BpfCoordinator { parcel.dstL2Address = dstMac.toByteArray(); return parcel; } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Ipv6ForwardingRule)) return false; + Ipv6ForwardingRule that = (Ipv6ForwardingRule) o; + return this.upstreamIfindex == that.upstreamIfindex + && this.downstreamIfindex == that.downstreamIfindex + && Objects.equals(this.address, that.address) + && Objects.equals(this.srcMac, that.srcMac) + && Objects.equals(this.dstMac, that.dstMac); + } + + @Override + public int hashCode() { + // TODO: if this is ever used in production code, don't pass ifindices + // to Objects.hash() to avoid autoboxing overhead. + return Objects.hash(upstreamIfindex, downstreamIfindex, address, srcMac, dstMac); + } } /** @@ -245,7 +434,22 @@ public class BpfCoordinator { @Override public void onSetLimit(@NonNull String iface, long quotaBytes) { - // no-op + if (quotaBytes < QUOTA_UNLIMITED) { + throw new IllegalArgumentException("invalid quota value " + quotaBytes); + } + + mHandler.post(() -> { + final Long curIfaceQuota = mInterfaceQuotas.get(iface); + + if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return; + + if (quotaBytes == QUOTA_UNLIMITED) { + mInterfaceQuotas.remove(iface); + } else { + mInterfaceQuotas.put(iface, quotaBytes); + } + maybeUpdateDataLimit(iface); + }); } @VisibleForTesting @@ -270,9 +474,79 @@ public class BpfCoordinator { } } + private int getInterfaceIndexFromRules(@NonNull String ifName) { + for (LinkedHashMap rules : mIpv6ForwardingRules + .values()) { + for (Ipv6ForwardingRule rule : rules.values()) { + final int upstreamIfindex = rule.upstreamIfindex; + if (TextUtils.equals(ifName, mInterfaceNames.get(upstreamIfindex))) { + return upstreamIfindex; + } + } + } + return 0; + } + + private long getQuotaBytes(@NonNull String iface) { + final Long limit = mInterfaceQuotas.get(iface); + final long quotaBytes = (limit != null) ? limit : QUOTA_UNLIMITED; + + return quotaBytes; + } + + private boolean sendDataLimitToNetd(int ifIndex, long quotaBytes) { + if (ifIndex == 0) { + Log.wtf(TAG, "Invalid interface index."); + return false; + } + + try { + mNetd.tetherOffloadSetInterfaceQuota(ifIndex, quotaBytes); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Exception when updating quota " + quotaBytes + ": ", e); + return false; + } + + return true; + } + + // Handle the data limit update from the service which is the stats provider registered for. + private void maybeUpdateDataLimit(@NonNull String iface) { + // Set data limit only on a given upstream which has at least one rule. If we can't get + // an interface index for a given interface name, it means either there is no rule for + // a given upstream or the interface name is not an upstream which is monitored by the + // coordinator. + final int ifIndex = getInterfaceIndexFromRules(iface); + if (ifIndex == 0) return; + + final long quotaBytes = getQuotaBytes(iface); + sendDataLimitToNetd(ifIndex, quotaBytes); + } + + // Handle the data limit update while adding forwarding rules. + private boolean updateDataLimit(int ifIndex) { + final String iface = mInterfaceNames.get(ifIndex); + if (iface == null) { + mLog.e("Fail to get the interface name for index " + ifIndex); + return false; + } + final long quotaBytes = getQuotaBytes(iface); + return sendDataLimitToNetd(ifIndex, quotaBytes); + } + + private boolean isAnyRuleOnUpstream(int upstreamIfindex) { + for (LinkedHashMap rules : mIpv6ForwardingRules + .values()) { + for (Ipv6ForwardingRule rule : rules.values()) { + if (upstreamIfindex == rule.upstreamIfindex) return true; + } + } + return false; + } + @NonNull private NetworkStats buildNetworkStats(@NonNull StatsType type, int ifIndex, - @NonNull ForwardedStats diff) { + @NonNull final ForwardedStats diff) { NetworkStats stats = new NetworkStats(0L, 0); final String iface = mInterfaceNames.get(ifIndex); if (iface == null) { @@ -302,17 +576,8 @@ public class BpfCoordinator { } } - private void updateForwardedStatsFromNetd() { - final TetherStatsParcel[] tetherStatsList; - try { - // The reported tether stats are total data usage for all currently-active upstream - // interfaces since tethering start. - tetherStatsList = mNetd.tetherOffloadGetStats(); - } catch (RemoteException | ServiceSpecificException e) { - mLog.e("Problem fetching tethering stats: ", e); - return; - } - + private void updateQuotaAndStatsFromSnapshot( + @NonNull final TetherStatsParcel[] tetherStatsList) { long usedAlertQuota = 0; for (TetherStatsParcel tetherStats : tetherStatsList) { final Integer ifIndex = tetherStats.ifIndex; @@ -332,7 +597,7 @@ public class BpfCoordinator { buildNetworkStats(StatsType.STATS_PER_IFACE, ifIndex, diff), buildNetworkStats(StatsType.STATS_PER_UID, ifIndex, diff)); } catch (ArrayIndexOutOfBoundsException e) { - Log.wtf("Fail to update the accumulated stats delta for interface index " + Log.wtf(TAG, "Fail to update the accumulated stats delta for interface index " + ifIndex + " : ", e); } } @@ -344,10 +609,24 @@ public class BpfCoordinator { updateAlertQuota(newQuota); } + // TODO: Count the used limit quota for notifying data limit reached. + } + + private void updateForwardedStatsFromNetd() { + final TetherStatsParcel[] tetherStatsList; + try { + // The reported tether stats are total data usage for all currently-active upstream + // interfaces since tethering start. + tetherStatsList = mNetd.tetherOffloadGetStats(); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Problem fetching tethering stats: ", e); + return; + } + updateQuotaAndStatsFromSnapshot(tetherStatsList); } private void maybeSchedulePollingStats() { - if (!mStarted) return; + if (!mPollingStarted) return; if (mHandler.hasCallbacks(mScheduledPollingTask)) { mHandler.removeCallbacks(mScheduledPollingTask); diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 00723ac73b..a3597f1584 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -1709,7 +1709,7 @@ public class Tethering { } // TODO: Check the upstream interface if it is managed by BPF offload. - mBpfCoordinator.start(); + mBpfCoordinator.startPolling(); } @Override @@ -1722,7 +1722,7 @@ public class Tethering { mTetherUpstream = null; reportUpstreamChanged(null); } - mBpfCoordinator.stop(); + mBpfCoordinator.stopPolling(); } private boolean updateUpstreamWanted() { diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 433aacfaff..c3bc915a23 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -54,12 +54,14 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.app.usage.NetworkStatsManager; import android.net.INetd; import android.net.InetAddresses; import android.net.InterfaceConfigurationParcel; @@ -69,6 +71,7 @@ import android.net.LinkProperties; import android.net.MacAddress; import android.net.RouteInfo; import android.net.TetherOffloadRuleParcel; +import android.net.TetherStatsParcel; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpEventCallbacks; import android.net.dhcp.IDhcpServer; @@ -80,14 +83,17 @@ import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; import android.net.util.SharedLog; +import android.os.Handler; import android.os.RemoteException; import android.os.test.TestLooper; import android.text.TextUtils; +import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.networkstack.tethering.BpfCoordinator; +import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule; import com.android.networkstack.tethering.PrivateAddressCoordinator; import org.junit.Before; @@ -101,6 +107,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.util.Arrays; import java.util.List; @@ -127,7 +134,6 @@ public class IpServerTest { private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24"); @Mock private INetd mNetd; - @Mock private BpfCoordinator mBpfCoordinator; @Mock private IpServer.Callback mCallback; @Mock private SharedLog mSharedLog; @Mock private IDhcpServer mDhcpServer; @@ -135,6 +141,7 @@ public class IpServerTest { @Mock private IpNeighborMonitor mIpNeighborMonitor; @Mock private IpServer.Dependencies mDependencies; @Mock private PrivateAddressCoordinator mAddressCoordinator; + @Mock private NetworkStatsManager mStatsManager; @Captor private ArgumentCaptor mDhcpParamsCaptor; @@ -144,6 +151,7 @@ public class IpServerTest { private IpServer mIpServer; private InterfaceConfigurationParcel mInterfaceConfiguration; private NeighborEventConsumer mNeighborEventConsumer; + private BpfCoordinator mBpfCoordinator; private void initStateMachine(int interfaceType) throws Exception { initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD); @@ -217,6 +225,10 @@ public class IpServerTest { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); + + BpfCoordinator bc = new BpfCoordinator(new Handler(mLooper.getLooper()), mNetd, + mStatsManager, mSharedLog, new BpfCoordinator.Dependencies()); + mBpfCoordinator = spy(bc); } @Test @@ -621,6 +633,10 @@ public class IpServerTest { * (actual: "android.net.TetherOffloadRuleParcel@8c827b0" or some such), but at least it does * work. * + * TODO: consider making the error message more readable by adding a method that catching the + * AssertionFailedError and throwing a new assertion with more details. See + * NetworkMonitorTest#verifyNetworkTested. + * * See ConnectivityServiceTest#assertRoutesAdded for an alternative approach which solves the * TooManyActualInvocations problem described above by forcing the caller of the custom assert * method to specify all expected invocations in one call. This is useful when the stable @@ -660,6 +676,27 @@ public class IpServerTest { return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac)); } + private static Ipv6ForwardingRule makeForwardingRule( + int upstreamIfindex, @NonNull InetAddress dst, @NonNull MacAddress dstMac) { + return new Ipv6ForwardingRule(upstreamIfindex, TEST_IFACE_PARAMS.index, + (Inet6Address) dst, TEST_IFACE_PARAMS.macAddr, dstMac); + } + + private TetherStatsParcel buildEmptyTetherStatsParcel(int ifIndex) { + TetherStatsParcel parcel = new TetherStatsParcel(); + parcel.ifIndex = ifIndex; + return parcel; + } + + private void resetNetdAndBpfCoordinator() throws Exception { + reset(mNetd, mBpfCoordinator); + when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]); + when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX)) + .thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX)); + when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX2)) + .thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX2)); + } + @Test public void addRemoveipv6ForwardingRules() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, @@ -677,75 +714,100 @@ public class IpServerTest { final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b"); - reset(mNetd); + resetNetdAndBpfCoordinator(); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); + + // TODO: Perhaps verify the interaction of tetherOffloadSetInterfaceQuota and + // tetherOffloadGetAndClearStats in netd while the rules are changed. // Events on other interfaces are ignored. recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA); - verifyNoMoreInteractions(mNetd); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); // Events on this interface are received and sent to netd. recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); - reset(mNetd); + resetNetdAndBpfCoordinator(); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); - reset(mNetd); + resetNetdAndBpfCoordinator(); // Link-local and multicast neighbors are ignored. recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA); - verifyNoMoreInteractions(mNetd); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA); - verifyNoMoreInteractions(mNetd); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); // A neighbor that is no longer valid causes the rule to be removed. // NUD_FAILED events do not have a MAC address. recvNewNeigh(myIfindex, neighA, NUD_FAILED, null); + verify(mBpfCoordinator).tetherOffloadRuleRemove( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macNull)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macNull)); - reset(mNetd); + resetNetdAndBpfCoordinator(); // A neighbor that is deleted causes the rule to be removed. recvDelNeigh(myIfindex, neighB, NUD_STALE, macB); + verify(mBpfCoordinator).tetherOffloadRuleRemove( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macNull)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macNull)); - reset(mNetd); + resetNetdAndBpfCoordinator(); - // Upstream changes result in deleting and re-adding the rules. + // Upstream changes result in updating the rules. recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); - reset(mNetd); + resetNetdAndBpfCoordinator(); InOrder inOrder = inOrder(mNetd); LinkProperties lp = new LinkProperties(); lp.setInterfaceName(UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1); - inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA)); + verify(mBpfCoordinator).tetherOffloadRuleUpdate(mIpServer, UPSTREAM_IFINDEX2); inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); - inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB)); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA)); inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); - reset(mNetd); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB)); + resetNetdAndBpfCoordinator(); // When the upstream is lost, rules are removed. dispatchTetherConnectionChanged(null, null, 0); + // Clear function is called two times by: + // - processMessage CMD_TETHER_CONNECTION_CHANGED for the upstream is lost. + // - processMessage CMD_IPV6_TETHER_UPDATE for the IPv6 upstream is lost. + // See dispatchTetherConnectionChanged. + verify(mBpfCoordinator, times(2)).tetherOffloadRuleClear(mIpServer); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB)); - reset(mNetd); + resetNetdAndBpfCoordinator(); // If the upstream is IPv4-only, no rules are added. dispatchTetherConnectionChanged(UPSTREAM_IFACE); - reset(mNetd); + resetNetdAndBpfCoordinator(); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); - verifyNoMoreInteractions(mNetd); + // Clear function is called by #updateIpv6ForwardingRules for the IPv6 upstream is lost. + verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); // Rules can be added again once upstream IPv6 connectivity is available. lp.setInterfaceName(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); + verify(mBpfCoordinator, never()).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); // If upstream IPv6 connectivity is lost, rules are removed. - reset(mNetd); + resetNetdAndBpfCoordinator(); dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0); + verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); // When the interface goes down, rules are removed. @@ -753,15 +815,20 @@ public class IpServerTest { dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); - reset(mNetd); + resetNetdAndBpfCoordinator(); mIpServer.stop(); mLooper.dispatchAll(); + verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); - reset(mNetd); + resetNetdAndBpfCoordinator(); } @Test @@ -771,35 +838,46 @@ public class IpServerTest { final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00"); - reset(mNetd); - // Expect that rules can be only added/removed when the BPF offload config is enabled. - // Note that the usingBpfOffload false case is not a realistic test case. Because IP + // Note that the BPF offload disabled case is not a realistic test case. Because IP // neighbor monitor doesn't start if BPF offload is disabled, there should have no // neighbor event listening. This is used for testing the protection check just in case. - // TODO: Perhaps remove this test once we don't need this check anymore. - for (boolean usingBpfOffload : new boolean[]{true, false}) { - initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, - usingBpfOffload); + // TODO: Perhaps remove the BPF offload disabled case test once this check isn't needed + // anymore. - // A neighbor is added. - recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA); - if (usingBpfOffload) { - verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA)); - } else { - verify(mNetd, never()).tetherOffloadRuleAdd(any()); - } - reset(mNetd); + // [1] Enable BPF offload. + // A neighbor that is added or deleted causes the rule to be added or removed. + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + true /* usingBpfOffload */); + resetNetdAndBpfCoordinator(); - // A neighbor is deleted. - recvDelNeigh(myIfindex, neigh, NUD_STALE, macA); - if (usingBpfOffload) { - verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull)); - } else { - verify(mNetd, never()).tetherOffloadRuleRemove(any()); - } - reset(mNetd); - } + recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macA)); + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA)); + resetNetdAndBpfCoordinator(); + + recvDelNeigh(myIfindex, neigh, NUD_STALE, macA); + verify(mBpfCoordinator).tetherOffloadRuleRemove( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macNull)); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull)); + resetNetdAndBpfCoordinator(); + + // [2] Disable BPF offload. + // A neighbor that is added or deleted doesn’t cause the rule to be added or removed. + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + false /* usingBpfOffload */); + resetNetdAndBpfCoordinator(); + + recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA); + verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(any(), any()); + verify(mNetd, never()).tetherOffloadRuleAdd(any()); + resetNetdAndBpfCoordinator(); + + recvDelNeigh(myIfindex, neigh, NUD_STALE, macA); + verify(mBpfCoordinator, never()).tetherOffloadRuleRemove(any(), any()); + verify(mNetd, never()).tetherOffloadRuleRemove(any()); + resetNetdAndBpfCoordinator(); } @Test diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java index 3e19ddfc0b..e2d7aab4e3 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -141,7 +141,7 @@ public class BpfCoordinatorTest { setupFunctioningNetdInterface(); final BpfCoordinator coordinator = makeBpfCoordinator(); - coordinator.start(); + coordinator.startPolling(); final String wlanIface = "wlan0"; final Integer wlanIfIndex = 100; @@ -197,7 +197,7 @@ public class BpfCoordinatorTest { // [3] Stop coordinator. // Shutdown the coordinator and clear the invocation history, especially the // tetherOffloadGetStats() calls. - coordinator.stop(); + coordinator.stopPolling(); clearInvocations(mNetd); // Verify the polling update thread stopped. @@ -211,7 +211,7 @@ public class BpfCoordinatorTest { setupFunctioningNetdInterface(); final BpfCoordinator coordinator = makeBpfCoordinator(); - coordinator.start(); + coordinator.startPolling(); final String mobileIface = "rmnet_data0"; final Integer mobileIfIndex = 100; From 23710588f9069743387fc7f870fbeeb27978f188 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 10 Jun 2020 00:45:26 +0800 Subject: [PATCH 1193/1415] Fix MultinetworkApiTest fail problem in instant mode CtsNetUtils#storePrivateDnsSetting might require WRITE_SECURE_SETTINGS permission to run. Therefore, move it from setUp to only belong to the required test case. Bug: 158538281 Test: run cts --include-filter "arm64-v8a CtsNetTestCases[instant] android.net.cts.MultinetworkApiTest" Change-Id: I8ecadd134824a4023a3c6e173d52ba088d46b103 --- tests/cts/net/src/android/net/cts/MultinetworkApiTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index 985e313a92..6d3db8912d 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -68,7 +68,6 @@ public class MultinetworkApiTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - mCtsNetUtils.storePrivateDnsSetting(); } @Override @@ -223,6 +222,7 @@ public class MultinetworkApiTest extends AndroidTestCase { @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") public void testResNApiNXDomainPrivateDns() throws InterruptedException { + mCtsNetUtils.storePrivateDnsSetting(); // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 try { From dfd08cab51983cc2e580ee81a54afa7bb0159427 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 9 Jun 2020 20:22:44 +0000 Subject: [PATCH 1194/1415] Fix tests that failed on devices without IPsec tunnel feature Three tests failed when they try to set up IKE Session with a tunnel mode Child SA and the device does not have ipsec tunnel feature. This commit changed these tests to set up IKE Session with a transport mode SA because 1) the logic these tests are verifying is unrelated to the Child SA type and 2) using transport mode make sure these tests run on all the devices. Bug: 158268209 Test: CtsIkeTestCases, verified on taimen Change-Id: I9a8c7f631f0e6e02492816e3fbf0d751017dc2b3 Merged-In: I9a8c7f631f0e6e02492816e3fbf0d751017dc2b3 (cherry picked from commit 0224324097f36106dfb7eccad3325024403e0381) --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 62 +++++++++++-------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 7 +++ 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index 0509fc0c92..13f953a50d 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -18,13 +18,14 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; -import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.net.LinkAddress; +import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionParams; @@ -84,7 +85,15 @@ public class IkeSessionPskTest extends IkeSessionTestBase { + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" + "6743A7CEB2BE34AC00095A5B8"; - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { + private IkeSession openIkeSessionWithTunnelModeChild(InetAddress remoteAddress) { + return openIkeSession(remoteAddress, buildTunnelModeChildSessionParams()); + } + + private IkeSession openIkeSessionWithTransportModeChild(InetAddress remoteAddress) { + return openIkeSession(remoteAddress, buildTransportModeChildParamsWithDefaultTs()); + } + + private IkeSession openIkeSession(InetAddress remoteAddress, ChildSessionParams childParams) { IkeSessionParams ikeParams = new IkeSessionParams.Builder(sContext) .setNetwork(mTunNetwork) @@ -98,7 +107,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { return new IkeSession( sContext, ikeParams, - buildTunnelModeChildSessionParams(), + childParams, mUserCbExecutor, mIkeSessionCallback, mFirstChildSessionCallback); @@ -124,7 +133,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { if (!hasTunnelsFeature()) return; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 @@ -222,7 +231,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { setUpTestNetwork(mLocalAddress); // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking( ikeInitResp, 1 /* expectedAuthReqPktCnt */, @@ -258,7 +267,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { if (!hasTunnelsFeature()) return; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); ikeSession.kill(); @@ -272,7 +281,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( IKE_DETERMINISTIC_INITIATOR_SPI, @@ -309,7 +318,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { + "AB6E4808BAC0CA1DAD6ADD0A126A41BD"; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthFailRespHex); mFirstChildSessionCallback.awaitOnClosed(); @@ -322,27 +331,28 @@ public class IkeSessionPskTest extends IkeSessionTestBase { @Test public void testIkeAuthHandlesFirstChildCreationFail() throws Exception { final String ikeInitRespHex = - "46B8ECA1E0D72A182B300285DA19E6452120222000000000000001502200" - + "00300000002C010100040300000C0100000C800E01000300000803000005" - + "0300000802000004000000080400000228000088000200005C9DE629981F" - + "DB1FC45DB6CCF15D076C1F51BD9F63C771DC089F05CCDE6247965D15C616" - + "C7B5A62342491715E4D1FEA19326477D24143E8E56AB6AD93F54B19BC32A" - + "44BC0A5B5632E57D0A3C43E466E1547D8E4EF65EA4B864A348161666E229" - + "84975A486251A17C4F096A6D5CF3DB83874B70324A31AA7ADDE2D73BADD8" - + "238029000024CF06260F7C4923295E7C91F2B8479212892DA7A519A0322F" - + "F5B2BF570B92972B2900001C00004004C7ACC2C7D58CF8C9F5E953993AF4" - + "6CAC976635B42900001C00004005B64B190DFE7BDE8B9B1475EDE67B63D6" - + "F1DBBF44290000080000402E290000100000402F00020003000400050000" + "46B8ECA1E0D72A18F5ABBF896A1240BE2120222000000000000001502200" + + "00300000002C010100040300000C0100000C800E0100030000080300000C" + + "03000008020000050000000804000002280000880002000074950F016B85" + + "605E57E24651843AB70E41B552EDEE227DFE51E6CBEC00E75FFEFC7D5453" + + "109B15F721FCD811FC9F113BE06050882F2FC5F5FF25857E555CCFB5AB64" + + "8B0D1D7A819A3B05DE1FE89A4A627C60D5AA06CD0F66ACD3748722F9CD4F" + + "F30AE7477CBC12049821F07AD6C9F0ED732321A6A36FA817722E025AC34B" + + "ABE62900002432E3807F595070E95EDA341A787599B24B1151B535B0222B" + + "65C003401B9B38F82900001C000040043BB760DB3037B51768DFFAB4B21D" + + "B1716EA1C1382900001C0000400531098EB04DF1BE3F304606BD59B454A8" + + "CC7E7311290000080000402E290000100000402F00020003000400050000" + "000800004014"; final String ikeAuthCreateChildFailHex = - "46B8ECA1E0D72A182B300285DA19E6452E202320000000010000008C2400" - + "0070386FC9CCC67495A17915D0544390A2963A769F4A42C6FA668CEEC07F" - + "EC0C87D681DE34267023DD394F1401B5A563E71002C0CE0928D0ABC0C4570" - + "E39C2EDEF820F870AB71BD70A3F3EB5C96CA294B6D3F01677690DCF9F8CFC" - + "9584650957573502BA83E32F18207A9ADEB1FA"; + "46B8ECA1E0D72A18F5ABBF896A1240BE2E20232000000001000000B02400" + + "009400B0861242E0C88ECB3848D772B560CAD65B6AC9DFFDC8622A394B8E" + + "64E550BDD69FCD7E768129787ED9062992C1D6DB0F0631C2E05765B403CF" + + "EF1D0A055B32F6698FF7DB5B8FB1B6A83A81634D00E22C86E35B3BFBEC73" + + "EAC6806678926945BC7A57003DC1A3528A1EC423EE56C1075B36C0B57A6B" + + "C6DD990182F6FABFFA167D199C7D629E5B830AAD2AFBD31CEBA6"; // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); + IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthCreateChildFailHex); // Even though the child creation failed, the authentication succeeded, so the IKE Session's @@ -352,7 +362,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Verify Child Creation failed IkeProtocolException protocolException = (IkeProtocolException) mFirstChildSessionCallback.awaitOnClosedException(); - assertEquals(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE, protocolException.getErrorType()); + assertEquals(ERROR_TYPE_TS_UNACCEPTABLE, protocolException.getErrorType()); assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); ikeSession.kill(); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index 2458b25e33..a81063b30a 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -276,6 +276,13 @@ abstract class IkeSessionTestBase extends IkeTestBase { .build(); } + TransportModeChildSessionParams buildTransportModeChildParamsWithDefaultTs() { + return new TransportModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .build(); + } + TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { return new TunnelModeChildSessionParams.Builder() .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) From 791d142a9862f41168434a5d0c8b59628efa2825 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Thu, 11 Jun 2020 01:37:16 +0000 Subject: [PATCH 1195/1415] Fix MultinetworkApiTest fail problem in instant mode CtsNetUtils#storePrivateDnsSetting might require WRITE_SECURE_SETTINGS permission to run. Therefore, move it from setUp to only belong to the required test case. Bug: 158538281 Test: run cts --include-filter "arm64-v8a CtsNetTestCases[instant] android.net.cts.MultinetworkApiTest" Merged-In: I8ecadd134824a4023a3c6e173d52ba088d46b103 Change-Id: Ic8fa1421b1092efdb011a124836d9f466a231f43 (cherry picked from commit 9451fdf5031d2de02ac9011696b56760ea4943a0) --- tests/cts/net/src/android/net/cts/MultinetworkApiTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index 985e313a92..6d3db8912d 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -68,7 +68,6 @@ public class MultinetworkApiTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mCR = getContext().getContentResolver(); mCtsNetUtils = new CtsNetUtils(getContext()); - mCtsNetUtils.storePrivateDnsSetting(); } @Override @@ -223,6 +222,7 @@ public class MultinetworkApiTest extends AndroidTestCase { @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") public void testResNApiNXDomainPrivateDns() throws InterruptedException { + mCtsNetUtils.storePrivateDnsSetting(); // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. // b/144521720 try { From 47f7a4435086d7f3b3dc3ca414f2baf591ab1690 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Sat, 16 May 2020 22:59:24 +0800 Subject: [PATCH 1196/1415] [BOT.10] Add unit test for data limit and rule change in BpfCoordinator The applying data limit is based on the forwarding rule changes. Add the tests for verifying their interactions with netd. Bug: 150736748 Test: BpfCoordinatorTest Change-Id: I5a98c4cd74e2de6005ee05defa761f6af3fd4e75 --- .../tethering/BpfCoordinatorTest.java | 231 ++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java index e2d7aab4e3..ba0f41c4fa 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -31,10 +31,16 @@ import static com.android.networkstack.tethering.BpfCoordinator.StatsType; import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE; import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.fail; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -42,8 +48,12 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.app.usage.NetworkStatsManager; import android.net.INetd; +import android.net.InetAddresses; +import android.net.MacAddress; import android.net.NetworkStats; +import android.net.TetherOffloadRuleParcel; import android.net.TetherStatsParcel; +import android.net.ip.IpServer; import android.net.util.SharedLog; import android.os.Handler; import android.os.test.TestLooper; @@ -51,22 +61,37 @@ import android.os.test.TestLooper; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule; import com.android.testutils.TestableNetworkStatsProviderCbBinder; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.net.Inet6Address; +import java.net.InetAddress; import java.util.ArrayList; +import java.util.Arrays; @RunWith(AndroidJUnit4.class) @SmallTest public class BpfCoordinatorTest { + private static final int DOWNSTREAM_IFINDEX = 10; + private static final MacAddress DOWNSTREAM_MAC = MacAddress.ALL_ZEROS_ADDRESS; + private static final InetAddress NEIGH_A = InetAddresses.parseNumericAddress("2001:db8::1"); + private static final InetAddress NEIGH_B = InetAddresses.parseNumericAddress("2001:db8::2"); + private static final MacAddress MAC_A = MacAddress.fromString("00:00:00:00:00:0a"); + private static final MacAddress MAC_B = MacAddress.fromString("11:22:33:00:00:0b"); + @Mock private NetworkStatsManager mStatsManager; @Mock private INetd mNetd; + @Mock private IpServer mIpServer; + // Late init since methods must be called by the thread that created this object. private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb; private BpfCoordinator.BpfTetherStatsProvider mTetherStatsProvider; @@ -243,4 +268,210 @@ public class BpfCoordinatorTest { waitForIdle(); mTetherStatsProviderCb.assertNoCallback(); } + + // The custom ArgumentMatcher simply comes from IpServerTest. + // TODO: move both of them into a common utility class for reusing the code. + private static class TetherOffloadRuleParcelMatcher implements + ArgumentMatcher { + public final int upstreamIfindex; + public final int downstreamIfindex; + public final Inet6Address address; + public final MacAddress srcMac; + public final MacAddress dstMac; + + TetherOffloadRuleParcelMatcher(@NonNull Ipv6ForwardingRule rule) { + upstreamIfindex = rule.upstreamIfindex; + downstreamIfindex = rule.downstreamIfindex; + address = rule.address; + srcMac = rule.srcMac; + dstMac = rule.dstMac; + } + + public boolean matches(@NonNull TetherOffloadRuleParcel parcel) { + return upstreamIfindex == parcel.inputInterfaceIndex + && (downstreamIfindex == parcel.outputInterfaceIndex) + && Arrays.equals(address.getAddress(), parcel.destination) + && (128 == parcel.prefixLength) + && Arrays.equals(srcMac.toByteArray(), parcel.srcL2Address) + && Arrays.equals(dstMac.toByteArray(), parcel.dstL2Address); + } + + public String toString() { + return String.format("TetherOffloadRuleParcelMatcher(%d, %d, %s, %s, %s", + upstreamIfindex, downstreamIfindex, address.getHostAddress(), srcMac, dstMac); + } + } + + @NonNull + private TetherOffloadRuleParcel matches(@NonNull Ipv6ForwardingRule rule) { + return argThat(new TetherOffloadRuleParcelMatcher(rule)); + } + + @NonNull + private static Ipv6ForwardingRule buildTestForwardingRule( + int upstreamIfindex, @NonNull InetAddress address, @NonNull MacAddress dstMac) { + return new Ipv6ForwardingRule(upstreamIfindex, DOWNSTREAM_IFINDEX, (Inet6Address) address, + DOWNSTREAM_MAC, dstMac); + } + + @Test + public void testSetDataLimit() throws Exception { + setupFunctioningNetdInterface(); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + + final String mobileIface = "rmnet_data0"; + final Integer mobileIfIndex = 100; + coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface); + + // [1] Default limit. + // Set the unlimited quota as default if the service has never applied a data limit for a + // given upstream. Note that the data limit only be applied on an upstream which has rules. + final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A); + final InOrder inOrder = inOrder(mNetd); + coordinator.tetherOffloadRuleAdd(mIpServer, rule); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(rule)); + inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, QUOTA_UNLIMITED); + inOrder.verifyNoMoreInteractions(); + + // [2] Specific limit. + // Applying the data limit boundary {min, max, infinity} on current upstream. + for (final long quota : new long[] {0, Long.MAX_VALUE, QUOTA_UNLIMITED}) { + mTetherStatsProvider.onSetLimit(mobileIface, quota); + waitForIdle(); + inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, quota); + inOrder.verifyNoMoreInteractions(); + } + + // [3] Invalid limit. + // The valid range of quota is 0..max_int64 or -1 (unlimited). + final long invalidLimit = Long.MIN_VALUE; + try { + mTetherStatsProvider.onSetLimit(mobileIface, invalidLimit); + waitForIdle(); + fail("No exception thrown for invalid limit " + invalidLimit + "."); + } catch (IllegalArgumentException expected) { + assertEquals(expected.getMessage(), "invalid quota value " + invalidLimit); + } + } + + // TODO: Test the case in which the rules are changed from different IpServer objects. + @Test + public void testSetDataLimitOnRuleChange() throws Exception { + setupFunctioningNetdInterface(); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + + final String mobileIface = "rmnet_data0"; + final Integer mobileIfIndex = 100; + coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface); + + // Applying a data limit to the current upstream does not take any immediate action. + // The data limit could be only set on an upstream which has rules. + final long limit = 12345; + final InOrder inOrder = inOrder(mNetd); + mTetherStatsProvider.onSetLimit(mobileIface, limit); + waitForIdle(); + inOrder.verify(mNetd, never()).tetherOffloadSetInterfaceQuota(anyInt(), anyLong()); + + // Adding the first rule on current upstream immediately sends the quota to netd. + final Ipv6ForwardingRule ruleA = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A); + coordinator.tetherOffloadRuleAdd(mIpServer, ruleA); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(ruleA)); + inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, limit); + inOrder.verifyNoMoreInteractions(); + + // Adding the second rule on current upstream does not send the quota to netd. + final Ipv6ForwardingRule ruleB = buildTestForwardingRule(mobileIfIndex, NEIGH_B, MAC_B); + coordinator.tetherOffloadRuleAdd(mIpServer, ruleB); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(ruleB)); + inOrder.verify(mNetd, never()).tetherOffloadSetInterfaceQuota(anyInt(), anyLong()); + + // Removing the second rule on current upstream does not send the quota to netd. + coordinator.tetherOffloadRuleRemove(mIpServer, ruleB); + inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(ruleB)); + inOrder.verify(mNetd, never()).tetherOffloadSetInterfaceQuota(anyInt(), anyLong()); + + // Removing the last rule on current upstream immediately sends the cleanup stuff to netd. + when(mNetd.tetherOffloadGetAndClearStats(mobileIfIndex)) + .thenReturn(buildTestTetherStatsParcel(mobileIfIndex, 0, 0, 0, 0)); + coordinator.tetherOffloadRuleRemove(mIpServer, ruleA); + inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(ruleA)); + inOrder.verify(mNetd).tetherOffloadGetAndClearStats(mobileIfIndex); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testTetherOffloadRuleUpdateAndClear() throws Exception { + setupFunctioningNetdInterface(); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + + final String ethIface = "eth1"; + final String mobileIface = "rmnet_data0"; + final Integer ethIfIndex = 100; + final Integer mobileIfIndex = 101; + coordinator.addUpstreamNameToLookupTable(ethIfIndex, ethIface); + coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface); + + final InOrder inOrder = inOrder(mNetd); + + // Before the rule test, here are the additional actions while the rules are changed. + // - After adding the first rule on a given upstream, the coordinator adds a data limit. + // If the service has never applied the data limit, set an unlimited quota as default. + // - After removing the last rule on a given upstream, the coordinator gets the last stats. + // Then, it clears the stats and the limit entry from BPF maps. + // See tetherOffloadRule{Add, Remove, Clear, Clean}. + + // [1] Adding rules on the upstream Ethernet. + // Note that the default data limit is applied after the first rule is added. + final Ipv6ForwardingRule ethernetRuleA = buildTestForwardingRule( + ethIfIndex, NEIGH_A, MAC_A); + final Ipv6ForwardingRule ethernetRuleB = buildTestForwardingRule( + ethIfIndex, NEIGH_B, MAC_B); + + coordinator.tetherOffloadRuleAdd(mIpServer, ethernetRuleA); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(ethernetRuleA)); + inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(ethIfIndex, QUOTA_UNLIMITED); + + coordinator.tetherOffloadRuleAdd(mIpServer, ethernetRuleB); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(ethernetRuleB)); + + // [2] Update the existing rules from Ethernet to cellular. + final Ipv6ForwardingRule mobileRuleA = buildTestForwardingRule( + mobileIfIndex, NEIGH_A, MAC_A); + final Ipv6ForwardingRule mobileRuleB = buildTestForwardingRule( + mobileIfIndex, NEIGH_B, MAC_B); + when(mNetd.tetherOffloadGetAndClearStats(ethIfIndex)) + .thenReturn(buildTestTetherStatsParcel(ethIfIndex, 10, 20, 30, 40)); + + // Update the existing rules for upstream changes. The rules are removed and re-added one + // by one for updating upstream interface index by #tetherOffloadRuleUpdate. + coordinator.tetherOffloadRuleUpdate(mIpServer, mobileIfIndex); + inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(ethernetRuleA)); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(mobileRuleA)); + inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, QUOTA_UNLIMITED); + inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(ethernetRuleB)); + inOrder.verify(mNetd).tetherOffloadGetAndClearStats(ethIfIndex); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(mobileRuleB)); + + // [3] Clear all rules for a given IpServer. + when(mNetd.tetherOffloadGetAndClearStats(mobileIfIndex)) + .thenReturn(buildTestTetherStatsParcel(mobileIfIndex, 50, 60, 70, 80)); + coordinator.tetherOffloadRuleClear(mIpServer); + inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(mobileRuleA)); + inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(mobileRuleB)); + inOrder.verify(mNetd).tetherOffloadGetAndClearStats(mobileIfIndex); + + // [4] Force pushing stats update to verify that the last diff of stats is reported on all + // upstreams. + mTetherStatsProvider.pushTetherStats(); + mTetherStatsProviderCb.expectNotifyStatsUpdated( + new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_IFACE, ethIface, 10, 20, 30, 40)) + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 50, 60, 70, 80)), + new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_UID, ethIface, 10, 20, 30, 40)) + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 50, 60, 70, 80))); + } } From 484f0d4901887e141d7384560fa7e382820a3e8e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 12 Jun 2020 17:59:16 +0900 Subject: [PATCH 1197/1415] Move Inet[4]AddressUtils to libs/net The classes should not be picked up from frameworks/base, as they are part of several mainline modules. Bug: 151052811 Test: m; manual: flashed, wifi and telephony working Test: atest CtsNetTestCasesLatestSdk:CaptivePortalApiTest Change-Id: Ic7534afe3a437f2089ed33cebdad391dc498d187 --- tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt index 68d5281650..ef2b0cee2f 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt @@ -35,8 +35,6 @@ import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_DISCOVER import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_REQUEST import android.net.dhcp.DhcpRequestPacket -import android.net.shared.Inet4AddressUtils.getBroadcastAddress -import android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address import android.os.Build import android.os.HandlerThread import android.platform.test.annotations.AppModeFull @@ -44,6 +42,8 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity import com.android.compatibility.common.util.ThrowingRunnable +import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress +import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DhcpClientPacketFilter From 24d8b8391e85dc14c5f5635da90b503f8496b4af Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 11 Jun 2020 19:20:38 +0800 Subject: [PATCH 1198/1415] Fix CtsTetheringTest on devices without permanent softAp interfaces. Normally stop wifi tethering flow would be: Tethering#stopTethering -> WifiManager#stopSoftAp -> softAp disabled, then have WIIF_AP_STATE_CHANGED intent -> stop IpServer and broadcast TETHER_STATE_CHANGED intent. SoftAp is disabled before tethering stop. Because tethering would shutdown the corresponding IpServer if it observed the interface is removed. For those devices that softAp interface would be removed when stop tethering, the flow may be Tethering#stopTethering -> WifiManager#stopSoftAp -> softAp disabing, softAp interface is removed -> tethering trigger stop IpServer and broadcast TETHER_STATE_CHANGED intent -> -> softAp disabled, then wifi broadcast WIIF_AP_STATE_CHANGED intent. In this case, tethering is stopped ready before softap is disabled. For this case, CtsTeteringTest would have race between two test cases. If two case need to start wifi tethering for testing and stop wifi tethering after finish testing. The second test may suffer from startTethering fail problem due to softAP is not disabled yet. E WifiService: Tethering is already active. Bug: 157806780 Test: atest CtsTetheringTest Change-Id: I0ba6bc9dcbf7829dcad5561c707d5f5c5540f10b --- .../tethering/cts/TetheringManagerTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index f7160dd502..5e2f62787c 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -57,8 +57,11 @@ import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; import android.net.cts.util.CtsNetUtils; import android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import android.net.wifi.WifiClient; import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.SoftApCallback; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.telephony.CarrierConfigManager; @@ -135,6 +138,40 @@ public class TetheringManagerTest { dropShellPermissionIdentity(); } + private static class StopSoftApCallback implements SoftApCallback { + private final ConditionVariable mWaiting = new ConditionVariable(); + @Override + public void onStateChanged(int state, int failureReason) { + if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open(); + } + + @Override + public void onConnectedClientsChanged(List clients) { } + + public void waitForSoftApStopped() { + if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { + fail("stopSoftAp Timeout"); + } + } + } + + // Wait for softAp to be disabled. This is necessary on devices where stopping softAp + // deletes the interface. On these devices, tethering immediately stops when the softAp + // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be + // fully disabled, because otherwise the next test might fail because it attempts to + // start softAp before it's fully stopped. + private void expectSoftApDisabled() { + final StopSoftApCallback callback = new StopSoftApCallback(); + try { + mWm.registerSoftApCallback(c -> c.run(), callback); + // registerSoftApCallback will immediately call the callback with the current state, so + // this callback will fire even if softAp is already disabled. + callback.waitForSoftApStopped(); + } finally { + mWm.unregisterSoftApCallback(callback); + } + } + private class TetherChangeReceiver extends BroadcastReceiver { private class TetherState { final ArrayList mAvailable; @@ -294,6 +331,7 @@ public class TetheringManagerTest { mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); mTM.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); } @@ -544,6 +582,7 @@ public class TetheringManagerTest { private void stopWifiTethering(final TestTetheringEventCallback callback) { mTM.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); callback.expectTetheredInterfacesChanged(null); callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); } From 0d0ea27274afe400644754f2505d3fb18ec43416 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 15 Jun 2020 08:03:02 +0000 Subject: [PATCH 1199/1415] Use unstable networkstack AIDLs in development branches Development branches should use the -unstable version of the NetworkStack AIDLs so that refreezing is not necessary for each modification. The versions will be re-frozen before each release instead. Bug: 157534516 Change-Id: I74b4a16266bda7b8ac740b3a0193268da260fc2f Test: m --- Tethering/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 9eba6bd0dc..9c8c0aab2d 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -27,7 +27,8 @@ java_defaults { "androidx.annotation_annotation", "netd_aidl_interface-unstable-java", "netlink-client", - "networkstack-aidl-interfaces-java", + // TODO: use networkstack-client instead of just including the AIDL interface + "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.config-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "net-utils-framework-common", From fa761d59174072b7bdf07a83ead15226d6509220 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 15 Jun 2020 12:19:58 +0900 Subject: [PATCH 1200/1415] Toggle wifi when running CaptivePortalTest Instead of reconnecting without disabling/re-enabling wifi in CaptivePortalTest, actually do the toggle during the test and on teardown to ensure that the BSSID blacklist is cleared. CaptivePortalTest intentionally makes the network not validate, which causes it to be added to the BSSID blacklist. Toggling wifi is necessary to make sure the test does not affect other tests. Also check development SDK instead of the exact SDK_INT number so that the test can pass on current AOSP builds. Bug: 158924461 Test: atest CtsNetTestCasesLatestSdk:CaptivePortalTest \ CtsNetTestCasesLatestSdk:ConnectivityManagerTest Change-Id: I31f9f4a9678e11042005c29535af840246358764 --- .../src/android/net/cts/CaptivePortalTest.kt | 15 ++-- .../android/net/cts/util/CtsNetUtils.java | 83 +++++++++++++++++-- 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 0816aba750..4a7d38a172 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -41,6 +41,7 @@ import android.text.TextUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 import com.android.compatibility.common.util.SystemUtil +import com.android.testutils.isDevSdkInRange import fi.iki.elonen.NanoHTTPD import fi.iki.elonen.NanoHTTPD.Response.IStatus import fi.iki.elonen.NanoHTTPD.Response.Status @@ -105,6 +106,9 @@ class CaptivePortalTest { @After fun tearDown() { clearTestUrls() + if (pm.hasSystemFeature(FEATURE_WIFI)) { + reconnectWifi() + } server.stop() } @@ -167,7 +171,7 @@ class CaptivePortalTest { assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) val startPortalAppPermission = - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) CONNECTIVITY_INTERNAL + if (isDevSdkInRange(0, Build.VERSION_CODES.Q)) CONNECTIVITY_INTERNAL else NETWORK_SETTINGS doAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " + @@ -180,9 +184,6 @@ class CaptivePortalTest { // disconnectFromCell should be called after connectToCell utils.disconnectFromCell() } - - clearTestUrls() - reconnectWifi() } private fun setHttpsUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING, url) @@ -203,10 +204,8 @@ class CaptivePortalTest { } private fun reconnectWifi() { - doAsShell(NETWORK_SETTINGS) { - assertTrue(wm.disconnect()) - assertTrue(wm.reconnect()) - } + utils.ensureWifiDisconnected(null /* wifiNetworkToCheck */) + utils.ensureWifiConnected() } /** 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 b1f3602950..85d2113d89 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 @@ -157,8 +157,36 @@ public final class CtsNetUtils { } } - /** Enable WiFi and wait for it to become connected to a network. */ + /** + * Enable WiFi and wait for it to become connected to a network. + * + * This method expects to receive a legacy broadcast on connect, which may not be sent if the + * network does not become default or if it is not the first network. + */ public Network connectToWifi() { + return connectToWifi(true /* expectLegacyBroadcast */); + } + + /** + * Enable WiFi and wait for it to become connected to a network. + * + * A network is considered connected when a {@link NetworkCallback#onAvailable(Network)} + * callback is received. + */ + public Network ensureWifiConnected() { + return connectToWifi(false /* expectLegacyBroadcast */); + } + + /** + * Enable WiFi and wait for it to become connected to a network. + * + * @param expectLegacyBroadcast Whether to check for a legacy CONNECTIVITY_ACTION connected + * broadcast. The broadcast is typically not sent if the network + * does not become the default network, and is not the first + * network to appear. + * @return The network that was newly connected. + */ + private Network connectToWifi(boolean expectLegacyBroadcast) { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); Network wifiNetwork = null; @@ -170,15 +198,16 @@ public final class CtsNetUtils { mContext.registerReceiver(receiver, filter); boolean connected = false; + final String err = "Wifi must be configured to connect to an access point for this test."; try { clearWifiBlacklist(); SystemUtil.runShellCommand("svc wifi enable"); SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(), NETWORK_SETTINGS); - // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. + // Ensure we get an onAvailable callback and possibly a CONNECTIVITY_ACTION. wifiNetwork = callback.waitForAvailable(); - assertNotNull(wifiNetwork); - connected = receiver.waitForState(); + assertNotNull(err, wifiNetwork); + connected = !expectLegacyBroadcast || receiver.waitForState(); } catch (InterruptedException ex) { fail("connectToWifi was interrupted"); } finally { @@ -186,8 +215,7 @@ public final class CtsNetUtils { mContext.unregisterReceiver(receiver); } - assertTrue("Wifi must be configured to connect to an access point for this test.", - connected); + assertTrue(err, connected); return wifiNetwork; } @@ -204,8 +232,47 @@ public final class CtsNetUtils { }); } - /** Disable WiFi and wait for it to become disconnected from the network. */ + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * This method expects to receive a legacy broadcast on disconnect, which may not be sent if the + * network was not default, or was not the first network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + */ public void disconnectFromWifi(Network wifiNetworkToCheck) { + disconnectFromWifi(wifiNetworkToCheck, true /* expectLegacyBroadcast */); + } + + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + */ + public void ensureWifiDisconnected(Network wifiNetworkToCheck) { + disconnectFromWifi(wifiNetworkToCheck, false /* expectLegacyBroadcast */); + } + + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + * @param expectLegacyBroadcast Whether to check for a legacy CONNECTIVITY_ACTION disconnected + * broadcast. The broadcast is typically not sent if the network + * was not the default network and not the first network to appear. + * The check will always be skipped if the device was not connected + * to wifi in the first place. + */ + private void disconnectFromWifi(Network wifiNetworkToCheck, boolean expectLegacyBroadcast) { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); @@ -238,6 +305,8 @@ public final class CtsNetUtils { // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. assertNotNull("Did not receive onLost callback after disabling wifi", callback.waitForLost()); + } + if (wasWifiConnected && expectLegacyBroadcast) { assertTrue("Wifi failed to reach DISCONNECTED state.", receiver.waitForState()); } } catch (InterruptedException ex) { From 53430127ecc8d004645c4f1ee405f1a01a9e00e2 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 13 Jun 2020 00:47:44 +0900 Subject: [PATCH 1201/1415] Bump CtsNetTestCasesLatestSdk to target SDK 30. This is not necessary for the tests to be able to use APIs introduced in R because they can already access hidden APIs. But it is important to ensure that they are subject to whatever new system behaviour is applied to SDK 30 apps. Fix: 158839774 Test: treehugger Test: atest CtsNetTestCasesLatestSdk has no new failures Change-Id: Ic86fe84b28b5becc722903650f00e9ca7d6e5f3f --- tests/cts/net/Android.bp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 052ab263d2..2b99a40202 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -72,15 +72,15 @@ android_test { test_config_template: "AndroidTestTemplate.xml", } -// Networking CTS tests that have a min_sdk_version of the latest released SDK. These tests can -// be installed on release devices at any point in the release cycle and are useful for qualifying -// mainline modules on release devices. +// Networking CTS tests that target the latest released SDK. These tests can be installed on release +// devices at any point in the Android release cycle and are useful for qualifying mainline modules +// on release devices. android_test { name: "CtsNetTestCasesLatestSdk", defaults: ["CtsNetTestCasesDefaults"], jni_uses_sdk_apis: true, min_sdk_version: "29", - target_sdk_version: "29", + target_sdk_version: "30", test_suites: [ "device-tests", "mts", From 3abe36567c8afd63f116e7fe736584d80cb63165 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Mon, 15 Jun 2020 10:18:21 +0000 Subject: [PATCH 1202/1415] Fix CtsTetheringTest on devices without permanent softAp interfaces. Normally stop wifi tethering flow would be: Tethering#stopTethering -> WifiManager#stopSoftAp -> softAp disabled, then have WIIF_AP_STATE_CHANGED intent -> stop IpServer and broadcast TETHER_STATE_CHANGED intent. SoftAp is disabled before tethering stop. Because tethering would shutdown the corresponding IpServer if it observed the interface is removed. For those devices that softAp interface would be removed when stop tethering, the flow may be Tethering#stopTethering -> WifiManager#stopSoftAp -> softAp disabing, softAp interface is removed -> tethering trigger stop IpServer and broadcast TETHER_STATE_CHANGED intent -> -> softAp disabled, then wifi broadcast WIIF_AP_STATE_CHANGED intent. In this case, tethering is stopped ready before softap is disabled. For this case, CtsTeteringTest would have race between two test cases. If two case need to start wifi tethering for testing and stop wifi tethering after finish testing. The second test may suffer from startTethering fail problem due to softAP is not disabled yet. E WifiService: Tethering is already active. Bug: 157806780 Test: atest CtsTetheringTest Original-Change: https://android-review.googlesource.com/1331096 Merged-In: I0ba6bc9dcbf7829dcad5561c707d5f5c5540f10b Change-Id: I0ba6bc9dcbf7829dcad5561c707d5f5c5540f10b --- .../tethering/cts/TetheringManagerTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index f7160dd502..5e2f62787c 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -57,8 +57,11 @@ import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; import android.net.cts.util.CtsNetUtils; import android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import android.net.wifi.WifiClient; import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.SoftApCallback; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.telephony.CarrierConfigManager; @@ -135,6 +138,40 @@ public class TetheringManagerTest { dropShellPermissionIdentity(); } + private static class StopSoftApCallback implements SoftApCallback { + private final ConditionVariable mWaiting = new ConditionVariable(); + @Override + public void onStateChanged(int state, int failureReason) { + if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open(); + } + + @Override + public void onConnectedClientsChanged(List clients) { } + + public void waitForSoftApStopped() { + if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { + fail("stopSoftAp Timeout"); + } + } + } + + // Wait for softAp to be disabled. This is necessary on devices where stopping softAp + // deletes the interface. On these devices, tethering immediately stops when the softAp + // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be + // fully disabled, because otherwise the next test might fail because it attempts to + // start softAp before it's fully stopped. + private void expectSoftApDisabled() { + final StopSoftApCallback callback = new StopSoftApCallback(); + try { + mWm.registerSoftApCallback(c -> c.run(), callback); + // registerSoftApCallback will immediately call the callback with the current state, so + // this callback will fire even if softAp is already disabled. + callback.waitForSoftApStopped(); + } finally { + mWm.unregisterSoftApCallback(callback); + } + } + private class TetherChangeReceiver extends BroadcastReceiver { private class TetherState { final ArrayList mAvailable; @@ -294,6 +331,7 @@ public class TetheringManagerTest { mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); mTM.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); } @@ -544,6 +582,7 @@ public class TetheringManagerTest { private void stopWifiTethering(final TestTetheringEventCallback callback) { mTM.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); callback.expectTetheredInterfacesChanged(null); callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); } From e571cfd53f662e250b95986e58531108a948780d Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 6 May 2020 16:59:32 +0800 Subject: [PATCH 1203/1415] [BOT.8] Dump BPF offload information in dumpsys $ adb shell dumpsys tethering BPF offload: Polling started Stats provider registered Upstream quota: {rmnet_data2=9223372036854775807} Forwarding stats: 12(rmnet_data2) - ForwardedStats(rxb: 1065, rxp: 5, txb: 0, txp: 0) Forwarding rules: [wlan1]: iif(iface) oif(iface) v6addr srcmac dstmac 12(rmnet_data2) 31(wlan1) /2401:e180:8831:77ae:a900:a03b:41fb.. Bug: 150736748 Test: Enable tethering on mobile data and check dumpsys tethering Change-Id: I95ea3050d92f3ba8136a63cd399d3450d183c8dc --- .../tethering/BpfCoordinator.java | 73 +++++++++++++++++++ .../networkstack/tethering/Tethering.java | 5 ++ 2 files changed, 78 insertions(+) diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index fc27b6add0..4315485f06 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -36,6 +36,7 @@ import android.net.ip.IpServer; import android.net.netstats.provider.NetworkStatsProvider; import android.net.util.SharedLog; import android.net.util.TetheringUtils.ForwardedStats; +import android.os.ConditionVariable; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -47,11 +48,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import java.net.Inet6Address; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.Map; import java.util.Objects; /** @@ -65,6 +68,7 @@ import java.util.Objects; */ public class BpfCoordinator { private static final String TAG = BpfCoordinator.class.getSimpleName(); + private static final int DUMP_TIMEOUT_MS = 10_000; @VisibleForTesting static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; // TODO: Make it customizable. @@ -344,6 +348,75 @@ public class BpfCoordinator { } } + /** + * Dump information. + * Block the function until all the data are dumped on the handler thread or timed-out. The + * reason is that dumpsys invokes this function on the thread of caller and the data may only + * be allowed to be accessed on the handler thread. + */ + public void dump(@NonNull IndentingPrintWriter pw) { + final ConditionVariable dumpDone = new ConditionVariable(); + mHandler.post(() -> { + pw.println("Polling " + (mPollingStarted ? "started" : "not started")); + pw.println("Stats provider " + (mStatsProvider != null + ? "registered" : "not registered")); + pw.println("Upstream quota: " + mInterfaceQuotas.toString()); + + pw.println("Forwarding stats:"); + pw.increaseIndent(); + if (mStats.size() == 0) { + pw.println(""); + } else { + dumpStats(pw); + } + pw.decreaseIndent(); + + pw.println("Forwarding rules:"); + pw.increaseIndent(); + if (mIpv6ForwardingRules.size() == 0) { + pw.println(""); + } else { + dumpIpv6ForwardingRules(pw); + } + pw.decreaseIndent(); + + dumpDone.open(); + }); + if (!dumpDone.block(DUMP_TIMEOUT_MS)) { + pw.println("... dump timed-out after " + DUMP_TIMEOUT_MS + "ms"); + } + } + + private void dumpStats(@NonNull IndentingPrintWriter pw) { + for (int i = 0; i < mStats.size(); i++) { + final int upstreamIfindex = mStats.keyAt(i); + final ForwardedStats stats = mStats.get(upstreamIfindex); + pw.println(String.format("%d(%s) - %s", upstreamIfindex, mInterfaceNames.get( + upstreamIfindex), stats.toString())); + } + } + + private void dumpIpv6ForwardingRules(@NonNull IndentingPrintWriter pw) { + for (Map.Entry> entry : + mIpv6ForwardingRules.entrySet()) { + IpServer ipServer = entry.getKey(); + // The rule downstream interface index is paired with the interface name from + // IpServer#interfaceName. See #startIPv6, #updateIpv6ForwardingRules in IpServer. + final String downstreamIface = ipServer.interfaceName(); + pw.println("[" + downstreamIface + "]: iif(iface) oif(iface) v6addr srcmac dstmac"); + + pw.increaseIndent(); + LinkedHashMap rules = entry.getValue(); + for (Ipv6ForwardingRule rule : rules.values()) { + final int upstreamIfindex = rule.upstreamIfindex; + pw.println(String.format("%d(%s) %d(%s) %s %s %s", upstreamIfindex, + mInterfaceNames.get(upstreamIfindex), rule.downstreamIfindex, + downstreamIface, rule.address, rule.srcMac, rule.dstMac)); + } + pw.decreaseIndent(); + } + } + /** IPv6 forwarding rule class. */ public static class Ipv6ForwardingRule { public final int upstreamIfindex; diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 8deac537ff..a3175c84b1 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -2217,6 +2217,11 @@ public class Tethering { mOffloadController.dump(pw); pw.decreaseIndent(); + pw.println("BPF offload:"); + pw.increaseIndent(); + mBpfCoordinator.dump(pw); + pw.decreaseIndent(); + pw.println("Private address coordinator:"); pw.increaseIndent(); mPrivateAddressCoordinator.dump(pw); From 519f1201ca63ffee90eeb1b5ce424fb2f1e8caa5 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Mon, 18 May 2020 20:08:36 +0800 Subject: [PATCH 1204/1415] [BOT.11] BpfCoordinator could be disabled by device config Bug: 150736748 Test: BpfCoordinatorTest Change-Id: Id413b7f2f7edb2e5c3e02d5677fe536ed52fbbcb --- .../tethering/BpfCoordinator.java | 65 ++++++++++++++++--- .../networkstack/tethering/Tethering.java | 34 +++++++++- .../tethering/TetheringDependencies.java | 5 +- .../unit/src/android/net/ip/IpServerTest.java | 42 ++++++++++-- .../tethering/BpfCoordinatorTest.java | 41 ++++++++++-- .../networkstack/tethering/TetheringTest.java | 4 +- 6 files changed, 162 insertions(+), 29 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index 4315485f06..aa1d59de89 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -89,6 +89,13 @@ public class BpfCoordinator { @Nullable private final BpfTetherStatsProvider mStatsProvider; + // True if BPF offload is supported, false otherwise. The BPF offload could be disabled by + // a runtime resource overlay package or device configuration. This flag is only initialized + // in the constructor because it is hard to unwind all existing change once device + // configuration is changed. Especially the forwarding rules. Keep the same setting + // to make it simpler. See also TetheringConfiguration. + private final boolean mUsingBpf; + // Tracks whether BPF tethering is started or not. This is set by tethering before it // starts the first IpServer and is cleared by tethering shortly before the last IpServer // is stopped. Note that rule updates (especially deletions, but sometimes additions as @@ -146,22 +153,42 @@ public class BpfCoordinator { }; @VisibleForTesting - public static class Dependencies { - int getPerformPollInterval() { + public abstract static class Dependencies { + /** + * Get polling Interval in milliseconds. + */ + public int getPerformPollInterval() { // TODO: Consider make this configurable. return DEFAULT_PERFORM_POLL_INTERVAL_MS; } + + /** Get handler. */ + @NonNull public abstract Handler getHandler(); + + /** Get netd. */ + @NonNull public abstract INetd getNetd(); + + /** Get network stats manager. */ + @NonNull public abstract NetworkStatsManager getNetworkStatsManager(); + + /** Get shared log. */ + @NonNull public abstract SharedLog getSharedLog(); + + /** Get tethering configuration. */ + @Nullable public abstract TetheringConfiguration getTetherConfig(); } @VisibleForTesting - public BpfCoordinator(@NonNull Handler handler, @NonNull INetd netd, - @NonNull NetworkStatsManager nsm, @NonNull SharedLog log, @NonNull Dependencies deps) { - mHandler = handler; - mNetd = netd; - mLog = log.forSubComponent(TAG); + public BpfCoordinator(@NonNull Dependencies deps) { + mDeps = deps; + mHandler = mDeps.getHandler(); + mNetd = mDeps.getNetd(); + mLog = mDeps.getSharedLog().forSubComponent(TAG); + mUsingBpf = isOffloadEnabled(); BpfTetherStatsProvider provider = new BpfTetherStatsProvider(); try { - nsm.registerNetworkStatsProvider(getClass().getSimpleName(), provider); + mDeps.getNetworkStatsManager().registerNetworkStatsProvider( + getClass().getSimpleName(), provider); } catch (RuntimeException e) { // TODO: Perhaps not allow to use BPF offload because the reregistration failure // implied that no data limit could be applies on a metered upstream if any. @@ -169,7 +196,6 @@ public class BpfCoordinator { provider = null; } mStatsProvider = provider; - mDeps = deps; } /** @@ -181,6 +207,11 @@ public class BpfCoordinator { public void startPolling() { if (mPollingStarted) return; + if (!mUsingBpf) { + mLog.i("Offload disabled"); + return; + } + mPollingStarted = true; maybeSchedulePollingStats(); @@ -215,6 +246,8 @@ public class BpfCoordinator { */ public void tetherOffloadRuleAdd( @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) { + if (!mUsingBpf) return; + try { // TODO: Perhaps avoid to add a duplicate rule. mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel()); @@ -254,6 +287,8 @@ public class BpfCoordinator { */ public void tetherOffloadRuleRemove( @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) { + if (!mUsingBpf) return; + try { // TODO: Perhaps avoid to remove a non-existent rule. mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel()); @@ -297,6 +332,8 @@ public class BpfCoordinator { * Note that this can be only called on handler thread. */ public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) { + if (!mUsingBpf) return; + final LinkedHashMap rules = mIpv6ForwardingRules.get( ipServer); if (rules == null) return; @@ -312,6 +349,8 @@ public class BpfCoordinator { * Note that this can be only called on handler thread. */ public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) { + if (!mUsingBpf) return; + final LinkedHashMap rules = mIpv6ForwardingRules.get( ipServer); if (rules == null) return; @@ -334,6 +373,8 @@ public class BpfCoordinator { * Note that this can be only called on handler thread. */ public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) { + if (!mUsingBpf) return; + if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return; // The same interface index to name mapping may be added by different IpServer objects or @@ -357,6 +398,7 @@ public class BpfCoordinator { public void dump(@NonNull IndentingPrintWriter pw) { final ConditionVariable dumpDone = new ConditionVariable(); mHandler.post(() -> { + pw.println("mUsingBpf: " + mUsingBpf); pw.println("Polling " + (mPollingStarted ? "started" : "not started")); pw.println("Stats provider " + (mStatsProvider != null ? "registered" : "not registered")); @@ -547,6 +589,11 @@ public class BpfCoordinator { } } + private boolean isOffloadEnabled() { + final TetheringConfiguration config = mDeps.getTetherConfig(); + return (config != null) ? config.enableBpfOffload : true /* default value */; + } + private int getInterfaceIndexFromRules(@NonNull String ifName) { for (LinkedHashMap rules : mIpv6ForwardingRules .values()) { diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index a3175c84b1..974f799c50 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -62,6 +62,7 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; +import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; @@ -285,8 +286,6 @@ public class Tethering { mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new LinkedHashSet<>(); - mBpfCoordinator = mDeps.getBpfCoordinator( - mHandler, mNetd, mLog, new BpfCoordinator.Dependencies()); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); @@ -324,6 +323,37 @@ public class Tethering { // Load tethering configuration. updateConfiguration(); + // Must be initialized after tethering configuration is loaded because BpfCoordinator + // constructor needs to use the configuration. + mBpfCoordinator = mDeps.getBpfCoordinator( + new BpfCoordinator.Dependencies() { + @NonNull + public Handler getHandler() { + return mHandler; + } + + @NonNull + public INetd getNetd() { + return mNetd; + } + + @NonNull + public NetworkStatsManager getNetworkStatsManager() { + return (NetworkStatsManager) mContext.getSystemService( + Context.NETWORK_STATS_SERVICE); + } + + @NonNull + public SharedLog getSharedLog() { + return mLog; + } + + @Nullable + public TetheringConfiguration getTetherConfig() { + return mConfig; + } + }); + startStateMachineUpdaters(); } diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index d637c8646b..8f4b964323 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -44,11 +44,8 @@ public abstract class TetheringDependencies { * Get a reference to the BpfCoordinator to be used by tethering. */ public @NonNull BpfCoordinator getBpfCoordinator( - @NonNull Handler handler, @NonNull INetd netd, @NonNull SharedLog log, @NonNull BpfCoordinator.Dependencies deps) { - final NetworkStatsManager statsManager = - (NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE); - return new BpfCoordinator(handler, netd, statsManager, log, deps); + return new BpfCoordinator(deps); } /** diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index c3bc915a23..fdfd92617b 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -89,12 +89,14 @@ import android.os.test.TestLooper; import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.networkstack.tethering.BpfCoordinator; import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule; import com.android.networkstack.tethering.PrivateAddressCoordinator; +import com.android.networkstack.tethering.TetheringConfiguration; import org.junit.Before; import org.junit.Test; @@ -226,9 +228,36 @@ public class IpServerTest { when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); - BpfCoordinator bc = new BpfCoordinator(new Handler(mLooper.getLooper()), mNetd, - mStatsManager, mSharedLog, new BpfCoordinator.Dependencies()); - mBpfCoordinator = spy(bc); + mBpfCoordinator = spy(new BpfCoordinator( + new BpfCoordinator.Dependencies() { + @NonNull + public Handler getHandler() { + return new Handler(mLooper.getLooper()); + } + + @NonNull + public INetd getNetd() { + return mNetd; + } + + @NonNull + public NetworkStatsManager getNetworkStatsManager() { + return mStatsManager; + } + + @NonNull + public SharedLog getSharedLog() { + return mSharedLog; + } + + @Nullable + public TetheringConfiguration getTetherConfig() { + // Returning null configuration object is a hack to enable BPF offload. + // See BpfCoordinator#isOffloadEnabled. + // TODO: Mock TetheringConfiguration to test. + return null; + } + })); } @Test @@ -671,18 +700,21 @@ public class IpServerTest { } } - private TetherOffloadRuleParcel matches( + @NonNull + private static TetherOffloadRuleParcel matches( int upstreamIfindex, InetAddress dst, MacAddress dstMac) { return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac)); } + @NonNull private static Ipv6ForwardingRule makeForwardingRule( int upstreamIfindex, @NonNull InetAddress dst, @NonNull MacAddress dstMac) { return new Ipv6ForwardingRule(upstreamIfindex, TEST_IFACE_PARAMS.index, (Inet6Address) dst, TEST_IFACE_PARAMS.macAddr, dstMac); } - private TetherStatsParcel buildEmptyTetherStatsParcel(int ifIndex) { + @NonNull + private static TetherStatsParcel buildEmptyTetherStatsParcel(int ifIndex) { TetherStatsParcel parcel = new TetherStatsParcel(); parcel.ifIndex = ifIndex; return parcel; diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java index ba0f41c4fa..f63a473f1d 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -45,7 +45,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.annotation.NonNull; import android.app.usage.NetworkStatsManager; import android.net.INetd; import android.net.InetAddresses; @@ -58,6 +57,8 @@ import android.net.util.SharedLog; import android.os.Handler; import android.os.test.TestLooper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -101,9 +102,37 @@ public class BpfCoordinatorTest { private BpfCoordinator.Dependencies mDeps = new BpfCoordinator.Dependencies() { @Override - int getPerformPollInterval() { + public int getPerformPollInterval() { return DEFAULT_PERFORM_POLL_INTERVAL_MS; } + + @NonNull + public Handler getHandler() { + return new Handler(mTestLooper.getLooper()); + } + + @NonNull + public INetd getNetd() { + return mNetd; + } + + @NonNull + public NetworkStatsManager getNetworkStatsManager() { + return mStatsManager; + } + + @NonNull + public SharedLog getSharedLog() { + return new SharedLog("test"); + } + + @Nullable + public TetheringConfiguration getTetherConfig() { + // Returning null configuration object is a hack to enable BPF offload. + // See BpfCoordinator#isOffloadEnabled. + // TODO: Mock TetheringConfiguration to test. + return null; + } }; @Before public void setUp() { @@ -120,9 +149,7 @@ public class BpfCoordinatorTest { @NonNull private BpfCoordinator makeBpfCoordinator() throws Exception { - BpfCoordinator coordinator = new BpfCoordinator( - new Handler(mTestLooper.getLooper()), mNetd, mStatsManager, new SharedLog("test"), - mDeps); + final BpfCoordinator coordinator = new BpfCoordinator(mDeps); final ArgumentCaptor tetherStatsProviderCaptor = ArgumentCaptor.forClass(BpfCoordinator.BpfTetherStatsProvider.class); @@ -335,8 +362,8 @@ public class BpfCoordinatorTest { inOrder.verifyNoMoreInteractions(); // [2] Specific limit. - // Applying the data limit boundary {min, max, infinity} on current upstream. - for (final long quota : new long[] {0, Long.MAX_VALUE, QUOTA_UNLIMITED}) { + // Applying the data limit boundary {min, 1gb, max, infinity} on current upstream. + for (final long quota : new long[] {0, 1048576000, Long.MAX_VALUE, QUOTA_UNLIMITED}) { mTetherStatsProvider.onSetLimit(mobileIface, quota); waitForIdle(); inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, quota); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 02dbd4cc1c..2b2dfae5c9 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -338,8 +338,8 @@ public class TetheringTest { } @Override - public BpfCoordinator getBpfCoordinator(Handler handler, INetd netd, - SharedLog log, BpfCoordinator.Dependencies deps) { + public BpfCoordinator getBpfCoordinator( + BpfCoordinator.Dependencies deps) { return mBpfCoordinator; } From 21bf8ba8e782398512072a0b5b950ffdc87f3854 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 15 Jun 2020 17:54:29 +0000 Subject: [PATCH 1205/1415] Verify owner of IKEv2 VPNs This change adds assertions to ensure that the owner UIDs of IKEv2 VPNs are correctly set. Bug: 150135470 Test: This Merged-In: Iabf2859c289aa86ec38aea1edcc1fb248b9d0d26 Change-Id: Iabf2859c289aa86ec38aea1edcc1fb248b9d0d26 (cherry picked from commit 30234827aa24716062a23f28b1effc59e9ef46de) --- tests/cts/net/src/android/net/cts/Ikev2VpnTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index 81dfed507a..9eab024cf0 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -16,6 +16,7 @@ package android.net.cts; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; @@ -40,6 +41,7 @@ import android.net.Ikev2VpnProfile; import android.net.IpSecAlgorithm; import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.ProxyInfo; import android.net.TestNetworkInterface; @@ -47,6 +49,7 @@ import android.net.TestNetworkManager; import android.net.VpnManager; import android.net.cts.util.CtsNetUtils; import android.os.Build; +import android.os.Process; import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; @@ -426,6 +429,11 @@ public class Ikev2VpnTest { final Network vpnNetwork = cb.currentNetwork; assertNotNull(vpnNetwork); + final NetworkCapabilities caps = sCM.getNetworkCapabilities(vpnNetwork); + assertTrue(caps.hasTransport(TRANSPORT_VPN)); + assertTrue(caps.hasCapability(NET_CAPABILITY_INTERNET)); + assertEquals(Process.myUid(), caps.getOwnerUid()); + sVpnMgr.stopProvisionedVpnProfile(); cb.waitForLost(); assertEquals(vpnNetwork, cb.lastLostNetwork); From ec38685a7f6e2de6478226d381835710985e1221 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 16 Jun 2020 01:16:18 +0000 Subject: [PATCH 1206/1415] Toggle wifi when running CaptivePortalTest Instead of reconnecting without disabling/re-enabling wifi in CaptivePortalTest, actually do the toggle during the test and on teardown to ensure that the BSSID blacklist is cleared. CaptivePortalTest intentionally makes the network not validate, which causes it to be added to the BSSID blacklist. Toggling wifi is necessary to make sure the test does not affect other tests. Also check development SDK instead of the exact SDK_INT number so that the test can pass on current AOSP builds. Bug: 158924461 Test: atest CtsNetTestCasesLatestSdk:CaptivePortalTest \ CtsNetTestCasesLatestSdk:ConnectivityManagerTest Original-Change: https://android-review.googlesource.com/1336114 Merged-In: I31f9f4a9678e11042005c29535af840246358764 Change-Id: I31f9f4a9678e11042005c29535af840246358764 --- .../src/android/net/cts/CaptivePortalTest.kt | 15 ++-- .../android/net/cts/util/CtsNetUtils.java | 83 +++++++++++++++++-- 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 0816aba750..4a7d38a172 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -41,6 +41,7 @@ import android.text.TextUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 import com.android.compatibility.common.util.SystemUtil +import com.android.testutils.isDevSdkInRange import fi.iki.elonen.NanoHTTPD import fi.iki.elonen.NanoHTTPD.Response.IStatus import fi.iki.elonen.NanoHTTPD.Response.Status @@ -105,6 +106,9 @@ class CaptivePortalTest { @After fun tearDown() { clearTestUrls() + if (pm.hasSystemFeature(FEATURE_WIFI)) { + reconnectWifi() + } server.stop() } @@ -167,7 +171,7 @@ class CaptivePortalTest { assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) val startPortalAppPermission = - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) CONNECTIVITY_INTERNAL + if (isDevSdkInRange(0, Build.VERSION_CODES.Q)) CONNECTIVITY_INTERNAL else NETWORK_SETTINGS doAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " + @@ -180,9 +184,6 @@ class CaptivePortalTest { // disconnectFromCell should be called after connectToCell utils.disconnectFromCell() } - - clearTestUrls() - reconnectWifi() } private fun setHttpsUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING, url) @@ -203,10 +204,8 @@ class CaptivePortalTest { } private fun reconnectWifi() { - doAsShell(NETWORK_SETTINGS) { - assertTrue(wm.disconnect()) - assertTrue(wm.reconnect()) - } + utils.ensureWifiDisconnected(null /* wifiNetworkToCheck */) + utils.ensureWifiConnected() } /** 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 b1f3602950..85d2113d89 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 @@ -157,8 +157,36 @@ public final class CtsNetUtils { } } - /** Enable WiFi and wait for it to become connected to a network. */ + /** + * Enable WiFi and wait for it to become connected to a network. + * + * This method expects to receive a legacy broadcast on connect, which may not be sent if the + * network does not become default or if it is not the first network. + */ public Network connectToWifi() { + return connectToWifi(true /* expectLegacyBroadcast */); + } + + /** + * Enable WiFi and wait for it to become connected to a network. + * + * A network is considered connected when a {@link NetworkCallback#onAvailable(Network)} + * callback is received. + */ + public Network ensureWifiConnected() { + return connectToWifi(false /* expectLegacyBroadcast */); + } + + /** + * Enable WiFi and wait for it to become connected to a network. + * + * @param expectLegacyBroadcast Whether to check for a legacy CONNECTIVITY_ACTION connected + * broadcast. The broadcast is typically not sent if the network + * does not become the default network, and is not the first + * network to appear. + * @return The network that was newly connected. + */ + private Network connectToWifi(boolean expectLegacyBroadcast) { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); Network wifiNetwork = null; @@ -170,15 +198,16 @@ public final class CtsNetUtils { mContext.registerReceiver(receiver, filter); boolean connected = false; + final String err = "Wifi must be configured to connect to an access point for this test."; try { clearWifiBlacklist(); SystemUtil.runShellCommand("svc wifi enable"); SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(), NETWORK_SETTINGS); - // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. + // Ensure we get an onAvailable callback and possibly a CONNECTIVITY_ACTION. wifiNetwork = callback.waitForAvailable(); - assertNotNull(wifiNetwork); - connected = receiver.waitForState(); + assertNotNull(err, wifiNetwork); + connected = !expectLegacyBroadcast || receiver.waitForState(); } catch (InterruptedException ex) { fail("connectToWifi was interrupted"); } finally { @@ -186,8 +215,7 @@ public final class CtsNetUtils { mContext.unregisterReceiver(receiver); } - assertTrue("Wifi must be configured to connect to an access point for this test.", - connected); + assertTrue(err, connected); return wifiNetwork; } @@ -204,8 +232,47 @@ public final class CtsNetUtils { }); } - /** Disable WiFi and wait for it to become disconnected from the network. */ + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * This method expects to receive a legacy broadcast on disconnect, which may not be sent if the + * network was not default, or was not the first network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + */ public void disconnectFromWifi(Network wifiNetworkToCheck) { + disconnectFromWifi(wifiNetworkToCheck, true /* expectLegacyBroadcast */); + } + + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + */ + public void ensureWifiDisconnected(Network wifiNetworkToCheck) { + disconnectFromWifi(wifiNetworkToCheck, false /* expectLegacyBroadcast */); + } + + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + * @param expectLegacyBroadcast Whether to check for a legacy CONNECTIVITY_ACTION disconnected + * broadcast. The broadcast is typically not sent if the network + * was not the default network and not the first network to appear. + * The check will always be skipped if the device was not connected + * to wifi in the first place. + */ + private void disconnectFromWifi(Network wifiNetworkToCheck, boolean expectLegacyBroadcast) { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); @@ -238,6 +305,8 @@ public final class CtsNetUtils { // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. assertNotNull("Did not receive onLost callback after disabling wifi", callback.waitForLost()); + } + if (wasWifiConnected && expectLegacyBroadcast) { assertTrue("Wifi failed to reach DISCONNECTED state.", receiver.waitForState()); } } catch (InterruptedException ex) { From 8b3af8d775c57c2706838637613594ce0d3adb61 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 19 May 2020 15:23:56 +0800 Subject: [PATCH 1207/1415] [BOT.12] Add unit test for disabling BpfCoordinator by config Bug: 150736748 Test: BpfCoordinatorTest Change-Id: Iedb936b7592b6be773d1b84a2498bfc5a440a198 --- .../tethering/BpfCoordinator.java | 39 +++++++--- .../networkstack/tethering/Tethering.java | 5 +- .../tethering/TetheringConfiguration.java | 14 ++-- .../unit/src/android/net/ip/IpServerTest.java | 7 +- .../tethering/BpfCoordinatorTest.java | 74 +++++++++++++++++-- .../tethering/TetheringConfigurationTest.java | 8 +- 6 files changed, 112 insertions(+), 35 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index aa1d59de89..12464e1289 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -94,7 +94,7 @@ public class BpfCoordinator { // in the constructor because it is hard to unwind all existing change once device // configuration is changed. Especially the forwarding rules. Keep the same setting // to make it simpler. See also TetheringConfiguration. - private final boolean mUsingBpf; + private final boolean mIsBpfEnabled; // Tracks whether BPF tethering is started or not. This is set by tethering before it // starts the first IpServer and is cleared by tethering shortly before the last IpServer @@ -184,7 +184,7 @@ public class BpfCoordinator { mHandler = mDeps.getHandler(); mNetd = mDeps.getNetd(); mLog = mDeps.getSharedLog().forSubComponent(TAG); - mUsingBpf = isOffloadEnabled(); + mIsBpfEnabled = isBpfEnabled(); BpfTetherStatsProvider provider = new BpfTetherStatsProvider(); try { mDeps.getNetworkStatsManager().registerNetworkStatsProvider( @@ -207,7 +207,7 @@ public class BpfCoordinator { public void startPolling() { if (mPollingStarted) return; - if (!mUsingBpf) { + if (!mIsBpfEnabled) { mLog.i("Offload disabled"); return; } @@ -246,7 +246,7 @@ public class BpfCoordinator { */ public void tetherOffloadRuleAdd( @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) { - if (!mUsingBpf) return; + if (!mIsBpfEnabled) return; try { // TODO: Perhaps avoid to add a duplicate rule. @@ -287,7 +287,7 @@ public class BpfCoordinator { */ public void tetherOffloadRuleRemove( @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) { - if (!mUsingBpf) return; + if (!mIsBpfEnabled) return; try { // TODO: Perhaps avoid to remove a non-existent rule. @@ -332,7 +332,7 @@ public class BpfCoordinator { * Note that this can be only called on handler thread. */ public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) { - if (!mUsingBpf) return; + if (!mIsBpfEnabled) return; final LinkedHashMap rules = mIpv6ForwardingRules.get( ipServer); @@ -349,7 +349,7 @@ public class BpfCoordinator { * Note that this can be only called on handler thread. */ public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) { - if (!mUsingBpf) return; + if (!mIsBpfEnabled) return; final LinkedHashMap rules = mIpv6ForwardingRules.get( ipServer); @@ -373,7 +373,7 @@ public class BpfCoordinator { * Note that this can be only called on handler thread. */ public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) { - if (!mUsingBpf) return; + if (!mIsBpfEnabled) return; if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return; @@ -398,7 +398,7 @@ public class BpfCoordinator { public void dump(@NonNull IndentingPrintWriter pw) { final ConditionVariable dumpDone = new ConditionVariable(); mHandler.post(() -> { - pw.println("mUsingBpf: " + mUsingBpf); + pw.println("mIsBpfEnabled: " + mIsBpfEnabled); pw.println("Polling " + (mPollingStarted ? "started" : "not started")); pw.println("Stats provider " + (mStatsProvider != null ? "registered" : "not registered")); @@ -589,9 +589,9 @@ public class BpfCoordinator { } } - private boolean isOffloadEnabled() { + private boolean isBpfEnabled() { final TetheringConfiguration config = mDeps.getTetherConfig(); - return (config != null) ? config.enableBpfOffload : true /* default value */; + return (config != null) ? config.isBpfOffloadEnabled() : true /* default value */; } private int getInterfaceIndexFromRules(@NonNull String ifName) { @@ -754,4 +754,21 @@ public class BpfCoordinator { mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval()); } + + // Return forwarding rule map. This is used for testing only. + // Note that this can be only called on handler thread. + @NonNull + @VisibleForTesting + final HashMap> + getForwardingRulesForTesting() { + return mIpv6ForwardingRules; + } + + // Return upstream interface name map. This is used for testing only. + // Note that this can be only called on handler thread. + @NonNull + @VisibleForTesting + final SparseArray getInterfaceNamesForTesting() { + return mInterfaceNames; + } } diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 974f799c50..71ab176764 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -339,8 +339,7 @@ public class Tethering { @NonNull public NetworkStatsManager getNetworkStatsManager() { - return (NetworkStatsManager) mContext.getSystemService( - Context.NETWORK_STATS_SERVICE); + return mContext.getSystemService(NetworkStatsManager.class); } @NonNull @@ -2386,7 +2385,7 @@ public class Tethering { final TetherState tetherState = new TetherState( new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator, makeControlCallback(), mConfig.enableLegacyDhcpServer, - mConfig.enableBpfOffload, mPrivateAddressCoordinator, + mConfig.isBpfOffloadEnabled(), mPrivateAddressCoordinator, mDeps.getIpServerDependencies())); mTetherStates.put(iface, tetherState); tetherState.ipServer.start(); diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 48a600dfe6..1e94de12ce 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -101,8 +101,6 @@ public class TetheringConfiguration { public final String[] legacyDhcpRanges; public final String[] defaultIPv4DNS; public final boolean enableLegacyDhcpServer; - // TODO: Add to TetheringConfigurationParcel if required. - public final boolean enableBpfOffload; public final String[] provisioningApp; public final String provisioningAppNoUi; @@ -111,6 +109,8 @@ public class TetheringConfiguration { public final int activeDataSubId; private final int mOffloadPollInterval; + // TODO: Add to TetheringConfigurationParcel if required. + private final boolean mEnableBpfOffload; public TetheringConfiguration(Context ctx, SharedLog log, int id) { final SharedLog configLog = log.forSubComponent("config"); @@ -137,7 +137,7 @@ public class TetheringConfiguration { legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); - enableBpfOffload = getEnableBpfOffload(res); + mEnableBpfOffload = getEnableBpfOffload(res); enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); @@ -218,7 +218,7 @@ public class TetheringConfiguration { pw.println(provisioningAppNoUi); pw.print("enableBpfOffload: "); - pw.println(enableBpfOffload); + pw.println(mEnableBpfOffload); pw.print("enableLegacyDhcpServer: "); pw.println(enableLegacyDhcpServer); @@ -240,7 +240,7 @@ public class TetheringConfiguration { toIntArray(preferredUpstreamIfaceTypes))); sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi)); - sj.add(String.format("enableBpfOffload:%s", enableBpfOffload)); + sj.add(String.format("enableBpfOffload:%s", mEnableBpfOffload)); sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer)); return String.format("TetheringConfiguration{%s}", sj.toString()); } @@ -279,6 +279,10 @@ public class TetheringConfiguration { return mOffloadPollInterval; } + public boolean isBpfOffloadEnabled() { + return mEnableBpfOffload; + } + private static Collection getUpstreamIfaceTypes(Resources res, boolean dunRequired) { final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types); final ArrayList upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index fdfd92617b..4f88605391 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -144,6 +144,7 @@ public class IpServerTest { @Mock private IpServer.Dependencies mDependencies; @Mock private PrivateAddressCoordinator mAddressCoordinator; @Mock private NetworkStatsManager mStatsManager; + @Mock private TetheringConfiguration mTetherConfig; @Captor private ArgumentCaptor mDhcpParamsCaptor; @@ -227,6 +228,7 @@ public class IpServerTest { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); + when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */); mBpfCoordinator = spy(new BpfCoordinator( new BpfCoordinator.Dependencies() { @@ -252,10 +254,7 @@ public class IpServerTest { @Nullable public TetheringConfiguration getTetherConfig() { - // Returning null configuration object is a hack to enable BPF offload. - // See BpfCoordinator#isOffloadEnabled. - // TODO: Mock TetheringConfiguration to test. - return null; + return mTetherConfig; } })); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java index f63a473f1d..31d98147c7 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -31,10 +31,11 @@ import static com.android.networkstack.tethering.BpfCoordinator.StatsType; import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE; import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.fail; - +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; @@ -78,6 +79,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashMap; @RunWith(AndroidJUnit4.class) @SmallTest @@ -92,6 +94,7 @@ public class BpfCoordinatorTest { @Mock private NetworkStatsManager mStatsManager; @Mock private INetd mNetd; @Mock private IpServer mIpServer; + @Mock private TetheringConfiguration mTetherConfig; // Late init since methods must be called by the thread that created this object. private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb; @@ -128,15 +131,13 @@ public class BpfCoordinatorTest { @Nullable public TetheringConfiguration getTetherConfig() { - // Returning null configuration object is a hack to enable BPF offload. - // See BpfCoordinator#isOffloadEnabled. - // TODO: Mock TetheringConfiguration to test. - return null; + return mTetherConfig; } }; @Before public void setUp() { MockitoAnnotations.initMocks(this); + when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */); } private void waitForIdle() { @@ -501,4 +502,61 @@ public class BpfCoordinatorTest { .addEntry(buildTestEntry(STATS_PER_UID, ethIface, 10, 20, 30, 40)) .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 50, 60, 70, 80))); } + + @Test + public void testTetheringConfigDisable() throws Exception { + setupFunctioningNetdInterface(); + when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(false); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + coordinator.startPolling(); + + // The tether stats polling task should not be scheduled. + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + verify(mNetd, never()).tetherOffloadGetStats(); + + // The interface name lookup table can't be added. + final String iface = "rmnet_data0"; + final Integer ifIndex = 100; + coordinator.addUpstreamNameToLookupTable(ifIndex, iface); + assertEquals(0, coordinator.getInterfaceNamesForTesting().size()); + + // The rule can't be added. + final InetAddress neigh = InetAddresses.parseNumericAddress("2001:db8::1"); + final MacAddress mac = MacAddress.fromString("00:00:00:00:00:0a"); + final Ipv6ForwardingRule rule = buildTestForwardingRule(ifIndex, neigh, mac); + coordinator.tetherOffloadRuleAdd(mIpServer, rule); + verify(mNetd, never()).tetherOffloadRuleAdd(any()); + LinkedHashMap rules = + coordinator.getForwardingRulesForTesting().get(mIpServer); + assertNull(rules); + + // The rule can't be removed. This is not a realistic case because adding rule is not + // allowed. That implies no rule could be removed, cleared or updated. Verify these + // cases just in case. + rules = new LinkedHashMap(); + rules.put(rule.address, rule); + coordinator.getForwardingRulesForTesting().put(mIpServer, rules); + coordinator.tetherOffloadRuleRemove(mIpServer, rule); + verify(mNetd, never()).tetherOffloadRuleRemove(any()); + rules = coordinator.getForwardingRulesForTesting().get(mIpServer); + assertNotNull(rules); + assertEquals(1, rules.size()); + + // The rule can't be cleared. + coordinator.tetherOffloadRuleClear(mIpServer); + verify(mNetd, never()).tetherOffloadRuleRemove(any()); + rules = coordinator.getForwardingRulesForTesting().get(mIpServer); + assertNotNull(rules); + assertEquals(1, rules.size()); + + // The rule can't be updated. + coordinator.tetherOffloadRuleUpdate(mIpServer, rule.upstreamIfindex + 1 /* new */); + verify(mNetd, never()).tetherOffloadRuleRemove(any()); + verify(mNetd, never()).tetherOffloadRuleAdd(any()); + rules = coordinator.getForwardingRulesForTesting().get(mIpServer); + assertNotNull(rules); + assertEquals(1, rules.size()); + } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index 1999ad786e..3f4cfe7afb 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -292,7 +292,7 @@ public class TetheringConfigurationTest { initializeBpfOffloadConfiguration(true, null /* unset */); final TetheringConfiguration enableByRes = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); - assertTrue(enableByRes.enableBpfOffload); + assertTrue(enableByRes.isBpfOffloadEnabled()); } @Test @@ -301,7 +301,7 @@ public class TetheringConfigurationTest { initializeBpfOffloadConfiguration(res, "true"); final TetheringConfiguration enableByDevConOverride = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); - assertTrue(enableByDevConOverride.enableBpfOffload); + assertTrue(enableByDevConOverride.isBpfOffloadEnabled()); } } @@ -310,7 +310,7 @@ public class TetheringConfigurationTest { initializeBpfOffloadConfiguration(false, null /* unset */); final TetheringConfiguration disableByRes = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); - assertFalse(disableByRes.enableBpfOffload); + assertFalse(disableByRes.isBpfOffloadEnabled()); } @Test @@ -319,7 +319,7 @@ public class TetheringConfigurationTest { initializeBpfOffloadConfiguration(res, "false"); final TetheringConfiguration disableByDevConOverride = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); - assertFalse(disableByDevConOverride.enableBpfOffload); + assertFalse(disableByDevConOverride.isBpfOffloadEnabled()); } } From bfdcfe4ecdd29f8db0e1dcea4327bde6cb3897aa Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 20 May 2020 18:09:01 +0800 Subject: [PATCH 1208/1415] [BOT.13] Make offload coordinator poll interval configurable Bug: 150736748 Test: BpfCoordinatorTest Change-Id: I7f8dde3b57ee14eb33edbe2fd383df33cccc231c --- .../tethering/BpfCoordinator.java | 26 ++++--- .../tethering/BpfCoordinatorTest.java | 71 +++++++++++++++---- 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index 12464e1289..20f30ea7a4 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -25,6 +25,8 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStats.UID_TETHERING; import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; +import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; + import android.app.usage.NetworkStatsManager; import android.net.INetd; import android.net.MacAddress; @@ -69,8 +71,6 @@ import java.util.Objects; public class BpfCoordinator { private static final String TAG = BpfCoordinator.class.getSimpleName(); private static final int DUMP_TIMEOUT_MS = 10_000; - @VisibleForTesting - static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; // TODO: Make it customizable. @VisibleForTesting enum StatsType { @@ -154,14 +154,6 @@ public class BpfCoordinator { @VisibleForTesting public abstract static class Dependencies { - /** - * Get polling Interval in milliseconds. - */ - public int getPerformPollInterval() { - // TODO: Consider make this configurable. - return DEFAULT_PERFORM_POLL_INTERVAL_MS; - } - /** Get handler. */ @NonNull public abstract Handler getHandler(); @@ -403,6 +395,7 @@ public class BpfCoordinator { pw.println("Stats provider " + (mStatsProvider != null ? "registered" : "not registered")); pw.println("Upstream quota: " + mInterfaceQuotas.toString()); + pw.println("Polling interval: " + getPollingInterval() + " ms"); pw.println("Forwarding stats:"); pw.increaseIndent(); @@ -745,6 +738,17 @@ public class BpfCoordinator { updateQuotaAndStatsFromSnapshot(tetherStatsList); } + @VisibleForTesting + int getPollingInterval() { + // The valid range of interval is DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS..max_long. + // Ignore the config value is less than the minimum polling interval. Note that the + // minimum interval definition is invoked as OffloadController#isPollingStatsNeeded does. + // TODO: Perhaps define a minimum polling interval constant. + final TetheringConfiguration config = mDeps.getTetherConfig(); + final int configInterval = (config != null) ? config.getOffloadPollInterval() : 0; + return Math.max(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, configInterval); + } + private void maybeSchedulePollingStats() { if (!mPollingStarted) return; @@ -752,7 +756,7 @@ public class BpfCoordinator { mHandler.removeCallbacks(mScheduledPollingTask); } - mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval()); + mHandler.postDelayed(mScheduledPollingTask, getPollingInterval()); } // Return forwarding rule map. This is used for testing only. diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java index 31d98147c7..64242ae825 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -25,11 +25,10 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStats.UID_TETHERING; import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; -import static com.android.networkstack.tethering.BpfCoordinator - .DEFAULT_PERFORM_POLL_INTERVAL_MS; import static com.android.networkstack.tethering.BpfCoordinator.StatsType; import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE; import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID; +import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -104,11 +103,6 @@ public class BpfCoordinatorTest { private final TestLooper mTestLooper = new TestLooper(); private BpfCoordinator.Dependencies mDeps = new BpfCoordinator.Dependencies() { - @Override - public int getPerformPollInterval() { - return DEFAULT_PERFORM_POLL_INTERVAL_MS; - } - @NonNull public Handler getHandler() { return new Handler(mTestLooper.getLooper()); @@ -183,9 +177,11 @@ public class BpfCoordinatorTest { return parcel; } + // Set up specific tether stats list and wait for the stats cache is updated by polling thread + // in the coordinator. Beware of that it is only used for the default polling interval. private void setTetherOffloadStatsList(TetherStatsParcel[] tetherStatsList) throws Exception { when(mNetd.tetherOffloadGetStats()).thenReturn(tetherStatsList); - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); } @@ -254,7 +250,7 @@ public class BpfCoordinatorTest { clearInvocations(mNetd); // Verify the polling update thread stopped. - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); verify(mNetd, never()).tetherOffloadGetStats(); } @@ -279,20 +275,20 @@ public class BpfCoordinatorTest { when(mNetd.tetherOffloadGetStats()).thenReturn( new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 0, 0, 0, 0)}); mTetherStatsProvider.onSetAlert(100); - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); mTetherStatsProviderCb.assertNoCallback(); // Verify that notifyAlertReached fired when quota is reached. when(mNetd.tetherOffloadGetStats()).thenReturn( new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 50, 0, 50, 0)}); - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); mTetherStatsProviderCb.expectNotifyAlertReached(); // Verify that set quota with UNLIMITED won't trigger any callback. mTetherStatsProvider.onSetAlert(QUOTA_UNLIMITED); - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); mTetherStatsProviderCb.assertNoCallback(); } @@ -512,7 +508,7 @@ public class BpfCoordinatorTest { coordinator.startPolling(); // The tether stats polling task should not be scheduled. - mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); waitForIdle(); verify(mNetd, never()).tetherOffloadGetStats(); @@ -559,4 +555,53 @@ public class BpfCoordinatorTest { assertNotNull(rules); assertEquals(1, rules.size()); } + + @Test + public void testTetheringConfigSetPollingInterval() throws Exception { + setupFunctioningNetdInterface(); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + + // [1] The default polling interval. + coordinator.startPolling(); + assertEquals(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, coordinator.getPollingInterval()); + coordinator.stopPolling(); + + // [2] Expect the invalid polling interval isn't applied. The valid range of interval is + // DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS..max_long. + for (final int interval + : new int[] {0, 100, DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS - 1}) { + when(mTetherConfig.getOffloadPollInterval()).thenReturn(interval); + coordinator.startPolling(); + assertEquals(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, coordinator.getPollingInterval()); + coordinator.stopPolling(); + } + + // [3] Set a specific polling interval which is larger than default value. + // Use a large polling interval to avoid flaky test because the time forwarding + // approximation is used to verify the scheduled time of the polling thread. + final int pollingInterval = 100_000; + when(mTetherConfig.getOffloadPollInterval()).thenReturn(pollingInterval); + coordinator.startPolling(); + + // Expect the specific polling interval to be applied. + assertEquals(pollingInterval, coordinator.getPollingInterval()); + + // Start on a new polling time slot. + mTestLooper.moveTimeForward(pollingInterval); + waitForIdle(); + clearInvocations(mNetd); + + // Move time forward to 90% polling interval time. Expect that the polling thread has not + // scheduled yet. + mTestLooper.moveTimeForward((long) (pollingInterval * 0.9)); + waitForIdle(); + verify(mNetd, never()).tetherOffloadGetStats(); + + // Move time forward to the remaining 10% polling interval time. Expect that the polling + // thread has scheduled. + mTestLooper.moveTimeForward((long) (pollingInterval * 0.1)); + waitForIdle(); + verify(mNetd).tetherOffloadGetStats(); + } } From 7d1159a2d4d64ccf7e93ed7cdb46438c976003c9 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 21 May 2020 09:15:44 -0700 Subject: [PATCH 1209/1415] CTS test ConnectivityDiagnostics via CarrierPrivilegesTracker. This change adds a CTS test for ConnectivityDiagnostics using CarrierPrivilegesTracker to receive permissions for ConnectivityDiagnostics callbacks. Specifically, the test provides CarrierPrivileges to the test package (android.net.cts) for the active subscription via Carrier Configs overrides. CarrierPrivilegesTracker listens to the Carrier Configs change and matches the loaded certificate with the test package, then includes the test package UID as an administrator for the Network in ConnectivityService. Then, a ConnectivityDiagnosticsCallback is registered and receives a ConnectivityReport on register for the active subscription. Bug: 148032944 Bug: 151332031 Test: atest ConnectivityDiagnosticsManagerTest Change-Id: Iee8a428ada0b6e2127410267a13c3b688df83e6d --- .../ConnectivityDiagnosticsManagerTest.java | 166 +++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 0248f971dc..5fe05bce64 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -16,6 +16,7 @@ package android.net.cts; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK; @@ -31,6 +32,7 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; @@ -41,9 +43,15 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityManager; import android.net.LinkAddress; @@ -57,10 +65,15 @@ import android.os.Build; import android.os.IBinder; import android.os.PersistableBundle; import android.os.Process; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.Pair; import androidx.test.InstrumentationRegistry; +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.util.ArrayUtils; import com.android.testutils.ArrayTrackRecord; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; @@ -70,7 +83,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.security.MessageDigest; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q @@ -83,6 +99,7 @@ public class ConnectivityDiagnosticsManagerTest { private static final int FAIL_RATE_PERCENTAGE = 100; private static final int UNKNOWN_DETECTION_METHOD = 4; private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; + private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -93,15 +110,23 @@ public class ConnectivityDiagnosticsManagerTest { .removeCapability(NET_CAPABILITY_NOT_VPN) .build(); + private static final String SHA_256 = "SHA-256"; + // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests // for it. private static final TestNetworkCallback TEST_NETWORK_CALLBACK = new TestNetworkCallback(); + private static final NetworkRequest CELLULAR_NETWORK_REQUEST = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + private static final IBinder BINDER = new Binder(); private Context mContext; private ConnectivityManager mConnectivityManager; private ConnectivityDiagnosticsManager mCdm; + private CarrierConfigManager mCarrierConfigManager; + private PackageManager mPackageManager; + private TelephonyManager mTelephonyManager; private Network mTestNetwork; @Before @@ -109,6 +134,9 @@ public class ConnectivityDiagnosticsManagerTest { mContext = InstrumentationRegistry.getContext(); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class); + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mPackageManager = mContext.getPackageManager(); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, TEST_NETWORK_CALLBACK); } @@ -139,6 +167,98 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } + @Test + public void testRegisterCallbackWithCarrierPrivileges() throws Exception { + assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); + + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + fail("Need an active subscription. Please ensure that the device has working mobile" + + " data."); + } + + final CarrierConfigReceiver carrierConfigReceiver = new CarrierConfigReceiver(subId); + mContext.registerReceiver( + carrierConfigReceiver, + new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + + final TestNetworkCallback testNetworkCallback = new TestNetworkCallback(); + final TestConnectivityDiagnosticsCallback connDiagsCallback = + new TestConnectivityDiagnosticsCallback(); + try { + doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( + subId, carrierConfigReceiver, testNetworkCallback, connDiagsCallback); + } finally { + runWithShellPermissionIdentity( + () -> mCarrierConfigManager.overrideConfig(subId, null), + android.Manifest.permission.MODIFY_PHONE_STATE); + mConnectivityManager.unregisterNetworkCallback(testNetworkCallback); + mCdm.unregisterConnectivityDiagnosticsCallback(connDiagsCallback); + mContext.unregisterReceiver(carrierConfigReceiver); + } + } + + private String getCertHashForThisPackage() throws Exception { + final PackageInfo pkgInfo = + mPackageManager.getPackageInfo( + mContext.getOpPackageName(), PackageManager.GET_SIGNATURES); + final MessageDigest md = MessageDigest.getInstance(SHA_256); + final byte[] certHash = md.digest(pkgInfo.signatures[0].toByteArray()); + return IccUtils.bytesToHexString(certHash); + } + + private void doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( + int subId, + @NonNull CarrierConfigReceiver carrierConfigReceiver, + @NonNull TestNetworkCallback testNetworkCallback, + @NonNull TestConnectivityDiagnosticsCallback connDiagsCallback) + throws Exception { + final PersistableBundle carrierConfigs = new PersistableBundle(); + carrierConfigs.putStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, + new String[] {getCertHashForThisPackage()}); + + runWithShellPermissionIdentity( + () -> { + mCarrierConfigManager.overrideConfig(subId, carrierConfigs); + mCarrierConfigManager.notifyConfigChangedForSubId(subId); + }, + android.Manifest.permission.MODIFY_PHONE_STATE); + + // TODO(b/157779832): This should use android.permission.CHANGE_NETWORK_STATE. However, the + // shell does not have CHANGE_NETWORK_STATE, so use CONNECTIVITY_INTERNAL until the shell + // permissions are updated. + runWithShellPermissionIdentity( + () -> mConnectivityManager.requestNetwork( + CELLULAR_NETWORK_REQUEST, testNetworkCallback), + android.Manifest.permission.CONNECTIVITY_INTERNAL); + + final Network network = testNetworkCallback.waitForAvailable(); + assertNotNull(network); + + assertTrue("Didn't receive broadcast for ACTION_CARRIER_CONFIG_CHANGED for subId=" + subId, + carrierConfigReceiver.waitForCarrierConfigChanged()); + assertTrue("Don't have Carrier Privileges after adding cert for this package", + mTelephonyManager.createForSubscriptionId(subId).hasCarrierPrivileges()); + + // Wait for CarrierPrivilegesTracker to receive the ACTION_CARRIER_CONFIG_CHANGED + // broadcast. CPT then needs to update the corresponding DataConnection, which then + // updates ConnectivityService. Unfortunately, this update to the NetworkCapabilities in + // CS does not trigger NetworkCallback#onCapabilitiesChanged as changing the + // administratorUids is not a publicly visible change. In lieu of a better signal to + // detministically wait for, use Thread#sleep here. + Thread.sleep(500); + + mCdm.registerConnectivityDiagnosticsCallback( + CELLULAR_NETWORK_REQUEST, INLINE_EXECUTOR, connDiagsCallback); + + final String interfaceName = + mConnectivityManager.getLinkProperties(network).getInterfaceName(); + connDiagsCallback.expectOnConnectivityReportAvailable( + network, interfaceName, TRANSPORT_CELLULAR); + connDiagsCallback.assertNoCallback(); + } + @Test public void testRegisterDuplicateConnectivityDiagnosticsCallback() { final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); @@ -324,13 +444,18 @@ public class ConnectivityDiagnosticsManagerTest { public void expectOnConnectivityReportAvailable( @NonNull Network network, @NonNull String interfaceName) { + expectOnConnectivityReportAvailable(network, interfaceName, TRANSPORT_TEST); + } + + public void expectOnConnectivityReportAvailable( + @NonNull Network network, @NonNull String interfaceName, int transportType) { final ConnectivityReport result = (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); assertEquals(network, result.getNetwork()); final NetworkCapabilities nc = result.getNetworkCapabilities(); assertNotNull(nc); - assertTrue(nc.hasTransport(TRANSPORT_TEST)); + assertTrue(nc.hasTransport(transportType)); assertNotNull(result.getLinkProperties()); assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); @@ -384,4 +509,43 @@ public class ConnectivityDiagnosticsManagerTest { mHistory.poll(NO_CALLBACK_INVOKED_TIMEOUT, x -> true)); } } + + private class CarrierConfigReceiver extends BroadcastReceiver { + private final CountDownLatch mLatch = new CountDownLatch(1); + private final int mSubId; + + CarrierConfigReceiver(int subId) { + mSubId = subId; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { + return; + } + + final int subId = + intent.getIntExtra( + CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (mSubId != subId) return; + + final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) return; + + final String[] certs = + carrierConfigs.getStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); + try { + if (ArrayUtils.contains(certs, getCertHashForThisPackage())) { + mLatch.countDown(); + } + } catch (Exception e) { + } + } + + boolean waitForCarrierConfigChanged() throws Exception { + return mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS); + } + } } From 8f3a1b5091bffc8c49faa1c6e8631938f8fee85c Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 16 Jun 2020 10:55:43 +0800 Subject: [PATCH 1210/1415] Update DnsPacket package name The package name needs to be updated as the class is moved into com.android.net.module.util. Bug: 149403767 Test: atest DnsResolverTest Change-Id: I908cb5f7bc6150e461748c8e34c92a19aa0206e4 --- tests/cts/net/src/android/net/cts/DnsResolverTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 28753ffc41..e6f75c353b 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -30,7 +30,6 @@ import android.content.Context; import android.content.ContentResolver; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; -import android.net.DnsPacket; import android.net.DnsResolver; import android.net.LinkProperties; import android.net.Network; @@ -47,6 +46,8 @@ import android.system.ErrnoException; import android.test.AndroidTestCase; import android.util.Log; +import com.android.net.module.util.DnsPacket; + import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; From c907a99efd0290916bae293eec310807f2a2da87 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 17 Jun 2020 00:23:23 +0800 Subject: [PATCH 1211/1415] Add owneship of tethering module Bug: 158961959 Test: build/make/tools/checkowners.py packages/NetworkStack/OWNERS Test: ./build/make/tools/checkowners.py \ frameworks/base/packages/Tethering/OWNERS Change-Id: I13b291e5db6a8a8c9f2bfa477acabaea250aa48c --- Tethering/OWNERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Tethering/OWNERS diff --git a/Tethering/OWNERS b/Tethering/OWNERS new file mode 100644 index 0000000000..5b42d49041 --- /dev/null +++ b/Tethering/OWNERS @@ -0,0 +1,2 @@ +include platform/packages/modules/NetworkStack/:/OWNERS +markchien@google.com From 7c9d2128de2b3b3457403c2ebd0d04abaa93c7d9 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 8 Jun 2020 13:38:11 -0700 Subject: [PATCH 1212/1415] Only run ConnectivityDiagnosticsManagerTest as AppModeFull. This CL restricts ConnectivityDiagnosticsManagerTest to only being run as @AppModeFull. This is required, as Instant Apps are not allowed CHANGE_NETWORK_STATE (required for CM#requestNetwork) or MANAGE_TEST_NETWORKS (required for TestNetworkManager#setupTestNetwork) permissions - both of which are required for ConnectivityDiagnosticsManagerTest. Bug: 158431112 Test: atest android.net.cts.ConnectivityDiagnosticsManagerTest Change-Id: Id867b8dcaca758cfeb83009848e1099e900a0790 --- .../src/android/net/cts/ConnectivityDiagnosticsManagerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 0248f971dc..d17d8e53ae 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -57,6 +57,7 @@ import android.os.Build; import android.os.IBinder; import android.os.PersistableBundle; import android.os.Process; +import android.platform.test.annotations.AppModeFull; import android.util.Pair; import androidx.test.InstrumentationRegistry; @@ -74,6 +75,7 @@ import java.util.concurrent.Executor; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q +@AppModeFull(reason = "CHANGE_NETWORK_STATE, MANAGE_TEST_NETWORKS not grantable to instant apps") public class ConnectivityDiagnosticsManagerTest { private static final int CALLBACK_TIMEOUT_MILLIS = 5000; private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500; From d244bd097c096a8da1a6751145aff02b87987ec3 Mon Sep 17 00:00:00 2001 From: "h.zhang" Date: Sun, 14 Jun 2020 14:46:54 +0800 Subject: [PATCH 1213/1415] Memory leak due to no stop for IpNeighborMonitor. 1. When Wi-Fi enabled, ap0 interface is added and IpNeighborMonitor's start() is invoked in IpServer's constructor. 2. There's no stop for IpNeighborMonitor when IpServer stop. 3. During overnight test for Wi-Fi, networkstack is too slow to process request due to memory leak in IpNeighborMonitor and binder buffer is blocked causing exception. Solution: Invoke IpNeighborMonitor.stop() in UnavailableState.enter(). Bug: 159097215 Test: automatic, turn on and off Wi-Fi every 6 seconds overnight Change-Id: I8f60c13706f05306e8f25a15f7861d7ecabbc10e --- Tethering/src/android/net/ip/IpServer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 1671dda4bd..2871e7f682 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -1321,6 +1321,7 @@ public class IpServer extends StateMachine { class UnavailableState extends State { @Override public void enter() { + mIpNeighborMonitor.stop(); mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; sendInterfaceState(STATE_UNAVAILABLE); } From 00ea6cecd8c06318c52923613be4ba3064b076a3 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 18 Jun 2020 23:44:51 +0900 Subject: [PATCH 1214/1415] Test that IpNeighborMonitor is stopped when IpServer stops. Bug: 159097215 Test: test-only change Change-Id: I2292c1cbff06a304f70191b88d833b19af2b8b92 --- Tethering/tests/unit/src/android/net/ip/IpServerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 4f88605391..05cf58ab84 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -859,6 +859,7 @@ public class IpServerTest { verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); + verify(mIpNeighborMonitor).stop(); resetNetdAndBpfCoordinator(); } From 9807816e094d716336a6061bff26521630082308 Mon Sep 17 00:00:00 2001 From: Milim Lee Date: Tue, 26 May 2020 03:11:29 +0900 Subject: [PATCH 1215/1415] Let only Ethernet manage ethernet interface up and down When LAN link is changed for using ethernet interface from Ethernet tethering to Ethernet, there is confiict as Ethernet Tethering is trying to make ethernet link down and Ethernet is trying to make ethernet link up. So, this would make Ethernet only manage ethernet interface link state. Test: manual Bug: 130840861 Change-Id: I1cd40ae764bdeecbb59e3889e9399b7f4b05f9cc --- Tethering/src/android/net/ip/IpServer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 1671dda4bd..4cc35b42d9 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -615,8 +615,9 @@ public class IpServer extends StateMachine { final Boolean setIfaceUp; if (mInterfaceType == TetheringManager.TETHERING_WIFI - || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) { - // The WiFi stack has ownership of the interface up/down state. + || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P + || mInterfaceType == TetheringManager.TETHERING_ETHERNET) { + // The WiFi and Ethernet stack has ownership of the interface up/down state. // It is unclear whether the Bluetooth or USB stacks will manage their own // state. setIfaceUp = null; From 902043f5c374d529353386aa7724179f7abc1142 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 8 Jun 2020 11:30:18 +0800 Subject: [PATCH 1216/1415] Pass entitlement configuration to Settings for entitlement check Tethering resource configuration is move from framwork to tethering module. Since tethering resource would not be accessible from outside of tethering module, EntitlementManager would tell Settings the entitlement configuration via intent extra when run entitlement check. Bug: 146918263 Test: atest TetheringTests Change-Id: I6f23553bb1da5f0b767f920b32a86fafb9e00b9e Merged-In: I6f23553bb1da5f0b767f920b32a86fafb9e00b9e --- .../src/android/net/TetheringConstants.java | 38 +++++++++++-- .../tethering/EntitlementManager.java | 33 +++++++----- .../tethering/TetheringConfiguration.java | 10 ++-- .../tethering/EntitlementManagerTest.java | 53 ++++++++++++++++++- .../tethering/TetheringConfigurationTest.java | 10 +++- 5 files changed, 122 insertions(+), 22 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java index fd6f171487..f14def6a3a 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java @@ -37,8 +37,8 @@ public final class TetheringConstants { private TetheringConstants() { } /** - * Extra used for communicating with the TetherService. Includes the type of tethering to - * enable if any. + * Extra used for communicating with the TetherService and TetherProvisioningActivity. + * Includes the type of tethering to enable if any. */ public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; /** @@ -56,8 +56,38 @@ public final class TetheringConstants { */ public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; /** - * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver} - * which will receive provisioning results. Can be left empty. + * Extra used for communicating with the TetherService and TetherProvisioningActivity. + * Contains the {@link ResultReceiver} which will receive provisioning results. + * Can not be empty. */ public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback"; + + /** + * Extra used for communicating with the TetherService and TetherProvisioningActivity. + * Contains the subId of current active cellular upstream. + * @hide + */ + public static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID"; + + /** + * Extra used for telling TetherProvisioningActivity the entitlement package name and class + * name to start UI entitlement check. + * @hide + */ + public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME = + "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME"; + + /** + * Extra used for telling TetherService the intent action to start silent entitlement check. + * @hide + */ + public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION = + "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION"; + + /** + * Extra used for TetherService to receive the response of provisioning check. + * @hide + */ + public static final String EXTRA_TETHER_PROVISIONING_RESPONSE = + "android.net.extra.TETHER_PROVISIONING_RESPONSE"; } diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java index 3c6e8d88ed..9dace709d7 100644 --- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java +++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java @@ -19,6 +19,10 @@ package com.android.networkstack.tethering; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; +import static android.net.TetheringConstants.EXTRA_TETHER_PROVISIONING_RESPONSE; +import static android.net.TetheringConstants.EXTRA_TETHER_SILENT_PROVISIONING_ACTION; +import static android.net.TetheringConstants.EXTRA_TETHER_SUBID; +import static android.net.TetheringConstants.EXTRA_TETHER_UI_PROVISIONING_APP_NAME; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_INVALID; @@ -69,7 +73,6 @@ public class EntitlementManager { protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning"; private static final String ACTION_PROVISIONING_ALARM = "com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM"; - private static final String EXTRA_SUBID = "subId"; private final ComponentName mSilentProvisioningService; private static final int MS_PER_HOUR = 60 * 60 * 1000; @@ -197,9 +200,9 @@ public class EntitlementManager { // till upstream change to cellular. if (mUsingCellularAsUpstream) { if (showProvisioningUi) { - runUiTetherProvisioning(downstreamType, config.activeDataSubId); + runUiTetherProvisioning(downstreamType, config); } else { - runSilentTetherProvisioning(downstreamType, config.activeDataSubId); + runSilentTetherProvisioning(downstreamType, config); } mNeedReRunProvisioningUi = false; } else { @@ -262,9 +265,9 @@ public class EntitlementManager { if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) { if (mNeedReRunProvisioningUi) { mNeedReRunProvisioningUi = false; - runUiTetherProvisioning(downstream, config.activeDataSubId); + runUiTetherProvisioning(downstream, config); } else { - runSilentTetherProvisioning(downstream, config.activeDataSubId); + runSilentTetherProvisioning(downstream, config); } } } @@ -361,7 +364,7 @@ public class EntitlementManager { * @param subId default data subscription ID. */ @VisibleForTesting - protected void runSilentTetherProvisioning(int type, int subId) { + protected Intent runSilentTetherProvisioning(int type, final TetheringConfiguration config) { if (DBG) mLog.i("runSilentTetherProvisioning: " + type); // For silent provisioning, settings would stop tethering when entitlement fail. ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null); @@ -369,17 +372,20 @@ public class EntitlementManager { Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); intent.putExtra(EXTRA_RUN_PROVISION, true); + intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, config.provisioningAppNoUi); + intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, config.provisioningResponse); intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); - intent.putExtra(EXTRA_SUBID, subId); + intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId); intent.setComponent(mSilentProvisioningService); // Only admin user can change tethering and SilentTetherProvisioning don't need to // show UI, it is fine to always start setting's background service as system user. mContext.startService(intent); + return intent; } - private void runUiTetherProvisioning(int type, int subId) { + private void runUiTetherProvisioning(int type, final TetheringConfiguration config) { ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null); - runUiTetherProvisioning(type, subId, receiver); + runUiTetherProvisioning(type, config, receiver); } /** @@ -389,17 +395,20 @@ public class EntitlementManager { * @param receiver to receive entitlement check result. */ @VisibleForTesting - protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) { + protected Intent runUiTetherProvisioning(int type, final TetheringConfiguration config, + ResultReceiver receiver) { if (DBG) mLog.i("runUiTetherProvisioning: " + type); Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING_UI); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); + intent.putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, config.provisioningApp); intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); - intent.putExtra(EXTRA_SUBID, subId); + intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Only launch entitlement UI for system user. Entitlement UI should not appear for other // user because only admin user is allowed to change tethering. mContext.startActivity(intent); + return intent; } // Not needed to check if this don't run on the handler thread because it's private. @@ -631,7 +640,7 @@ public class EntitlementManager { receiver.send(cacheValue, null); } else { ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver); - runUiTetherProvisioning(downstream, config.activeDataSubId, proxy); + runUiTetherProvisioning(downstream, config, proxy); } } } diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 1e94de12ce..18b2b7804f 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -105,6 +105,7 @@ public class TetheringConfiguration { public final String[] provisioningApp; public final String provisioningAppNoUi; public final int provisioningCheckPeriod; + public final String provisioningResponse; public final int activeDataSubId; @@ -141,10 +142,13 @@ public class TetheringConfiguration { enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); - provisioningAppNoUi = getProvisioningAppNoUi(res); + provisioningAppNoUi = getResourceString(res, + R.string.config_mobile_hotspot_provision_app_no_ui); provisioningCheckPeriod = getResourceInteger(res, R.integer.config_mobile_hotspot_provision_check_period, 0 /* No periodic re-check */); + provisioningResponse = getResourceString(res, + R.string.config_mobile_hotspot_provision_response); mOffloadPollInterval = getResourceInteger(res, R.integer.config_tether_offload_poll_interval, @@ -341,9 +345,9 @@ public class TetheringConfiguration { return copy(LEGACY_DHCP_DEFAULT_RANGE); } - private static String getProvisioningAppNoUi(Resources res) { + private static String getResourceString(Resources res, final int resId) { try { - return res.getString(R.string.config_mobile_hotspot_provision_app_no_ui); + return res.getString(resId); } catch (Resources.NotFoundException e) { return ""; } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java index 72fa916b9e..354e75356e 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java @@ -16,8 +16,16 @@ package com.android.networkstack.tethering; +import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; +import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; +import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; +import static android.net.TetheringConstants.EXTRA_TETHER_PROVISIONING_RESPONSE; +import static android.net.TetheringConstants.EXTRA_TETHER_SILENT_PROVISIONING_ACTION; +import static android.net.TetheringConstants.EXTRA_TETHER_SUBID; +import static android.net.TetheringConstants.EXTRA_TETHER_UI_PROVISIONING_APP_NAME; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_ETHERNET; +import static android.net.TetheringManager.TETHERING_INVALID; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; @@ -44,6 +52,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.Intent; import android.content.res.Resources; import android.net.util.SharedLog; import android.os.Bundle; @@ -53,6 +62,7 @@ import android.os.ResultReceiver; import android.os.SystemProperties; import android.os.test.TestLooper; import android.provider.DeviceConfig; +import android.provider.Settings; import android.telephony.CarrierConfigManager; import androidx.test.filters.SmallTest; @@ -76,6 +86,7 @@ public final class EntitlementManagerTest { private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; + private static final String PROVISIONING_APP_RESPONSE = "app_response"; @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private Context mContext; @@ -122,15 +133,51 @@ public final class EntitlementManagerTest { } @Override - protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) { + protected Intent runUiTetherProvisioning(int type, + final TetheringConfiguration config, final ResultReceiver receiver) { + Intent intent = super.runUiTetherProvisioning(type, config, receiver); + assertUiTetherProvisioningIntent(type, config, receiver, intent); uiProvisionCount++; receiver.send(fakeEntitlementResult, null); + return intent; + } + + private void assertUiTetherProvisioningIntent(int type, final TetheringConfiguration config, + final ResultReceiver receiver, final Intent intent) { + assertEquals(Settings.ACTION_TETHER_PROVISIONING_UI, intent.getAction()); + assertEquals(type, intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID)); + final String[] appName = intent.getStringArrayExtra( + EXTRA_TETHER_UI_PROVISIONING_APP_NAME); + assertEquals(PROVISIONING_APP_NAME.length, appName.length); + for (int i = 0; i < PROVISIONING_APP_NAME.length; i++) { + assertEquals(PROVISIONING_APP_NAME[i], appName[i]); + } + assertEquals(receiver, intent.getParcelableExtra(EXTRA_PROVISION_CALLBACK)); + assertEquals(config.activeDataSubId, + intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID)); } @Override - protected void runSilentTetherProvisioning(int type, int subId) { + protected Intent runSilentTetherProvisioning(int type, + final TetheringConfiguration config) { + Intent intent = super.runSilentTetherProvisioning(type, config); + assertSilentTetherProvisioning(type, config, intent); silentProvisionCount++; addDownstreamMapping(type, fakeEntitlementResult); + return intent; + } + + private void assertSilentTetherProvisioning(int type, final TetheringConfiguration config, + final Intent intent) { + assertEquals(type, intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID)); + assertEquals(true, intent.getBooleanExtra(EXTRA_RUN_PROVISION, false)); + assertEquals(PROVISIONING_NO_UI_APP_NAME, + intent.getStringExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION)); + assertEquals(PROVISIONING_APP_RESPONSE, + intent.getStringExtra(EXTRA_TETHER_PROVISIONING_RESPONSE)); + assertTrue(intent.hasExtra(EXTRA_PROVISION_CALLBACK)); + assertEquals(config.activeDataSubId, + intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID)); } } @@ -187,6 +234,8 @@ public final class EntitlementManagerTest { .thenReturn(PROVISIONING_APP_NAME); when(mResources.getString(R.string.config_mobile_hotspot_provision_app_no_ui)) .thenReturn(PROVISIONING_NO_UI_APP_NAME); + when(mResources.getString(R.string.config_mobile_hotspot_provision_response)).thenReturn( + PROVISIONING_APP_RESPONSE); // Act like the CarrierConfigManager is present and ready unless told otherwise. when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) .thenReturn(mCarrierConfigManager); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index 3f4cfe7afb..a9ac4e2851 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -61,6 +61,8 @@ public class TetheringConfigurationTest { private final SharedLog mLog = new SharedLog("TetheringConfigurationTest"); private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; + private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; + private static final String PROVISIONING_APP_RESPONSE = "app_response"; @Mock private Context mContext; @Mock private TelephonyManager mTelephonyManager; @Mock private Resources mResources; @@ -388,6 +390,8 @@ public class TetheringConfigurationTest { new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId); assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]); assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]); + assertEquals(mockCfg.provisioningAppNoUi, PROVISIONING_NO_UI_APP_NAME); + assertEquals(mockCfg.provisioningResponse, PROVISIONING_APP_RESPONSE); } private void setUpResourceForSubId() { @@ -403,6 +407,10 @@ public class TetheringConfigurationTest { new int[0]); when(mResourcesForSubId.getStringArray( R.array.config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME); + when(mResourcesForSubId.getString(R.string.config_mobile_hotspot_provision_app_no_ui)) + .thenReturn(PROVISIONING_NO_UI_APP_NAME); + when(mResourcesForSubId.getString( + R.string.config_mobile_hotspot_provision_response)).thenReturn( + PROVISIONING_APP_RESPONSE); } - } From 4c9428a135c0b5a072c3ab3df8403e9a2cb438aa Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 3 Jun 2020 12:27:37 +0800 Subject: [PATCH 1217/1415] Protect invalid entitlement app configuration There is a protection in Settings that Settings would gray out if tethering requires entitlement check but the entitlement app is invalid. Tethering resource is moved from framework to tethering module, so Settings can not fetch entitlement app name anymore. In this change, tethering module would check whether entitltement app package name is exsited if entitlement check is needed. Tethering would be not supported (Settings tethering option would be hidded) if entitlement app is not installed. After moving the protection into tethering module, TetherUtil#isProvisioningNeeded is no longer needed. Because The only use case is Settings wants to gray out tethering setting when entitltement check is needed but entitlement app is invalid. Bug: 146918263 Test: atest TetheringCoverageTests Change-Id: I9a5ff5dbc1db3f3be7fcd7146862a16b373507e6 Merged-In: I9a5ff5dbc1db3f3be7fcd7146862a16b373507e6 --- .../networkstack/tethering/Tethering.java | 28 ++++++++++++++--- .../tethering/TetheringDependencies.java | 9 ++++++ .../networkstack/tethering/TetheringTest.java | 30 +++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 71ab176764..8d720e7539 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -18,6 +18,7 @@ package com.android.networkstack.tethering; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STACK; +import static android.content.pm.PackageManager.GET_ACTIVITIES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; @@ -71,6 +72,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.EthernetManager; @@ -110,7 +112,6 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceSpecificException; -import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -811,11 +812,30 @@ public class Tethering { } } + private boolean isProvisioningNeededButUnavailable() { + return isTetherProvisioningRequired() && !doesEntitlementPackageExist(); + } + boolean isTetherProvisioningRequired() { final TetheringConfiguration cfg = mConfig; return mEntitlementMgr.isTetherProvisioningRequired(cfg); } + private boolean doesEntitlementPackageExist() { + // provisioningApp must contain package and class name. + if (mConfig.provisioningApp.length != 2) { + return false; + } + + final PackageManager pm = mContext.getPackageManager(); + try { + pm.getPackageInfo(mConfig.provisioningApp[0], GET_ACTIVITIES); + } catch (PackageManager.NameNotFoundException e) { + return false; + } + return true; + } + // TODO: Figure out how to update for local hotspot mode interfaces. private void sendTetherStateChangedBroadcast() { if (!isTetheringSupported()) return; @@ -2175,14 +2195,14 @@ public class Tethering { // gservices could set the secure setting to 1 though to enable it on a build where it // had previously been turned off. boolean isTetheringSupported() { - final int defaultVal = - SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1; + final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1; final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.TETHER_SUPPORTED, defaultVal) != 0; final boolean tetherEnabledInSettings = tetherSupported && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); - return tetherEnabledInSettings && hasTetherableConfiguration(); + return tetherEnabledInSettings && hasTetherableConfiguration() + && !isProvisioningNeededButUnavailable(); } void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 8f4b964323..131a5fbf2a 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -26,6 +26,8 @@ import android.net.util.SharedLog; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.SystemProperties; +import android.text.TextUtils; import androidx.annotation.NonNull; @@ -147,4 +149,11 @@ public abstract class TetheringDependencies { * Get a reference to BluetoothAdapter to be used by tethering. */ public abstract BluetoothAdapter getBluetoothAdapter(); + + /** + * Get SystemProperties which indicate whether tethering is denied. + */ + public boolean isTetheringDenied() { + return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true"); + } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 2b2dfae5c9..d37aad26d1 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -16,6 +16,7 @@ package com.android.networkstack.tethering; +import static android.content.pm.PackageManager.GET_ACTIVITIES; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM; @@ -81,6 +82,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; @@ -204,6 +206,7 @@ public class TetheringTest { @Mock private EthernetManager mEm; @Mock private TetheringNotificationUpdater mNotificationUpdater; @Mock private BpfCoordinator mBpfCoordinator; + @Mock private PackageManager mPackageManager; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -263,6 +266,11 @@ public class TetheringTest { return super.getSystemService(name); } + @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + @Override public String getSystemServiceName(Class serviceClass) { if (TelephonyManager.class.equals(serviceClass)) return Context.TELEPHONY_SERVICE; @@ -425,6 +433,11 @@ public class TetheringTest { public TetheringNotificationUpdater getNotificationUpdater(Context ctx, Looper looper) { return mNotificationUpdater; } + + @Override + public boolean isTetheringDenied() { + return false; + } } private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4, @@ -1951,6 +1964,23 @@ public class TetheringTest { assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastTetherError(TEST_ETH_IFNAME)); } + @Test + public void testProvisioningNeededButUnavailable() throws Exception { + assertTrue(mTethering.isTetheringSupported()); + verify(mPackageManager, never()).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES); + + setupForRequiredProvisioning(); + assertTrue(mTethering.isTetheringSupported()); + verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES); + reset(mPackageManager); + + doThrow(PackageManager.NameNotFoundException.class).when(mPackageManager).getPackageInfo( + PROVISIONING_APP_NAME[0], GET_ACTIVITIES); + setupForRequiredProvisioning(); + assertFalse(mTethering.isTetheringSupported()); + verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES); + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } From a9dda298748ea1cd288e1cd41f8a487ebff707a5 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 21 May 2020 09:15:44 -0700 Subject: [PATCH 1218/1415] CTS test ConnectivityDiagnostics via CarrierPrivilegesTracker. This change adds a CTS test for ConnectivityDiagnostics using CarrierPrivilegesTracker to receive permissions for ConnectivityDiagnostics callbacks. Specifically, the test provides CarrierPrivileges to the test package (android.net.cts) for the active subscription via Carrier Configs overrides. CarrierPrivilegesTracker listens to the Carrier Configs change and matches the loaded certificate with the test package, then includes the test package UID as an administrator for the Network in ConnectivityService. Then, a ConnectivityDiagnosticsCallback is registered and receives a ConnectivityReport on register for the active subscription. Bug: 148032944 Bug: 151332031 Test: atest ConnectivityDiagnosticsManagerTest Change-Id: Iee8a428ada0b6e2127410267a13c3b688df83e6d Merged-In: Iee8a428ada0b6e2127410267a13c3b688df83e6d --- .../ConnectivityDiagnosticsManagerTest.java | 166 +++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index d17d8e53ae..1e64d83a17 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -16,6 +16,7 @@ package android.net.cts; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK; @@ -31,6 +32,7 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; @@ -41,9 +43,15 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityManager; import android.net.LinkAddress; @@ -58,10 +66,15 @@ import android.os.IBinder; import android.os.PersistableBundle; import android.os.Process; import android.platform.test.annotations.AppModeFull; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.Pair; import androidx.test.InstrumentationRegistry; +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.util.ArrayUtils; import com.android.testutils.ArrayTrackRecord; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; @@ -71,7 +84,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.security.MessageDigest; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q @@ -85,6 +101,7 @@ public class ConnectivityDiagnosticsManagerTest { private static final int FAIL_RATE_PERCENTAGE = 100; private static final int UNKNOWN_DETECTION_METHOD = 4; private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; + private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -95,15 +112,23 @@ public class ConnectivityDiagnosticsManagerTest { .removeCapability(NET_CAPABILITY_NOT_VPN) .build(); + private static final String SHA_256 = "SHA-256"; + // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests // for it. private static final TestNetworkCallback TEST_NETWORK_CALLBACK = new TestNetworkCallback(); + private static final NetworkRequest CELLULAR_NETWORK_REQUEST = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + private static final IBinder BINDER = new Binder(); private Context mContext; private ConnectivityManager mConnectivityManager; private ConnectivityDiagnosticsManager mCdm; + private CarrierConfigManager mCarrierConfigManager; + private PackageManager mPackageManager; + private TelephonyManager mTelephonyManager; private Network mTestNetwork; @Before @@ -111,6 +136,9 @@ public class ConnectivityDiagnosticsManagerTest { mContext = InstrumentationRegistry.getContext(); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class); + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mPackageManager = mContext.getPackageManager(); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, TEST_NETWORK_CALLBACK); } @@ -141,6 +169,98 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } + @Test + public void testRegisterCallbackWithCarrierPrivileges() throws Exception { + assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); + + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + fail("Need an active subscription. Please ensure that the device has working mobile" + + " data."); + } + + final CarrierConfigReceiver carrierConfigReceiver = new CarrierConfigReceiver(subId); + mContext.registerReceiver( + carrierConfigReceiver, + new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + + final TestNetworkCallback testNetworkCallback = new TestNetworkCallback(); + final TestConnectivityDiagnosticsCallback connDiagsCallback = + new TestConnectivityDiagnosticsCallback(); + try { + doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( + subId, carrierConfigReceiver, testNetworkCallback, connDiagsCallback); + } finally { + runWithShellPermissionIdentity( + () -> mCarrierConfigManager.overrideConfig(subId, null), + android.Manifest.permission.MODIFY_PHONE_STATE); + mConnectivityManager.unregisterNetworkCallback(testNetworkCallback); + mCdm.unregisterConnectivityDiagnosticsCallback(connDiagsCallback); + mContext.unregisterReceiver(carrierConfigReceiver); + } + } + + private String getCertHashForThisPackage() throws Exception { + final PackageInfo pkgInfo = + mPackageManager.getPackageInfo( + mContext.getOpPackageName(), PackageManager.GET_SIGNATURES); + final MessageDigest md = MessageDigest.getInstance(SHA_256); + final byte[] certHash = md.digest(pkgInfo.signatures[0].toByteArray()); + return IccUtils.bytesToHexString(certHash); + } + + private void doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( + int subId, + @NonNull CarrierConfigReceiver carrierConfigReceiver, + @NonNull TestNetworkCallback testNetworkCallback, + @NonNull TestConnectivityDiagnosticsCallback connDiagsCallback) + throws Exception { + final PersistableBundle carrierConfigs = new PersistableBundle(); + carrierConfigs.putStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, + new String[] {getCertHashForThisPackage()}); + + runWithShellPermissionIdentity( + () -> { + mCarrierConfigManager.overrideConfig(subId, carrierConfigs); + mCarrierConfigManager.notifyConfigChangedForSubId(subId); + }, + android.Manifest.permission.MODIFY_PHONE_STATE); + + // TODO(b/157779832): This should use android.permission.CHANGE_NETWORK_STATE. However, the + // shell does not have CHANGE_NETWORK_STATE, so use CONNECTIVITY_INTERNAL until the shell + // permissions are updated. + runWithShellPermissionIdentity( + () -> mConnectivityManager.requestNetwork( + CELLULAR_NETWORK_REQUEST, testNetworkCallback), + android.Manifest.permission.CONNECTIVITY_INTERNAL); + + final Network network = testNetworkCallback.waitForAvailable(); + assertNotNull(network); + + assertTrue("Didn't receive broadcast for ACTION_CARRIER_CONFIG_CHANGED for subId=" + subId, + carrierConfigReceiver.waitForCarrierConfigChanged()); + assertTrue("Don't have Carrier Privileges after adding cert for this package", + mTelephonyManager.createForSubscriptionId(subId).hasCarrierPrivileges()); + + // Wait for CarrierPrivilegesTracker to receive the ACTION_CARRIER_CONFIG_CHANGED + // broadcast. CPT then needs to update the corresponding DataConnection, which then + // updates ConnectivityService. Unfortunately, this update to the NetworkCapabilities in + // CS does not trigger NetworkCallback#onCapabilitiesChanged as changing the + // administratorUids is not a publicly visible change. In lieu of a better signal to + // detministically wait for, use Thread#sleep here. + Thread.sleep(500); + + mCdm.registerConnectivityDiagnosticsCallback( + CELLULAR_NETWORK_REQUEST, INLINE_EXECUTOR, connDiagsCallback); + + final String interfaceName = + mConnectivityManager.getLinkProperties(network).getInterfaceName(); + connDiagsCallback.expectOnConnectivityReportAvailable( + network, interfaceName, TRANSPORT_CELLULAR); + connDiagsCallback.assertNoCallback(); + } + @Test public void testRegisterDuplicateConnectivityDiagnosticsCallback() { final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); @@ -326,13 +446,18 @@ public class ConnectivityDiagnosticsManagerTest { public void expectOnConnectivityReportAvailable( @NonNull Network network, @NonNull String interfaceName) { + expectOnConnectivityReportAvailable(network, interfaceName, TRANSPORT_TEST); + } + + public void expectOnConnectivityReportAvailable( + @NonNull Network network, @NonNull String interfaceName, int transportType) { final ConnectivityReport result = (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); assertEquals(network, result.getNetwork()); final NetworkCapabilities nc = result.getNetworkCapabilities(); assertNotNull(nc); - assertTrue(nc.hasTransport(TRANSPORT_TEST)); + assertTrue(nc.hasTransport(transportType)); assertNotNull(result.getLinkProperties()); assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); @@ -386,4 +511,43 @@ public class ConnectivityDiagnosticsManagerTest { mHistory.poll(NO_CALLBACK_INVOKED_TIMEOUT, x -> true)); } } + + private class CarrierConfigReceiver extends BroadcastReceiver { + private final CountDownLatch mLatch = new CountDownLatch(1); + private final int mSubId; + + CarrierConfigReceiver(int subId) { + mSubId = subId; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { + return; + } + + final int subId = + intent.getIntExtra( + CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (mSubId != subId) return; + + final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) return; + + final String[] certs = + carrierConfigs.getStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); + try { + if (ArrayUtils.contains(certs, getCertHashForThisPackage())) { + mLatch.countDown(); + } + } catch (Exception e) { + } + } + + boolean waitForCarrierConfigChanged() throws Exception { + return mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS); + } + } } From 6261d27a9f5c8a30d2a1afb089bb66794e9b0bce Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Sat, 20 Jun 2020 11:49:40 +0800 Subject: [PATCH 1219/1415] Add net-utils-framework-common to cts-net In order to avoid class package missing problem, add net-utils-framework-common in cts net test build. Also jarjar the package name to prevent conflict. Test: build Test: atest DnsResolverTest Bug: 150952393 Change-Id: I40e2d4c4945a0579f6e1923e4722b09354ff050c --- tests/cts/net/Android.bp | 7 ++++--- tests/cts/net/jarjar-rules-shared.txt | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 tests/cts/net/jarjar-rules-shared.txt diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 2b99a40202..112799b716 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -36,19 +36,20 @@ java_defaults { "src/**/*.java", "src/**/*.kt", ], - + jarjar_rules: "jarjar-rules-shared.txt", static_libs: [ "FrameworksNetCommonTests", "TestNetworkStackLib", - "core-tests-support", "compatibility-device-util-axt", + "core-tests-support", "cts-net-utils", "ctstestrunner-axt", "ctstestserver", - "mockwebserver", "junit", "junit-params", "libnanohttpd", + "mockwebserver", + "net-utils-framework-common", "truth-prebuilt", ], diff --git a/tests/cts/net/jarjar-rules-shared.txt b/tests/cts/net/jarjar-rules-shared.txt new file mode 100644 index 0000000000..11dba74096 --- /dev/null +++ b/tests/cts/net/jarjar-rules-shared.txt @@ -0,0 +1,2 @@ +# Module library in frameworks/libs/net +rule com.android.net.module.util.** android.net.cts.util.@1 \ No newline at end of file From e5e07430576291f36f0221f81813cbd937531fce Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 19 Jun 2020 12:04:13 +0900 Subject: [PATCH 1220/1415] Use unstable networkstack AIDLs in development branches Development branches should use the -unstable version of the NetworkStack AIDLs so that refreezing is not necessary for each modification. The versions will be re-frozen before each release instead. Bug: 157534516 Test: m Merged-In: I74b4a16266bda7b8ac740b3a0193268da260fc2f Change-Id: I1c2fe707d865e6a1953b4ab82194d4b9132258f9 --- Tethering/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 4116afca98..f89ee24f95 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -27,7 +27,8 @@ java_defaults { "androidx.annotation_annotation", "netd_aidl_interface-unstable-java", "netlink-client", - "networkstack-aidl-interfaces-java", + // TODO: use networkstack-client instead of just including the AIDL interface + "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.config-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "net-utils-framework-common", From 6896f6193f7ee0fc1e3f6a68d985af567303db46 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Thu, 21 Nov 2019 00:36:14 +0200 Subject: [PATCH 1221/1415] Tethering: Add WiGig support This change is a combination of following changes: 1) Tethering: add TETHERING_WIGIG type Currently both WIFI and WIGIG use the same tethering type, TETHERING_WIFI. This causes conflicts between the frameworks, when both WIFI and WIGIG SoftAPs are started, one or both will not work. Fix this by using a seperate tethering type for WIGIG. 2) Tethering: remove TETHERING_WIGIG state machine on interface down The wigig state machine relies on a TETHERING_STATE_CHANGED broadcast that is sent when the tethering state machine is first created, during interface up. Currently the tethering state machine is not removed on interface down except for TETHERING_BLUETOOTH, and as a result wigig tethering only works the first time SoftAP is started. In order to fix this, remove the tethering state machine on interface down for TETHERING_WIGIG as well. Bug: 143356416 Test: TetheringCoverageTests Change-Id: Ic4d3aca0ed69234093af7f0206dab3335938c52a --- .../TetheringLib/src/android/net/TetheringManager.java | 8 ++++++++ Tethering/res/values/config.xml | 7 +++++++ Tethering/res/values/overlayable.xml | 1 + Tethering/src/android/net/ip/IpServer.java | 3 ++- .../src/com/android/networkstack/tethering/Tethering.java | 6 +++++- .../networkstack/tethering/TetheringConfiguration.java | 7 +++++++ 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 04ca033828..87e5c1e521 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -171,6 +171,14 @@ public class TetheringManager { */ public static final int TETHERING_ETHERNET = 5; + /** + * WIGIG tethering type. Use a separate type to prevent + * conflicts with TETHERING_WIFI + * This type is only used internally by the tethering module + * @hide + */ + public static final int TETHERING_WIGIG = 6; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index 3f5bc901d0..4807e52804 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -42,6 +42,13 @@ "softap\\d" + + + "wigig\\d" + + diff --git a/Tethering/res/values/overlayable.xml b/Tethering/res/values/overlayable.xml index 4e2bb1e31b..6a33d55cb0 100644 --- a/Tethering/res/values/overlayable.xml +++ b/Tethering/res/values/overlayable.xml @@ -20,6 +20,7 @@ + diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index e24fc29589..a61fcfb819 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -616,7 +616,8 @@ public class IpServer extends StateMachine { final Boolean setIfaceUp; if (mInterfaceType == TetheringManager.TETHERING_WIFI || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P - || mInterfaceType == TetheringManager.TETHERING_ETHERNET) { + || mInterfaceType == TetheringManager.TETHERING_ETHERNET + || mInterfaceType == TetheringManager.TETHERING_WIGIG) { // The WiFi and Ethernet stack has ownership of the interface up/down state. // It is unclear whether the Bluetooth or USB stacks will manage their own // state. diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 8d720e7539..3627085cb6 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -40,6 +40,7 @@ import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHERING_WIGIG; import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; @@ -495,7 +496,8 @@ public class Tethering { if (up) { maybeTrackNewInterfaceLocked(iface); } else { - if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) { + if (ifaceNameToType(iface) == TETHERING_BLUETOOTH + || ifaceNameToType(iface) == TETHERING_WIGIG) { stopTrackingInterfaceLocked(iface); } else { // Ignore usb0 down after enabling RNDIS. @@ -517,6 +519,8 @@ public class Tethering { if (cfg.isWifi(iface)) { return TETHERING_WIFI; + } else if (cfg.isWigig(iface)) { + return TETHERING_WIGIG; } else if (cfg.isWifiP2p(iface)) { return TETHERING_WIFI_P2P; } else if (cfg.isUsb(iface)) { diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 18b2b7804f..e1771a5613 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -92,6 +92,7 @@ public class TetheringConfiguration { public final String[] tetherableUsbRegexs; public final String[] tetherableWifiRegexs; + public final String[] tetherableWigigRegexs; public final String[] tetherableWifiP2pRegexs; public final String[] tetherableBluetoothRegexs; public final String[] tetherableNcmRegexs; @@ -125,6 +126,7 @@ public class TetheringConfiguration { // us an interface name. Careful consideration needs to be given to // implications for Settings and for provisioning checks. tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs); + tetherableWigigRegexs = getResourceStringArray(res, R.array.config_tether_wigig_regexs); tetherableWifiP2pRegexs = getResourceStringArray( res, R.array.config_tether_wifi_p2p_regexs); tetherableBluetoothRegexs = getResourceStringArray( @@ -167,6 +169,11 @@ public class TetheringConfiguration { return matchesDownstreamRegexs(iface, tetherableWifiRegexs); } + /** Check whether input interface belong to wigig.*/ + public boolean isWigig(String iface) { + return matchesDownstreamRegexs(iface, tetherableWigigRegexs); + } + /** Check whether this interface is Wifi P2P interface. */ public boolean isWifiP2p(String iface) { return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs); From cce29fc44df22478eca67480d56ee1ea17345c18 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 29 May 2020 12:08:15 -0700 Subject: [PATCH 1222/1415] Fix ConnDiags Test for invoke-after-validate and unregister CBs. This change fixes several things in ConnectivityDiagnosticsManagerTest: - testOnConnectivityReportAvailable creates the Test Network after registering the ConnectivityDiagnosticsCallback. This ensures that the callback is invoked only after the network is validated (not for the on-register behavior). - The TestNetworkInterface created while setting up the Test Network is held onto for the duration of each test. This ensures that the interface is not garbage collected during the test. While the interface is not needed for the test, this change makes it clear when the interface is cleaned up. - All registered ConnectivityDiagnosticsCallbacks are unregistered at the end of each test. This ensures that all accompanying NetworkRequests are cleaned up. If NetworkRequests are leaked, unrelated test failures can occur (the platform limits the number of NetworkRequests per UID). Bug: 156294356 Bug: 148032944 Test: atest android.net.cts.ConnectivityDiagnosticsManagerTest Change-Id: I1836536fe60a65ba33170cd80e8f4996f1965d19 --- .../ConnectivityDiagnosticsManagerTest.java | 101 ++++++++++-------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 1e64d83a17..a19ba64d7f 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -36,6 +36,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import static org.junit.Assert.assertEquals; @@ -63,6 +64,7 @@ import android.net.TestNetworkManager; import android.os.Binder; import android.os.Build; import android.os.IBinder; +import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; import android.platform.test.annotations.AppModeFull; @@ -85,6 +87,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -114,10 +118,6 @@ public class ConnectivityDiagnosticsManagerTest { private static final String SHA_256 = "SHA-256"; - // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests - // for it. - private static final TestNetworkCallback TEST_NETWORK_CALLBACK = new TestNetworkCallback(); - private static final NetworkRequest CELLULAR_NETWORK_REQUEST = new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); @@ -129,7 +129,14 @@ public class ConnectivityDiagnosticsManagerTest { private CarrierConfigManager mCarrierConfigManager; private PackageManager mPackageManager; private TelephonyManager mTelephonyManager; + + // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests + // for it. + private TestNetworkCallback mTestNetworkCallback; private Network mTestNetwork; + private ParcelFileDescriptor mTestNetworkFD; + + private List mRegisteredCallbacks; @Before public void setUp() throws Exception { @@ -140,27 +147,40 @@ public class ConnectivityDiagnosticsManagerTest { mPackageManager = mContext.getPackageManager(); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); - mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, TEST_NETWORK_CALLBACK); + mTestNetworkCallback = new TestNetworkCallback(); + mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, mTestNetworkCallback); + + mRegisteredCallbacks = new ArrayList<>(); } @After public void tearDown() throws Exception { - mConnectivityManager.unregisterNetworkCallback(TEST_NETWORK_CALLBACK); - + mConnectivityManager.unregisterNetworkCallback(mTestNetworkCallback); if (mTestNetwork != null) { runWithShellPermissionIdentity(() -> { final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); tnm.teardownTestNetwork(mTestNetwork); }); + mTestNetwork = null; + } + + if (mTestNetworkFD != null) { + mTestNetworkFD.close(); + mTestNetworkFD = null; + } + + for (TestConnectivityDiagnosticsCallback cb : mRegisteredCallbacks) { + mCdm.unregisterConnectivityDiagnosticsCallback(cb); } } @Test public void testRegisterConnectivityDiagnosticsCallback() throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -185,17 +205,15 @@ public class ConnectivityDiagnosticsManagerTest { new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); final TestNetworkCallback testNetworkCallback = new TestNetworkCallback(); - final TestConnectivityDiagnosticsCallback connDiagsCallback = - new TestConnectivityDiagnosticsCallback(); + try { doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( - subId, carrierConfigReceiver, testNetworkCallback, connDiagsCallback); + subId, carrierConfigReceiver, testNetworkCallback); } finally { runWithShellPermissionIdentity( () -> mCarrierConfigManager.overrideConfig(subId, null), android.Manifest.permission.MODIFY_PHONE_STATE); mConnectivityManager.unregisterNetworkCallback(testNetworkCallback); - mCdm.unregisterConnectivityDiagnosticsCallback(connDiagsCallback); mContext.unregisterReceiver(carrierConfigReceiver); } } @@ -212,8 +230,7 @@ public class ConnectivityDiagnosticsManagerTest { private void doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( int subId, @NonNull CarrierConfigReceiver carrierConfigReceiver, - @NonNull TestNetworkCallback testNetworkCallback, - @NonNull TestConnectivityDiagnosticsCallback connDiagsCallback) + @NonNull TestNetworkCallback testNetworkCallback) throws Exception { final PersistableBundle carrierConfigs = new PersistableBundle(); carrierConfigs.putStringArray( @@ -251,8 +268,8 @@ public class ConnectivityDiagnosticsManagerTest { // detministically wait for, use Thread#sleep here. Thread.sleep(500); - mCdm.registerConnectivityDiagnosticsCallback( - CELLULAR_NETWORK_REQUEST, INLINE_EXECUTOR, connDiagsCallback); + final TestConnectivityDiagnosticsCallback connDiagsCallback = + createAndRegisterConnectivityDiagnosticsCallback(CELLULAR_NETWORK_REQUEST); final String interfaceName = mConnectivityManager.getLinkProperties(network).getInterfaceName(); @@ -263,8 +280,8 @@ public class ConnectivityDiagnosticsManagerTest { @Test public void testRegisterDuplicateConnectivityDiagnosticsCallback() { - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); try { mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); @@ -288,10 +305,11 @@ public class ConnectivityDiagnosticsManagerTest { @Test public void testOnConnectivityReportAvailable() throws Exception { - mTestNetwork = setUpTestNetwork(); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -339,10 +357,11 @@ public class ConnectivityDiagnosticsManagerTest { long timestampMillis, @NonNull PersistableBundle extras) throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -370,10 +389,11 @@ public class ConnectivityDiagnosticsManagerTest { } private void verifyOnNetworkConnectivityReported(boolean hasConnectivity) throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); // onConnectivityReportAvailable always invoked when the test network is established final String interfaceName = @@ -394,17 +414,12 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } - @NonNull - private Network waitForConnectivityServiceIdleAndGetNetwork() throws InterruptedException { - // Get a new Network. This requires going through the ConnectivityService thread. Once it - // completes, all previously enqueued messages on the ConnectivityService main Handler have - // completed. - final TestNetworkCallback callback = new TestNetworkCallback(); - mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, callback); - final Network network = callback.waitForAvailable(); - mConnectivityManager.unregisterNetworkCallback(callback); - assertNotNull(network); - return network; + private TestConnectivityDiagnosticsCallback createAndRegisterConnectivityDiagnosticsCallback( + NetworkRequest request) { + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, cb); + mRegisteredCallbacks.add(cb); + return cb; } /** @@ -412,16 +427,16 @@ public class ConnectivityDiagnosticsManagerTest { * to the Network being validated. */ @NonNull - private Network setUpTestNetwork() throws Exception { + private TestNetworkInterface setUpTestNetwork() throws Exception { final int[] administratorUids = new int[] {Process.myUid()}; - runWithShellPermissionIdentity( + return callWithShellPermissionIdentity( () -> { final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); final TestNetworkInterface tni = tnm.createTunInterface(new LinkAddress[0]); tnm.setupTestNetwork(tni.getInterfaceName(), administratorUids, BINDER); + return tni; }); - return waitForConnectivityServiceIdleAndGetNetwork(); } private static class TestConnectivityDiagnosticsCallback From a5c4682505d0336113654bb7f5ea77b9d8dad626 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Thu, 11 Jun 2020 16:37:31 +0100 Subject: [PATCH 1223/1415] Sync with libnativehelper refactoring jniGetFDFromFileDescriptor() is now a legacy method and moved to a separate header. Bug: 151443957 Bug: 158749603 Test: m Change-Id: Icd06e9a315680c2251dbb9032a904dd6d66aa359 --- Tethering/jni/android_net_util_TetheringUtils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp index 5493440644..f6eb40a842 100644 --- a/Tethering/jni/android_net_util_TetheringUtils.cpp +++ b/Tethering/jni/android_net_util_TetheringUtils.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include From 4feab037a55449f9f8b3d65b744598b9fffa42b2 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 24 Jun 2020 13:06:41 +0900 Subject: [PATCH 1224/1415] Skip flaky CTS tests for presubmit Skip testRegisterCallbackWithCarrierPrivileges and testContinuousQueriesInline for presubmit, as they are highly flaky. These tests are still run in postsubmit as part of MTS. In order to put the CTS suite in presubmit as early as possible, add the annotation so they are skipped in TEST_MAPPING. Bug: 158153057 Bug: 159718782 Bug: 159762682 Test: m Change-Id: I4763db869fbc714767ea5ca3651e4a0b0c9e9378 --- .../src/android/net/cts/ConnectivityDiagnosticsManagerTest.java | 2 ++ tests/cts/net/src/android/net/cts/DnsResolverTest.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index a19ba64d7f..34ca9a4e69 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -80,6 +80,7 @@ import com.android.internal.util.ArrayUtils; import com.android.testutils.ArrayTrackRecord; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.SkipPresubmit; import org.junit.After; import org.junit.Before; @@ -189,6 +190,7 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } + @SkipPresubmit(reason = "Flaky: b/159718782; add to presubmit after fixing") @Test public void testRegisterCallbackWithCarrierPrivileges() throws Exception { assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index e6f75c353b..4acbbcfbdd 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -47,6 +47,7 @@ import android.test.AndroidTestCase; import android.util.Log; import com.android.net.module.util.DnsPacket; +import com.android.testutils.SkipPresubmit; import java.net.Inet4Address; import java.net.Inet6Address; @@ -585,6 +586,7 @@ public class DnsResolverTest extends AndroidTestCase { doTestContinuousQueries(mExecutor); } + @SkipPresubmit(reason = "Flaky: b/159762682; add to presubmit after fixing") public void testContinuousQueriesInline() throws Exception { doTestContinuousQueries(mExecutorInline); } From 895594dcc28a5cd114eb12dedd7d91dd2943f96d Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 16 Jun 2020 08:13:28 +0800 Subject: [PATCH 1225/1415] Move DnsPacket to libs net This class might be used by some mainline modules. Bug: 151052811 Test: atest DnsPacketTest Test: atest DnsResolverTest (clean cherry-pick from internal branch) Merged-In: I8841d91456952ded5efbf8ea221289aecc7746ad Change-Id: I8841d91456952ded5efbf8ea221289aecc7746ad --- Tethering/jarjar-rules.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt index e90a2ccaa2..8f072e4cd2 100644 --- a/Tethering/jarjar-rules.txt +++ b/Tethering/jarjar-rules.txt @@ -15,3 +15,6 @@ rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.t rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1 + +# Classes from net-utils-framework-common +rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1 \ No newline at end of file From d9daaff707da2208306377f114699c090888be37 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 16 Jun 2020 10:55:43 +0800 Subject: [PATCH 1226/1415] Update DnsPacket package name The package name needs to be updated as the class is moved into com.android.net.module.util. Bug: 149403767 Test: atest DnsResolverTest (clean cherry-pick from internal branch) Merged-In: I908cb5f7bc6150e461748c8e34c92a19aa0206e4 Change-Id: I908cb5f7bc6150e461748c8e34c92a19aa0206e4 --- tests/cts/net/src/android/net/cts/DnsResolverTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 28753ffc41..e6f75c353b 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -30,7 +30,6 @@ import android.content.Context; import android.content.ContentResolver; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; -import android.net.DnsPacket; import android.net.DnsResolver; import android.net.LinkProperties; import android.net.Network; @@ -47,6 +46,8 @@ import android.system.ErrnoException; import android.test.AndroidTestCase; import android.util.Log; +import com.android.net.module.util.DnsPacket; + import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; From 1eebfa3d87870f44a068c07113dd43b5b38ab6af Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Sat, 20 Jun 2020 11:49:40 +0800 Subject: [PATCH 1227/1415] Add net-utils-framework-common to cts-net In order to avoid class package missing problem, add net-utils-framework-common in cts net test build. Also jarjar the package name to prevent conflict. Test: build Test: atest DnsResolverTest Bug: 150952393 (clean cherry-pick from internal branch) Merged-In: I40e2d4c4945a0579f6e1923e4722b09354ff050c Change-Id: I40e2d4c4945a0579f6e1923e4722b09354ff050c --- tests/cts/net/Android.bp | 7 ++++--- tests/cts/net/jarjar-rules-shared.txt | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 tests/cts/net/jarjar-rules-shared.txt diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 052ab263d2..1ede5f75f9 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -36,19 +36,20 @@ java_defaults { "src/**/*.java", "src/**/*.kt", ], - + jarjar_rules: "jarjar-rules-shared.txt", static_libs: [ "FrameworksNetCommonTests", "TestNetworkStackLib", - "core-tests-support", "compatibility-device-util-axt", + "core-tests-support", "cts-net-utils", "ctstestrunner-axt", "ctstestserver", - "mockwebserver", "junit", "junit-params", "libnanohttpd", + "mockwebserver", + "net-utils-framework-common", "truth-prebuilt", ], diff --git a/tests/cts/net/jarjar-rules-shared.txt b/tests/cts/net/jarjar-rules-shared.txt new file mode 100644 index 0000000000..11dba74096 --- /dev/null +++ b/tests/cts/net/jarjar-rules-shared.txt @@ -0,0 +1,2 @@ +# Module library in frameworks/libs/net +rule com.android.net.module.util.** android.net.cts.util.@1 \ No newline at end of file From 697ec868d2478aa6ea7249f756ad4f7f6fe75d64 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Thu, 11 Jun 2020 16:37:31 +0100 Subject: [PATCH 1228/1415] Sync with libnativehelper refactoring jniGetFDFromFileDescriptor() is now a legacy method and moved to a separate header. Bug: 151443957 Bug: 158749603 Test: m Change-Id: Icd06e9a315680c2251dbb9032a904dd6d66aa359 Merged-In: Icd06e9a315680c2251dbb9032a904dd6d66aa359 Exempt-From-Owner-Approval: cherry pick (cherry picked from commit a5c4682505d0336113654bb7f5ea77b9d8dad626) --- Tethering/jni/android_net_util_TetheringUtils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp index 5493440644..f6eb40a842 100644 --- a/Tethering/jni/android_net_util_TetheringUtils.cpp +++ b/Tethering/jni/android_net_util_TetheringUtils.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include From 0cdccd707fab25c6f63bd72f87260b71ecaf3f1b Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Thu, 11 Jun 2020 16:37:31 +0100 Subject: [PATCH 1229/1415] Sync with libnativehelper refactoring jniGetFDFromFileDescriptor() is now a legacy method and moved to a separate header. Bug: 151443957 Bug: 158749603 Test: m Change-Id: Icd06e9a315680c2251dbb9032a904dd6d66aa359 Merged-In: Icd06e9a315680c2251dbb9032a904dd6d66aa359 Exempt-From-Owner-Approval: cherry pick (cherry picked from commit a5c4682505d0336113654bb7f5ea77b9d8dad626) --- Tethering/jni/android_net_util_TetheringUtils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp index 5493440644..f6eb40a842 100644 --- a/Tethering/jni/android_net_util_TetheringUtils.cpp +++ b/Tethering/jni/android_net_util_TetheringUtils.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include From 5c2e383949a517b48d3b9c5638f9396709c6681c Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 8 Jun 2020 13:38:11 -0700 Subject: [PATCH 1230/1415] Only run ConnectivityDiagnosticsManagerTest as AppModeFull. This CL restricts ConnectivityDiagnosticsManagerTest to only being run as @AppModeFull. This is required, as Instant Apps are not allowed CHANGE_NETWORK_STATE (required for CM#requestNetwork) or MANAGE_TEST_NETWORKS (required for TestNetworkManager#setupTestNetwork) permissions - both of which are required for ConnectivityDiagnosticsManagerTest. Bug: 158431112 Test: atest android.net.cts.ConnectivityDiagnosticsManagerTest Change-Id: Id867b8dcaca758cfeb83009848e1099e900a0790 Merged-In: Id867b8dcaca758cfeb83009848e1099e900a0790 --- .../src/android/net/cts/ConnectivityDiagnosticsManagerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 5fe05bce64..1e64d83a17 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -65,6 +65,7 @@ import android.os.Build; import android.os.IBinder; import android.os.PersistableBundle; import android.os.Process; +import android.platform.test.annotations.AppModeFull; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -90,6 +91,7 @@ import java.util.concurrent.TimeUnit; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q +@AppModeFull(reason = "CHANGE_NETWORK_STATE, MANAGE_TEST_NETWORKS not grantable to instant apps") public class ConnectivityDiagnosticsManagerTest { private static final int CALLBACK_TIMEOUT_MILLIS = 5000; private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500; From 7bb96e0987323580e57566e39be8272d7b0c5883 Mon Sep 17 00:00:00 2001 From: android-build-team Robot Date: Wed, 24 Jun 2020 16:53:55 +0000 Subject: [PATCH 1231/1415] Make change and version bump to r_aml_300802600 for mainline module file: packages/Tethering/apex/manifest.json Change-Id: I1fec7c5e3e3222df6ccd9b3c00d03b59178388b5 --- Tethering/apex/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/apex/manifest.json b/Tethering/apex/manifest.json index 36d32dcb15..a452bb0101 100644 --- a/Tethering/apex/manifest.json +++ b/Tethering/apex/manifest.json @@ -1,4 +1,4 @@ { "name": "com.android.tethering", - "version": 300802500 + "version": 300802600 } From ee8feba3c12bed28e754c872ec4adea21394d42f Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 29 May 2020 12:08:15 -0700 Subject: [PATCH 1232/1415] Fix ConnDiags Test for invoke-after-validate and unregister CBs. This change fixes several things in ConnectivityDiagnosticsManagerTest: - testOnConnectivityReportAvailable creates the Test Network after registering the ConnectivityDiagnosticsCallback. This ensures that the callback is invoked only after the network is validated (not for the on-register behavior). - The TestNetworkInterface created while setting up the Test Network is held onto for the duration of each test. This ensures that the interface is not garbage collected during the test. While the interface is not needed for the test, this change makes it clear when the interface is cleaned up. - All registered ConnectivityDiagnosticsCallbacks are unregistered at the end of each test. This ensures that all accompanying NetworkRequests are cleaned up. If NetworkRequests are leaked, unrelated test failures can occur (the platform limits the number of NetworkRequests per UID). Bug: 156294356 Bug: 148032944 Test: atest android.net.cts.ConnectivityDiagnosticsManagerTest Change-Id: I1836536fe60a65ba33170cd80e8f4996f1965d19 Merged-In: I1836536fe60a65ba33170cd80e8f4996f1965d19 --- .../ConnectivityDiagnosticsManagerTest.java | 101 ++++++++++-------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 1e64d83a17..a19ba64d7f 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -36,6 +36,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import static org.junit.Assert.assertEquals; @@ -63,6 +64,7 @@ import android.net.TestNetworkManager; import android.os.Binder; import android.os.Build; import android.os.IBinder; +import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; import android.platform.test.annotations.AppModeFull; @@ -85,6 +87,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -114,10 +118,6 @@ public class ConnectivityDiagnosticsManagerTest { private static final String SHA_256 = "SHA-256"; - // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests - // for it. - private static final TestNetworkCallback TEST_NETWORK_CALLBACK = new TestNetworkCallback(); - private static final NetworkRequest CELLULAR_NETWORK_REQUEST = new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); @@ -129,7 +129,14 @@ public class ConnectivityDiagnosticsManagerTest { private CarrierConfigManager mCarrierConfigManager; private PackageManager mPackageManager; private TelephonyManager mTelephonyManager; + + // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests + // for it. + private TestNetworkCallback mTestNetworkCallback; private Network mTestNetwork; + private ParcelFileDescriptor mTestNetworkFD; + + private List mRegisteredCallbacks; @Before public void setUp() throws Exception { @@ -140,27 +147,40 @@ public class ConnectivityDiagnosticsManagerTest { mPackageManager = mContext.getPackageManager(); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); - mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, TEST_NETWORK_CALLBACK); + mTestNetworkCallback = new TestNetworkCallback(); + mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, mTestNetworkCallback); + + mRegisteredCallbacks = new ArrayList<>(); } @After public void tearDown() throws Exception { - mConnectivityManager.unregisterNetworkCallback(TEST_NETWORK_CALLBACK); - + mConnectivityManager.unregisterNetworkCallback(mTestNetworkCallback); if (mTestNetwork != null) { runWithShellPermissionIdentity(() -> { final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); tnm.teardownTestNetwork(mTestNetwork); }); + mTestNetwork = null; + } + + if (mTestNetworkFD != null) { + mTestNetworkFD.close(); + mTestNetworkFD = null; + } + + for (TestConnectivityDiagnosticsCallback cb : mRegisteredCallbacks) { + mCdm.unregisterConnectivityDiagnosticsCallback(cb); } } @Test public void testRegisterConnectivityDiagnosticsCallback() throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -185,17 +205,15 @@ public class ConnectivityDiagnosticsManagerTest { new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); final TestNetworkCallback testNetworkCallback = new TestNetworkCallback(); - final TestConnectivityDiagnosticsCallback connDiagsCallback = - new TestConnectivityDiagnosticsCallback(); + try { doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( - subId, carrierConfigReceiver, testNetworkCallback, connDiagsCallback); + subId, carrierConfigReceiver, testNetworkCallback); } finally { runWithShellPermissionIdentity( () -> mCarrierConfigManager.overrideConfig(subId, null), android.Manifest.permission.MODIFY_PHONE_STATE); mConnectivityManager.unregisterNetworkCallback(testNetworkCallback); - mCdm.unregisterConnectivityDiagnosticsCallback(connDiagsCallback); mContext.unregisterReceiver(carrierConfigReceiver); } } @@ -212,8 +230,7 @@ public class ConnectivityDiagnosticsManagerTest { private void doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( int subId, @NonNull CarrierConfigReceiver carrierConfigReceiver, - @NonNull TestNetworkCallback testNetworkCallback, - @NonNull TestConnectivityDiagnosticsCallback connDiagsCallback) + @NonNull TestNetworkCallback testNetworkCallback) throws Exception { final PersistableBundle carrierConfigs = new PersistableBundle(); carrierConfigs.putStringArray( @@ -251,8 +268,8 @@ public class ConnectivityDiagnosticsManagerTest { // detministically wait for, use Thread#sleep here. Thread.sleep(500); - mCdm.registerConnectivityDiagnosticsCallback( - CELLULAR_NETWORK_REQUEST, INLINE_EXECUTOR, connDiagsCallback); + final TestConnectivityDiagnosticsCallback connDiagsCallback = + createAndRegisterConnectivityDiagnosticsCallback(CELLULAR_NETWORK_REQUEST); final String interfaceName = mConnectivityManager.getLinkProperties(network).getInterfaceName(); @@ -263,8 +280,8 @@ public class ConnectivityDiagnosticsManagerTest { @Test public void testRegisterDuplicateConnectivityDiagnosticsCallback() { - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); try { mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); @@ -288,10 +305,11 @@ public class ConnectivityDiagnosticsManagerTest { @Test public void testOnConnectivityReportAvailable() throws Exception { - mTestNetwork = setUpTestNetwork(); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -339,10 +357,11 @@ public class ConnectivityDiagnosticsManagerTest { long timestampMillis, @NonNull PersistableBundle extras) throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -370,10 +389,11 @@ public class ConnectivityDiagnosticsManagerTest { } private void verifyOnNetworkConnectivityReported(boolean hasConnectivity) throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); // onConnectivityReportAvailable always invoked when the test network is established final String interfaceName = @@ -394,17 +414,12 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } - @NonNull - private Network waitForConnectivityServiceIdleAndGetNetwork() throws InterruptedException { - // Get a new Network. This requires going through the ConnectivityService thread. Once it - // completes, all previously enqueued messages on the ConnectivityService main Handler have - // completed. - final TestNetworkCallback callback = new TestNetworkCallback(); - mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, callback); - final Network network = callback.waitForAvailable(); - mConnectivityManager.unregisterNetworkCallback(callback); - assertNotNull(network); - return network; + private TestConnectivityDiagnosticsCallback createAndRegisterConnectivityDiagnosticsCallback( + NetworkRequest request) { + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, cb); + mRegisteredCallbacks.add(cb); + return cb; } /** @@ -412,16 +427,16 @@ public class ConnectivityDiagnosticsManagerTest { * to the Network being validated. */ @NonNull - private Network setUpTestNetwork() throws Exception { + private TestNetworkInterface setUpTestNetwork() throws Exception { final int[] administratorUids = new int[] {Process.myUid()}; - runWithShellPermissionIdentity( + return callWithShellPermissionIdentity( () -> { final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); final TestNetworkInterface tni = tnm.createTunInterface(new LinkAddress[0]); tnm.setupTestNetwork(tni.getInterfaceName(), administratorUids, BINDER); + return tni; }); - return waitForConnectivityServiceIdleAndGetNetwork(); } private static class TestConnectivityDiagnosticsCallback From ce1daf5501642af59fa7f50a463606ef9e859c28 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 25 Jun 2020 03:58:10 +0000 Subject: [PATCH 1233/1415] Move CtsNetTestCasesLatestSdk to presubmit The last runs have been green, and triggering 20 remote runs found no flake. Bug: 158153057 Change-Id: I9d7954503990902ae807d74de14f4a2874328072 Test: m --- tests/cts/net/TEST_MAPPING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/TEST_MAPPING b/tests/cts/net/TEST_MAPPING index e2a9c75778..ff438e5a1c 100644 --- a/tests/cts/net/TEST_MAPPING +++ b/tests/cts/net/TEST_MAPPING @@ -1,6 +1,6 @@ { // TODO: move to mainline-presubmit once supported - "postsubmit": [ + "presubmit": [ { "name": "CtsNetTestCasesLatestSdk", "options": [ From c8d9a5706e7ccfcfc66424f54f475d58f3e6dcf0 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 24 Jun 2020 09:36:37 -0700 Subject: [PATCH 1234/1415] Increase ConnDiagsTest timeout for end-to-end test. This change increases the delay allowed for administratorUid updates to reach ConnectivityService in #testRegisterCallbackWithCarrierPrivileges. Currently, there is no deterministic signal that can be used to wait for this change, so Thread#sleep is required. This value is increased because the previous delay did not give enough time for the administratorUid change to reach CS, causing test flake. Bug: 159718782 Test: atest android.net.cts.ConnectivityDiagnosticsManagerTest Change-Id: I36347f6d52e3ce1bd30e3f74c35f4ecd15c8c65e --- .../android/net/cts/ConnectivityDiagnosticsManagerTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index a19ba64d7f..1726a47dd9 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -106,6 +106,7 @@ public class ConnectivityDiagnosticsManagerTest { private static final int UNKNOWN_DETECTION_METHOD = 4; private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000; + private static final int DELAY_FOR_ADMIN_UIDS_MILLIS = 2000; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -266,7 +267,8 @@ public class ConnectivityDiagnosticsManagerTest { // CS does not trigger NetworkCallback#onCapabilitiesChanged as changing the // administratorUids is not a publicly visible change. In lieu of a better signal to // detministically wait for, use Thread#sleep here. - Thread.sleep(500); + // TODO(b/157949581): replace this Thread#sleep with a deterministic signal + Thread.sleep(DELAY_FOR_ADMIN_UIDS_MILLIS); final TestConnectivityDiagnosticsCallback connDiagsCallback = createAndRegisterConnectivityDiagnosticsCallback(CELLULAR_NETWORK_REQUEST); From af7ca2d11f330f78b980f747a5f910037857ed52 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 26 Jun 2020 07:48:13 +0000 Subject: [PATCH 1235/1415] Increase ConnDiagsTest timeout for end-to-end test. This change increases the delay allowed for administratorUid updates to reach ConnectivityService in #testRegisterCallbackWithCarrierPrivileges. Currently, there is no deterministic signal that can be used to wait for this change, so Thread#sleep is required. This value is increased because the previous delay did not give enough time for the administratorUid change to reach CS, causing test flake. Bug: 159718782 Test: atest android.net.cts.ConnectivityDiagnosticsManagerTest Original-Change: https://android-review.googlesource.com/1349068 Merged-In: I36347f6d52e3ce1bd30e3f74c35f4ecd15c8c65e Change-Id: I36347f6d52e3ce1bd30e3f74c35f4ecd15c8c65e --- .../android/net/cts/ConnectivityDiagnosticsManagerTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 34ca9a4e69..8f42f79382 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -107,6 +107,7 @@ public class ConnectivityDiagnosticsManagerTest { private static final int UNKNOWN_DETECTION_METHOD = 4; private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000; + private static final int DELAY_FOR_ADMIN_UIDS_MILLIS = 2000; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -268,7 +269,8 @@ public class ConnectivityDiagnosticsManagerTest { // CS does not trigger NetworkCallback#onCapabilitiesChanged as changing the // administratorUids is not a publicly visible change. In lieu of a better signal to // detministically wait for, use Thread#sleep here. - Thread.sleep(500); + // TODO(b/157949581): replace this Thread#sleep with a deterministic signal + Thread.sleep(DELAY_FOR_ADMIN_UIDS_MILLIS); final TestConnectivityDiagnosticsCallback connDiagsCallback = createAndRegisterConnectivityDiagnosticsCallback(CELLULAR_NETWORK_REQUEST); From 67aeab2eeeefefbce11256bdccf2908d42fc3f08 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 29 Jun 2020 00:32:19 +0800 Subject: [PATCH 1236/1415] Correct PendingIntent#getActivity() flags TetheringNotificationUpdater create a PendingIntent with Intent#FLAG_ACTIVITY_NEW_TASK flag. But this flag is used for Intent only. Thus, move this flag into Intent. Bug: 158639789 Test: atest TetheringTests Change-Id: I4c3af75c87b797bcde9356a94c835c7422dac1c6 --- .../tethering/TetheringNotificationUpdater.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index 593d04a06b..a0198cc9c1 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -273,8 +273,9 @@ public class TetheringNotificationUpdater { mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), 0 /* requestCode */, new Intent(Settings.ACTION_TETHER_SETTINGS) - .setPackage(getSettingsPackageName(mContext.getPackageManager())), - Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE, + .setPackage(getSettingsPackageName(mContext.getPackageManager())) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), + PendingIntent.FLAG_IMMUTABLE, null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, @@ -317,8 +318,9 @@ public class TetheringNotificationUpdater { mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), 0 /* requestCode */, new Intent(Settings.ACTION_TETHER_SETTINGS) - .setPackage(getSettingsPackageName(mContext.getPackageManager())), - Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE, + .setPackage(getSettingsPackageName(mContext.getPackageManager())) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), + PendingIntent.FLAG_IMMUTABLE, null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, From 5ed6690e6664834ecf7d1b24afc05d67c3d8dd70 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 25 Jun 2020 20:48:44 +0900 Subject: [PATCH 1237/1415] Let testB141603906 run over ADB-over-network This test (added in R) failed to take the adb-over-network case into account like most other tests in the same file. As such it erroneously fails when tested over such a test setup. This patch exempts the shell from being subject to the VPN, like other similar tests do, to avoid the adb connections being killed. Test: VpnTest Bug: 159761399 Change-Id: I0bc14d4d2cade7618c59b2cb88638bdf608d43d3 --- .../hostside/app/src/com/android/cts/net/hostside/VpnTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index 26397ef5af..a451ea8585 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -1016,7 +1016,8 @@ public class VpnTest extends InstrumentationTestCase { final Thread[] threads = new Thread[NUM_THREADS]; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"0.0.0.0/0", "::/0"}, - "", "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */); + "" /* allowedApplications */, "com.android.shell" /* disallowedApplications */, + null /* proxyInfo */, null /* underlyingNetworks */, false /* isAlwaysMetered */); for (int i = 0; i < NUM_THREADS; i++) { threads[i] = new Thread(() -> { From 4072d4d5d4078cc53efeeee7fc5439f3cd232747 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 19 May 2020 21:12:39 +0900 Subject: [PATCH 1238/1415] Drop .stubs from android.test.[base|runner|mock].stubs The .stubs library refer to the stub library of a java_sdk_library. Since the name of the stub library is the implementation detail of the build system, direct use of the name should be prohibited. Actually, clients don't need to use the stub name directly because the build system automatically redirects to .stubs. Exempt-From-Owner-Approval: too many owners are involved. This is a simple build script change. Bug: 157007292 Test: m Change-Id: I32502de3d87c5cfdbbcfe5545dd7db5e9bb551a7 --- tests/cts/hostside/app/Android.bp | 4 ++-- tests/cts/net/Android.bp | 2 +- tests/cts/net/api23Test/Android.bp | 2 +- tests/cts/net/ipsec/Android.bp | 2 +- tests/cts/tethering/Android.bp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index 7a1145609f..e129be7b7d 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp @@ -28,8 +28,8 @@ android_test_helper_app { "CtsHostsideNetworkTestsAidl", ], libs: [ - "android.test.runner.stubs", - "android.test.base.stubs", + "android.test.runner", + "android.test.base", ], srcs: ["src/**/*.java"], // Tag this module as a cts test artifact diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 112799b716..27c8293b72 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -22,7 +22,7 @@ java_defaults { libs: [ "voip-common", "org.apache.http.legacy", - "android.test.base.stubs", + "android.test.base", ], jni_libs: [ diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index ffeef48a88..0ce9826a2b 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -20,7 +20,7 @@ android_test { compile_multilib: "both", libs: [ - "android.test.base.stubs", + "android.test.base", ], srcs: [ diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp index 124e93c650..948cc05d76 100644 --- a/tests/cts/net/ipsec/Android.bp +++ b/tests/cts/net/ipsec/Android.bp @@ -21,7 +21,7 @@ android_test { libs: [ "android.net.ipsec.ike.stubs.system", - "android.test.base.stubs", + "android.test.base", ], srcs: [ diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 85bb0e03f1..b1d4a6052b 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -17,7 +17,7 @@ android_test { defaults: ["cts_defaults"], libs: [ - "android.test.base.stubs", + "android.test.base", ], srcs: [ From 82bb526062d94e2a64a5a2a22a4f056f03c4b56d Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 19 May 2020 21:12:39 +0900 Subject: [PATCH 1239/1415] Drop .stubs from android.test.[base|runner|mock].stubs The .stubs library refer to the stub library of a java_sdk_library. Since the name of the stub library is the implementation detail of the build system, direct use of the name should be prohibited. Actually, clients don't need to use the stub name directly because the build system automatically redirects to .stubs. Exempt-From-Owner-Approval: too many owners are involved. This is a simple build script change. Bug: 157007292 Test: m Merged-In: I32502de3d87c5cfdbbcfe5545dd7db5e9bb551a7 (cherry picked from commit 4072d4d5d4078cc53efeeee7fc5439f3cd232747) Change-Id: I32502de3d87c5cfdbbcfe5545dd7db5e9bb551a7 --- tests/cts/hostside/app/Android.bp | 4 ++-- tests/cts/net/Android.bp | 2 +- tests/cts/net/api23Test/Android.bp | 2 +- tests/cts/net/ipsec/Android.bp | 2 +- tests/cts/tethering/Android.bp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index 7a1145609f..e129be7b7d 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp @@ -28,8 +28,8 @@ android_test_helper_app { "CtsHostsideNetworkTestsAidl", ], libs: [ - "android.test.runner.stubs", - "android.test.base.stubs", + "android.test.runner", + "android.test.base", ], srcs: ["src/**/*.java"], // Tag this module as a cts test artifact diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 112799b716..27c8293b72 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -22,7 +22,7 @@ java_defaults { libs: [ "voip-common", "org.apache.http.legacy", - "android.test.base.stubs", + "android.test.base", ], jni_libs: [ diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index ffeef48a88..0ce9826a2b 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -20,7 +20,7 @@ android_test { compile_multilib: "both", libs: [ - "android.test.base.stubs", + "android.test.base", ], srcs: [ diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp index 124e93c650..948cc05d76 100644 --- a/tests/cts/net/ipsec/Android.bp +++ b/tests/cts/net/ipsec/Android.bp @@ -21,7 +21,7 @@ android_test { libs: [ "android.net.ipsec.ike.stubs.system", - "android.test.base.stubs", + "android.test.base", ], srcs: [ diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 85bb0e03f1..b1d4a6052b 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -17,7 +17,7 @@ android_test { defaults: ["cts_defaults"], libs: [ - "android.test.base.stubs", + "android.test.base", ], srcs: [ From b589520368c6d7a55c97d3c86db43318e74b31b1 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 29 Jun 2020 23:00:03 +0800 Subject: [PATCH 1240/1415] Don't run testRequestLatestEntitlementResult if not supported If tethering is not supported, skip testRequestLatestEntitlementResult which test TetheringManager#requestLatestTetheringEntitlementResult API. Bug: 159869957 Test: atest CtsTetheringTest Change-Id: I65c32d5bc26f18f8c9d91593ab0c178e69e75c39 --- .../src/android/tethering/cts/TetheringManagerTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 5e2f62787c..f47f4549c9 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -697,6 +697,7 @@ public class TetheringManagerTest { @Test public void testRequestLatestEntitlementResult() throws Exception { + assumeTrue(mTM.isTetheringSupported()); // Verify that requestLatestTetheringEntitlementResult() can get entitlement // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener. assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( @@ -715,6 +716,9 @@ public class TetheringManagerTest { }, false), TETHER_ERROR_ENTITLEMENT_UNKNOWN); + // Do not request TETHERING_WIFI entitlement result if TETHERING_WIFI is not available. + assumeTrue(mTM.getTetherableWifiRegexs().length > 0); + // Verify that null listener will cause IllegalArgumentException. try { mTM.requestLatestTetheringEntitlementResult( From ba6f3be791a8b80d2d53f29fdc675573c7e0aaec Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 12 Jun 2020 17:59:16 +0900 Subject: [PATCH 1241/1415] Move Inet[4]AddressUtils to libs/net The classes should not be picked up from frameworks/base, as they are part of several mainline modules. Bug: 151052811 Test: m; manual: flashed, wifi and telephony working Test: atest CtsNetTestCasesLatestSdk:CaptivePortalApiTest (clean cherry-pick from internal branch) Merged-In: Ic7534afe3a437f2089ed33cebdad391dc498d187 Change-Id: Ic7534afe3a437f2089ed33cebdad391dc498d187 --- tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt index 68d5281650..ef2b0cee2f 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt @@ -35,8 +35,6 @@ import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_DISCOVER import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_REQUEST import android.net.dhcp.DhcpRequestPacket -import android.net.shared.Inet4AddressUtils.getBroadcastAddress -import android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address import android.os.Build import android.os.HandlerThread import android.platform.test.annotations.AppModeFull @@ -44,6 +42,8 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity import com.android.compatibility.common.util.ThrowingRunnable +import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress +import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DhcpClientPacketFilter From a8ac97cf22fb7016d87b68f1aabb30d6cfd9d5f4 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 30 Jun 2020 22:56:12 +0800 Subject: [PATCH 1242/1415] Fix tethering jarjar rule for LocalLog LocalLog is in android.util* instead of android.net*. No crash happen becaue the methods used by tethering are @UnsupportedAppUsage. Bug: 160113128 Test: atest TetheringTests (cherry-pick from internal branch with conflicts) Merged-In: I5f070b96f96aaabf7ec8da52a3d3444ed940fb56 Change-Id: I5f070b96f96aaabf7ec8da52a3d3444ed940fb56 --- Tethering/jarjar-rules.txt | 2 +- Tethering/tests/unit/jarjar-rules.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt index 8f072e4cd2..2c4059dda9 100644 --- a/Tethering/jarjar-rules.txt +++ b/Tethering/jarjar-rules.txt @@ -12,7 +12,7 @@ rule com.android.internal.util.State* com.android.networkstack.tethering.util.St rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 -rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 +rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1 rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1 diff --git a/Tethering/tests/unit/jarjar-rules.txt b/Tethering/tests/unit/jarjar-rules.txt index 1ea56cdf1a..ec2d2b0200 100644 --- a/Tethering/tests/unit/jarjar-rules.txt +++ b/Tethering/tests/unit/jarjar-rules.txt @@ -8,4 +8,4 @@ rule com.android.internal.util.State* com.android.networkstack.tethering.util.St rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 -rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 +rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1 From 616e299222ef6642a13e173181d75fa03ad01d3f Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 19 May 2020 21:12:39 +0900 Subject: [PATCH 1243/1415] Drop .stubs from android.test.[base|runner|mock].stubs The .stubs library refer to the stub library of a java_sdk_library. Since the name of the stub library is the implementation detail of the build system, direct use of the name should be prohibited. Actually, clients don't need to use the stub name directly because the build system automatically redirects to .stubs. Exempt-From-Owner-Approval: too many owners are involved. This is a simple build script change. Bug: 157007292 Test: m Merged-In: I32502de3d87c5cfdbbcfe5545dd7db5e9bb551a7 (cherry picked from commit 89c4e06853f7ea4b5a62a3b02b4f5113617b2c60) Change-Id: I32502de3d87c5cfdbbcfe5545dd7db5e9bb551a7 --- tests/cts/hostside/app/Android.bp | 4 ++-- tests/cts/net/Android.bp | 2 +- tests/cts/net/api23Test/Android.bp | 2 +- tests/cts/net/ipsec/Android.bp | 2 +- tests/cts/tethering/Android.bp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index 7a1145609f..e129be7b7d 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp @@ -28,8 +28,8 @@ android_test_helper_app { "CtsHostsideNetworkTestsAidl", ], libs: [ - "android.test.runner.stubs", - "android.test.base.stubs", + "android.test.runner", + "android.test.base", ], srcs: ["src/**/*.java"], // Tag this module as a cts test artifact diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 1ede5f75f9..c90ca5e4ab 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -22,7 +22,7 @@ java_defaults { libs: [ "voip-common", "org.apache.http.legacy", - "android.test.base.stubs", + "android.test.base", ], jni_libs: [ diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index ffeef48a88..0ce9826a2b 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -20,7 +20,7 @@ android_test { compile_multilib: "both", libs: [ - "android.test.base.stubs", + "android.test.base", ], srcs: [ diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp index 16bdb0548a..f27bb6f09c 100644 --- a/tests/cts/net/ipsec/Android.bp +++ b/tests/cts/net/ipsec/Android.bp @@ -21,7 +21,7 @@ android_test { libs: [ "android.net.ipsec.ike.stubs.system", - "android.test.base.stubs", + "android.test.base", ], srcs: [ diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 85bb0e03f1..b1d4a6052b 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -17,7 +17,7 @@ android_test { defaults: ["cts_defaults"], libs: [ - "android.test.base.stubs", + "android.test.base", ], srcs: [ From 8742267b94d81107127a88de053c6bbdcd189d35 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 1 Jul 2020 13:57:56 +0000 Subject: [PATCH 1244/1415] Let testB141603906 run over ADB-over-network This test (added in R) failed to take the adb-over-network case into account like most other tests in the same file. As such it erroneously fails when tested over such a test setup. This patch exempts the shell from being subject to the VPN, like other similar tests do, to avoid the adb connections being killed. Test: VpnTest Bug: 159761399 Original-Change: https://android-review.googlesource.com/1349862 Merged-In: I0bc14d4d2cade7618c59b2cb88638bdf608d43d3 Change-Id: I0bc14d4d2cade7618c59b2cb88638bdf608d43d3 --- .../hostside/app/src/com/android/cts/net/hostside/VpnTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index 26397ef5af..a451ea8585 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -1016,7 +1016,8 @@ public class VpnTest extends InstrumentationTestCase { final Thread[] threads = new Thread[NUM_THREADS]; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"0.0.0.0/0", "::/0"}, - "", "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */); + "" /* allowedApplications */, "com.android.shell" /* disallowedApplications */, + null /* proxyInfo */, null /* underlyingNetworks */, false /* isAlwaysMetered */); for (int i = 0; i < NUM_THREADS; i++) { threads[i] = new Thread(() -> { From cf86031c12405ddb5817cf834c49a032480547b3 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 8 Jun 2020 15:40:06 +0900 Subject: [PATCH 1245/1415] Move Inet[4]AddressUtils to libs/net The classes should not be picked up from frameworks/base, as they are part of several mainline modules. Also refine comments in DhcpResults following feedback in previous change. (cherry-pick from internal branch skipping wifi classes; no other conflict) Bug: 151052811 Test: m; manual: flashed, wifi and telephony working Test: atest NetworkStackCoverageTests Merged-In: I7074651c6a2a7a6b11bcf13cc4bb03833d7d655f Change-Id: I7074651c6a2a7a6b11bcf13cc4bb03833d7d655f --- Tethering/jarjar-rules.txt | 15 +++------------ .../net/dhcp/DhcpServingParamsParcelExt.java | 2 +- Tethering/src/android/net/ip/IpServer.java | 3 ++- .../unit/src/android/net/ip/IpServerTest.java | 3 ++- .../networkstack/tethering/TetheringTest.java | 2 +- 5 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt index 2c4059dda9..591861f5b8 100644 --- a/Tethering/jarjar-rules.txt +++ b/Tethering/jarjar-rules.txt @@ -1,17 +1,8 @@ # These must be kept in sync with the framework-tethering-shared-srcs filegroup. -# If there are files in that filegroup that do not appear here, the classes in the +# Classes from the framework-tethering-shared-srcs filegroup. +# If there are files in that filegroup that are not covered below, the classes in the # module will be overwritten by the ones in the framework. -# Don't jar-jar the entire package because tethering still use some internal classes -# (like TrafficStatsConstants in com.android.internal.util) -# TODO: simply these when tethering is built as system_current. -rule com.android.internal.util.BitUtils* com.android.networkstack.tethering.util.BitUtils@1 -rule com.android.internal.util.IndentingPrintWriter.java* com.android.networkstack.tethering.util.IndentingPrintWriter.java@1 -rule com.android.internal.util.IState.java* com.android.networkstack.tethering.util.IState.java@1 -rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.util.MessageUtils@1 -rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 -rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 -rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 - +rule com.android.internal.util.** com.android.networkstack.tethering.util.@1 rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1 rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1 diff --git a/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java index 4710a30b29..aaaec17bf9 100644 --- a/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -16,7 +16,7 @@ package android.net.dhcp; -import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; import android.net.LinkAddress; import android.util.ArraySet; diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index a61fcfb819..8af1797a9d 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -19,13 +19,14 @@ package android.net.ip; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; -import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.net.util.NetworkConstants.asByte; import static android.net.util.PrefixUtils.asIpPrefix; import static android.net.util.TetheringMessageBase.BASE_IPSERVER; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; + import android.net.INetd; import android.net.INetworkStackStatusCallback; import android.net.IpPrefix; diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 05cf58ab84..30a9d2252e 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -36,7 +36,8 @@ import static android.net.netlink.NetlinkConstants.RTM_NEWNEIGH; import static android.net.netlink.StructNdMsg.NUD_FAILED; import static android.net.netlink.StructNdMsg.NUD_REACHABLE; import static android.net.netlink.StructNdMsg.NUD_STALE; -import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; + +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index d37aad26d1..f1da1c7225 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -40,7 +40,6 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; -import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -49,6 +48,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES; From 37ad92e0580ce20ba6e56e9724cdb3bf3282f0e7 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 2 Jul 2020 23:20:18 +0800 Subject: [PATCH 1246/1415] Skip testPhysicalEthernet if the test run adb over network If the test run adb over network and ethernet is available, it is likely that adb may run over ethernet. Then the test would fail because adb would break when ethernet is switching from client mode to server mode. Bug: 160389275 Test: atest CtsTetheringTest Change-Id: I57d365d33316881c50c3bf7fd1c98926d10842d3 --- .../src/android/net/EthernetTetheringTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index 74df11370e..e10bab4b36 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -42,6 +42,7 @@ import android.net.dhcp.DhcpPacket; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; +import android.os.SystemProperties; import android.system.Os; import android.util.Log; @@ -224,9 +225,19 @@ public class EthernetTetheringTest { } + private boolean isAdbOverNetwork() { + // If adb TCP port opened, this test may running by adb over network. + return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1) + || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1); + } + @Test public void testPhysicalEthernet() throws Exception { assumeTrue(mEm.isAvailable()); + // Do not run this test if adb is over network and ethernet is connected. + // It is likely the adb run over ethernet, the adb would break when ethernet is switching + // from client mode to server mode. See b/160389275. + assumeFalse(isAdbOverNetwork()); // Get an interface to use. final String iface = mTetheredInterfaceRequester.getInterface(); From 6b66d70ba198054a4172e34703d201776185069c Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 2 Jul 2020 13:59:44 +0000 Subject: [PATCH 1247/1415] Revert "Move Inet[4]AddressUtils to libs/net" This reverts commit cf86031c12405ddb5817cf834c49a032480547b3. Reason for revert: Breaks the build b/160390899 Merged-In: Icd141a992c46290c74929785e261a1cd57bc001b Change-Id: Ie10e66f61393602f17fbb61bf17230b176bf1f44 --- Tethering/jarjar-rules.txt | 15 ++++++++++++--- .../net/dhcp/DhcpServingParamsParcelExt.java | 2 +- Tethering/src/android/net/ip/IpServer.java | 3 +-- .../unit/src/android/net/ip/IpServerTest.java | 3 +-- .../networkstack/tethering/TetheringTest.java | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt index 591861f5b8..2c4059dda9 100644 --- a/Tethering/jarjar-rules.txt +++ b/Tethering/jarjar-rules.txt @@ -1,8 +1,17 @@ # These must be kept in sync with the framework-tethering-shared-srcs filegroup. -# Classes from the framework-tethering-shared-srcs filegroup. -# If there are files in that filegroup that are not covered below, the classes in the +# If there are files in that filegroup that do not appear here, the classes in the # module will be overwritten by the ones in the framework. -rule com.android.internal.util.** com.android.networkstack.tethering.util.@1 +# Don't jar-jar the entire package because tethering still use some internal classes +# (like TrafficStatsConstants in com.android.internal.util) +# TODO: simply these when tethering is built as system_current. +rule com.android.internal.util.BitUtils* com.android.networkstack.tethering.util.BitUtils@1 +rule com.android.internal.util.IndentingPrintWriter.java* com.android.networkstack.tethering.util.IndentingPrintWriter.java@1 +rule com.android.internal.util.IState.java* com.android.networkstack.tethering.util.IState.java@1 +rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.util.MessageUtils@1 +rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 +rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 +rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 + rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1 rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1 diff --git a/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java index aaaec17bf9..4710a30b29 100644 --- a/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -16,7 +16,7 @@ package android.net.dhcp; -import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; import android.net.LinkAddress; import android.util.ArraySet; diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 8af1797a9d..a61fcfb819 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -19,14 +19,13 @@ package android.net.ip; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.net.util.NetworkConstants.asByte; import static android.net.util.PrefixUtils.asIpPrefix; import static android.net.util.TetheringMessageBase.BASE_IPSERVER; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; -import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; - import android.net.INetd; import android.net.INetworkStackStatusCallback; import android.net.IpPrefix; diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 30a9d2252e..05cf58ab84 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -36,8 +36,7 @@ import static android.net.netlink.NetlinkConstants.RTM_NEWNEIGH; import static android.net.netlink.StructNdMsg.NUD_FAILED; import static android.net.netlink.StructNdMsg.NUD_REACHABLE; import static android.net.netlink.StructNdMsg.NUD_STALE; - -import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index f1da1c7225..d37aad26d1 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -40,6 +40,7 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -48,7 +49,6 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES; From f70d762a5560681822e71d7c865e0aaf1262007a Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 27 May 2020 15:48:50 +0900 Subject: [PATCH 1248/1415] Ignore non-matching callbacks to fix flakiness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a host-side tests that receives its network callbacks through a custom AIDL that proxies them to this host-side process. As this runs of the real callbacks from a real network, this test receives unrelated callbacks – in particular calls to onCapabilitiesUpdated to warn the process of updates of the signal strength. This skips these callbacks across the board by only matching the expected callback. This will fix flakiness in the test. Also, as a drive-by fix, this also checks the network in the onBlockedStatusChanged callback. If the network object is not the expected one, the test should not pass. Bug: 160270536 Test: NetworkCallbackTests Change-Id: I67c685ebfb2c5e2ee6f7615196eedea8292ca3ff --- .../cts/net/hostside/NetworkCallbackTest.java | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index aa59959994..eedccb63ad 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.fail; import android.net.Network; import android.net.NetworkCapabilities; +import android.util.Log; import org.junit.After; import org.junit.Before; @@ -141,15 +142,16 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa } public void expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) { - expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, - expectBlocked); + expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, expectBlocked); } - public void waitBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) { + public void expectBlockedStatusCallbackEventually(Network expectedNetwork, + boolean expectBlocked) { final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS; do { final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis())); - if (cb.state == CallbackState.BLOCKED_STATUS) { + if (cb.state == CallbackState.BLOCKED_STATUS + && cb.network.equals(expectedNetwork)) { assertEquals(expectBlocked, cb.arg); return; } @@ -157,17 +159,23 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa fail("Didn't receive onBlockedStatusChanged()"); } - public void expectCapabilitiesCallback(Network expectedNetwork, boolean hasCapability, - int capability) { - final CallbackInfo cb = nextCallback(TEST_CALLBACK_TIMEOUT_MS); - final NetworkCapabilities cap = (NetworkCapabilities) cb.arg; - assertEquals(expectedNetwork, cb.network); - assertEquals(CallbackState.CAPABILITIES, cb.state); - if (hasCapability != cap.hasCapability(capability)) { - fail("NetworkCapabilities callback " - + (hasCapability ? "missing expected" : "has unexpected") - + " capability. " + cb); - } + public void expectCapabilitiesCallbackEventually(Network expectedNetwork, boolean hasCap, + int cap) { + final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS; + do { + final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis())); + if (cb.state != CallbackState.CAPABILITIES + || !expectedNetwork.equals(cb.network) + || (hasCap != ((NetworkCapabilities) cb.arg).hasCapability(cap))) { + Log.i("NetworkCallbackTest#expectCapabilitiesCallback", + "Ignoring non-matching callback : " + cb); + continue; + } + // Found a match, return + return; + } while (System.currentTimeMillis() <= deadline); + fail("Didn't receive the expected callback to onCapabilitiesChanged(). Check the " + + "log for a list of received callbacks, if any."); } } @@ -194,8 +202,8 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa // callback to ensure wifi is connected before the test and store the default network. mNetwork = mTestNetworkCallback.expectAvailableCallbackAndGetNetwork(); // Check that the network is metered. - mTestNetworkCallback.expectCapabilitiesCallback(mNetwork, false /* hasCapability */, - NET_CAPABILITY_NOT_METERED); + mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork, + false /* hasCapability */, NET_CAPABILITY_NOT_METERED); mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); } @@ -215,28 +223,28 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa // Enable restrict background setRestrictBackground(true); assertBackgroundNetworkAccess(false); - mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, true); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true); // Add to whitelist addRestrictBackgroundWhitelist(mUid); assertBackgroundNetworkAccess(true); - mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, false); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false); // Remove from whitelist removeRestrictBackgroundWhitelist(mUid); assertBackgroundNetworkAccess(false); - mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, true); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true); } finally { mMeterednessConfiguration.resetNetworkMeteredness(); } // Set to non-metered network mMeterednessConfiguration.configureNetworkMeteredness(false); - mTestNetworkCallback.expectCapabilitiesCallback(mNetwork, true /* hasCapability */, - NET_CAPABILITY_NOT_METERED); + mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork, + true /* hasCapability */, NET_CAPABILITY_NOT_METERED); try { assertBackgroundNetworkAccess(true); - mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, false); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false); // Disable restrict background, should not trigger callback setRestrictBackground(false); @@ -253,30 +261,30 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa // Enable Power Saver setBatterySaverMode(true); assertBackgroundNetworkAccess(false); - mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, true); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true); // Disable Power Saver setBatterySaverMode(false); assertBackgroundNetworkAccess(true); - mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, false); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false); } finally { mMeterednessConfiguration.resetNetworkMeteredness(); } // Set to non-metered network mMeterednessConfiguration.configureNetworkMeteredness(false); - mTestNetworkCallback.expectCapabilitiesCallback(mNetwork, true /* hasCapability */, - NET_CAPABILITY_NOT_METERED); + mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork, + true /* hasCapability */, NET_CAPABILITY_NOT_METERED); try { // Enable Power Saver setBatterySaverMode(true); assertBackgroundNetworkAccess(false); - mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, true); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true); // Disable Power Saver setBatterySaverMode(false); assertBackgroundNetworkAccess(true); - mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, false); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false); } finally { mMeterednessConfiguration.resetNetworkMeteredness(); } From a1b13d6d39ef4b9e0b5244c74046daa4726d25d3 Mon Sep 17 00:00:00 2001 From: easoncylee Date: Fri, 12 Jun 2020 14:14:14 +0800 Subject: [PATCH 1249/1415] Add CtsNetTestCasesLatestSdk to mainline-presubmit This is the pilot run for mainline testing in Test Mapping Suite. For supporting mainline testing in Test Mapping Suite, developers can run tests by configuring the TEST_MAPPING file, the 3 simple steps are: - Add tests to be part of general-tests suite if the test does not depend on a device specific features. - Update test configureation for TradeFed to run mainline testing. - Update TEST_MAPPING file with test-group as "mainline-presubmit" It's only for postsubmit now, and will be moved to actual presubmit once the whole mechanism is stable. For more details about the usage, please refer to go/test-mapping-mainline-user-guide Bug: 160753366 Test: forrest. Change-Id: I8704cc5626a3e049eb3c27adb86e9c1a4d828273 --- tests/cts/net/Android.bp | 2 +- tests/cts/net/AndroidTestTemplate.xml | 2 ++ tests/cts/net/TEST_MAPPING | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index c90ca5e4ab..926b45c9d3 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -83,7 +83,7 @@ android_test { min_sdk_version: "29", target_sdk_version: "29", test_suites: [ - "device-tests", + "general-tests", "mts", ], test_config_template: "AndroidTestTemplate.xml", diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml index 1f75da1860..4e937512ad 100644 --- a/tests/cts/net/AndroidTestTemplate.xml +++ b/tests/cts/net/AndroidTestTemplate.xml @@ -19,6 +19,8 @@ From 0e9b130cbcbc5d158a6914df70069e9a8a90400f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 16 Jul 2020 19:17:39 +0900 Subject: [PATCH 1277/1415] Add utilities for network validation testing Refactor out TestHttpServer to share it between CaptivePortalApiTest and CaptivePortalTest, move it to frameworks/libs/net, and add a NetworkValidationTestUtil class with utilities to set the test validation URLs. Test: atest CtsNetTestCasesLatestSdk:CaptivePortal[Api]Test Bug: 160617623 Bug: 160656765 Change-Id: Icd7829e680b2dddd1ddaa3dc2d946c14c20b5a15 --- tests/cts/net/Android.bp | 1 - .../src/android/net/cts/CaptivePortalTest.kt | 140 +++++------------- ...talApiTest.kt => NetworkValidationTest.kt} | 66 +++------ .../net/cts/NetworkValidationTestUtil.kt | 79 ++++++++++ 4 files changed, 136 insertions(+), 150 deletions(-) rename tests/cts/net/src/android/net/cts/{CaptivePortalApiTest.kt => NetworkValidationTest.kt} (84%) create mode 100644 tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 926b45c9d3..be8b43d60d 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -47,7 +47,6 @@ java_defaults { "ctstestserver", "junit", "junit-params", - "libnanohttpd", "mockwebserver", "net-utils-framework-common", "truth-prebuilt", diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 4a7d38a172..12a966fd31 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -19,7 +19,6 @@ package android.net.cts import android.Manifest.permission.CONNECTIVITY_INTERNAL import android.Manifest.permission.NETWORK_SETTINGS import android.Manifest.permission.READ_DEVICE_CONFIG -import android.Manifest.permission.WRITE_DEVICE_CONFIG import android.content.pm.PackageManager.FEATURE_TELEPHONY import android.content.pm.PackageManager.FEATURE_WIFI import android.net.ConnectivityManager @@ -30,20 +29,25 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkRequest import android.net.Uri +import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig +import android.net.cts.NetworkValidationTestUtil.runAsShell +import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig +import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig +import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig +import com.android.testutils.TestHttpServer.Request import android.net.cts.util.CtsNetUtils +import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL +import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL import android.net.wifi.WifiManager import android.os.Build -import android.os.ConditionVariable import android.platform.test.annotations.AppModeFull import android.provider.DeviceConfig import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY import android.text.TextUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 -import com.android.compatibility.common.util.SystemUtil +import com.android.testutils.TestHttpServer import com.android.testutils.isDevSdkInRange -import fi.iki.elonen.NanoHTTPD -import fi.iki.elonen.NanoHTTPD.Response.IStatus import fi.iki.elonen.NanoHTTPD.Response.Status import junit.framework.AssertionFailedError import org.junit.After @@ -55,15 +59,12 @@ import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException import kotlin.test.Test import kotlin.test.assertNotEquals +import kotlin.test.assertNotNull import kotlin.test.assertTrue -private const val TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING = "test_captive_portal_https_url" -private const val TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING = "test_captive_portal_http_url" -private const val TEST_URL_EXPIRATION_TIME = "test_url_expiration_time" - -private const val TEST_HTTPS_URL_PATH = "https_path" -private const val TEST_HTTP_URL_PATH = "http_path" -private const val TEST_PORTAL_URL_PATH = "portal_path" +private const val TEST_HTTPS_URL_PATH = "/https_path" +private const val TEST_HTTP_URL_PATH = "/http_path" +private const val TEST_PORTAL_URL_PATH = "/portal_path" private const val LOCALHOST_HOSTNAME = "localhost" @@ -88,24 +89,24 @@ class CaptivePortalTest { private val pm by lazy { context.packageManager } private val utils by lazy { CtsNetUtils(context) } - private val server = HttpServer() + private val server = TestHttpServer("localhost") @Before fun setUp() { - doAsShell(READ_DEVICE_CONFIG) { + runAsShell(READ_DEVICE_CONFIG) { // Verify that the test URLs are not normally set on the device, but do not fail if the // test URLs are set to what this test uses (URLs on localhost), in case the test was // interrupted manually and rerun. - assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING) - assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING) + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL) + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL) } - clearTestUrls() + clearValidationTestUrlsDeviceConfig() server.start() } @After fun tearDown() { - clearTestUrls() + clearValidationTestUrlsDeviceConfig() if (pm.hasSystemFeature(FEATURE_WIFI)) { reconnectWifi() } @@ -118,12 +119,6 @@ class CaptivePortalTest { "$urlKey must not be set in production scenarios (current value: $url)") } - private fun clearTestUrls() { - setHttpsUrl(null) - setHttpUrl(null) - setUrlExpiration(null) - } - @Test fun testCaptivePortalIsNotDefaultNetwork() { assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY)) @@ -132,19 +127,15 @@ class CaptivePortalTest { utils.connectToCell() // Have network validation use a local server that serves a HTTPS error / HTTP redirect - server.addResponse(TEST_PORTAL_URL_PATH, Status.OK, + server.addResponse(Request(TEST_PORTAL_URL_PATH), Status.OK, content = "Test captive portal content") - server.addResponse(TEST_HTTPS_URL_PATH, Status.INTERNAL_ERROR) - server.addResponse(TEST_HTTP_URL_PATH, Status.REDIRECT, - locationHeader = server.makeUrl(TEST_PORTAL_URL_PATH)) - setHttpsUrl(server.makeUrl(TEST_HTTPS_URL_PATH)) - setHttpUrl(server.makeUrl(TEST_HTTP_URL_PATH)) + server.addResponse(Request(TEST_HTTPS_URL_PATH), Status.INTERNAL_ERROR) + server.addResponse(Request(TEST_HTTP_URL_PATH), Status.REDIRECT, + locationHeader = makeUrl(TEST_PORTAL_URL_PATH)) + setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH)) + setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH)) // URL expiration needs to be in the next 10 minutes - setUrlExpiration(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)) - - // Expect the portal content to be fetched at some point after detecting the portal. - // Some implementations may fetch the URL before startCaptivePortalApp is called. - val portalContentRequestCv = server.addExpectRequestCv(TEST_PORTAL_URL_PATH) + setUrlExpirationDeviceConfig(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)) // Wait for a captive portal to be detected on the network val wifiNetworkFuture = CompletableFuture() @@ -173,9 +164,14 @@ class CaptivePortalTest { val startPortalAppPermission = if (isDevSdkInRange(0, Build.VERSION_CODES.Q)) CONNECTIVITY_INTERNAL else NETWORK_SETTINGS - doAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } - assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " + - "page was still not fetched ${TEST_TIMEOUT_MS}ms after startCaptivePortalApp.") + runAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } + + // Expect the portal content to be fetched at some point after detecting the portal. + // Some implementations may fetch the URL before startCaptivePortalApp is called. + assertNotNull(server.requestsRecord.poll(TEST_TIMEOUT_MS, pos = 0) { + it.path == TEST_PORTAL_URL_PATH + }, "The captive portal login page was still not fetched ${TEST_TIMEOUT_MS}ms " + + "after startCaptivePortalApp.") assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) } finally { @@ -186,73 +182,13 @@ class CaptivePortalTest { } } - private fun setHttpsUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING, url) - private fun setHttpUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING, url) - private fun setUrlExpiration(timestamp: Long?) = setConfig(TEST_URL_EXPIRATION_TIME, - timestamp?.toString()) - - private fun setConfig(configKey: String, value: String?) { - doAsShell(WRITE_DEVICE_CONFIG) { - DeviceConfig.setProperty( - NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) - } - } - - private fun doAsShell(vararg permissions: String, action: () -> Unit) { - // Wrap the below call to allow for more kotlin-like syntax - SystemUtil.runWithShellPermissionIdentity(action, permissions) - } + /** + * Create a URL string that, when fetched, will hit the test server with the given URL [path]. + */ + private fun makeUrl(path: String) = "http://localhost:${server.listeningPort}" + path private fun reconnectWifi() { utils.ensureWifiDisconnected(null /* wifiNetworkToCheck */) utils.ensureWifiConnected() } - - /** - * A minimal HTTP server running on localhost (loopback), on a random available port. - */ - private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) { - // Map of URL path -> HTTP response code - private val responses = HashMap() - - // Map of path -> CV to open as soon as a request to the path is received - private val waitForRequestCv = HashMap() - - /** - * Create a URL string that, when fetched, will hit this server with the given URL [path]. - */ - fun makeUrl(path: String): String { - return Uri.Builder() - .scheme("http") - .encodedAuthority("localhost:$listeningPort") - .query(path) - .build() - .toString() - } - - fun addResponse( - path: String, - statusCode: IStatus, - locationHeader: String? = null, - content: String = "" - ) { - val response = newFixedLengthResponse(statusCode, "text/plain", content) - locationHeader?.let { response.addHeader("Location", it) } - responses[path] = response - } - - /** - * Create a [ConditionVariable] that will open when a request to [path] is received. - */ - fun addExpectRequestCv(path: String): ConditionVariable { - return ConditionVariable().apply { waitForRequestCv[path] = this } - } - - override fun serve(session: IHTTPSession): Response { - waitForRequestCv[session.queryParameterString]?.open() - return responses[session.queryParameterString] - // Default response is a 404 - ?: super.serve(session) - } - } } \ No newline at end of file diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt similarity index 84% rename from tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt rename to tests/cts/net/src/android/net/cts/NetworkValidationTest.kt index ef2b0cee2f..52c383d906 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt @@ -29,6 +29,7 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.Uri +import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.dhcp.DhcpDiscoverPacket import android.net.dhcp.DhcpPacket import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE @@ -40,18 +41,18 @@ import android.os.HandlerThread import android.platform.test.annotations.AppModeFull import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 -import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity -import com.android.compatibility.common.util.ThrowingRunnable import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY +import com.android.testutils.ArpResponder import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DhcpClientPacketFilter import com.android.testutils.DhcpOptionFilter import com.android.testutils.RecorderCallback.CallbackEntry import com.android.testutils.TapPacketReader +import com.android.testutils.TestHttpServer import com.android.testutils.TestableNetworkCallback -import fi.iki.elonen.NanoHTTPD +import fi.iki.elonen.NanoHTTPD.Response.Status import org.junit.After import org.junit.Assume.assumeFalse import org.junit.Before @@ -59,8 +60,6 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import java.net.Inet4Address -import java.util.concurrent.ArrayBlockingQueue -import java.util.concurrent.TimeUnit import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -79,7 +78,7 @@ private const val TEST_MTU = 1500.toShort() @AppModeFull(reason = "Instant apps cannot create test networks") @RunWith(AndroidJUnit4::class) -class CaptivePortalApiTest { +class NetworkValidationTest { @JvmField @Rule val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) @@ -89,10 +88,10 @@ class CaptivePortalApiTest { private val eth by lazy { context.assertHasService(EthernetManager::class.java) } private val cm by lazy { context.assertHasService(ConnectivityManager::class.java) } - private val handlerThread = HandlerThread(CaptivePortalApiTest::class.java.simpleName) + private val handlerThread = HandlerThread(NetworkValidationTest::class.java.simpleName) private val serverIpAddr = InetAddresses.parseNumericAddress("192.0.2.222") as Inet4Address private val clientIpAddr = InetAddresses.parseNumericAddress("192.0.2.111") as Inet4Address - private val httpServer = HttpServer() + private val httpServer = TestHttpServer() private val ethRequest = NetworkRequest.Builder() // ETHERNET|TEST transport networks do not have NET_CAPABILITY_TRUSTED .removeCapability(NET_CAPABILITY_TRUSTED) @@ -151,7 +150,15 @@ class CaptivePortalApiTest { } @Test - fun testApiCallbacks() { + fun testCapportApiCallbacks() { + httpServer.addResponse(capportUrl, Status.OK, content = """ + |{ + | "captive": true, + | "user-portal-url": "$TEST_LOGIN_URL", + | "venue-info-url": "$TEST_VENUE_INFO_URL" + |} + """.trimMargin()) + // Handle the DHCP handshake that includes the capport API URL val discover = reader.assertDhcpPacketReceived( DhcpDiscoverPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER) @@ -163,11 +170,9 @@ class CaptivePortalApiTest { assertEquals(clientIpAddr, request.mRequestedIp) reader.sendResponse(makeAckPacket(request.clientMac, request.transactionId)) - // Expect a request to the capport API - val capportReq = httpServer.recordedRequests.poll(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS) - assertNotNull(capportReq, "The device did not fetch captive portal API data within timeout") - assertEquals(capportUrl.path, capportReq.uri) - assertEquals(capportUrl.query, capportReq.queryParameterString) + // The first request received by the server should be for the portal API + assertTrue(httpServer.requestsRecord.poll(TEST_TIMEOUT_MS, 0)?.matches(capportUrl) ?: false, + "The device did not fetch captive portal API data within timeout") // Expect network callbacks with capport info val testCb = TestableNetworkCallback(TEST_TIMEOUT_MS) @@ -216,30 +221,6 @@ class CaptivePortalApiTest { listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */, serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */, TEST_MTU, false /* rapidCommit */, capportUrl.toString()) - - private fun parseDhcpPacket(bytes: ByteArray) = DhcpPacket.decodeFullPacket( - bytes, MAX_PACKET_LENGTH, DhcpPacket.ENCAP_L2) -} - -/** - * A minimal HTTP server running on localhost (loopback), on a random available port. - * - * The server records each request in [recordedRequests] and will not serve any further request - * until the last one is removed from the queue for verification. - */ -private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) { - val recordedRequests = ArrayBlockingQueue(1 /* capacity */) - - override fun serve(session: IHTTPSession): Response { - recordedRequests.offer(session) - return newFixedLengthResponse(""" - |{ - | "captive": true, - | "user-portal-url": "$TEST_LOGIN_URL", - | "venue-info-url": "$TEST_VENUE_INFO_URL" - |} - """.trimMargin()) - } } private fun TapPacketReader.assertDhcpPacketReceived( @@ -259,12 +240,3 @@ private fun TapPacketReader.assertDhcpPacketReceived( private fun Context.assertHasService(manager: Class): T { return getSystemService(manager) ?: fail("Service $manager not found") } - -/** - * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. - */ -private fun runAsShell(vararg permissions: String, task: () -> T): T { - var ret: T? = null - runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) - return ret ?: fail("ThrowingRunnable was not run") -} diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt new file mode 100644 index 0000000000..5ef185432c --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -0,0 +1,79 @@ +/* + * 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 android.Manifest +import android.net.util.NetworkStackUtils +import android.provider.DeviceConfig +import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import com.android.compatibility.common.util.ThrowingRunnable +import kotlin.test.fail + +/** + * Collection of utility methods for configuring network validation. + */ +internal object NetworkValidationTestUtil { + + /** + * Clear the test network validation URLs. + */ + fun clearValidationTestUrlsDeviceConfig() { + setHttpsUrlDeviceConfig(null) + setHttpUrlDeviceConfig(null) + setUrlExpirationDeviceConfig(null) + } + + /** + * Set the test validation HTTPS URL. + * + * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL + */ + fun setHttpsUrlDeviceConfig(url: String?) = + setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL, url) + + /** + * Set the test validation HTTP URL. + * + * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL + */ + fun setHttpUrlDeviceConfig(url: String?) = + setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL, url) + + /** + * Set the test validation URL expiration. + * + * @see NetworkStackUtils.TEST_URL_EXPIRATION_TIME + */ + fun setUrlExpirationDeviceConfig(timestamp: Long?) = + setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString()) + + private fun setConfig(configKey: String, value: String?) { + runAsShell(Manifest.permission.WRITE_DEVICE_CONFIG) { + DeviceConfig.setProperty( + DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) + } + } + + /** + * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. + */ + fun runAsShell(vararg permissions: String, task: () -> T): T { + var ret: T? = null + runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) + return ret ?: fail("ThrowingRunnable did not return") + } +} \ No newline at end of file From c47fa617f20a71e48dfd9e175fa49f6bcc93ced5 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 14 Aug 2020 16:53:03 +0900 Subject: [PATCH 1278/1415] Run validation tests even with an eth interface The test actually does not need the ethernet interface to be the only ethernet interface, as ethernet test interfaces now have TRANSPORT_TEST|TRANSPORT_ETHERNET, which can be used to differentiate them in the network request. Bug: 162469293 Test: atest CtsNetTestCasesLatestSdk:NetworkValidationTest Change-Id: I84cc8b6b9aaa764705d91ed298655d869c4388a6 --- .../src/android/net/cts/NetworkValidationTest.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt index 52c383d906..ec656de653 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt @@ -19,12 +19,14 @@ package android.net.cts import android.Manifest.permission.MANAGE_TEST_NETWORKS import android.Manifest.permission.NETWORK_SETTINGS import android.content.Context +import android.content.pm.PackageManager import android.net.ConnectivityManager import android.net.EthernetManager import android.net.InetAddresses import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED import android.net.NetworkCapabilities.TRANSPORT_ETHERNET +import android.net.NetworkCapabilities.TRANSPORT_TEST import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager @@ -55,6 +57,7 @@ import com.android.testutils.TestableNetworkCallback import fi.iki.elonen.NanoHTTPD.Response.Status import org.junit.After import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -95,7 +98,8 @@ class NetworkValidationTest { private val ethRequest = NetworkRequest.Builder() // ETHERNET|TEST transport networks do not have NET_CAPABILITY_TRUSTED .removeCapability(NET_CAPABILITY_TRUSTED) - .addTransportType(TRANSPORT_ETHERNET).build() + .addTransportType(TRANSPORT_ETHERNET) + .addTransportType(TRANSPORT_TEST).build() private val ethRequestCb = TestableNetworkCallback() private lateinit var iface: TestNetworkInterface @@ -106,9 +110,10 @@ class NetworkValidationTest { @Before fun setUp() { - // This test requires using a tap interface as the default ethernet interface: skip if there - // is already an ethernet interface connected. - testSkipped = eth.isAvailable() + // This test requires using a tap interface as an ethernet interface. + val pm = context.getPackageManager() + testSkipped = !pm.hasSystemFeature(PackageManager.FEATURE_ETHERNET) && + context.getSystemService(EthernetManager::class.java) == null assumeFalse(testSkipped) // Register a request so the network does not get torn down From 1e2aabf99fed6d7fff21cbcb4f185e69d72a9848 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 26 Jun 2020 18:50:24 +0900 Subject: [PATCH 1279/1415] Move some utils to a more appropriate package/directory Test: builds Merged-In: Id0f0f89c34502deb6d0e50503e5534fcc51c3f9b Change-Id: Id0f0f89c34502deb6d0e50503e5534fcc51c3f9b --- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 2 +- .../ConnectivityDiagnosticsManagerTest.java | 2 +- .../src/android/net/cts/NetworkAgentTest.kt | 20 +++++++++---------- .../tethering/cts/TetheringManagerTest.java | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index a81063b30a..6264ceab99 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -56,7 +56,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.compatibility.common.util.SystemUtil; -import com.android.testutils.ArrayTrackRecord; +import com.android.net.module.util.ArrayTrackRecord; import org.junit.After; import org.junit.AfterClass; diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 8f42f79382..858a677678 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -77,7 +77,7 @@ import androidx.test.InstrumentationRegistry; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.util.ArrayUtils; -import com.android.testutils.ArrayTrackRecord; +import com.android.net.module.util.ArrayTrackRecord; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; import com.android.testutils.SkipPresubmit; diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index c8e1fc3ae2..d2ca3f88cd 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -39,13 +39,6 @@ import android.net.NetworkRequest import android.net.SocketKeepalive import android.net.StringNetworkSpecifier import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.os.Handler -import android.os.HandlerThread -import android.os.Looper -import android.os.Message -import android.os.Messenger import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested @@ -56,15 +49,21 @@ import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSig import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper +import android.os.Message +import android.os.Messenger import androidx.test.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.AsyncChannel -import com.android.testutils.ArrayTrackRecord +import com.android.net.module.util.ArrayTrackRecord import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback -import java.util.UUID import org.junit.After import org.junit.Assert.assertArrayEquals import org.junit.Assert.fail @@ -74,9 +73,10 @@ import org.junit.Test import org.junit.runner.RunWith import java.net.InetAddress import java.time.Duration +import java.util.UUID import kotlin.test.assertEquals -import kotlin.test.assertFalse import kotlin.test.assertFailsWith +import kotlin.test.assertFalse import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index f47f4549c9..65a8c7c76b 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -72,7 +72,7 @@ import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; -import com.android.testutils.ArrayTrackRecord; +import com.android.net.module.util.ArrayTrackRecord; import org.junit.After; import org.junit.Before; From ccaef39c4271f14f5db391087b3a8007887c9e0b Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 30 Jun 2020 15:04:20 +0900 Subject: [PATCH 1280/1415] Rename Kotlin util files to not include the Kt suffix Callers don't care what language the utilities are written in Test: builds Merged-In: I06bf9838432e429b3d03649654e1bcef04b89dd9 Change-Id: I06bf9838432e429b3d03649654e1bcef04b89dd9 --- tests/cts/net/src/android/net/cts/IpConfigurationTest.java | 2 +- tests/cts/net/src/android/net/cts/MacAddressTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java index c6bc0770b8..56ab2a7531 100644 --- a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java +++ b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java @@ -16,7 +16,7 @@ package android.net.cts; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; diff --git a/tests/cts/net/src/android/net/cts/MacAddressTest.java b/tests/cts/net/src/android/net/cts/MacAddressTest.java index 4d25e620d4..3fd3bbac8c 100644 --- a/tests/cts/net/src/android/net/cts/MacAddressTest.java +++ b/tests/cts/net/src/android/net/cts/MacAddressTest.java @@ -20,7 +20,7 @@ import static android.net.MacAddress.TYPE_BROADCAST; import static android.net.MacAddress.TYPE_MULTICAST; import static android.net.MacAddress.TYPE_UNICAST; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; From 48d952a502a7f317d965d1782f5a23b6b8a28beb Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Mon, 24 Aug 2020 12:48:05 +0800 Subject: [PATCH 1281/1415] Add working internet precondition check ConnectivityManagerTest expects a working internet before testing but is not verified before each test. Add a working internet check in setup to clearly test it. Bug: 161370134 Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest Change-Id: I47073ebff19fcf59d5d2ac86b43f8d54e621a55a --- tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 0bba1719da..0790acb54e 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -204,6 +204,8 @@ public class ConnectivityManagerTest { } catch (Exception e) {} } mUiAutomation = mInstrumentation.getUiAutomation(); + + assertNotNull("CTS requires a working Internet connection", mCm.getActiveNetwork()); } @After From 3addf0d1770c802b2c5021881d70b0b4e7fd0888 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 14 Aug 2020 16:53:03 +0900 Subject: [PATCH 1282/1415] Run validation tests even with an eth interface The test actually does not need the ethernet interface to be the only ethernet interface, as ethernet test interfaces now have TRANSPORT_TEST|TRANSPORT_ETHERNET, which can be used to differentiate them in the network request. Bug: 162469293 Bug: 160612321 Test: atest CtsNetTestCasesLatestSdk:NetworkValidationTest Change-Id: I84cc8b6b9aaa764705d91ed298655d869c4388a6 Merged-In: I84cc8b6b9aaa764705d91ed298655d869c4388a6 --- .../net/src/android/net/cts/CaptivePortalApiTest.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt index ef2b0cee2f..99fcd4c95d 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt @@ -19,12 +19,14 @@ package android.net.cts import android.Manifest.permission.MANAGE_TEST_NETWORKS import android.Manifest.permission.NETWORK_SETTINGS import android.content.Context +import android.content.pm.PackageManager import android.net.ConnectivityManager import android.net.EthernetManager import android.net.InetAddresses import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED import android.net.NetworkCapabilities.TRANSPORT_ETHERNET +import android.net.NetworkCapabilities.TRANSPORT_TEST import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager @@ -54,6 +56,7 @@ import com.android.testutils.TestableNetworkCallback import fi.iki.elonen.NanoHTTPD import org.junit.After import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -96,7 +99,8 @@ class CaptivePortalApiTest { private val ethRequest = NetworkRequest.Builder() // ETHERNET|TEST transport networks do not have NET_CAPABILITY_TRUSTED .removeCapability(NET_CAPABILITY_TRUSTED) - .addTransportType(TRANSPORT_ETHERNET).build() + .addTransportType(TRANSPORT_ETHERNET) + .addTransportType(TRANSPORT_TEST).build() private val ethRequestCb = TestableNetworkCallback() private lateinit var iface: TestNetworkInterface @@ -107,9 +111,10 @@ class CaptivePortalApiTest { @Before fun setUp() { - // This test requires using a tap interface as the default ethernet interface: skip if there - // is already an ethernet interface connected. - testSkipped = eth.isAvailable() + // This test requires using a tap interface as an ethernet interface. + val pm = context.getPackageManager() + testSkipped = !pm.hasSystemFeature(PackageManager.FEATURE_ETHERNET) && + context.getSystemService(EthernetManager::class.java) == null assumeFalse(testSkipped) // Register a request so the network does not get torn down From cb00911ada550756123a944ce61dbfdba82c63c5 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 31 Aug 2020 10:43:57 -0700 Subject: [PATCH 1283/1415] Specify CAPABILITY_INTERNET for ConnDiags CTS test. This CL updates the NetworkCapabilities used for getting a cellular data network in ConnectivityDiagnosticsManagerTest to require CAPABILITY_INTERNET. Bug: 166732795 Test: atest CtsNetTestCases Change-Id: Ia32ac00f949a2ee9319c80c25f294bfa834ad0f9 --- .../android/net/cts/ConnectivityDiagnosticsManagerTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index c2ebc463ac..6fd27f1fd3 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -30,6 +30,7 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE; import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -120,7 +121,10 @@ public class ConnectivityDiagnosticsManagerTest { private static final String SHA_256 = "SHA-256"; private static final NetworkRequest CELLULAR_NETWORK_REQUEST = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); private static final IBinder BINDER = new Binder(); From 243c42a9b9955c39432bb2e36b5285fed1ef4959 Mon Sep 17 00:00:00 2001 From: Tse Ho Lin Date: Mon, 27 Jul 2020 06:46:25 +0000 Subject: [PATCH 1284/1415] Don't require WiFi in CtsHostsideNetworkTests. Skip test for non-WiFi connections. Bug: 162192335 Test: run cts -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideNetworkCallbackTests#testOnBlockedStatusChanged_dataSaver Change-Id: I7c20e3454a2fe81671162e0a50f90d64ed7516d0 --- .../com/android/cts/net/hostside/NetworkCallbackTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index eedccb63ad..2ac29e77ff 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -17,7 +17,9 @@ package com.android.cts.net.hostside; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; @@ -26,6 +28,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.net.Network; import android.net.NetworkCapabilities; @@ -183,6 +186,8 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa public void setUp() throws Exception { super.setUp(); + assumeTrue(isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness()); + registerBroadcastReceiver(); removeRestrictBackgroundWhitelist(mUid); From ed2521af1eb10390e193b6126c1ec62fc7b8a468 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 1 Sep 2020 08:02:33 +0000 Subject: [PATCH 1285/1415] Specify CAPABILITY_INTERNET for ConnDiags CTS test. This CL updates the NetworkCapabilities used for getting a cellular data network in ConnectivityDiagnosticsManagerTest to require CAPABILITY_INTERNET. Bug: 166732795 Test: atest CtsNetTestCases Change-Id: Ia32ac00f949a2ee9319c80c25f294bfa834ad0f9 Merged-In: Ia32ac00f949a2ee9319c80c25f294bfa834ad0f9 (cherry picked from commit 67fb0cc3d4152f890012bbb4f1f91fb657b8dd55) --- .../android/net/cts/ConnectivityDiagnosticsManagerTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 8f42f79382..bd56f4b771 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -30,6 +30,7 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE; import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -121,7 +122,10 @@ public class ConnectivityDiagnosticsManagerTest { private static final String SHA_256 = "SHA-256"; private static final NetworkRequest CELLULAR_NETWORK_REQUEST = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); private static final IBinder BINDER = new Binder(); From 71f417f3eb2c998df6653cf967df93291fb1a81c Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Mon, 24 Aug 2020 10:15:41 -0700 Subject: [PATCH 1286/1415] Update tests to use Doze DeviceConfig flags. Update tests to set DeviceConfig flags for DeviceIdleController settings. Bug: 124466289 Test: atest CtsHostsideNetworkTests Test: atest FrameworksMockingServicesTests:DeviceIdleControllerTest Test: atest SettingsProviderTest:SettingsBackupTest Change-Id: Ie6d8d30897e192ef7a26656242034a3e820caa12 --- .../hostside/AbstractDozeModeTestCase.java | 2 +- ...ractRestrictBackgroundNetworkTestCase.java | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index 6f32c563c1..e0ce4ead39 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -101,7 +101,7 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor @Test public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() throws Exception { - setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); + setPendingIntentAllowlistDuration(NETWORK_TIMEOUT_MS); try { registerNotificationListenerService(); setDozeMode(true); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 71f6f2f5f0..0883b1aaa6 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -25,7 +25,6 @@ import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCo import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager; import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext; import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager; import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; @@ -46,15 +45,17 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; -import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; +import android.provider.DeviceConfig; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.util.Log; +import com.android.compatibility.common.util.SystemUtil; + import org.junit.Rule; import org.junit.rules.RuleChain; import org.junit.runner.RunWith; @@ -130,7 +131,6 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { protected int mUid; private int mMyUid; private MyServiceClient mServiceClient; - private String mDeviceIdleConstantsSetting; @Rule public final RuleChain mRuleChain = RuleChain.outerRule(new RequiredPropertiesRule()) @@ -147,7 +147,6 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); mServiceClient.bind(); - mDeviceIdleConstantsSetting = "device_idle_constants"; executeShellCommand("cmd netpolicy start-watching " + mUid); setAppIdle(false); @@ -721,15 +720,18 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { nm.isNotificationListenerAccessGranted(listenerComponent)); } - protected void setPendingIntentWhitelistDuration(int durationMs) throws Exception { - executeSilentShellCommand(String.format( - "settings put global %s %s=%d", mDeviceIdleConstantsSetting, - "notification_whitelist_duration", durationMs)); + protected void setPendingIntentAllowlistDuration(long durationMs) { + SystemUtil.runWithShellPermissionIdentity(() -> { + DeviceConfig.setProperty( + DeviceConfig.NAMESPACE_DEVICE_IDLE, "notification_allowlist_duration_ms", + String.valueOf(durationMs), /* makeDefault */ false); + }); } - protected void resetDeviceIdleSettings() throws Exception { - executeShellCommand(String.format("settings delete global %s", - mDeviceIdleConstantsSetting)); + protected void resetDeviceIdleSettings() { + SystemUtil.runWithShellPermissionIdentity(() -> + DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS, + DeviceConfig.NAMESPACE_DEVICE_IDLE)); } protected void launchComponentAndAssertNetworkAccess(int type) throws Exception { From ac8f65a5443e5315d03d25ce7635966a5be8ed1d Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 3 Sep 2020 08:32:04 +0000 Subject: [PATCH 1287/1415] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I946ba0e5ca40f934bdc7588eb244969103813c4c --- Tethering/res/values-af/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-am/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ar/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-as/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-az/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-b+sr+Latn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-be/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bg/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bs/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ca/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-cs/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-da/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-de/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-el/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rAU/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rCA/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rGB/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rIN/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rXC/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-es-rUS/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-es/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-et/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-eu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fa/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fr-rCA/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-gl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-gu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hy/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-in/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-is/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-it/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-iw/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ja/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ka/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-kk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-km/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-kn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ko/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ky/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lo/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lt/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lv/strings.xml | 29 ++++++++++++++++--- .../res/values-mcc310-mnc004-af/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-am/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ar/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-as/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-az/strings.xml | 24 +++++++++++++++ .../strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-be/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bg/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bs/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ca/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-cs/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-da/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-de/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-el/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rAU/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rCA/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rGB/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rIN/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rXC/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-es-rUS/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-es/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-et/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-eu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fa/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fi/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-fr-rCA/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-gl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-gu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hi/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hy/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-in/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-is/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-it/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-iw/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ja/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ka/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-kk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-km/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-kn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ko/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ky/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lo/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lt/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lv/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ml/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ms/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-my/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-nb/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ne/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-nl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-or/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pa/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pl/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-pt-rBR/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-pt-rPT/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pt/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ro/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ru/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-si/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sq/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sv/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sw/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ta/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-te/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-th/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-tl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-tr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-uk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ur/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-uz/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-vi/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rCN/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rHK/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rTW/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-zu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-af/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-am/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ar/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-as/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-az/strings.xml | 24 +++++++++++++++ .../strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-be/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bg/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bs/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ca/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-cs/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-da/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-de/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-el/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rAU/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rCA/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rGB/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rIN/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rXC/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-es-rUS/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-es/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-et/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-eu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fa/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fi/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-fr-rCA/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-gl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-gu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hi/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hy/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-in/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-is/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-it/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-iw/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ja/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ka/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-kk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-km/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-kn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ko/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ky/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lo/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lt/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lv/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ml/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ms/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-my/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-nb/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ne/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-nl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-or/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pa/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pl/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-pt-rBR/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-pt-rPT/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pt/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ro/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ru/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-si/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sq/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sv/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sw/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ta/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-te/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-th/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-tl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-tr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-uk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ur/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-uz/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-vi/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rCN/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rHK/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rTW/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-zu/strings.xml | 24 +++++++++++++++ Tethering/res/values-mk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ml/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-mn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-mr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ms/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-my/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-nb/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ne/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-nl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-or/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pa/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt-rBR/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt-rPT/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ro/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ru/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-si/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sq/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sv/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sw/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ta/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-te/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-th/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-tl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-tr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-uk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ur/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-uz/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-vi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rCN/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rHK/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rTW/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zu/strings.xml | 29 ++++++++++++++++--- 255 files changed, 6205 insertions(+), 340 deletions(-) create mode 100644 Tethering/res/values-mcc310-mnc004-af/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-am/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ar/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-as/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-az/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-be/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bg/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ca/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-cs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-da/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-de/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-el/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-et/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-eu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hy/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-in/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-is/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-it/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-iw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ja/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ka/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-km/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ko/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ky/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lo/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ml/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ms/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-my/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nb/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ne/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-or/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ro/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ru/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-si/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sq/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ta/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-te/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-th/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ur/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uz/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-vi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-af/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-am/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ar/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-as/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-az/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-be/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bg/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ca/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-cs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-da/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-de/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-el/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-et/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-eu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hy/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-in/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-is/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-it/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-iw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ja/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ka/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-km/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ko/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ky/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lo/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ml/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ms/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-my/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nb/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ne/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-or/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ro/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ru/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-si/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sq/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ta/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-te/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-th/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ur/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uz/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-vi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zu/strings.xml diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index 1258805378..056168b12e 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -1,8 +1,29 @@ + + - "Verbinding of Wi-Fi-warmkol aktief" - "Tik om op te stel." - "Verbinding is gedeaktiveer" - "Kontak jou administrateur vir besonderhede" + "Verbinding of warmkol is aktief" + "Tik om op te stel." + "Verbinding is gedeaktiveer" + "Kontak jou administrateur vir besonderhede" + "Warmkol- en verbindingstatus" + + + + + diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 9c36192257..ac468dd144 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -1,8 +1,29 @@ + + - "መሰካት ወይም ገባሪ ድረስ ነጥብ" - "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" - "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" + "ለማዋቀር መታ ያድርጉ።" + "እንደ ሞደም መሰካት ተሰናክሏል" + "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" + + + + + diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 9f84ce4090..7d5bad34da 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -1,8 +1,29 @@ + + - "النطاق أو نقطة الاتصال نشطة" - "انقر للإعداد." - "تم إيقاف التوصيل" - "اتصل بالمشرف للحصول على التفاصيل" + "النطاق نشط أو نقطة الاتصال نشطة" + "انقر للإعداد." + "التوصيل متوقف." + "تواصَل مع المشرف للحصول على التفاصيل." + "حالة نقطة الاتصال والتوصيل" + + + + + diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index 8855822e7c..091350455b 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -1,8 +1,29 @@ + + - "টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে" - "ছেট আপ কৰিবলৈ টিপক।" - "টেডাৰিং অক্ষম কৰি থোৱা হৈছে" - "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" + "ছেট আপ কৰিবলৈ টিপক।" + "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" + "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" + + + + + diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index eba50eb636..dce70da178 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -1,8 +1,29 @@ + + - "Tezerinq və ya hotspot aktivdir" - "Quraşdırmaq üçün tıklayın." - "Birləşmə deaktivdir" - "Məlumat üçün adminlə əlaqə saxlayın" + "Birləşmə və ya hotspot aktivdir" + "Ayarlamaq üçün toxunun." + "Birləşmə deaktivdir" + "Detallar üçün adminlə əlaqə saxlayın" + "Hotspot & birləşmə statusu" + + + + + diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 5b0e488ba5..b0774ec9a8 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -1,8 +1,29 @@ + + - "Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot" - "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" - "Potražite detalje od administratora" + "Privezivanje ili hotspot je aktivan" + "Dodirnite da biste podesili." + "Privezivanje je onemogućeno" + "Potražite detalje od administratora" + "Status hotspota i privezivanja" + + + + + diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 5966c7155e..a8acebe2e9 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -1,8 +1,29 @@ + + - "USB-мадэм або хот-спот Wi-Fi актыўныя" - "Дакраніцеся, каб наладзіць." - "Рэжым мадэма адключаны" - "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Мадэм або хот-спот актыўныя" + "Дакраніцеся, каб наладзіць." + "Рэжым мадэма выключаны" + "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Стан \"Хот-спот і мадэм\"" + + + + + diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index ed58d7311a..94fb2d8f17 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -1,8 +1,29 @@ + + - "Има активна споделена връзка или безжична точка за достъп" - "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" - "Свържете се с администратора си за подробности" + "Има активна споделена връзка или точка за достъп" + "Докоснете, за да настроите." + "Функцията за тетъринг е деактивирана" + "Свържете се с администратора си за подробности" + "Състояние на функцията за точка за достъп и тетъринг" + + + + + diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 8d9880aa9a..aea02b9ddf 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -1,8 +1,29 @@ + + - "টিথারিং বা হটস্পট সক্রিয় আছে" - "সেট-আপ করার জন্য আলতো চাপুন৷" - "টিথারিং অক্ষম করা আছে" - "বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন" + "টিথারিং বা হটস্পট চালু আছে" + "সেট-আপ করতে ট্যাপ করুন।" + "টিথারিং বন্ধ করা আছে" + "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" + "হটস্পট ও টিথারিং স্ট্যাটাস" + + + + + diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index 2361b9dd38..de232724c5 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -1,8 +1,29 @@ + + - "Uređaj dijeli vezu ili djeluje kao pristupna tačka" - "Dodirnite za postavke" - "Povezivanje putem mobitela je onemogućeno" - "Kontaktirajte svog administratora za dodatne detalje" + "Aktivno je povezivanje putem mobitela ili pristupna tačka" + "Dodirnite da postavite." + "Povezivanje putem mobitela je onemogućeno" + "Kontaktirajte svog administratora za detalje" + "Status pristupne tačke i povezivanja putem mobitela" + + + + + diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index 6752b519e2..88b795c1f8 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -1,8 +1,29 @@ + + - "Compartició de xarxa o punt d\'accés Wi-Fi activat" - "Toca per configurar." - "La compartició de xarxa està desactivada" - "Contacta amb el teu administrador per obtenir més informació" + "Compartició de xarxa o punt d\'accés Wi‑Fi actius" + "Toca per configurar." + "La compartició de xarxa està desactivada" + "Contacta amb el teu administrador per obtenir més informació" + "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" + + + + + diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5fdd53adf1..8c1b83bf3e 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -1,8 +1,29 @@ + + - "Sdílené připojení nebo hotspot je aktivní." - "Klepnutím zahájíte nastavení." - "Tethering je zakázán" - "O podrobnosti požádejte administrátora" + "Tethering nebo hotspot je aktivní" + "Klepnutím zahájíte nastavení." + "Tethering je zakázán" + "O podrobnosti požádejte administrátora" + "Stav hotspotu a tetheringu" + + + + + diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 2775dfa551..f413e70548 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -1,8 +1,29 @@ + + - "Netdeling eller hotspot er aktivt" - "Tryk for at konfigurere" - "Netdeling er deaktiveret" - "Kontakt din administrator for at få oplysninger" + "Netdeling eller hotspot er aktivt" + "Tryk for at konfigurere." + "Netdeling er deaktiveret" + "Kontakt din administrator for at få oplysninger" + "Status for hotspot og netdeling" + + + + + diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 9046cd5e11..f057d7824e 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering oder Hotspot aktiv" - "Zum Einrichten tippen." - "Tethering ist deaktiviert" - "Bitte wende dich für weitere Informationen an den Administrator" + "Tethering oder Hotspot aktiv" + "Zum Einrichten tippen." + "Tethering ist deaktiviert" + "Bitte wende dich für weitere Informationen an den Administrator" + "Hotspot- und Tethering-Status" + + + + + diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3b9f53733b..b3c986bdaf 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -1,8 +1,29 @@ + + - "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" - "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" - "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" + "Πατήστε για ρύθμιση." + "Η σύνδεση είναι απενεργοποιημένη" + "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" + + + + + diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 7f47fc89d2..f1674bed4e 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -1,8 +1,29 @@ + + - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎Tethering is disabled‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" + + + + + diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index e4618b8cec..63689f4399 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -1,8 +1,29 @@ + + - "Anclaje a red o zona activa conectados" - "Presiona para configurar." - "Se inhabilitó la conexión mediante dispositivo portátil" - "Para obtener más información, comunícate con el administrador" + "Conexión a red o hotspot conectados" + "Presiona para configurar esta opción." + "Se inhabilitó la conexión mediante dispositivo portátil" + "Para obtener más información, comunícate con el administrador" + "Estado del hotspot y la conexión mediante dispositivo portátil" + + + + + diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 8dc1575ce8..9a34ed5e38 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -1,8 +1,29 @@ + + - "Compartir conexión/Zona Wi-Fi activada" - "Toca para configurar." - "La conexión compartida está inhabilitada" - "Ponte en contacto con el administrador para obtener más información" + "Conexión compartida o punto de acceso activos" + "Toca para configurar." + "La conexión compartida está inhabilitada" + "Solicita más información a tu administrador" + "Estado del punto de acceso y de la conexión compartida" + + + + + diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index 872c8a74cc..0970341ab0 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -1,8 +1,29 @@ + + - "Jagamine või kuumkoht on aktiivne" - "Puudutage seadistamiseks." - "Jagamine on keelatud" - "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Jagamine või kuumkoht on aktiivne" + "Puudutage seadistamiseks." + "Jagamine on keelatud" + "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Kuumkoha ja jagamise olek" + + + + + diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index 6c4605e616..632019e2ef 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -1,8 +1,29 @@ + + - "Konexioa partekatzea edo sare publikoa aktibo" - "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" - "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Konexioa partekatzea edo wifi-gunea aktibo dago" + "Sakatu konfiguratzeko." + "Desgaituta dago konexioa partekatzeko aukera" + "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Wifi-gunearen eta konexioa partekatzeko eginbidearen egoera" + + + + + diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index bc2ee23609..2e21c85fa1 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -1,8 +1,29 @@ + + - "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" - "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" - "برای جزئیات، با سرپرستتان تماس بگیرید" + "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" + "برای راه‌اندازی ضربه بزنید." + "اشتراک‌گذاری اینترنت غیرفعال است" + "برای جزئیات، با سرپرستتان تماس بگیرید" + "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" + + + + + diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index ff0fca6502..413db3f0f8 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -1,8 +1,29 @@ + + - "Internetin jakaminen tai yhteyspiste käytössä" - "Määritä napauttamalla." - "Yhteyden jakaminen poistettu käytöstä" - "Kysy lisätietoja järjestelmänvalvojalta." + "Yhteyden jakaminen tai hotspot käytössä" + "Ota käyttöön napauttamalla." + "Yhteyden jakaminen on poistettu käytöstä" + "Pyydä lisätietoja järjestelmänvalvojalta" + "Hotspotin ja yhteyden jakamisen tila" + + + + + diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 1f5df0ee0c..eb2e4ba540 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -1,8 +1,29 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Touchez pour configurer." - "Le partage de connexion est désactivé" - "Communiquez avec votre administrateur pour obtenir plus de détails" + "Partage de connexion ou point d\'accès sans fil activé" + "Touchez pour configurer." + "Le partage de connexion est désactivé" + "Communiquez avec votre administrateur pour obtenir plus de détails" + "Point d\'accès et partage de connexion" + + + + + diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index daf7c9d830..22259c52ab 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -1,8 +1,29 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Appuyez ici pour configurer." - "Le partage de connexion est désactivé" - "Pour en savoir plus, contactez votre administrateur" + "Partage de connexion ou point d\'accès activé" + "Appuyez pour effectuer la configuration." + "Le partage de connexion est désactivé" + "Pour en savoir plus, contactez votre administrateur" + "État du point d\'accès et du partage de connexion" + + + + + diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 0d16a1de09..ded82fcd54 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -1,8 +1,29 @@ + + - "Conexión compartida ou zona wifi activada" - "Tocar para configurar." - "A conexión compartida está desactivada" - "Contacta co administrador para obter información" + "Conexión compartida ou zona wifi activada" + "Toca para configurar." + "A conexión compartida está desactivada" + "Contacta co administrador para obter información" + "Estado da zona wifi e da conexión compartida" + + + + + diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index 9d6b02f85f..7cbbc2de3d 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -1,8 +1,29 @@ + + - "ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય" - "સેટ કરવા માટે ટૅપ કરો." - "ટિથરિંગ અક્ષમ કરેલ છે" - "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" + "સેટઅપ કરવા માટે ટૅપ કરો." + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" + "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" + + + + + diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index 9c29d9a8f9..08af81b826 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -1,8 +1,29 @@ + + - "टेदरिंग या हॉटस्‍पॉट सक्रिय" - "सेट करने के लिए टैप करें." - "टेदरिंग अक्षम है" - "जानकारी के लिए अपने एडमिन से संपर्क करें" + "टेदरिंग या हॉटस्पॉट चालू है" + "सेट अप करने के लिए टैप करें." + "टेदरिंग बंद है" + "जानकारी के लिए अपने एडमिन से संपर्क करें" + "हॉटस्पॉट और टेदरिंग की स्थिति" + + + + + diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index d0d25bb755..827c135f20 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -1,8 +1,29 @@ + + - "Ograničenje ili aktivan hotspot" - "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" - "Obratite se administratoru da biste saznali pojedinosti" + "Modemsko povezivanje ili žarišna točka aktivni" + "Dodirnite da biste postavili." + "Modemsko je povezivanje onemogućeno" + "Obratite se administratoru da biste saznali pojedinosti" + "Status žarišne točke i modemskog povezivanja" + + + + + diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index 3129659923..eb68d6babf 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -1,8 +1,29 @@ + + - "Megosztás vagy aktív hotspot" - "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" - "A részletekért forduljon rendszergazdájához" + "Megosztás vagy aktív hotspot" + "Koppintson a beállításhoz." + "Az internetmegosztás le van tiltva" + "A részletekért forduljon rendszergazdájához" + "Hotspot és internetmegosztás állapota" + + + + + diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index 8ba6435fd5..912941e538 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -1,8 +1,29 @@ + + - "Մոդեմի ռեժիմը միացված է" - "Հպեք՝ կարգավորելու համար:" - "Մոդեմի ռեժիմն անջատված է" - "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Մոդեմի ռեժիմը միացված է" + "Հպեք՝ կարգավորելու համար։" + "Մոդեմի ռեժիմն անջատված է" + "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" + + + + + diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 1e093ab237..a4e175a439 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering (Penambatan) atau hotspot aktif" - "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" - "Hubungi admin untuk mengetahui detailnya" + "Tethering atau hotspot aktif" + "Ketuk untuk menyiapkan." + "Tethering dinonaktifkan" + "Hubungi admin untuk mengetahui detailnya" + "Status hotspot & tethering" + + + + + diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index f5769d5344..e9f6670bcd 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -1,8 +1,29 @@ + + - "Kveikt á tjóðrun eða aðgangsstað" - "Ýttu til að setja upp." - "Slökkt er á tjóðrun" - "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Kveikt á tjóðrun eða aðgangsstað" + "Ýttu til að setja upp." + "Slökkt er á tjóðrun" + "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Staða heits reits og tjóðrunar" + + + + + diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index e0b3724325..ffb9196f5e 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering oppure hotspot attivo" - "Tocca per impostare." - "Tethering disattivato" - "Contatta il tuo amministratore per avere informazioni dettagliate" + "Hotspot o tethering attivo" + "Tocca per impostare." + "Tethering disattivato" + "Contatta il tuo amministratore per avere informazioni dettagliate" + "Stato hotspot e tethering" + + + + + diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c002c44b23..7adcb47350 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -1,8 +1,29 @@ + + - "שיתוף אינטרנט פעיל" - "הקש כדי להגדיר." - "שיתוף האינטרנט בין ניידים מושבת" - "לפרטים, יש לפנות למנהל המערכת" + "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" + "יש להקיש כדי להגדיר." + "שיתוף האינטרנט בין מכשירים מושבת" + "לפרטים, יש לפנות למנהל המערכת" + "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" + + + + + diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index 314bde00df..f68a73010b 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -1,8 +1,29 @@ + + - "テザリングまたはアクセスポイントが有効です" - "タップしてセットアップします。" - "テザリングは無効に設定されています" - "詳しくは、管理者にお問い合わせください" + "テザリングまたはアクセス ポイントが有効です" + "タップしてセットアップします。" + "テザリングは無効に設定されています" + "詳しくは、管理者にお問い合わせください" + "アクセス ポイントとテザリングのステータス" + + + + + diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 7bbd81d343..7c22e82bd3 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -1,8 +1,29 @@ + + - "ტეტერინგი ან უსადენო ქსელი აქტიურია" - "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" - "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "ტეტერინგი ან უსადენო ქსელი აქტიურია" + "შეეხეთ დასაყენებლად." + "ტეტერინგი გათიშულია" + "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "უსადენო ქსელის და ტეტერინგის სტატუსი" + + + + + diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 7fd87a1596..0857d06de2 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -1,8 +1,29 @@ + + - "Тетеринг немесе хотспот қосулы" - "Реттеу үшін түртіңіз." - "Тетеринг өшірілді" - "Мәліметтерді әкімшіден алыңыз" + "Тетеринг немесе хотспот қосулы" + "Реттеу үшін түртіңіз." + "Тетеринг өшірілді." + "Мәліметтерді әкімшіден алыңыз." + "Хотспот және тетеринг күйі" + + + + + diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 2f85224679..536e3d1703 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -1,8 +1,29 @@ + + - "ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម" - "ប៉ះដើម្បីកំណត់" - "ការភ្ជាប់​ត្រូវបានបិទ" - "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត" + "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" + "ចុច​ដើម្បី​រៀបចំ។" + "ការភ្ជាប់​ត្រូវបានបិទ" + "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" + "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" + + + + + diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index f11a83ea40..32f54926f4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -1,8 +1,29 @@ + + - "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" - "ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" - "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" + "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." + "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" + "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" + + + + + diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index 57f24f5b1a..156b24786d 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -1,8 +1,29 @@ + + - "테더링 또는 핫스팟 사용" - "설정하려면 탭하세요." - "테더링이 사용 중지됨" - "자세한 정보는 관리자에게 문의하세요." + "테더링 또는 핫스팟 사용" + "설정하려면 탭하세요." + "테더링이 사용 중지됨" + "자세한 정보는 관리자에게 문의하세요." + "핫스팟 및 테더링 상태" + + + + + diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 79854859d4..18ee5fd357 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -1,8 +1,29 @@ + + - "Жалгаштыруу же хотспот жандырылган" - "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" - "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Модем режими күйүп турат" + "Жөндөө үчүн таптап коюңуз." + "Телефонду модем катары колдонууга болбойт" + "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Байланыш түйүнүнүн жана модем режиминин статусу" + + + + + diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index 78f1585f60..b12767018c 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -1,8 +1,29 @@ + + - "ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ" - "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" - "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" + "ແຕະເພື່ອຕັ້ງຄ່າ." + "ການປ່ອຍສັນຍານຖືກປິດໄວ້" + "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" + + + + + diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index ebff8ac9d1..8427baf39f 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -1,8 +1,29 @@ + + - "Susietas ar aktyvus" - "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" - "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" + "Palieskite, kad nustatytumėte." + "Įrenginio kaip modemo naudojimas išjungtas" + "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" + + + + + diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index 54d0048b52..aa2d6990e0 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -1,8 +1,29 @@ + + - "Piesaiste vai tīklājs ir aktīvs." - "Pieskarieties, lai iestatītu." - "Piesaiste ir atspējota" - "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Piesaiste vai tīklājs ir aktīvs." + "Pieskarieties, lai to iestatītu." + "Piesaiste ir atspējota" + "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Tīklāja un piesaistes statuss" + + + + + diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml new file mode 100644 index 0000000000..19d659c6ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -0,0 +1,24 @@ + + + + + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" + "Bykomende heffings kan geld terwyl jy swerf" + diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml new file mode 100644 index 0000000000..8995430b4f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -0,0 +1,24 @@ + + + + + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml new file mode 100644 index 0000000000..54f3b5389a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -0,0 +1,24 @@ + + + + + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." + diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml new file mode 100644 index 0000000000..e215141c9e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -0,0 +1,24 @@ + + + + + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml new file mode 100644 index 0000000000..1fd8e4c963 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..1abe4f3aa3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" + "Možda važe dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml new file mode 100644 index 0000000000..38dbd1e391 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -0,0 +1,24 @@ + + + + + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml new file mode 100644 index 0000000000..04b44db5c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml new file mode 100644 index 0000000000..579d1be1c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -0,0 +1,24 @@ + + + + + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" + diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml new file mode 100644 index 0000000000..9ce3efe6c3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml new file mode 100644 index 0000000000..46d4c35b9b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -0,0 +1,24 @@ + + + + + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" + "És possible que s\'apliquin costos addicionals en itinerància" + diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml new file mode 100644 index 0000000000..cc13860b3d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" + "Při roamingu mohou být účtovány dodatečné poplatky" + diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml new file mode 100644 index 0000000000..92c3ae1156 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -0,0 +1,24 @@ + + + + + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml new file mode 100644 index 0000000000..967eb4db2e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml new file mode 100644 index 0000000000..5fb497451f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -0,0 +1,24 @@ + + + + + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml new file mode 100644 index 0000000000..7877074afc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -0,0 +1,24 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml new file mode 100644 index 0000000000..08edd81a6b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml new file mode 100644 index 0000000000..79f51d00e2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" + "Puede que se apliquen cargos adicionales en itinerancia" + diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml new file mode 100644 index 0000000000..2da5f8a6d6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -0,0 +1,24 @@ + + + + + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" + "Rändluse kasutamisega võivad kaasneda lisatasud" + diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml new file mode 100644 index 0000000000..2073f2806c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" + diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml new file mode 100644 index 0000000000..e21b2a0852 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -0,0 +1,24 @@ + + + + + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml new file mode 100644 index 0000000000..88b0b13eb4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" + "Roaming voi aiheuttaa lisämaksuja" + diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml new file mode 100644 index 0000000000..3b781bc8db --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml new file mode 100644 index 0000000000..51d7203c36 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml new file mode 100644 index 0000000000..008ccb475d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -0,0 +1,24 @@ + + + + + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" + "Pódense aplicar cargos adicionais en itinerancia" + diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml new file mode 100644 index 0000000000..f2e3b4df78 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -0,0 +1,24 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" + diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml new file mode 100644 index 0000000000..b11839d760 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml new file mode 100644 index 0000000000..0a5aca25b1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" + "U roamingu su mogući dodatni troškovi" + diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml new file mode 100644 index 0000000000..21c689a44e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" + "Roaming során további díjak léphetnek fel" + diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml new file mode 100644 index 0000000000..689d92870e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -0,0 +1,24 @@ + + + + + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml new file mode 100644 index 0000000000..a5f4d19abf --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" + "Biaya tambahan mungkin berlaku saat roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml new file mode 100644 index 0000000000..fc7e8aaf4e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" + "Viðbótargjöld kunna að eiga við í reiki" + diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml new file mode 100644 index 0000000000..6456dd1b80 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml new file mode 100644 index 0000000000..46b24bd3c5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -0,0 +1,24 @@ + + + + + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml new file mode 100644 index 0000000000..e6eb277b90 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -0,0 +1,24 @@ + + + + + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" + "ローミング時に追加料金が発生することがあります" + diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml new file mode 100644 index 0000000000..aeddd7101d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -0,0 +1,24 @@ + + + + + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml new file mode 100644 index 0000000000..255f0a276f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml new file mode 100644 index 0000000000..2bceb1cf77 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -0,0 +1,24 @@ + + + + + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml new file mode 100644 index 0000000000..ed769305a6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -0,0 +1,24 @@ + + + + + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" + diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml new file mode 100644 index 0000000000..6e504941eb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -0,0 +1,24 @@ + + + + + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml new file mode 100644 index 0000000000..d68128b9a5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml new file mode 100644 index 0000000000..03e134a0fc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -0,0 +1,24 @@ + + + + + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" + diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml new file mode 100644 index 0000000000..652cedc6e6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml new file mode 100644 index 0000000000..221972298c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml new file mode 100644 index 0000000000..227f9e3466 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" + "При роаминг може да се наплатат дополнителни трошоци" + diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml new file mode 100644 index 0000000000..ec43885126 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -0,0 +1,24 @@ + + + + + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" + diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml new file mode 100644 index 0000000000..e263573799 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml new file mode 100644 index 0000000000..adf845d078 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml new file mode 100644 index 0000000000..f65c451e4c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -0,0 +1,24 @@ + + + + + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml new file mode 100644 index 0000000000..4118e775cd --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -0,0 +1,24 @@ + + + + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml new file mode 100644 index 0000000000..36853583ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" + "Ytterligere kostnader kan påløpe under roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml new file mode 100644 index 0000000000..d074f15699 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" + diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml new file mode 100644 index 0000000000..1d888942f4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml new file mode 100644 index 0000000000..8038815fe8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -0,0 +1,24 @@ + + + + + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" + diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml new file mode 100644 index 0000000000..819833eab0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -0,0 +1,24 @@ + + + + + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" + diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml new file mode 100644 index 0000000000..65e4380e39 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml new file mode 100644 index 0000000000..d8866170c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml new file mode 100644 index 0000000000..bfd45ca0a3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -0,0 +1,24 @@ + + + + + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" + "Podem aplicar-se custos adicionais em roaming." + diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml new file mode 100644 index 0000000000..d8866170c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml new file mode 100644 index 0000000000..8d87a9e516 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -0,0 +1,24 @@ + + + + + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" + "Se pot aplica taxe suplimentare pentru roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml new file mode 100644 index 0000000000..dbdb9ebe49 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -0,0 +1,24 @@ + + + + + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml new file mode 100644 index 0000000000..d8301e41c2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -0,0 +1,24 @@ + + + + + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml new file mode 100644 index 0000000000..bef71363f4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml new file mode 100644 index 0000000000..3202c62e8a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml new file mode 100644 index 0000000000..37f6ad2868 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml new file mode 100644 index 0000000000..5566d03ed1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" + "Можда важе додатни трошкови у ромингу" + diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml new file mode 100644 index 0000000000..9765acd0cf --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" + "Ytterligare avgifter kan tillkomma vid roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml new file mode 100644 index 0000000000..cf850c9cd2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -0,0 +1,24 @@ + + + + + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml new file mode 100644 index 0000000000..f4b15aab19 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -0,0 +1,24 @@ + + + + + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" + diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml new file mode 100644 index 0000000000..937d34d520 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -0,0 +1,24 @@ + + + + + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" + diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml new file mode 100644 index 0000000000..f781fae525 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -0,0 +1,24 @@ + + + + + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml new file mode 100644 index 0000000000..8d5d465373 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml new file mode 100644 index 0000000000..80cab33ac0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml new file mode 100644 index 0000000000..c05932a5ae --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" + "У роумінгу може стягуватися додаткова плата" + diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml new file mode 100644 index 0000000000..d820eee8ba --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -0,0 +1,24 @@ + + + + + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml new file mode 100644 index 0000000000..726148aaee --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" + diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml new file mode 100644 index 0000000000..b7cb0456b6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml new file mode 100644 index 0000000000..af91afff9a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + + + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" + "漫游时可能会产生额外的费用" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml new file mode 100644 index 0000000000..28e6b80c01 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" + "漫遊時可能需要支付額外費用" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml new file mode 100644 index 0000000000..528a1e5292 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網路共用連上網際網路" + "裝置無法連線" + "關閉網路共用" + "無線基地台或網路共用已開啟" + "使用漫遊服務可能須支付額外費用" + diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml new file mode 100644 index 0000000000..11eb666219 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml new file mode 100644 index 0000000000..9bfa5317a9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -0,0 +1,24 @@ + + + + + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" + "Bykomende heffings kan geld terwyl jy swerf" + diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml new file mode 100644 index 0000000000..5949dfa776 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -0,0 +1,24 @@ + + + + + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml new file mode 100644 index 0000000000..8467f9b1f5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -0,0 +1,24 @@ + + + + + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." + diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml new file mode 100644 index 0000000000..9776bd89da --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -0,0 +1,24 @@ + + + + + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml new file mode 100644 index 0000000000..e6d3eaf9f0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..4c8a1df8ee --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" + "Možda važe dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml new file mode 100644 index 0000000000..edfa41e1ff --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -0,0 +1,24 @@ + + + + + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml new file mode 100644 index 0000000000..f56398196f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml new file mode 100644 index 0000000000..d8ecd2e988 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -0,0 +1,24 @@ + + + + + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" + diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml new file mode 100644 index 0000000000..b85fd5e285 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml new file mode 100644 index 0000000000..a3572151be --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -0,0 +1,24 @@ + + + + + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" + "És possible que s\'apliquin costos addicionals en itinerància" + diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml new file mode 100644 index 0000000000..91196be9e5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" + "Při roamingu mohou být účtovány dodatečné poplatky" + diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml new file mode 100644 index 0000000000..196890011d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -0,0 +1,24 @@ + + + + + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml new file mode 100644 index 0000000000..eb3f8c52c0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml new file mode 100644 index 0000000000..56c3d81b63 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -0,0 +1,24 @@ + + + + + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml new file mode 100644 index 0000000000..d3347aae20 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -0,0 +1,24 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml new file mode 100644 index 0000000000..2f0504f07d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml new file mode 100644 index 0000000000..2d8f882425 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" + "Puede que se apliquen cargos adicionales en itinerancia" + diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml new file mode 100644 index 0000000000..8493c47071 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -0,0 +1,24 @@ + + + + + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" + "Rändluse kasutamisega võivad kaasneda lisatasud" + diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml new file mode 100644 index 0000000000..33bccab3e8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" + diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml new file mode 100644 index 0000000000..cf8a0cc277 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -0,0 +1,24 @@ + + + + + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml new file mode 100644 index 0000000000..6a3ab806db --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" + "Roaming voi aiheuttaa lisämaksuja" + diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml new file mode 100644 index 0000000000..ffb9bf6047 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml new file mode 100644 index 0000000000..768bce3f0a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml new file mode 100644 index 0000000000..0c4195a7ca --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -0,0 +1,24 @@ + + + + + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" + "Pódense aplicar cargos adicionais en itinerancia" + diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml new file mode 100644 index 0000000000..e9d33a7db2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -0,0 +1,24 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" + diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml new file mode 100644 index 0000000000..aa418ac5d3 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml new file mode 100644 index 0000000000..51c524afbc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" + "U roamingu su mogući dodatni troškovi" + diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml new file mode 100644 index 0000000000..164e45edd1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" + "Roaming során további díjak léphetnek fel" + diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml new file mode 100644 index 0000000000..e76c0a4c80 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -0,0 +1,24 @@ + + + + + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml new file mode 100644 index 0000000000..2b817f8abd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" + "Biaya tambahan mungkin berlaku saat roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml new file mode 100644 index 0000000000..a338d9c7ca --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" + "Viðbótargjöld kunna að eiga við í reiki" + diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml new file mode 100644 index 0000000000..77769c2ac5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml new file mode 100644 index 0000000000..5267b51264 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -0,0 +1,24 @@ + + + + + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml new file mode 100644 index 0000000000..66a9a6dd35 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -0,0 +1,24 @@ + + + + + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" + "ローミング時に追加料金が発生することがあります" + diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml new file mode 100644 index 0000000000..d8ad880849 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -0,0 +1,24 @@ + + + + + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml new file mode 100644 index 0000000000..1ddd6b419b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml new file mode 100644 index 0000000000..cf5a1379cc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -0,0 +1,24 @@ + + + + + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml new file mode 100644 index 0000000000..68ae68bc19 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -0,0 +1,24 @@ + + + + + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" + diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml new file mode 100644 index 0000000000..17185ba2d0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -0,0 +1,24 @@ + + + + + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml new file mode 100644 index 0000000000..6a9fb9810c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml new file mode 100644 index 0000000000..bcc4b57626 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -0,0 +1,24 @@ + + + + + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" + diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml new file mode 100644 index 0000000000..011c2c11fb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml new file mode 100644 index 0000000000..5cb2f3b7aa --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml new file mode 100644 index 0000000000..4cbfd887c5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" + "При роаминг може да се наплатат дополнителни трошоци" + diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml new file mode 100644 index 0000000000..9cf4eaf34a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -0,0 +1,24 @@ + + + + + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" + diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml new file mode 100644 index 0000000000..47c82c14d9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml new file mode 100644 index 0000000000..ad9e809ab2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml new file mode 100644 index 0000000000..e708cb8717 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -0,0 +1,24 @@ + + + + + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml new file mode 100644 index 0000000000..ba5462250b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -0,0 +1,24 @@ + + + + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml new file mode 100644 index 0000000000..57db484a25 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" + "Ytterligere kostnader kan påløpe under roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml new file mode 100644 index 0000000000..1503244f50 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" + diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml new file mode 100644 index 0000000000..b08133f4e5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml new file mode 100644 index 0000000000..1ad4ca354a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -0,0 +1,24 @@ + + + + + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" + diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml new file mode 100644 index 0000000000..88def563d8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -0,0 +1,24 @@ + + + + + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" + diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml new file mode 100644 index 0000000000..f9890abdc2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml new file mode 100644 index 0000000000..ce3b88479f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml new file mode 100644 index 0000000000..7e883ea576 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -0,0 +1,24 @@ + + + + + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" + "Podem aplicar-se custos adicionais em roaming." + diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml new file mode 100644 index 0000000000..ce3b88479f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml new file mode 100644 index 0000000000..1009417316 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -0,0 +1,24 @@ + + + + + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" + "Se pot aplica taxe suplimentare pentru roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml new file mode 100644 index 0000000000..88683bed95 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -0,0 +1,24 @@ + + + + + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml new file mode 100644 index 0000000000..176bcdb797 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -0,0 +1,24 @@ + + + + + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml new file mode 100644 index 0000000000..b9e2127fa8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml new file mode 100644 index 0000000000..e8140e686a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml new file mode 100644 index 0000000000..61e698d6e8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml new file mode 100644 index 0000000000..b4c411c354 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" + "Можда важе додатни трошкови у ромингу" + diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml new file mode 100644 index 0000000000..4f543e47b9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" + "Ytterligare avgifter kan tillkomma vid roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml new file mode 100644 index 0000000000..ac347ab485 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -0,0 +1,24 @@ + + + + + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml new file mode 100644 index 0000000000..2ea2467e58 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -0,0 +1,24 @@ + + + + + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" + diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml new file mode 100644 index 0000000000..9360297dd8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -0,0 +1,24 @@ + + + + + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" + diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml new file mode 100644 index 0000000000..9c4d7e08f2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -0,0 +1,24 @@ + + + + + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml new file mode 100644 index 0000000000..a7c78a5932 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml new file mode 100644 index 0000000000..93da2c3f79 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml new file mode 100644 index 0000000000..ee0dcd2c4b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" + "У роумінгу може стягуватися додаткова плата" + diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml new file mode 100644 index 0000000000..41cd28eef9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -0,0 +1,24 @@ + + + + + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml new file mode 100644 index 0000000000..c847bc943b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" + diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml new file mode 100644 index 0000000000..a74326f09e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml new file mode 100644 index 0000000000..d7370036e3 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + + + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" + "漫游时可能会产生额外的费用" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml new file mode 100644 index 0000000000..f378a9dc2c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" + "漫遊時可能需要支付額外費用" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml new file mode 100644 index 0000000000..cd653df1da --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網路共用連上網際網路" + "裝置無法連線" + "關閉網路共用" + "無線基地台或網路共用已開啟" + "使用漫遊服務可能須支付額外費用" + diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml new file mode 100644 index 0000000000..32f6df56f1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 0fab8aa476..9ad9b9a589 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -1,8 +1,29 @@ + + - "Поврзувањето или точката на пристап се активни" - "Допрете за поставување." - "Врзувањето е оневозможено" - "Контактирајте со администраторот за детали" + "Активно е врзување или точка на пристап" + "Допрете за поставување." + "Врзувањето е оневозможено" + "Контактирајте со администраторот за детали" + "Статус на точката на пристап и врзувањето" + + + + + diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index fd7e556e38..9db79ce220 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -1,8 +1,29 @@ + + - "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" - "സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" - "വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" + "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." + "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" + "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" + + + + + diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4596577c5d..42d1edbace 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -1,8 +1,29 @@ + + - "Модем болгох эсвэл идэвхтэй цэг болгох" - "Тохируулахын тулд товшино уу." - "Модем болгох боломжгүй байна" - "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" + "Тохируулахын тулд товшино уу." + "Модем болгохыг идэвхгүй болгосон" + "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Сүлжээний цэг болон модем болгох төлөв" + + + + + diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index 85c9ade4fe..13995b6b8a 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -1,8 +1,29 @@ + + - "टेदरिंग किंवा हॉटस्पॉट सक्रिय" - "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद आहे" - "तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा" + "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" + "सेट करण्यासाठी टॅप करा." + "टेदरिंग बंद केले आहे" + "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" + "हॉटस्पॉट आणि टेदरिंगची स्थिती" + + + + + diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index ec6bdbda08..d6a67f37b1 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -1,8 +1,29 @@ + + - "Penambatan atau titik panas aktif" - "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" - "Hubungi pentadbir anda untuk maklumat lanjut" + "Penambatan atau tempat liputan aktif" + "Ketik untuk membuat persediaan." + "Penambatan dilumpuhkan" + "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" + "Status tempat liputan & penambatan" + + + + + diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 83978b67d4..49f6b88a75 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -1,8 +1,29 @@ + + - "တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" - "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်" - "အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" + "စနစ်ထည့်သွင်းရန် တို့ပါ။" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" + "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" + + + + + diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 9abf32dd7b..9594e0a70a 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -1,8 +1,29 @@ + + - "Internettdeling eller trådløs sone er aktiv" - "Trykk for å konfigurere." - "Internettdeling er slått av" - "Ta kontakt med administratoren din for å få mer informasjon" + "Internettdeling eller Wi-Fi-sone er aktiv" + "Trykk for å konfigurere." + "Internettdeling er slått av" + "Ta kontakt med administratoren din for å få mer informasjon" + "Status for Wi-Fi-sone og internettdeling" + + + + + diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index c8869298a5..72ae3a80a9 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -1,8 +1,29 @@ + + - "टेथर गर्ने वा हटस्पट सक्रिय" - "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङलाई असक्षम पारिएको छ" - "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "टेदरिङ वा हटस्पट सक्रिय छ" + "सेटअप गर्न ट्याप गर्नुहोस्।" + "टेदरिङ सुविधा असक्षम पारिएको छ" + "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "हटस्पट तथा टेदरिङको स्थिति" + + + + + diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 0ec4bff621..18b2bbfc76 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering of hotspot actief" - "Tik om in te stellen." - "Tethering is uitgeschakeld" - "Neem contact op met je beheerder voor meer informatie" + "Tethering of hotspot actief" + "Tik om in te stellen." + "Tethering is uitgeschakeld" + "Neem contact op met je beheerder voor meer informatie" + "Status van hotspot en tethering" + + + + + diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 457685795a..a15a6db42a 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -1,8 +1,29 @@ + + - "ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି" - "ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।" - "ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି" - "ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" + "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" + "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" + "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" + + + + + diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index deddf2ea27..a8235e423e 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -1,8 +1,29 @@ + + - "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" - "ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ" - "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ" + "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" + "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" + "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" + "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" + + + + + diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index 48d8468935..ccb017d43f 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -1,8 +1,29 @@ + + - "Aktywny tethering lub punkt dostępu" - "Kliknij, by skonfigurować." - "Tethering został wyłączony" - "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Aktywny tethering lub punkt dostępu" + "Kliknij, by skonfigurować" + "Tethering został wyłączony" + "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Hotspot i tethering – stan" + + + + + diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 32c22b8713..a0a4745f93 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -1,8 +1,29 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 641e22f44f..e3f03fcc69 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -1,8 +1,29 @@ + + - "Ligação ponto a ponto ou hotspot activos" - "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." - "Contacte o gestor para obter detalhes." + "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" + "Toque para configurar." + "A ligação (à Internet) via telemóvel está desativada." + "Contacte o administrador para obter detalhes." + "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" + + + + + diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 32c22b8713..a0a4745f93 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -1,8 +1,29 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index f861f733b4..5706a4a69c 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering sau hotspot activ" - "Atingeți ca să configurați." - "Tetheringul este dezactivat" - "Contactați administratorul pentru detalii" + "Tethering sau hotspot activ" + "Atingeți ca să configurați." + "Tetheringul este dezactivat" + "Contactați administratorul pentru detalii" + "Starea hotspotului și a tetheringului" + + + + + diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 027cb410c5..7cb6f7db3f 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -1,8 +1,29 @@ + + - "Включен режим модема" - "Нажмите, чтобы настроить." - "Включить режим модема нельзя" - "Обратитесь к администратору, чтобы узнать подробности." + "Включен режим модема или точка доступа" + "Нажмите, чтобы настроить." + "Использование телефона в качестве модема запрещено" + "Чтобы узнать подробности, обратитесь к администратору." + "Статус хот-спота и режима модема" + + + + + diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index 7d8599f2c2..ec34c22de7 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -1,8 +1,29 @@ + + - "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" - "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" - "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" + "පිහිටුවීමට තට්ටු කරන්න." + "ටෙදරින් අබල කර ඇත" + "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" + + + + + diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index a8fe297c00..43e787c84f 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering alebo prístupový bod je aktívny" - "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" - "O podrobnosti požiadajte svojho správcu" + "Tethering alebo prístupový bod je aktívny" + "Klepnutím prejdete na nastavenie." + "Tethering je deaktivovaný" + "O podrobnosti požiadajte svojho správcu" + "Stav hotspotu a tetheringu" + + + + + diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index b5e5e3856f..59433626a1 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -1,8 +1,29 @@ + + - "Aktivna povezava z internetom ali dostopna točka sta aktivni" - "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" - "Za podrobnosti se obrnite na skrbnika" + "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" + "Dotaknite se, če želite nastaviti." + "Povezava z internetom prek mobilnega telefona je onemogočena" + "Za podrobnosti se obrnite na skrbnika" + "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" + + + + + diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index fdd4906cc5..21e11558bb 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -1,8 +1,29 @@ + + - "Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive" - "Trokit për ta konfiguruar." - "Lidhja e çiftimit është çaktivizuar" - "Kontakto me administratorin për detaje" + "Ndarja e internetit ose zona e qasjes së internetit është aktive" + "Trokit për ta konfiguruar." + "Ndarja e internetit është çaktivizuar" + "Kontakto me administratorin për detaje" + "Statusi i zonës së qasjes dhe ndarjes së internetit" + + + + + diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index 9fab345897..e2e4dc6361 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -1,8 +1,29 @@ + + - "Активно повезивање са интернетом преко мобилног уређаја или хотспот" - "Додирните да бисте подесили." - "Привезивање је онемогућено" - "Потражите детаље од администратора" + "Привезивање или хотспот је активан" + "Додирните да бисте подесили." + "Привезивање је онемогућено" + "Потражите детаље од администратора" + "Статус хотспота и привезивања" + + + + + diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index 10eeb0fe12..72702c2858 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -1,8 +1,29 @@ + + - "Internetdelning eller surfzon aktiverad" - "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" - "Kontakta administratören om du vill veta mer" + "Internetdelning eller surfzon har aktiverats" + "Tryck om du vill konfigurera." + "Internetdelning har inaktiverats" + "Kontakta administratören om du vill veta mer" + "Trådlös surfzon och internetdelning har inaktiverats" + + + + + diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index 3353963077..65e4aa8ceb 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -1,8 +1,29 @@ + + - "Kushiriki au kusambaza intaneti kumewashwa" - "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" - "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Kusambaza mtandao au mtandaopepe umewashwa" + "Gusa ili uweke mipangilio." + "Umezima kipengele cha kusambaza mtandao" + "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Mtandaopepe na hali ya kusambaza mtandao" + + + + + diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index b1e5cc2413..4aba62d4ab 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -1,8 +1,29 @@ + + - "டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது" - "அமைக்க, தட்டவும்." - "இணைப்பு முறை முடக்கப்பட்டுள்ளது" - "விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" + "அமைக்க, தட்டவும்." + "டெதெரிங் முடக்கப்பட்டுள்ளது" + "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" + + + + + diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index aae40dee40..1f91791341 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -1,8 +1,29 @@ + + - "టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది" - "సెటప్ చేయడానికి నొక్కండి." - "టెథెరింగ్ నిలిపివేయబడింది" - "వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి" + "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" + "సెటప్ చేయడానికి ట్యాప్ చేయండి." + "టెథరింగ్ డిజేబుల్ చేయబడింది" + "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" + "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" + + + + + diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index 1b800565ad..44171c0db8 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -1,8 +1,29 @@ + + - "การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่" - "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" - "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" + "แตะเพื่อตั้งค่า" + "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" + "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + + + + + diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 12863f90e1..7347dd3e62 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -1,8 +1,29 @@ + + - "Pagsasama o aktibong hotspot" - "I-tap upang i-set up." - "Naka-disable ang pag-tether" - "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Aktibo ang pag-tether o hotspot" + "I-tap para i-set up." + "Naka-disable ang pag-tether" + "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Status ng hotspot at pag-tether" + + + + + diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index bfcf1ace2c..32030f1765 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering veya hotspot etkin" - "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" - "Ayrıntılı bilgi için yöneticinize başvurun" + "Tethering veya hotspot etkin" + "Ayarlamak için dokunun." + "Tethering devre dışı bırakıldı" + "Ayrıntılı bilgi için yöneticinize başvurun" + "Hotspot ve tethering durumu" + + + + + diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 8e159c0723..1ca89b3f78 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -1,8 +1,29 @@ + + - "Прив\'язка чи точка дост. активна" - "Торкніться, щоб налаштувати." - "Використання телефона в режимі модема вимкнено" - "Щоб дізнатися більше, зв’яжіться з адміністратором" + "Модем чи точка доступу активні" + "Натисніть, щоб налаштувати." + "Використання телефона як модема вимкнено" + "Щоб дізнатися більше, зв\'яжіться з адміністратором" + "Статус точки доступу та модема" + + + + + diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 89195d4aae..d72c7d4195 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -1,8 +1,29 @@ + + - "ٹیدرنگ یا ہاٹ اسپاٹ فعال" - "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" - "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ٹیدرنگ یا ہاٹ اسپاٹ فعال" + "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" + "ٹیدرنگ غیر فعال ہے" + "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" + + + + + diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 0ac4d4a741..af3b2ebb35 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -1,8 +1,29 @@ + + - "Modem rejimi yoniq" - "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" - "Tafsilotlari uchun administratoringizga murojaat qiling" + "Modem rejimi yoki hotspot yoniq" + "Sozlash uchun bosing." + "Modem rejimi faolsizlantirildi" + "Tafsilotlari uchun administratoringizga murojaat qiling" + "Hotspot va modem rejimi holati" + + + + + diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 85a4db8aa5..21a0735922 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -1,8 +1,29 @@ + + - "Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động" - "Nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" - "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" + "Hãy nhấn để thiết lập." + "Đã tắt tính năng chia sẻ Internet" + "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Trạng thái điểm phát sóng và chia sẻ Internet" + + + + + diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index ff1fe03953..98e3b4b46f 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -1,8 +1,29 @@ + + - "网络共享或热点已启用" - "点按即可进行设置。" - "网络共享已停用" - "请与您的管理员联系以了解详情" + "网络共享或热点已启用" + "点按即可设置。" + "网络共享已停用" + "如需了解详情,请与您的管理员联系" + "热点和网络共享状态" + + + + + diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 0de39fac97..9cafd42dd4 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -1,8 +1,29 @@ + + - "已啟用網絡共享或熱點" - "輕按即可設定。" - "網絡共享已停用" - "請聯絡您的管理員以瞭解詳情" + "網絡共享或熱點已啟用" + "輕按即可設定。" + "網絡共享已停用" + "請聯絡您的管理員以瞭解詳情" + "熱點和網絡共享狀態" + + + + + diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9a117bbca4..50a50bf7a9 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -1,8 +1,29 @@ + + - "網路共用或無線基地台已啟用" - "輕觸即可進行設定。" - "數據連線已停用" - "詳情請洽你的管理員" + "網路共用或無線基地台已啟用" + "輕觸即可進行設定。" + "網路共用已停用" + "詳情請洽你的管理員" + "無線基地台與網路共用狀態" + + + + + diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index 8fe10d86cb..f210f8726e 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -1,8 +1,29 @@ + + - "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" - "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" - "Xhumana nomphathi wakho ukuze uthole imininingwane" + "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" + "Thepha ukuze usethe." + "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" + "Xhumana nomphathi wakho ukuze uthole imininingwane" + "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" + + + + + From 8643ebd6b1581ace739c045f3348c9418444c01d Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 1 Sep 2020 09:43:49 +0000 Subject: [PATCH 1288/1415] Don't require WiFi in CtsHostsideNetworkTests. Skip test for non-WiFi connections. Bug: 162192335 Test: run cts -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideNetworkCallbackTests#testOnBlockedStatusChanged_dataSaver Change-Id: I7c20e3454a2fe81671162e0a50f90d64ed7516d0 --- .../com/android/cts/net/hostside/NetworkCallbackTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java index eedccb63ad..2ac29e77ff 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -17,7 +17,9 @@ package com.android.cts.net.hostside; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; @@ -26,6 +28,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.net.Network; import android.net.NetworkCapabilities; @@ -183,6 +186,8 @@ public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCa public void setUp() throws Exception { super.setUp(); + assumeTrue(isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness()); + registerBroadcastReceiver(); removeRestrictBackgroundWhitelist(mUid); From 6c701f5341ebf5711448ac19bc8e8eab0ef1c513 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 5 Sep 2020 01:14:22 +0000 Subject: [PATCH 1289/1415] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: Ibfe7031a80e38ed3fe776e195514e6c7cad418ab --- Tethering/res/values-af/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-am/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ar/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-as/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-az/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-b+sr+Latn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-be/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bg/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bs/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ca/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-cs/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-da/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-de/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-el/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rAU/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rCA/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rGB/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rIN/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rXC/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-es-rUS/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-es/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-et/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-eu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fa/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fr-rCA/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-gl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-gu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hy/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-in/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-is/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-it/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-iw/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ja/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ka/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-kk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-km/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-kn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ko/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ky/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lo/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lt/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lv/strings.xml | 29 ++++++++++++++++--- .../res/values-mcc310-mnc004-af/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-am/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ar/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-as/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-az/strings.xml | 24 +++++++++++++++ .../strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-be/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bg/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bs/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ca/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-cs/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-da/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-de/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-el/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rAU/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rCA/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rGB/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rIN/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rXC/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-es-rUS/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-es/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-et/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-eu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fa/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fi/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-fr-rCA/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-gl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-gu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hi/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hy/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-in/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-is/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-it/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-iw/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ja/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ka/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-kk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-km/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-kn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ko/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ky/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lo/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lt/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lv/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ml/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ms/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-my/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-nb/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ne/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-nl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-or/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pa/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pl/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-pt-rBR/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-pt-rPT/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pt/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ro/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ru/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-si/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sq/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sv/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sw/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ta/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-te/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-th/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-tl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-tr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-uk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ur/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-uz/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-vi/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rCN/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rHK/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rTW/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-zu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-af/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-am/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ar/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-as/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-az/strings.xml | 24 +++++++++++++++ .../strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-be/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bg/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bs/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ca/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-cs/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-da/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-de/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-el/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rAU/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rCA/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rGB/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rIN/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rXC/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-es-rUS/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-es/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-et/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-eu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fa/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fi/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-fr-rCA/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-gl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-gu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hi/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hy/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-in/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-is/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-it/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-iw/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ja/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ka/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-kk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-km/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-kn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ko/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ky/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lo/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lt/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lv/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ml/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ms/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-my/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-nb/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ne/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-nl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-or/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pa/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pl/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-pt-rBR/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-pt-rPT/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pt/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ro/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ru/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-si/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sq/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sv/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sw/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ta/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-te/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-th/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-tl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-tr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-uk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ur/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-uz/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-vi/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rCN/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rHK/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rTW/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-zu/strings.xml | 24 +++++++++++++++ Tethering/res/values-mk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ml/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-mn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-mr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ms/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-my/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-nb/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ne/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-nl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-or/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pa/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt-rBR/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt-rPT/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ro/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ru/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-si/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sq/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sv/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sw/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ta/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-te/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-th/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-tl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-tr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-uk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ur/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-uz/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-vi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rCN/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rHK/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rTW/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zu/strings.xml | 29 ++++++++++++++++--- 255 files changed, 6205 insertions(+), 340 deletions(-) create mode 100644 Tethering/res/values-mcc310-mnc004-af/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-am/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ar/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-as/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-az/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-be/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bg/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ca/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-cs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-da/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-de/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-el/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-et/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-eu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hy/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-in/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-is/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-it/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-iw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ja/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ka/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-km/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ko/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ky/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lo/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ml/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ms/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-my/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nb/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ne/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-or/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ro/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ru/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-si/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sq/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ta/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-te/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-th/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ur/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uz/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-vi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-af/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-am/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ar/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-as/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-az/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-be/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bg/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ca/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-cs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-da/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-de/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-el/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-et/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-eu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hy/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-in/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-is/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-it/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-iw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ja/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ka/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-km/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ko/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ky/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lo/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ml/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ms/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-my/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nb/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ne/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-or/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ro/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ru/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-si/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sq/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ta/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-te/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-th/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ur/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uz/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-vi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zu/strings.xml diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index 1258805378..056168b12e 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -1,8 +1,29 @@ + + - "Verbinding of Wi-Fi-warmkol aktief" - "Tik om op te stel." - "Verbinding is gedeaktiveer" - "Kontak jou administrateur vir besonderhede" + "Verbinding of warmkol is aktief" + "Tik om op te stel." + "Verbinding is gedeaktiveer" + "Kontak jou administrateur vir besonderhede" + "Warmkol- en verbindingstatus" + + + + + diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 9c36192257..ac468dd144 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -1,8 +1,29 @@ + + - "መሰካት ወይም ገባሪ ድረስ ነጥብ" - "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" - "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" + "ለማዋቀር መታ ያድርጉ።" + "እንደ ሞደም መሰካት ተሰናክሏል" + "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" + + + + + diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 9f84ce4090..7d5bad34da 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -1,8 +1,29 @@ + + - "النطاق أو نقطة الاتصال نشطة" - "انقر للإعداد." - "تم إيقاف التوصيل" - "اتصل بالمشرف للحصول على التفاصيل" + "النطاق نشط أو نقطة الاتصال نشطة" + "انقر للإعداد." + "التوصيل متوقف." + "تواصَل مع المشرف للحصول على التفاصيل." + "حالة نقطة الاتصال والتوصيل" + + + + + diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index 8855822e7c..091350455b 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -1,8 +1,29 @@ + + - "টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে" - "ছেট আপ কৰিবলৈ টিপক।" - "টেডাৰিং অক্ষম কৰি থোৱা হৈছে" - "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" + "ছেট আপ কৰিবলৈ টিপক।" + "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" + "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" + + + + + diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index eba50eb636..dce70da178 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -1,8 +1,29 @@ + + - "Tezerinq və ya hotspot aktivdir" - "Quraşdırmaq üçün tıklayın." - "Birləşmə deaktivdir" - "Məlumat üçün adminlə əlaqə saxlayın" + "Birləşmə və ya hotspot aktivdir" + "Ayarlamaq üçün toxunun." + "Birləşmə deaktivdir" + "Detallar üçün adminlə əlaqə saxlayın" + "Hotspot & birləşmə statusu" + + + + + diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 5b0e488ba5..b0774ec9a8 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -1,8 +1,29 @@ + + - "Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot" - "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" - "Potražite detalje od administratora" + "Privezivanje ili hotspot je aktivan" + "Dodirnite da biste podesili." + "Privezivanje je onemogućeno" + "Potražite detalje od administratora" + "Status hotspota i privezivanja" + + + + + diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 5966c7155e..a8acebe2e9 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -1,8 +1,29 @@ + + - "USB-мадэм або хот-спот Wi-Fi актыўныя" - "Дакраніцеся, каб наладзіць." - "Рэжым мадэма адключаны" - "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Мадэм або хот-спот актыўныя" + "Дакраніцеся, каб наладзіць." + "Рэжым мадэма выключаны" + "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Стан \"Хот-спот і мадэм\"" + + + + + diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index ed58d7311a..94fb2d8f17 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -1,8 +1,29 @@ + + - "Има активна споделена връзка или безжична точка за достъп" - "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" - "Свържете се с администратора си за подробности" + "Има активна споделена връзка или точка за достъп" + "Докоснете, за да настроите." + "Функцията за тетъринг е деактивирана" + "Свържете се с администратора си за подробности" + "Състояние на функцията за точка за достъп и тетъринг" + + + + + diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 8d9880aa9a..aea02b9ddf 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -1,8 +1,29 @@ + + - "টিথারিং বা হটস্পট সক্রিয় আছে" - "সেট-আপ করার জন্য আলতো চাপুন৷" - "টিথারিং অক্ষম করা আছে" - "বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন" + "টিথারিং বা হটস্পট চালু আছে" + "সেট-আপ করতে ট্যাপ করুন।" + "টিথারিং বন্ধ করা আছে" + "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" + "হটস্পট ও টিথারিং স্ট্যাটাস" + + + + + diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index 2361b9dd38..de232724c5 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -1,8 +1,29 @@ + + - "Uređaj dijeli vezu ili djeluje kao pristupna tačka" - "Dodirnite za postavke" - "Povezivanje putem mobitela je onemogućeno" - "Kontaktirajte svog administratora za dodatne detalje" + "Aktivno je povezivanje putem mobitela ili pristupna tačka" + "Dodirnite da postavite." + "Povezivanje putem mobitela je onemogućeno" + "Kontaktirajte svog administratora za detalje" + "Status pristupne tačke i povezivanja putem mobitela" + + + + + diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index 6752b519e2..88b795c1f8 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -1,8 +1,29 @@ + + - "Compartició de xarxa o punt d\'accés Wi-Fi activat" - "Toca per configurar." - "La compartició de xarxa està desactivada" - "Contacta amb el teu administrador per obtenir més informació" + "Compartició de xarxa o punt d\'accés Wi‑Fi actius" + "Toca per configurar." + "La compartició de xarxa està desactivada" + "Contacta amb el teu administrador per obtenir més informació" + "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" + + + + + diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5fdd53adf1..8c1b83bf3e 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -1,8 +1,29 @@ + + - "Sdílené připojení nebo hotspot je aktivní." - "Klepnutím zahájíte nastavení." - "Tethering je zakázán" - "O podrobnosti požádejte administrátora" + "Tethering nebo hotspot je aktivní" + "Klepnutím zahájíte nastavení." + "Tethering je zakázán" + "O podrobnosti požádejte administrátora" + "Stav hotspotu a tetheringu" + + + + + diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 2775dfa551..f413e70548 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -1,8 +1,29 @@ + + - "Netdeling eller hotspot er aktivt" - "Tryk for at konfigurere" - "Netdeling er deaktiveret" - "Kontakt din administrator for at få oplysninger" + "Netdeling eller hotspot er aktivt" + "Tryk for at konfigurere." + "Netdeling er deaktiveret" + "Kontakt din administrator for at få oplysninger" + "Status for hotspot og netdeling" + + + + + diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 9046cd5e11..f057d7824e 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering oder Hotspot aktiv" - "Zum Einrichten tippen." - "Tethering ist deaktiviert" - "Bitte wende dich für weitere Informationen an den Administrator" + "Tethering oder Hotspot aktiv" + "Zum Einrichten tippen." + "Tethering ist deaktiviert" + "Bitte wende dich für weitere Informationen an den Administrator" + "Hotspot- und Tethering-Status" + + + + + diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3b9f53733b..b3c986bdaf 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -1,8 +1,29 @@ + + - "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" - "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" - "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" + "Πατήστε για ρύθμιση." + "Η σύνδεση είναι απενεργοποιημένη" + "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" + + + + + diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 7f47fc89d2..f1674bed4e 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -1,8 +1,29 @@ + + - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎Tethering is disabled‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" + + + + + diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index e4618b8cec..63689f4399 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -1,8 +1,29 @@ + + - "Anclaje a red o zona activa conectados" - "Presiona para configurar." - "Se inhabilitó la conexión mediante dispositivo portátil" - "Para obtener más información, comunícate con el administrador" + "Conexión a red o hotspot conectados" + "Presiona para configurar esta opción." + "Se inhabilitó la conexión mediante dispositivo portátil" + "Para obtener más información, comunícate con el administrador" + "Estado del hotspot y la conexión mediante dispositivo portátil" + + + + + diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 8dc1575ce8..9a34ed5e38 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -1,8 +1,29 @@ + + - "Compartir conexión/Zona Wi-Fi activada" - "Toca para configurar." - "La conexión compartida está inhabilitada" - "Ponte en contacto con el administrador para obtener más información" + "Conexión compartida o punto de acceso activos" + "Toca para configurar." + "La conexión compartida está inhabilitada" + "Solicita más información a tu administrador" + "Estado del punto de acceso y de la conexión compartida" + + + + + diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index 872c8a74cc..0970341ab0 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -1,8 +1,29 @@ + + - "Jagamine või kuumkoht on aktiivne" - "Puudutage seadistamiseks." - "Jagamine on keelatud" - "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Jagamine või kuumkoht on aktiivne" + "Puudutage seadistamiseks." + "Jagamine on keelatud" + "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Kuumkoha ja jagamise olek" + + + + + diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index 6c4605e616..632019e2ef 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -1,8 +1,29 @@ + + - "Konexioa partekatzea edo sare publikoa aktibo" - "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" - "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Konexioa partekatzea edo wifi-gunea aktibo dago" + "Sakatu konfiguratzeko." + "Desgaituta dago konexioa partekatzeko aukera" + "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Wifi-gunearen eta konexioa partekatzeko eginbidearen egoera" + + + + + diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index bc2ee23609..2e21c85fa1 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -1,8 +1,29 @@ + + - "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" - "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" - "برای جزئیات، با سرپرستتان تماس بگیرید" + "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" + "برای راه‌اندازی ضربه بزنید." + "اشتراک‌گذاری اینترنت غیرفعال است" + "برای جزئیات، با سرپرستتان تماس بگیرید" + "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" + + + + + diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index ff0fca6502..413db3f0f8 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -1,8 +1,29 @@ + + - "Internetin jakaminen tai yhteyspiste käytössä" - "Määritä napauttamalla." - "Yhteyden jakaminen poistettu käytöstä" - "Kysy lisätietoja järjestelmänvalvojalta." + "Yhteyden jakaminen tai hotspot käytössä" + "Ota käyttöön napauttamalla." + "Yhteyden jakaminen on poistettu käytöstä" + "Pyydä lisätietoja järjestelmänvalvojalta" + "Hotspotin ja yhteyden jakamisen tila" + + + + + diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 1f5df0ee0c..eb2e4ba540 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -1,8 +1,29 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Touchez pour configurer." - "Le partage de connexion est désactivé" - "Communiquez avec votre administrateur pour obtenir plus de détails" + "Partage de connexion ou point d\'accès sans fil activé" + "Touchez pour configurer." + "Le partage de connexion est désactivé" + "Communiquez avec votre administrateur pour obtenir plus de détails" + "Point d\'accès et partage de connexion" + + + + + diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index daf7c9d830..22259c52ab 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -1,8 +1,29 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Appuyez ici pour configurer." - "Le partage de connexion est désactivé" - "Pour en savoir plus, contactez votre administrateur" + "Partage de connexion ou point d\'accès activé" + "Appuyez pour effectuer la configuration." + "Le partage de connexion est désactivé" + "Pour en savoir plus, contactez votre administrateur" + "État du point d\'accès et du partage de connexion" + + + + + diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 0d16a1de09..ded82fcd54 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -1,8 +1,29 @@ + + - "Conexión compartida ou zona wifi activada" - "Tocar para configurar." - "A conexión compartida está desactivada" - "Contacta co administrador para obter información" + "Conexión compartida ou zona wifi activada" + "Toca para configurar." + "A conexión compartida está desactivada" + "Contacta co administrador para obter información" + "Estado da zona wifi e da conexión compartida" + + + + + diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index 9d6b02f85f..7cbbc2de3d 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -1,8 +1,29 @@ + + - "ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય" - "સેટ કરવા માટે ટૅપ કરો." - "ટિથરિંગ અક્ષમ કરેલ છે" - "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" + "સેટઅપ કરવા માટે ટૅપ કરો." + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" + "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" + + + + + diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index 9c29d9a8f9..08af81b826 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -1,8 +1,29 @@ + + - "टेदरिंग या हॉटस्‍पॉट सक्रिय" - "सेट करने के लिए टैप करें." - "टेदरिंग अक्षम है" - "जानकारी के लिए अपने एडमिन से संपर्क करें" + "टेदरिंग या हॉटस्पॉट चालू है" + "सेट अप करने के लिए टैप करें." + "टेदरिंग बंद है" + "जानकारी के लिए अपने एडमिन से संपर्क करें" + "हॉटस्पॉट और टेदरिंग की स्थिति" + + + + + diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index d0d25bb755..827c135f20 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -1,8 +1,29 @@ + + - "Ograničenje ili aktivan hotspot" - "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" - "Obratite se administratoru da biste saznali pojedinosti" + "Modemsko povezivanje ili žarišna točka aktivni" + "Dodirnite da biste postavili." + "Modemsko je povezivanje onemogućeno" + "Obratite se administratoru da biste saznali pojedinosti" + "Status žarišne točke i modemskog povezivanja" + + + + + diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index 3129659923..eb68d6babf 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -1,8 +1,29 @@ + + - "Megosztás vagy aktív hotspot" - "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" - "A részletekért forduljon rendszergazdájához" + "Megosztás vagy aktív hotspot" + "Koppintson a beállításhoz." + "Az internetmegosztás le van tiltva" + "A részletekért forduljon rendszergazdájához" + "Hotspot és internetmegosztás állapota" + + + + + diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index 8ba6435fd5..912941e538 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -1,8 +1,29 @@ + + - "Մոդեմի ռեժիմը միացված է" - "Հպեք՝ կարգավորելու համար:" - "Մոդեմի ռեժիմն անջատված է" - "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Մոդեմի ռեժիմը միացված է" + "Հպեք՝ կարգավորելու համար։" + "Մոդեմի ռեժիմն անջատված է" + "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" + + + + + diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 1e093ab237..a4e175a439 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering (Penambatan) atau hotspot aktif" - "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" - "Hubungi admin untuk mengetahui detailnya" + "Tethering atau hotspot aktif" + "Ketuk untuk menyiapkan." + "Tethering dinonaktifkan" + "Hubungi admin untuk mengetahui detailnya" + "Status hotspot & tethering" + + + + + diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index f5769d5344..e9f6670bcd 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -1,8 +1,29 @@ + + - "Kveikt á tjóðrun eða aðgangsstað" - "Ýttu til að setja upp." - "Slökkt er á tjóðrun" - "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Kveikt á tjóðrun eða aðgangsstað" + "Ýttu til að setja upp." + "Slökkt er á tjóðrun" + "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Staða heits reits og tjóðrunar" + + + + + diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index e0b3724325..ffb9196f5e 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering oppure hotspot attivo" - "Tocca per impostare." - "Tethering disattivato" - "Contatta il tuo amministratore per avere informazioni dettagliate" + "Hotspot o tethering attivo" + "Tocca per impostare." + "Tethering disattivato" + "Contatta il tuo amministratore per avere informazioni dettagliate" + "Stato hotspot e tethering" + + + + + diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c002c44b23..7adcb47350 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -1,8 +1,29 @@ + + - "שיתוף אינטרנט פעיל" - "הקש כדי להגדיר." - "שיתוף האינטרנט בין ניידים מושבת" - "לפרטים, יש לפנות למנהל המערכת" + "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" + "יש להקיש כדי להגדיר." + "שיתוף האינטרנט בין מכשירים מושבת" + "לפרטים, יש לפנות למנהל המערכת" + "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" + + + + + diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index 314bde00df..f68a73010b 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -1,8 +1,29 @@ + + - "テザリングまたはアクセスポイントが有効です" - "タップしてセットアップします。" - "テザリングは無効に設定されています" - "詳しくは、管理者にお問い合わせください" + "テザリングまたはアクセス ポイントが有効です" + "タップしてセットアップします。" + "テザリングは無効に設定されています" + "詳しくは、管理者にお問い合わせください" + "アクセス ポイントとテザリングのステータス" + + + + + diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 7bbd81d343..7c22e82bd3 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -1,8 +1,29 @@ + + - "ტეტერინგი ან უსადენო ქსელი აქტიურია" - "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" - "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "ტეტერინგი ან უსადენო ქსელი აქტიურია" + "შეეხეთ დასაყენებლად." + "ტეტერინგი გათიშულია" + "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "უსადენო ქსელის და ტეტერინგის სტატუსი" + + + + + diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 7fd87a1596..0857d06de2 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -1,8 +1,29 @@ + + - "Тетеринг немесе хотспот қосулы" - "Реттеу үшін түртіңіз." - "Тетеринг өшірілді" - "Мәліметтерді әкімшіден алыңыз" + "Тетеринг немесе хотспот қосулы" + "Реттеу үшін түртіңіз." + "Тетеринг өшірілді." + "Мәліметтерді әкімшіден алыңыз." + "Хотспот және тетеринг күйі" + + + + + diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 2f85224679..536e3d1703 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -1,8 +1,29 @@ + + - "ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម" - "ប៉ះដើម្បីកំណត់" - "ការភ្ជាប់​ត្រូវបានបិទ" - "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត" + "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" + "ចុច​ដើម្បី​រៀបចំ។" + "ការភ្ជាប់​ត្រូវបានបិទ" + "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" + "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" + + + + + diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index f11a83ea40..32f54926f4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -1,8 +1,29 @@ + + - "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" - "ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" - "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" + "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." + "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" + "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" + + + + + diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index 57f24f5b1a..156b24786d 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -1,8 +1,29 @@ + + - "테더링 또는 핫스팟 사용" - "설정하려면 탭하세요." - "테더링이 사용 중지됨" - "자세한 정보는 관리자에게 문의하세요." + "테더링 또는 핫스팟 사용" + "설정하려면 탭하세요." + "테더링이 사용 중지됨" + "자세한 정보는 관리자에게 문의하세요." + "핫스팟 및 테더링 상태" + + + + + diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 79854859d4..18ee5fd357 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -1,8 +1,29 @@ + + - "Жалгаштыруу же хотспот жандырылган" - "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" - "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Модем режими күйүп турат" + "Жөндөө үчүн таптап коюңуз." + "Телефонду модем катары колдонууга болбойт" + "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Байланыш түйүнүнүн жана модем режиминин статусу" + + + + + diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index 78f1585f60..b12767018c 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -1,8 +1,29 @@ + + - "ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ" - "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" - "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" + "ແຕະເພື່ອຕັ້ງຄ່າ." + "ການປ່ອຍສັນຍານຖືກປິດໄວ້" + "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" + + + + + diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index ebff8ac9d1..8427baf39f 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -1,8 +1,29 @@ + + - "Susietas ar aktyvus" - "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" - "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" + "Palieskite, kad nustatytumėte." + "Įrenginio kaip modemo naudojimas išjungtas" + "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" + + + + + diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index 54d0048b52..aa2d6990e0 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -1,8 +1,29 @@ + + - "Piesaiste vai tīklājs ir aktīvs." - "Pieskarieties, lai iestatītu." - "Piesaiste ir atspējota" - "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Piesaiste vai tīklājs ir aktīvs." + "Pieskarieties, lai to iestatītu." + "Piesaiste ir atspējota" + "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Tīklāja un piesaistes statuss" + + + + + diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml new file mode 100644 index 0000000000..19d659c6ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -0,0 +1,24 @@ + + + + + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" + "Bykomende heffings kan geld terwyl jy swerf" + diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml new file mode 100644 index 0000000000..8995430b4f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -0,0 +1,24 @@ + + + + + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml new file mode 100644 index 0000000000..54f3b5389a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -0,0 +1,24 @@ + + + + + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." + diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml new file mode 100644 index 0000000000..e215141c9e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -0,0 +1,24 @@ + + + + + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml new file mode 100644 index 0000000000..1fd8e4c963 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..1abe4f3aa3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" + "Možda važe dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml new file mode 100644 index 0000000000..38dbd1e391 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -0,0 +1,24 @@ + + + + + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml new file mode 100644 index 0000000000..04b44db5c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml new file mode 100644 index 0000000000..579d1be1c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -0,0 +1,24 @@ + + + + + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" + diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml new file mode 100644 index 0000000000..9ce3efe6c3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml new file mode 100644 index 0000000000..46d4c35b9b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -0,0 +1,24 @@ + + + + + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" + "És possible que s\'apliquin costos addicionals en itinerància" + diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml new file mode 100644 index 0000000000..cc13860b3d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" + "Při roamingu mohou být účtovány dodatečné poplatky" + diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml new file mode 100644 index 0000000000..92c3ae1156 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -0,0 +1,24 @@ + + + + + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml new file mode 100644 index 0000000000..967eb4db2e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml new file mode 100644 index 0000000000..5fb497451f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -0,0 +1,24 @@ + + + + + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml new file mode 100644 index 0000000000..7877074afc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -0,0 +1,24 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml new file mode 100644 index 0000000000..08edd81a6b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml new file mode 100644 index 0000000000..79f51d00e2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" + "Puede que se apliquen cargos adicionales en itinerancia" + diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml new file mode 100644 index 0000000000..2da5f8a6d6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -0,0 +1,24 @@ + + + + + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" + "Rändluse kasutamisega võivad kaasneda lisatasud" + diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml new file mode 100644 index 0000000000..2073f2806c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" + diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml new file mode 100644 index 0000000000..e21b2a0852 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -0,0 +1,24 @@ + + + + + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml new file mode 100644 index 0000000000..88b0b13eb4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" + "Roaming voi aiheuttaa lisämaksuja" + diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml new file mode 100644 index 0000000000..3b781bc8db --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml new file mode 100644 index 0000000000..51d7203c36 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml new file mode 100644 index 0000000000..008ccb475d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -0,0 +1,24 @@ + + + + + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" + "Pódense aplicar cargos adicionais en itinerancia" + diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml new file mode 100644 index 0000000000..f2e3b4df78 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -0,0 +1,24 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" + diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml new file mode 100644 index 0000000000..b11839d760 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml new file mode 100644 index 0000000000..0a5aca25b1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" + "U roamingu su mogući dodatni troškovi" + diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml new file mode 100644 index 0000000000..21c689a44e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" + "Roaming során további díjak léphetnek fel" + diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml new file mode 100644 index 0000000000..689d92870e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -0,0 +1,24 @@ + + + + + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml new file mode 100644 index 0000000000..a5f4d19abf --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" + "Biaya tambahan mungkin berlaku saat roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml new file mode 100644 index 0000000000..fc7e8aaf4e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" + "Viðbótargjöld kunna að eiga við í reiki" + diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml new file mode 100644 index 0000000000..6456dd1b80 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml new file mode 100644 index 0000000000..46b24bd3c5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -0,0 +1,24 @@ + + + + + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml new file mode 100644 index 0000000000..e6eb277b90 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -0,0 +1,24 @@ + + + + + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" + "ローミング時に追加料金が発生することがあります" + diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml new file mode 100644 index 0000000000..aeddd7101d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -0,0 +1,24 @@ + + + + + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml new file mode 100644 index 0000000000..255f0a276f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml new file mode 100644 index 0000000000..2bceb1cf77 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -0,0 +1,24 @@ + + + + + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml new file mode 100644 index 0000000000..ed769305a6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -0,0 +1,24 @@ + + + + + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" + diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml new file mode 100644 index 0000000000..6e504941eb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -0,0 +1,24 @@ + + + + + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml new file mode 100644 index 0000000000..d68128b9a5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml new file mode 100644 index 0000000000..03e134a0fc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -0,0 +1,24 @@ + + + + + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" + diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml new file mode 100644 index 0000000000..652cedc6e6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml new file mode 100644 index 0000000000..221972298c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml new file mode 100644 index 0000000000..227f9e3466 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" + "При роаминг може да се наплатат дополнителни трошоци" + diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml new file mode 100644 index 0000000000..ec43885126 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -0,0 +1,24 @@ + + + + + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" + diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml new file mode 100644 index 0000000000..e263573799 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml new file mode 100644 index 0000000000..adf845d078 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml new file mode 100644 index 0000000000..f65c451e4c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -0,0 +1,24 @@ + + + + + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml new file mode 100644 index 0000000000..4118e775cd --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -0,0 +1,24 @@ + + + + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml new file mode 100644 index 0000000000..36853583ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" + "Ytterligere kostnader kan påløpe under roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml new file mode 100644 index 0000000000..d074f15699 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" + diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml new file mode 100644 index 0000000000..1d888942f4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml new file mode 100644 index 0000000000..8038815fe8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -0,0 +1,24 @@ + + + + + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" + diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml new file mode 100644 index 0000000000..819833eab0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -0,0 +1,24 @@ + + + + + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" + diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml new file mode 100644 index 0000000000..65e4380e39 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml new file mode 100644 index 0000000000..d8866170c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml new file mode 100644 index 0000000000..bfd45ca0a3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -0,0 +1,24 @@ + + + + + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" + "Podem aplicar-se custos adicionais em roaming." + diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml new file mode 100644 index 0000000000..d8866170c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml new file mode 100644 index 0000000000..8d87a9e516 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -0,0 +1,24 @@ + + + + + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" + "Se pot aplica taxe suplimentare pentru roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml new file mode 100644 index 0000000000..dbdb9ebe49 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -0,0 +1,24 @@ + + + + + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml new file mode 100644 index 0000000000..d8301e41c2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -0,0 +1,24 @@ + + + + + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml new file mode 100644 index 0000000000..bef71363f4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml new file mode 100644 index 0000000000..3202c62e8a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml new file mode 100644 index 0000000000..37f6ad2868 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml new file mode 100644 index 0000000000..5566d03ed1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" + "Можда важе додатни трошкови у ромингу" + diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml new file mode 100644 index 0000000000..9765acd0cf --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" + "Ytterligare avgifter kan tillkomma vid roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml new file mode 100644 index 0000000000..cf850c9cd2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -0,0 +1,24 @@ + + + + + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml new file mode 100644 index 0000000000..f4b15aab19 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -0,0 +1,24 @@ + + + + + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" + diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml new file mode 100644 index 0000000000..937d34d520 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -0,0 +1,24 @@ + + + + + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" + diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml new file mode 100644 index 0000000000..f781fae525 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -0,0 +1,24 @@ + + + + + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml new file mode 100644 index 0000000000..8d5d465373 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml new file mode 100644 index 0000000000..80cab33ac0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml new file mode 100644 index 0000000000..c05932a5ae --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" + "У роумінгу може стягуватися додаткова плата" + diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml new file mode 100644 index 0000000000..d820eee8ba --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -0,0 +1,24 @@ + + + + + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml new file mode 100644 index 0000000000..726148aaee --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" + diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml new file mode 100644 index 0000000000..b7cb0456b6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml new file mode 100644 index 0000000000..af91afff9a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + + + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" + "漫游时可能会产生额外的费用" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml new file mode 100644 index 0000000000..28e6b80c01 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" + "漫遊時可能需要支付額外費用" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml new file mode 100644 index 0000000000..528a1e5292 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網路共用連上網際網路" + "裝置無法連線" + "關閉網路共用" + "無線基地台或網路共用已開啟" + "使用漫遊服務可能須支付額外費用" + diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml new file mode 100644 index 0000000000..11eb666219 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml new file mode 100644 index 0000000000..9bfa5317a9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -0,0 +1,24 @@ + + + + + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" + "Bykomende heffings kan geld terwyl jy swerf" + diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml new file mode 100644 index 0000000000..5949dfa776 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -0,0 +1,24 @@ + + + + + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml new file mode 100644 index 0000000000..8467f9b1f5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -0,0 +1,24 @@ + + + + + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." + diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml new file mode 100644 index 0000000000..9776bd89da --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -0,0 +1,24 @@ + + + + + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml new file mode 100644 index 0000000000..e6d3eaf9f0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..4c8a1df8ee --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" + "Možda važe dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml new file mode 100644 index 0000000000..edfa41e1ff --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -0,0 +1,24 @@ + + + + + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml new file mode 100644 index 0000000000..f56398196f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml new file mode 100644 index 0000000000..d8ecd2e988 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -0,0 +1,24 @@ + + + + + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" + diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml new file mode 100644 index 0000000000..b85fd5e285 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml new file mode 100644 index 0000000000..a3572151be --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -0,0 +1,24 @@ + + + + + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" + "És possible que s\'apliquin costos addicionals en itinerància" + diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml new file mode 100644 index 0000000000..91196be9e5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" + "Při roamingu mohou být účtovány dodatečné poplatky" + diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml new file mode 100644 index 0000000000..196890011d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -0,0 +1,24 @@ + + + + + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml new file mode 100644 index 0000000000..eb3f8c52c0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml new file mode 100644 index 0000000000..56c3d81b63 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -0,0 +1,24 @@ + + + + + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml new file mode 100644 index 0000000000..d3347aae20 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -0,0 +1,24 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml new file mode 100644 index 0000000000..2f0504f07d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml new file mode 100644 index 0000000000..2d8f882425 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" + "Puede que se apliquen cargos adicionales en itinerancia" + diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml new file mode 100644 index 0000000000..8493c47071 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -0,0 +1,24 @@ + + + + + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" + "Rändluse kasutamisega võivad kaasneda lisatasud" + diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml new file mode 100644 index 0000000000..33bccab3e8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" + diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml new file mode 100644 index 0000000000..cf8a0cc277 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -0,0 +1,24 @@ + + + + + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml new file mode 100644 index 0000000000..6a3ab806db --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" + "Roaming voi aiheuttaa lisämaksuja" + diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml new file mode 100644 index 0000000000..ffb9bf6047 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml new file mode 100644 index 0000000000..768bce3f0a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml new file mode 100644 index 0000000000..0c4195a7ca --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -0,0 +1,24 @@ + + + + + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" + "Pódense aplicar cargos adicionais en itinerancia" + diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml new file mode 100644 index 0000000000..e9d33a7db2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -0,0 +1,24 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" + diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml new file mode 100644 index 0000000000..aa418ac5d3 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml new file mode 100644 index 0000000000..51c524afbc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" + "U roamingu su mogući dodatni troškovi" + diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml new file mode 100644 index 0000000000..164e45edd1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" + "Roaming során további díjak léphetnek fel" + diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml new file mode 100644 index 0000000000..e76c0a4c80 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -0,0 +1,24 @@ + + + + + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml new file mode 100644 index 0000000000..2b817f8abd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" + "Biaya tambahan mungkin berlaku saat roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml new file mode 100644 index 0000000000..a338d9c7ca --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" + "Viðbótargjöld kunna að eiga við í reiki" + diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml new file mode 100644 index 0000000000..77769c2ac5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml new file mode 100644 index 0000000000..5267b51264 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -0,0 +1,24 @@ + + + + + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml new file mode 100644 index 0000000000..66a9a6dd35 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -0,0 +1,24 @@ + + + + + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" + "ローミング時に追加料金が発生することがあります" + diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml new file mode 100644 index 0000000000..d8ad880849 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -0,0 +1,24 @@ + + + + + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml new file mode 100644 index 0000000000..1ddd6b419b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml new file mode 100644 index 0000000000..cf5a1379cc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -0,0 +1,24 @@ + + + + + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml new file mode 100644 index 0000000000..68ae68bc19 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -0,0 +1,24 @@ + + + + + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" + diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml new file mode 100644 index 0000000000..17185ba2d0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -0,0 +1,24 @@ + + + + + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml new file mode 100644 index 0000000000..6a9fb9810c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml new file mode 100644 index 0000000000..bcc4b57626 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -0,0 +1,24 @@ + + + + + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" + diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml new file mode 100644 index 0000000000..011c2c11fb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml new file mode 100644 index 0000000000..5cb2f3b7aa --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml new file mode 100644 index 0000000000..4cbfd887c5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" + "При роаминг може да се наплатат дополнителни трошоци" + diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml new file mode 100644 index 0000000000..9cf4eaf34a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -0,0 +1,24 @@ + + + + + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" + diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml new file mode 100644 index 0000000000..47c82c14d9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml new file mode 100644 index 0000000000..ad9e809ab2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml new file mode 100644 index 0000000000..e708cb8717 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -0,0 +1,24 @@ + + + + + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml new file mode 100644 index 0000000000..ba5462250b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -0,0 +1,24 @@ + + + + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml new file mode 100644 index 0000000000..57db484a25 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" + "Ytterligere kostnader kan påløpe under roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml new file mode 100644 index 0000000000..1503244f50 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" + diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml new file mode 100644 index 0000000000..b08133f4e5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml new file mode 100644 index 0000000000..1ad4ca354a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -0,0 +1,24 @@ + + + + + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" + diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml new file mode 100644 index 0000000000..88def563d8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -0,0 +1,24 @@ + + + + + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" + diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml new file mode 100644 index 0000000000..f9890abdc2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml new file mode 100644 index 0000000000..ce3b88479f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml new file mode 100644 index 0000000000..7e883ea576 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -0,0 +1,24 @@ + + + + + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" + "Podem aplicar-se custos adicionais em roaming." + diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml new file mode 100644 index 0000000000..ce3b88479f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml new file mode 100644 index 0000000000..1009417316 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -0,0 +1,24 @@ + + + + + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" + "Se pot aplica taxe suplimentare pentru roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml new file mode 100644 index 0000000000..88683bed95 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -0,0 +1,24 @@ + + + + + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml new file mode 100644 index 0000000000..176bcdb797 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -0,0 +1,24 @@ + + + + + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml new file mode 100644 index 0000000000..b9e2127fa8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml new file mode 100644 index 0000000000..e8140e686a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml new file mode 100644 index 0000000000..61e698d6e8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml new file mode 100644 index 0000000000..b4c411c354 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" + "Можда важе додатни трошкови у ромингу" + diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml new file mode 100644 index 0000000000..4f543e47b9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" + "Ytterligare avgifter kan tillkomma vid roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml new file mode 100644 index 0000000000..ac347ab485 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -0,0 +1,24 @@ + + + + + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml new file mode 100644 index 0000000000..2ea2467e58 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -0,0 +1,24 @@ + + + + + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" + diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml new file mode 100644 index 0000000000..9360297dd8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -0,0 +1,24 @@ + + + + + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" + diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml new file mode 100644 index 0000000000..9c4d7e08f2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -0,0 +1,24 @@ + + + + + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml new file mode 100644 index 0000000000..a7c78a5932 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml new file mode 100644 index 0000000000..93da2c3f79 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml new file mode 100644 index 0000000000..ee0dcd2c4b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" + "У роумінгу може стягуватися додаткова плата" + diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml new file mode 100644 index 0000000000..41cd28eef9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -0,0 +1,24 @@ + + + + + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml new file mode 100644 index 0000000000..c847bc943b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" + diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml new file mode 100644 index 0000000000..a74326f09e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml new file mode 100644 index 0000000000..d7370036e3 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + + + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" + "漫游时可能会产生额外的费用" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml new file mode 100644 index 0000000000..f378a9dc2c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" + "漫遊時可能需要支付額外費用" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml new file mode 100644 index 0000000000..cd653df1da --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網路共用連上網際網路" + "裝置無法連線" + "關閉網路共用" + "無線基地台或網路共用已開啟" + "使用漫遊服務可能須支付額外費用" + diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml new file mode 100644 index 0000000000..32f6df56f1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 0fab8aa476..9ad9b9a589 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -1,8 +1,29 @@ + + - "Поврзувањето или точката на пристап се активни" - "Допрете за поставување." - "Врзувањето е оневозможено" - "Контактирајте со администраторот за детали" + "Активно е врзување или точка на пристап" + "Допрете за поставување." + "Врзувањето е оневозможено" + "Контактирајте со администраторот за детали" + "Статус на точката на пристап и врзувањето" + + + + + diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index fd7e556e38..9db79ce220 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -1,8 +1,29 @@ + + - "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" - "സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" - "വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" + "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." + "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" + "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" + + + + + diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4596577c5d..42d1edbace 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -1,8 +1,29 @@ + + - "Модем болгох эсвэл идэвхтэй цэг болгох" - "Тохируулахын тулд товшино уу." - "Модем болгох боломжгүй байна" - "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" + "Тохируулахын тулд товшино уу." + "Модем болгохыг идэвхгүй болгосон" + "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Сүлжээний цэг болон модем болгох төлөв" + + + + + diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index 85c9ade4fe..13995b6b8a 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -1,8 +1,29 @@ + + - "टेदरिंग किंवा हॉटस्पॉट सक्रिय" - "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद आहे" - "तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा" + "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" + "सेट करण्यासाठी टॅप करा." + "टेदरिंग बंद केले आहे" + "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" + "हॉटस्पॉट आणि टेदरिंगची स्थिती" + + + + + diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index ec6bdbda08..d6a67f37b1 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -1,8 +1,29 @@ + + - "Penambatan atau titik panas aktif" - "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" - "Hubungi pentadbir anda untuk maklumat lanjut" + "Penambatan atau tempat liputan aktif" + "Ketik untuk membuat persediaan." + "Penambatan dilumpuhkan" + "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" + "Status tempat liputan & penambatan" + + + + + diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 83978b67d4..49f6b88a75 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -1,8 +1,29 @@ + + - "တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" - "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်" - "အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" + "စနစ်ထည့်သွင်းရန် တို့ပါ။" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" + "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" + + + + + diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 9abf32dd7b..9594e0a70a 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -1,8 +1,29 @@ + + - "Internettdeling eller trådløs sone er aktiv" - "Trykk for å konfigurere." - "Internettdeling er slått av" - "Ta kontakt med administratoren din for å få mer informasjon" + "Internettdeling eller Wi-Fi-sone er aktiv" + "Trykk for å konfigurere." + "Internettdeling er slått av" + "Ta kontakt med administratoren din for å få mer informasjon" + "Status for Wi-Fi-sone og internettdeling" + + + + + diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index c8869298a5..72ae3a80a9 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -1,8 +1,29 @@ + + - "टेथर गर्ने वा हटस्पट सक्रिय" - "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङलाई असक्षम पारिएको छ" - "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "टेदरिङ वा हटस्पट सक्रिय छ" + "सेटअप गर्न ट्याप गर्नुहोस्।" + "टेदरिङ सुविधा असक्षम पारिएको छ" + "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "हटस्पट तथा टेदरिङको स्थिति" + + + + + diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 0ec4bff621..18b2bbfc76 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering of hotspot actief" - "Tik om in te stellen." - "Tethering is uitgeschakeld" - "Neem contact op met je beheerder voor meer informatie" + "Tethering of hotspot actief" + "Tik om in te stellen." + "Tethering is uitgeschakeld" + "Neem contact op met je beheerder voor meer informatie" + "Status van hotspot en tethering" + + + + + diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 457685795a..a15a6db42a 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -1,8 +1,29 @@ + + - "ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି" - "ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।" - "ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି" - "ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" + "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" + "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" + "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" + + + + + diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index deddf2ea27..a8235e423e 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -1,8 +1,29 @@ + + - "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" - "ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ" - "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ" + "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" + "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" + "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" + "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" + + + + + diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index 48d8468935..ccb017d43f 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -1,8 +1,29 @@ + + - "Aktywny tethering lub punkt dostępu" - "Kliknij, by skonfigurować." - "Tethering został wyłączony" - "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Aktywny tethering lub punkt dostępu" + "Kliknij, by skonfigurować" + "Tethering został wyłączony" + "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Hotspot i tethering – stan" + + + + + diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 32c22b8713..a0a4745f93 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -1,8 +1,29 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 641e22f44f..e3f03fcc69 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -1,8 +1,29 @@ + + - "Ligação ponto a ponto ou hotspot activos" - "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." - "Contacte o gestor para obter detalhes." + "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" + "Toque para configurar." + "A ligação (à Internet) via telemóvel está desativada." + "Contacte o administrador para obter detalhes." + "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" + + + + + diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 32c22b8713..a0a4745f93 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -1,8 +1,29 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index f861f733b4..5706a4a69c 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering sau hotspot activ" - "Atingeți ca să configurați." - "Tetheringul este dezactivat" - "Contactați administratorul pentru detalii" + "Tethering sau hotspot activ" + "Atingeți ca să configurați." + "Tetheringul este dezactivat" + "Contactați administratorul pentru detalii" + "Starea hotspotului și a tetheringului" + + + + + diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 027cb410c5..7cb6f7db3f 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -1,8 +1,29 @@ + + - "Включен режим модема" - "Нажмите, чтобы настроить." - "Включить режим модема нельзя" - "Обратитесь к администратору, чтобы узнать подробности." + "Включен режим модема или точка доступа" + "Нажмите, чтобы настроить." + "Использование телефона в качестве модема запрещено" + "Чтобы узнать подробности, обратитесь к администратору." + "Статус хот-спота и режима модема" + + + + + diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index 7d8599f2c2..ec34c22de7 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -1,8 +1,29 @@ + + - "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" - "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" - "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" + "පිහිටුවීමට තට්ටු කරන්න." + "ටෙදරින් අබල කර ඇත" + "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" + + + + + diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index a8fe297c00..43e787c84f 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering alebo prístupový bod je aktívny" - "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" - "O podrobnosti požiadajte svojho správcu" + "Tethering alebo prístupový bod je aktívny" + "Klepnutím prejdete na nastavenie." + "Tethering je deaktivovaný" + "O podrobnosti požiadajte svojho správcu" + "Stav hotspotu a tetheringu" + + + + + diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index b5e5e3856f..59433626a1 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -1,8 +1,29 @@ + + - "Aktivna povezava z internetom ali dostopna točka sta aktivni" - "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" - "Za podrobnosti se obrnite na skrbnika" + "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" + "Dotaknite se, če želite nastaviti." + "Povezava z internetom prek mobilnega telefona je onemogočena" + "Za podrobnosti se obrnite na skrbnika" + "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" + + + + + diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index fdd4906cc5..21e11558bb 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -1,8 +1,29 @@ + + - "Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive" - "Trokit për ta konfiguruar." - "Lidhja e çiftimit është çaktivizuar" - "Kontakto me administratorin për detaje" + "Ndarja e internetit ose zona e qasjes së internetit është aktive" + "Trokit për ta konfiguruar." + "Ndarja e internetit është çaktivizuar" + "Kontakto me administratorin për detaje" + "Statusi i zonës së qasjes dhe ndarjes së internetit" + + + + + diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index 9fab345897..e2e4dc6361 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -1,8 +1,29 @@ + + - "Активно повезивање са интернетом преко мобилног уређаја или хотспот" - "Додирните да бисте подесили." - "Привезивање је онемогућено" - "Потражите детаље од администратора" + "Привезивање или хотспот је активан" + "Додирните да бисте подесили." + "Привезивање је онемогућено" + "Потражите детаље од администратора" + "Статус хотспота и привезивања" + + + + + diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index 10eeb0fe12..72702c2858 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -1,8 +1,29 @@ + + - "Internetdelning eller surfzon aktiverad" - "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" - "Kontakta administratören om du vill veta mer" + "Internetdelning eller surfzon har aktiverats" + "Tryck om du vill konfigurera." + "Internetdelning har inaktiverats" + "Kontakta administratören om du vill veta mer" + "Trådlös surfzon och internetdelning har inaktiverats" + + + + + diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index 3353963077..65e4aa8ceb 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -1,8 +1,29 @@ + + - "Kushiriki au kusambaza intaneti kumewashwa" - "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" - "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Kusambaza mtandao au mtandaopepe umewashwa" + "Gusa ili uweke mipangilio." + "Umezima kipengele cha kusambaza mtandao" + "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Mtandaopepe na hali ya kusambaza mtandao" + + + + + diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index b1e5cc2413..4aba62d4ab 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -1,8 +1,29 @@ + + - "டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது" - "அமைக்க, தட்டவும்." - "இணைப்பு முறை முடக்கப்பட்டுள்ளது" - "விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" + "அமைக்க, தட்டவும்." + "டெதெரிங் முடக்கப்பட்டுள்ளது" + "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" + + + + + diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index aae40dee40..1f91791341 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -1,8 +1,29 @@ + + - "టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది" - "సెటప్ చేయడానికి నొక్కండి." - "టెథెరింగ్ నిలిపివేయబడింది" - "వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి" + "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" + "సెటప్ చేయడానికి ట్యాప్ చేయండి." + "టెథరింగ్ డిజేబుల్ చేయబడింది" + "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" + "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" + + + + + diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index 1b800565ad..44171c0db8 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -1,8 +1,29 @@ + + - "การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่" - "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" - "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" + "แตะเพื่อตั้งค่า" + "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" + "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + + + + + diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 12863f90e1..7347dd3e62 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -1,8 +1,29 @@ + + - "Pagsasama o aktibong hotspot" - "I-tap upang i-set up." - "Naka-disable ang pag-tether" - "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Aktibo ang pag-tether o hotspot" + "I-tap para i-set up." + "Naka-disable ang pag-tether" + "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Status ng hotspot at pag-tether" + + + + + diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index bfcf1ace2c..32030f1765 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering veya hotspot etkin" - "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" - "Ayrıntılı bilgi için yöneticinize başvurun" + "Tethering veya hotspot etkin" + "Ayarlamak için dokunun." + "Tethering devre dışı bırakıldı" + "Ayrıntılı bilgi için yöneticinize başvurun" + "Hotspot ve tethering durumu" + + + + + diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 8e159c0723..1ca89b3f78 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -1,8 +1,29 @@ + + - "Прив\'язка чи точка дост. активна" - "Торкніться, щоб налаштувати." - "Використання телефона в режимі модема вимкнено" - "Щоб дізнатися більше, зв’яжіться з адміністратором" + "Модем чи точка доступу активні" + "Натисніть, щоб налаштувати." + "Використання телефона як модема вимкнено" + "Щоб дізнатися більше, зв\'яжіться з адміністратором" + "Статус точки доступу та модема" + + + + + diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 89195d4aae..d72c7d4195 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -1,8 +1,29 @@ + + - "ٹیدرنگ یا ہاٹ اسپاٹ فعال" - "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" - "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ٹیدرنگ یا ہاٹ اسپاٹ فعال" + "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" + "ٹیدرنگ غیر فعال ہے" + "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" + + + + + diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 0ac4d4a741..af3b2ebb35 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -1,8 +1,29 @@ + + - "Modem rejimi yoniq" - "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" - "Tafsilotlari uchun administratoringizga murojaat qiling" + "Modem rejimi yoki hotspot yoniq" + "Sozlash uchun bosing." + "Modem rejimi faolsizlantirildi" + "Tafsilotlari uchun administratoringizga murojaat qiling" + "Hotspot va modem rejimi holati" + + + + + diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 85a4db8aa5..21a0735922 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -1,8 +1,29 @@ + + - "Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động" - "Nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" - "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" + "Hãy nhấn để thiết lập." + "Đã tắt tính năng chia sẻ Internet" + "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Trạng thái điểm phát sóng và chia sẻ Internet" + + + + + diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index ff1fe03953..98e3b4b46f 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -1,8 +1,29 @@ + + - "网络共享或热点已启用" - "点按即可进行设置。" - "网络共享已停用" - "请与您的管理员联系以了解详情" + "网络共享或热点已启用" + "点按即可设置。" + "网络共享已停用" + "如需了解详情,请与您的管理员联系" + "热点和网络共享状态" + + + + + diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 0de39fac97..9cafd42dd4 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -1,8 +1,29 @@ + + - "已啟用網絡共享或熱點" - "輕按即可設定。" - "網絡共享已停用" - "請聯絡您的管理員以瞭解詳情" + "網絡共享或熱點已啟用" + "輕按即可設定。" + "網絡共享已停用" + "請聯絡您的管理員以瞭解詳情" + "熱點和網絡共享狀態" + + + + + diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9a117bbca4..50a50bf7a9 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -1,8 +1,29 @@ + + - "網路共用或無線基地台已啟用" - "輕觸即可進行設定。" - "數據連線已停用" - "詳情請洽你的管理員" + "網路共用或無線基地台已啟用" + "輕觸即可進行設定。" + "網路共用已停用" + "詳情請洽你的管理員" + "無線基地台與網路共用狀態" + + + + + diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index 8fe10d86cb..f210f8726e 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -1,8 +1,29 @@ + + - "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" - "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" - "Xhumana nomphathi wakho ukuze uthole imininingwane" + "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" + "Thepha ukuze usethe." + "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" + "Xhumana nomphathi wakho ukuze uthole imininingwane" + "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" + + + + + From 2adde431b6898fb22b16c98fdbc4afd0f20b89db Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 5 Sep 2020 21:39:23 -0700 Subject: [PATCH 1290/1415] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I729ec6ac98a95690838697c28220b11b0f1b0399 --- Tethering/res/values-af/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-am/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ar/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-as/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-az/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-b+sr+Latn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-be/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bg/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-bs/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ca/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-cs/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-da/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-de/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-el/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rAU/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rCA/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rGB/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rIN/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-en-rXC/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-es-rUS/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-es/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-et/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-eu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fa/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fr-rCA/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-fr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-gl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-gu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hu/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-hy/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-in/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-is/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-it/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-iw/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ja/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ka/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-kk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-km/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-kn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ko/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ky/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lo/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lt/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-lv/strings.xml | 29 ++++++++++++++++--- .../res/values-mcc310-mnc004-af/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-am/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ar/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-as/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-az/strings.xml | 24 +++++++++++++++ .../strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-be/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bg/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-bs/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ca/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-cs/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-da/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-de/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-el/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rAU/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rCA/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rGB/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rIN/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-en-rXC/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-es-rUS/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-es/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-et/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-eu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fa/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fi/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-fr-rCA/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-fr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-gl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-gu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hi/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hu/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-hy/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-in/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-is/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-it/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-iw/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ja/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ka/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-kk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-km/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-kn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ko/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ky/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lo/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lt/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-lv/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ml/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mn/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-mr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ms/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-my/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-nb/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ne/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-nl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-or/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pa/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pl/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-pt-rBR/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-pt-rPT/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-pt/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ro/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ru/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-si/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sq/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sv/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-sw/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ta/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-te/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-th/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-tl/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-tr/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-uk/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-ur/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-uz/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-vi/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rCN/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rHK/strings.xml | 24 +++++++++++++++ .../values-mcc310-mnc004-zh-rTW/strings.xml | 24 +++++++++++++++ .../res/values-mcc310-mnc004-zu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-af/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-am/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ar/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-as/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-az/strings.xml | 24 +++++++++++++++ .../strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-be/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bg/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-bs/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ca/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-cs/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-da/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-de/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-el/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rAU/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rCA/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rGB/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rIN/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-en-rXC/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-es-rUS/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-es/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-et/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-eu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fa/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fi/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-fr-rCA/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-fr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-gl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-gu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hi/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hu/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-hy/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-in/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-is/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-it/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-iw/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ja/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ka/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-kk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-km/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-kn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ko/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ky/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lo/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lt/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-lv/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ml/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mn/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-mr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ms/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-my/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-nb/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ne/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-nl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-or/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pa/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pl/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-pt-rBR/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-pt-rPT/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-pt/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ro/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ru/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-si/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sq/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sv/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-sw/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ta/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-te/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-th/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-tl/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-tr/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-uk/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-ur/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-uz/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-vi/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rCN/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rHK/strings.xml | 24 +++++++++++++++ .../values-mcc311-mnc480-zh-rTW/strings.xml | 24 +++++++++++++++ .../res/values-mcc311-mnc480-zu/strings.xml | 24 +++++++++++++++ Tethering/res/values-mk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ml/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-mn/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-mr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ms/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-my/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-nb/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ne/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-nl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-or/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pa/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt-rBR/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt-rPT/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-pt/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ro/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ru/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-si/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sq/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sv/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-sw/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ta/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-te/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-th/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-tl/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-tr/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-uk/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-ur/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-uz/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-vi/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rCN/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rHK/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zh-rTW/strings.xml | 29 ++++++++++++++++--- Tethering/res/values-zu/strings.xml | 29 ++++++++++++++++--- 255 files changed, 6205 insertions(+), 340 deletions(-) create mode 100644 Tethering/res/values-mcc310-mnc004-af/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-am/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ar/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-as/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-az/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-be/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bg/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-bs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ca/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-cs/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-da/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-de/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-el/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-es/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-et/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-eu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-fr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-gu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hu/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-hy/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-in/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-is/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-it/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-iw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ja/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ka/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-km/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-kn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ko/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ky/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lo/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-lv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ml/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mn/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-mr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ms/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-my/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nb/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ne/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-nl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-or/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pa/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-pt/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ro/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ru/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-si/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sq/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sv/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-sw/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ta/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-te/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-th/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tl/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-tr/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uk/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-ur/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-uz/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-vi/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc310-mnc004-zu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-af/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-am/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ar/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-as/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-az/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-be/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bg/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-bs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ca/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-cs/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-da/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-de/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-el/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-es/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-et/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-eu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-fr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-gu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hu/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-hy/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-in/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-is/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-it/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-iw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ja/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ka/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-km/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-kn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ko/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ky/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lo/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-lv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ml/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mn/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-mr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ms/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-my/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nb/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ne/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-nl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-or/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pa/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-pt/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ro/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ru/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-si/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sq/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sv/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-sw/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ta/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-te/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-th/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tl/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-tr/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uk/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-ur/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-uz/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-vi/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml create mode 100644 Tethering/res/values-mcc311-mnc480-zu/strings.xml diff --git a/Tethering/res/values-af/strings.xml b/Tethering/res/values-af/strings.xml index 1258805378..056168b12e 100644 --- a/Tethering/res/values-af/strings.xml +++ b/Tethering/res/values-af/strings.xml @@ -1,8 +1,29 @@ + + - "Verbinding of Wi-Fi-warmkol aktief" - "Tik om op te stel." - "Verbinding is gedeaktiveer" - "Kontak jou administrateur vir besonderhede" + "Verbinding of warmkol is aktief" + "Tik om op te stel." + "Verbinding is gedeaktiveer" + "Kontak jou administrateur vir besonderhede" + "Warmkol- en verbindingstatus" + + + + + diff --git a/Tethering/res/values-am/strings.xml b/Tethering/res/values-am/strings.xml index 9c36192257..ac468dd144 100644 --- a/Tethering/res/values-am/strings.xml +++ b/Tethering/res/values-am/strings.xml @@ -1,8 +1,29 @@ + + - "መሰካት ወይም ገባሪ ድረስ ነጥብ" - "ለማዋቀር መታ ያድርጉ።" - "እንደ ሞደም መሰካት ተሰናክሏል" - "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ" + "ለማዋቀር መታ ያድርጉ።" + "እንደ ሞደም መሰካት ተሰናክሏል" + "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ" + "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ" + + + + + diff --git a/Tethering/res/values-ar/strings.xml b/Tethering/res/values-ar/strings.xml index 9f84ce4090..7d5bad34da 100644 --- a/Tethering/res/values-ar/strings.xml +++ b/Tethering/res/values-ar/strings.xml @@ -1,8 +1,29 @@ + + - "النطاق أو نقطة الاتصال نشطة" - "انقر للإعداد." - "تم إيقاف التوصيل" - "اتصل بالمشرف للحصول على التفاصيل" + "النطاق نشط أو نقطة الاتصال نشطة" + "انقر للإعداد." + "التوصيل متوقف." + "تواصَل مع المشرف للحصول على التفاصيل." + "حالة نقطة الاتصال والتوصيل" + + + + + diff --git a/Tethering/res/values-as/strings.xml b/Tethering/res/values-as/strings.xml index 8855822e7c..091350455b 100644 --- a/Tethering/res/values-as/strings.xml +++ b/Tethering/res/values-as/strings.xml @@ -1,8 +1,29 @@ + + - "টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে" - "ছেট আপ কৰিবলৈ টিপক।" - "টেডাৰিং অক্ষম কৰি থোৱা হৈছে" - "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে" + "ছেট আপ কৰিবলৈ টিপক।" + "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে" + "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক" + "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি" + + + + + diff --git a/Tethering/res/values-az/strings.xml b/Tethering/res/values-az/strings.xml index eba50eb636..dce70da178 100644 --- a/Tethering/res/values-az/strings.xml +++ b/Tethering/res/values-az/strings.xml @@ -1,8 +1,29 @@ + + - "Tezerinq və ya hotspot aktivdir" - "Quraşdırmaq üçün tıklayın." - "Birləşmə deaktivdir" - "Məlumat üçün adminlə əlaqə saxlayın" + "Birləşmə və ya hotspot aktivdir" + "Ayarlamaq üçün toxunun." + "Birləşmə deaktivdir" + "Detallar üçün adminlə əlaqə saxlayın" + "Hotspot & birləşmə statusu" + + + + + diff --git a/Tethering/res/values-b+sr+Latn/strings.xml b/Tethering/res/values-b+sr+Latn/strings.xml index 5b0e488ba5..b0774ec9a8 100644 --- a/Tethering/res/values-b+sr+Latn/strings.xml +++ b/Tethering/res/values-b+sr+Latn/strings.xml @@ -1,8 +1,29 @@ + + - "Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot" - "Dodirnite da biste podesili." - "Privezivanje je onemogućeno" - "Potražite detalje od administratora" + "Privezivanje ili hotspot je aktivan" + "Dodirnite da biste podesili." + "Privezivanje je onemogućeno" + "Potražite detalje od administratora" + "Status hotspota i privezivanja" + + + + + diff --git a/Tethering/res/values-be/strings.xml b/Tethering/res/values-be/strings.xml index 5966c7155e..a8acebe2e9 100644 --- a/Tethering/res/values-be/strings.xml +++ b/Tethering/res/values-be/strings.xml @@ -1,8 +1,29 @@ + + - "USB-мадэм або хот-спот Wi-Fi актыўныя" - "Дакраніцеся, каб наладзіць." - "Рэжым мадэма адключаны" - "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Мадэм або хот-спот актыўныя" + "Дакраніцеся, каб наладзіць." + "Рэжым мадэма выключаны" + "Звярніцеся да адміністратара па падрабязную інфармацыю" + "Стан \"Хот-спот і мадэм\"" + + + + + diff --git a/Tethering/res/values-bg/strings.xml b/Tethering/res/values-bg/strings.xml index ed58d7311a..94fb2d8f17 100644 --- a/Tethering/res/values-bg/strings.xml +++ b/Tethering/res/values-bg/strings.xml @@ -1,8 +1,29 @@ + + - "Има активна споделена връзка или безжична точка за достъп" - "Докоснете, за да настроите." - "Функцията за тетъринг е деактивирана" - "Свържете се с администратора си за подробности" + "Има активна споделена връзка или точка за достъп" + "Докоснете, за да настроите." + "Функцията за тетъринг е деактивирана" + "Свържете се с администратора си за подробности" + "Състояние на функцията за точка за достъп и тетъринг" + + + + + diff --git a/Tethering/res/values-bn/strings.xml b/Tethering/res/values-bn/strings.xml index 8d9880aa9a..aea02b9ddf 100644 --- a/Tethering/res/values-bn/strings.xml +++ b/Tethering/res/values-bn/strings.xml @@ -1,8 +1,29 @@ + + - "টিথারিং বা হটস্পট সক্রিয় আছে" - "সেট-আপ করার জন্য আলতো চাপুন৷" - "টিথারিং অক্ষম করা আছে" - "বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন" + "টিথারিং বা হটস্পট চালু আছে" + "সেট-আপ করতে ট্যাপ করুন।" + "টিথারিং বন্ধ করা আছে" + "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন" + "হটস্পট ও টিথারিং স্ট্যাটাস" + + + + + diff --git a/Tethering/res/values-bs/strings.xml b/Tethering/res/values-bs/strings.xml index 2361b9dd38..de232724c5 100644 --- a/Tethering/res/values-bs/strings.xml +++ b/Tethering/res/values-bs/strings.xml @@ -1,8 +1,29 @@ + + - "Uređaj dijeli vezu ili djeluje kao pristupna tačka" - "Dodirnite za postavke" - "Povezivanje putem mobitela je onemogućeno" - "Kontaktirajte svog administratora za dodatne detalje" + "Aktivno je povezivanje putem mobitela ili pristupna tačka" + "Dodirnite da postavite." + "Povezivanje putem mobitela je onemogućeno" + "Kontaktirajte svog administratora za detalje" + "Status pristupne tačke i povezivanja putem mobitela" + + + + + diff --git a/Tethering/res/values-ca/strings.xml b/Tethering/res/values-ca/strings.xml index 6752b519e2..88b795c1f8 100644 --- a/Tethering/res/values-ca/strings.xml +++ b/Tethering/res/values-ca/strings.xml @@ -1,8 +1,29 @@ + + - "Compartició de xarxa o punt d\'accés Wi-Fi activat" - "Toca per configurar." - "La compartició de xarxa està desactivada" - "Contacta amb el teu administrador per obtenir més informació" + "Compartició de xarxa o punt d\'accés Wi‑Fi actius" + "Toca per configurar." + "La compartició de xarxa està desactivada" + "Contacta amb el teu administrador per obtenir més informació" + "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa" + + + + + diff --git a/Tethering/res/values-cs/strings.xml b/Tethering/res/values-cs/strings.xml index 5fdd53adf1..8c1b83bf3e 100644 --- a/Tethering/res/values-cs/strings.xml +++ b/Tethering/res/values-cs/strings.xml @@ -1,8 +1,29 @@ + + - "Sdílené připojení nebo hotspot je aktivní." - "Klepnutím zahájíte nastavení." - "Tethering je zakázán" - "O podrobnosti požádejte administrátora" + "Tethering nebo hotspot je aktivní" + "Klepnutím zahájíte nastavení." + "Tethering je zakázán" + "O podrobnosti požádejte administrátora" + "Stav hotspotu a tetheringu" + + + + + diff --git a/Tethering/res/values-da/strings.xml b/Tethering/res/values-da/strings.xml index 2775dfa551..f413e70548 100644 --- a/Tethering/res/values-da/strings.xml +++ b/Tethering/res/values-da/strings.xml @@ -1,8 +1,29 @@ + + - "Netdeling eller hotspot er aktivt" - "Tryk for at konfigurere" - "Netdeling er deaktiveret" - "Kontakt din administrator for at få oplysninger" + "Netdeling eller hotspot er aktivt" + "Tryk for at konfigurere." + "Netdeling er deaktiveret" + "Kontakt din administrator for at få oplysninger" + "Status for hotspot og netdeling" + + + + + diff --git a/Tethering/res/values-de/strings.xml b/Tethering/res/values-de/strings.xml index 9046cd5e11..f057d7824e 100644 --- a/Tethering/res/values-de/strings.xml +++ b/Tethering/res/values-de/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering oder Hotspot aktiv" - "Zum Einrichten tippen." - "Tethering ist deaktiviert" - "Bitte wende dich für weitere Informationen an den Administrator" + "Tethering oder Hotspot aktiv" + "Zum Einrichten tippen." + "Tethering ist deaktiviert" + "Bitte wende dich für weitere Informationen an den Administrator" + "Hotspot- und Tethering-Status" + + + + + diff --git a/Tethering/res/values-el/strings.xml b/Tethering/res/values-el/strings.xml index 3b9f53733b..b3c986bdaf 100644 --- a/Tethering/res/values-el/strings.xml +++ b/Tethering/res/values-el/strings.xml @@ -1,8 +1,29 @@ + + - "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" - "Πατήστε για ρύθμιση." - "Η σύνδεση είναι απενεργοποιημένη" - "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή" + "Πατήστε για ρύθμιση." + "Η σύνδεση είναι απενεργοποιημένη" + "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες" + "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης" + + + + + diff --git a/Tethering/res/values-en-rAU/strings.xml b/Tethering/res/values-en-rAU/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rAU/strings.xml +++ b/Tethering/res/values-en-rAU/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rCA/strings.xml b/Tethering/res/values-en-rCA/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rCA/strings.xml +++ b/Tethering/res/values-en-rCA/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rGB/strings.xml b/Tethering/res/values-en-rGB/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rGB/strings.xml +++ b/Tethering/res/values-en-rGB/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rIN/strings.xml b/Tethering/res/values-en-rIN/strings.xml index 56b88a5fb3..769e01208a 100644 --- a/Tethering/res/values-en-rIN/strings.xml +++ b/Tethering/res/values-en-rIN/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering or hotspot active" - "Tap to set up." - "Tethering is disabled" - "Contact your admin for details" + "Tethering or hotspot active" + "Tap to set up." + "Tethering is disabled" + "Contact your admin for details" + "Hotspot and tethering status" + + + + + diff --git a/Tethering/res/values-en-rXC/strings.xml b/Tethering/res/values-en-rXC/strings.xml index 7f47fc89d2..f1674bed4e 100644 --- a/Tethering/res/values-en-rXC/strings.xml +++ b/Tethering/res/values-en-rXC/strings.xml @@ -1,8 +1,29 @@ + + - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎Tap to set up.‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎Tethering is disabled‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Tethering or hotspot active‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎Tap to set up.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎Tethering is disabled‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎Contact your admin for details‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Hotspot & tethering status‎‏‎‎‏‎" + + + + + diff --git a/Tethering/res/values-es-rUS/strings.xml b/Tethering/res/values-es-rUS/strings.xml index e4618b8cec..63689f4399 100644 --- a/Tethering/res/values-es-rUS/strings.xml +++ b/Tethering/res/values-es-rUS/strings.xml @@ -1,8 +1,29 @@ + + - "Anclaje a red o zona activa conectados" - "Presiona para configurar." - "Se inhabilitó la conexión mediante dispositivo portátil" - "Para obtener más información, comunícate con el administrador" + "Conexión a red o hotspot conectados" + "Presiona para configurar esta opción." + "Se inhabilitó la conexión mediante dispositivo portátil" + "Para obtener más información, comunícate con el administrador" + "Estado del hotspot y la conexión mediante dispositivo portátil" + + + + + diff --git a/Tethering/res/values-es/strings.xml b/Tethering/res/values-es/strings.xml index 8dc1575ce8..9a34ed5e38 100644 --- a/Tethering/res/values-es/strings.xml +++ b/Tethering/res/values-es/strings.xml @@ -1,8 +1,29 @@ + + - "Compartir conexión/Zona Wi-Fi activada" - "Toca para configurar." - "La conexión compartida está inhabilitada" - "Ponte en contacto con el administrador para obtener más información" + "Conexión compartida o punto de acceso activos" + "Toca para configurar." + "La conexión compartida está inhabilitada" + "Solicita más información a tu administrador" + "Estado del punto de acceso y de la conexión compartida" + + + + + diff --git a/Tethering/res/values-et/strings.xml b/Tethering/res/values-et/strings.xml index 872c8a74cc..0970341ab0 100644 --- a/Tethering/res/values-et/strings.xml +++ b/Tethering/res/values-et/strings.xml @@ -1,8 +1,29 @@ + + - "Jagamine või kuumkoht on aktiivne" - "Puudutage seadistamiseks." - "Jagamine on keelatud" - "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Jagamine või kuumkoht on aktiivne" + "Puudutage seadistamiseks." + "Jagamine on keelatud" + "Lisateabe saamiseks võtke ühendust oma administraatoriga" + "Kuumkoha ja jagamise olek" + + + + + diff --git a/Tethering/res/values-eu/strings.xml b/Tethering/res/values-eu/strings.xml index 6c4605e616..632019e2ef 100644 --- a/Tethering/res/values-eu/strings.xml +++ b/Tethering/res/values-eu/strings.xml @@ -1,8 +1,29 @@ + + - "Konexioa partekatzea edo sare publikoa aktibo" - "Sakatu konfiguratzeko." - "Desgaituta dago konexioa partekatzeko aukera" - "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Konexioa partekatzea edo wifi-gunea aktibo dago" + "Sakatu konfiguratzeko." + "Desgaituta dago konexioa partekatzeko aukera" + "Xehetasunak lortzeko, jarri administratzailearekin harremanetan" + "Wifi-gunearen eta konexioa partekatzeko eginbidearen egoera" + + + + + diff --git a/Tethering/res/values-fa/strings.xml b/Tethering/res/values-fa/strings.xml index bc2ee23609..2e21c85fa1 100644 --- a/Tethering/res/values-fa/strings.xml +++ b/Tethering/res/values-fa/strings.xml @@ -1,8 +1,29 @@ + + - "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" - "برای راه‌اندازی ضربه بزنید." - "اشتراک‌گذاری اینترنت غیرفعال است" - "برای جزئیات، با سرپرستتان تماس بگیرید" + "اشتراک‌گذاری اینترنت یا نقطه اتصال فعال" + "برای راه‌اندازی ضربه بزنید." + "اشتراک‌گذاری اینترنت غیرفعال است" + "برای جزئیات، با سرپرستتان تماس بگیرید" + "وضعیت نقطه اتصال و اشتراک‌گذاری اینترنت" + + + + + diff --git a/Tethering/res/values-fi/strings.xml b/Tethering/res/values-fi/strings.xml index ff0fca6502..413db3f0f8 100644 --- a/Tethering/res/values-fi/strings.xml +++ b/Tethering/res/values-fi/strings.xml @@ -1,8 +1,29 @@ + + - "Internetin jakaminen tai yhteyspiste käytössä" - "Määritä napauttamalla." - "Yhteyden jakaminen poistettu käytöstä" - "Kysy lisätietoja järjestelmänvalvojalta." + "Yhteyden jakaminen tai hotspot käytössä" + "Ota käyttöön napauttamalla." + "Yhteyden jakaminen on poistettu käytöstä" + "Pyydä lisätietoja järjestelmänvalvojalta" + "Hotspotin ja yhteyden jakamisen tila" + + + + + diff --git a/Tethering/res/values-fr-rCA/strings.xml b/Tethering/res/values-fr-rCA/strings.xml index 1f5df0ee0c..eb2e4ba540 100644 --- a/Tethering/res/values-fr-rCA/strings.xml +++ b/Tethering/res/values-fr-rCA/strings.xml @@ -1,8 +1,29 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Touchez pour configurer." - "Le partage de connexion est désactivé" - "Communiquez avec votre administrateur pour obtenir plus de détails" + "Partage de connexion ou point d\'accès sans fil activé" + "Touchez pour configurer." + "Le partage de connexion est désactivé" + "Communiquez avec votre administrateur pour obtenir plus de détails" + "Point d\'accès et partage de connexion" + + + + + diff --git a/Tethering/res/values-fr/strings.xml b/Tethering/res/values-fr/strings.xml index daf7c9d830..22259c52ab 100644 --- a/Tethering/res/values-fr/strings.xml +++ b/Tethering/res/values-fr/strings.xml @@ -1,8 +1,29 @@ + + - "Partage de connexion ou point d\'accès sans fil activé" - "Appuyez ici pour configurer." - "Le partage de connexion est désactivé" - "Pour en savoir plus, contactez votre administrateur" + "Partage de connexion ou point d\'accès activé" + "Appuyez pour effectuer la configuration." + "Le partage de connexion est désactivé" + "Pour en savoir plus, contactez votre administrateur" + "État du point d\'accès et du partage de connexion" + + + + + diff --git a/Tethering/res/values-gl/strings.xml b/Tethering/res/values-gl/strings.xml index 0d16a1de09..ded82fcd54 100644 --- a/Tethering/res/values-gl/strings.xml +++ b/Tethering/res/values-gl/strings.xml @@ -1,8 +1,29 @@ + + - "Conexión compartida ou zona wifi activada" - "Tocar para configurar." - "A conexión compartida está desactivada" - "Contacta co administrador para obter información" + "Conexión compartida ou zona wifi activada" + "Toca para configurar." + "A conexión compartida está desactivada" + "Contacta co administrador para obter información" + "Estado da zona wifi e da conexión compartida" + + + + + diff --git a/Tethering/res/values-gu/strings.xml b/Tethering/res/values-gu/strings.xml index 9d6b02f85f..7cbbc2de3d 100644 --- a/Tethering/res/values-gu/strings.xml +++ b/Tethering/res/values-gu/strings.xml @@ -1,8 +1,29 @@ + + - "ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય" - "સેટ કરવા માટે ટૅપ કરો." - "ટિથરિંગ અક્ષમ કરેલ છે" - "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે" + "સેટઅપ કરવા માટે ટૅપ કરો." + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે" + "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો" + "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ" + + + + + diff --git a/Tethering/res/values-hi/strings.xml b/Tethering/res/values-hi/strings.xml index 9c29d9a8f9..08af81b826 100644 --- a/Tethering/res/values-hi/strings.xml +++ b/Tethering/res/values-hi/strings.xml @@ -1,8 +1,29 @@ + + - "टेदरिंग या हॉटस्‍पॉट सक्रिय" - "सेट करने के लिए टैप करें." - "टेदरिंग अक्षम है" - "जानकारी के लिए अपने एडमिन से संपर्क करें" + "टेदरिंग या हॉटस्पॉट चालू है" + "सेट अप करने के लिए टैप करें." + "टेदरिंग बंद है" + "जानकारी के लिए अपने एडमिन से संपर्क करें" + "हॉटस्पॉट और टेदरिंग की स्थिति" + + + + + diff --git a/Tethering/res/values-hr/strings.xml b/Tethering/res/values-hr/strings.xml index d0d25bb755..827c135f20 100644 --- a/Tethering/res/values-hr/strings.xml +++ b/Tethering/res/values-hr/strings.xml @@ -1,8 +1,29 @@ + + - "Ograničenje ili aktivan hotspot" - "Dodirnite da biste postavili." - "Modemsko je povezivanje onemogućeno" - "Obratite se administratoru da biste saznali pojedinosti" + "Modemsko povezivanje ili žarišna točka aktivni" + "Dodirnite da biste postavili." + "Modemsko je povezivanje onemogućeno" + "Obratite se administratoru da biste saznali pojedinosti" + "Status žarišne točke i modemskog povezivanja" + + + + + diff --git a/Tethering/res/values-hu/strings.xml b/Tethering/res/values-hu/strings.xml index 3129659923..eb68d6babf 100644 --- a/Tethering/res/values-hu/strings.xml +++ b/Tethering/res/values-hu/strings.xml @@ -1,8 +1,29 @@ + + - "Megosztás vagy aktív hotspot" - "Koppintson a beállításhoz." - "Az internetmegosztás le van tiltva" - "A részletekért forduljon rendszergazdájához" + "Megosztás vagy aktív hotspot" + "Koppintson a beállításhoz." + "Az internetmegosztás le van tiltva" + "A részletekért forduljon rendszergazdájához" + "Hotspot és internetmegosztás állapota" + + + + + diff --git a/Tethering/res/values-hy/strings.xml b/Tethering/res/values-hy/strings.xml index 8ba6435fd5..912941e538 100644 --- a/Tethering/res/values-hy/strings.xml +++ b/Tethering/res/values-hy/strings.xml @@ -1,8 +1,29 @@ + + - "Մոդեմի ռեժիմը միացված է" - "Հպեք՝ կարգավորելու համար:" - "Մոդեմի ռեժիմն անջատված է" - "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Մոդեմի ռեժիմը միացված է" + "Հպեք՝ կարգավորելու համար։" + "Մոդեմի ռեժիմն անջատված է" + "Մանրամասների համար դիմեք ձեր ադմինիստրատորին" + "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը" + + + + + diff --git a/Tethering/res/values-in/strings.xml b/Tethering/res/values-in/strings.xml index 1e093ab237..a4e175a439 100644 --- a/Tethering/res/values-in/strings.xml +++ b/Tethering/res/values-in/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering (Penambatan) atau hotspot aktif" - "Ketuk untuk menyiapkan." - "Tethering dinonaktifkan" - "Hubungi admin untuk mengetahui detailnya" + "Tethering atau hotspot aktif" + "Ketuk untuk menyiapkan." + "Tethering dinonaktifkan" + "Hubungi admin untuk mengetahui detailnya" + "Status hotspot & tethering" + + + + + diff --git a/Tethering/res/values-is/strings.xml b/Tethering/res/values-is/strings.xml index f5769d5344..e9f6670bcd 100644 --- a/Tethering/res/values-is/strings.xml +++ b/Tethering/res/values-is/strings.xml @@ -1,8 +1,29 @@ + + - "Kveikt á tjóðrun eða aðgangsstað" - "Ýttu til að setja upp." - "Slökkt er á tjóðrun" - "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Kveikt á tjóðrun eða aðgangsstað" + "Ýttu til að setja upp." + "Slökkt er á tjóðrun" + "Hafðu samband við kerfisstjórann til að fá upplýsingar" + "Staða heits reits og tjóðrunar" + + + + + diff --git a/Tethering/res/values-it/strings.xml b/Tethering/res/values-it/strings.xml index e0b3724325..ffb9196f5e 100644 --- a/Tethering/res/values-it/strings.xml +++ b/Tethering/res/values-it/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering oppure hotspot attivo" - "Tocca per impostare." - "Tethering disattivato" - "Contatta il tuo amministratore per avere informazioni dettagliate" + "Hotspot o tethering attivo" + "Tocca per impostare." + "Tethering disattivato" + "Contatta il tuo amministratore per avere informazioni dettagliate" + "Stato hotspot e tethering" + + + + + diff --git a/Tethering/res/values-iw/strings.xml b/Tethering/res/values-iw/strings.xml index c002c44b23..7adcb47350 100644 --- a/Tethering/res/values-iw/strings.xml +++ b/Tethering/res/values-iw/strings.xml @@ -1,8 +1,29 @@ + + - "שיתוף אינטרנט פעיל" - "הקש כדי להגדיר." - "שיתוף האינטרנט בין ניידים מושבת" - "לפרטים, יש לפנות למנהל המערכת" + "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל" + "יש להקיש כדי להגדיר." + "שיתוף האינטרנט בין מכשירים מושבת" + "לפרטים, יש לפנות למנהל המערכת" + "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים" + + + + + diff --git a/Tethering/res/values-ja/strings.xml b/Tethering/res/values-ja/strings.xml index 314bde00df..f68a73010b 100644 --- a/Tethering/res/values-ja/strings.xml +++ b/Tethering/res/values-ja/strings.xml @@ -1,8 +1,29 @@ + + - "テザリングまたはアクセスポイントが有効です" - "タップしてセットアップします。" - "テザリングは無効に設定されています" - "詳しくは、管理者にお問い合わせください" + "テザリングまたはアクセス ポイントが有効です" + "タップしてセットアップします。" + "テザリングは無効に設定されています" + "詳しくは、管理者にお問い合わせください" + "アクセス ポイントとテザリングのステータス" + + + + + diff --git a/Tethering/res/values-ka/strings.xml b/Tethering/res/values-ka/strings.xml index 7bbd81d343..7c22e82bd3 100644 --- a/Tethering/res/values-ka/strings.xml +++ b/Tethering/res/values-ka/strings.xml @@ -1,8 +1,29 @@ + + - "ტეტერინგი ან უსადენო ქსელი აქტიურია" - "შეეხეთ დასაყენებლად." - "ტეტერინგი გათიშულია" - "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "ტეტერინგი ან უსადენო ქსელი აქტიურია" + "შეეხეთ დასაყენებლად." + "ტეტერინგი გათიშულია" + "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს" + "უსადენო ქსელის და ტეტერინგის სტატუსი" + + + + + diff --git a/Tethering/res/values-kk/strings.xml b/Tethering/res/values-kk/strings.xml index 7fd87a1596..0857d06de2 100644 --- a/Tethering/res/values-kk/strings.xml +++ b/Tethering/res/values-kk/strings.xml @@ -1,8 +1,29 @@ + + - "Тетеринг немесе хотспот қосулы" - "Реттеу үшін түртіңіз." - "Тетеринг өшірілді" - "Мәліметтерді әкімшіден алыңыз" + "Тетеринг немесе хотспот қосулы" + "Реттеу үшін түртіңіз." + "Тетеринг өшірілді." + "Мәліметтерді әкімшіден алыңыз." + "Хотспот және тетеринг күйі" + + + + + diff --git a/Tethering/res/values-km/strings.xml b/Tethering/res/values-km/strings.xml index 2f85224679..536e3d1703 100644 --- a/Tethering/res/values-km/strings.xml +++ b/Tethering/res/values-km/strings.xml @@ -1,8 +1,29 @@ + + - "ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម" - "ប៉ះដើម្បីកំណត់" - "ការភ្ជាប់​ត្រូវបានបិទ" - "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត" + "ការភ្ជាប់ ឬហតស្ប៉ត​កំពុងដំណើរការ" + "ចុច​ដើម្បី​រៀបចំ។" + "ការភ្ជាប់​ត្រូវបានបិទ" + "ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត" + "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត" + + + + + diff --git a/Tethering/res/values-kn/strings.xml b/Tethering/res/values-kn/strings.xml index f11a83ea40..32f54926f4 100644 --- a/Tethering/res/values-kn/strings.xml +++ b/Tethering/res/values-kn/strings.xml @@ -1,8 +1,29 @@ + + - "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" - "ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" - "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ" + "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ." + "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ" + "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್‌ ಸ್ಥಿತಿ" + + + + + diff --git a/Tethering/res/values-ko/strings.xml b/Tethering/res/values-ko/strings.xml index 57f24f5b1a..156b24786d 100644 --- a/Tethering/res/values-ko/strings.xml +++ b/Tethering/res/values-ko/strings.xml @@ -1,8 +1,29 @@ + + - "테더링 또는 핫스팟 사용" - "설정하려면 탭하세요." - "테더링이 사용 중지됨" - "자세한 정보는 관리자에게 문의하세요." + "테더링 또는 핫스팟 사용" + "설정하려면 탭하세요." + "테더링이 사용 중지됨" + "자세한 정보는 관리자에게 문의하세요." + "핫스팟 및 테더링 상태" + + + + + diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml index 79854859d4..18ee5fd357 100644 --- a/Tethering/res/values-ky/strings.xml +++ b/Tethering/res/values-ky/strings.xml @@ -1,8 +1,29 @@ + + - "Жалгаштыруу же хотспот жандырылган" - "Жөндөө үчүн таптап коюңуз." - "Жалгаштыруу функциясы өчүрүлгөн" - "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Модем режими күйүп турат" + "Жөндөө үчүн таптап коюңуз." + "Телефонду модем катары колдонууга болбойт" + "Кеңири маалымат үчүн администраторуңузга кайрылыңыз" + "Байланыш түйүнүнүн жана модем режиминин статусу" + + + + + diff --git a/Tethering/res/values-lo/strings.xml b/Tethering/res/values-lo/strings.xml index 78f1585f60..b12767018c 100644 --- a/Tethering/res/values-lo/strings.xml +++ b/Tethering/res/values-lo/strings.xml @@ -1,8 +1,29 @@ + + - "ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ" - "ແຕະເພື່ອຕັ້ງຄ່າ." - "ການປ່ອຍສັນຍານຖືກປິດໄວ້" - "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ" + "ແຕະເພື່ອຕັ້ງຄ່າ." + "ການປ່ອຍສັນຍານຖືກປິດໄວ້" + "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ" + "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ" + + + + + diff --git a/Tethering/res/values-lt/strings.xml b/Tethering/res/values-lt/strings.xml index ebff8ac9d1..8427baf39f 100644 --- a/Tethering/res/values-lt/strings.xml +++ b/Tethering/res/values-lt/strings.xml @@ -1,8 +1,29 @@ + + - "Susietas ar aktyvus" - "Palieskite, kad nustatytumėte." - "Įrenginio kaip modemo naudojimas išjungtas" - "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas" + "Palieskite, kad nustatytumėte." + "Įrenginio kaip modemo naudojimas išjungtas" + "Jei reikia išsamios informacijos, susisiekite su administratoriumi" + "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena" + + + + + diff --git a/Tethering/res/values-lv/strings.xml b/Tethering/res/values-lv/strings.xml index 54d0048b52..aa2d6990e0 100644 --- a/Tethering/res/values-lv/strings.xml +++ b/Tethering/res/values-lv/strings.xml @@ -1,8 +1,29 @@ + + - "Piesaiste vai tīklājs ir aktīvs." - "Pieskarieties, lai iestatītu." - "Piesaiste ir atspējota" - "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Piesaiste vai tīklājs ir aktīvs." + "Pieskarieties, lai to iestatītu." + "Piesaiste ir atspējota" + "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru." + "Tīklāja un piesaistes statuss" + + + + + diff --git a/Tethering/res/values-mcc310-mnc004-af/strings.xml b/Tethering/res/values-mcc310-mnc004-af/strings.xml new file mode 100644 index 0000000000..19d659c6ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-af/strings.xml @@ -0,0 +1,24 @@ + + + + + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" + "Bykomende heffings kan geld terwyl jy swerf" + diff --git a/Tethering/res/values-mcc310-mnc004-am/strings.xml b/Tethering/res/values-mcc310-mnc004-am/strings.xml new file mode 100644 index 0000000000..8995430b4f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-am/strings.xml @@ -0,0 +1,24 @@ + + + + + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + diff --git a/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/Tethering/res/values-mcc310-mnc004-ar/strings.xml new file mode 100644 index 0000000000..54f3b5389a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ar/strings.xml @@ -0,0 +1,24 @@ + + + + + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." + diff --git a/Tethering/res/values-mcc310-mnc004-as/strings.xml b/Tethering/res/values-mcc310-mnc004-as/strings.xml new file mode 100644 index 0000000000..e215141c9e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-as/strings.xml @@ -0,0 +1,24 @@ + + + + + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + diff --git a/Tethering/res/values-mcc310-mnc004-az/strings.xml b/Tethering/res/values-mcc310-mnc004-az/strings.xml new file mode 100644 index 0000000000..1fd8e4c963 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-az/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + diff --git a/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..1abe4f3aa3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" + "Možda važe dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc310-mnc004-be/strings.xml b/Tethering/res/values-mcc310-mnc004-be/strings.xml new file mode 100644 index 0000000000..38dbd1e391 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-be/strings.xml @@ -0,0 +1,24 @@ + + + + + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + diff --git a/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/Tethering/res/values-mcc310-mnc004-bg/strings.xml new file mode 100644 index 0000000000..04b44db5c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + diff --git a/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/Tethering/res/values-mcc310-mnc004-bn/strings.xml new file mode 100644 index 0000000000..579d1be1c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bn/strings.xml @@ -0,0 +1,24 @@ + + + + + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" + diff --git a/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/Tethering/res/values-mcc310-mnc004-bs/strings.xml new file mode 100644 index 0000000000..9ce3efe6c3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-bs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/Tethering/res/values-mcc310-mnc004-ca/strings.xml new file mode 100644 index 0000000000..46d4c35b9b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ca/strings.xml @@ -0,0 +1,24 @@ + + + + + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" + "És possible que s\'apliquin costos addicionals en itinerància" + diff --git a/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/Tethering/res/values-mcc310-mnc004-cs/strings.xml new file mode 100644 index 0000000000..cc13860b3d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" + "Při roamingu mohou být účtovány dodatečné poplatky" + diff --git a/Tethering/res/values-mcc310-mnc004-da/strings.xml b/Tethering/res/values-mcc310-mnc004-da/strings.xml new file mode 100644 index 0000000000..92c3ae1156 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-da/strings.xml @@ -0,0 +1,24 @@ + + + + + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-de/strings.xml b/Tethering/res/values-mcc310-mnc004-de/strings.xml new file mode 100644 index 0000000000..967eb4db2e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-de/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + diff --git a/Tethering/res/values-mcc310-mnc004-el/strings.xml b/Tethering/res/values-mcc310-mnc004-el/strings.xml new file mode 100644 index 0000000000..5fb497451f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-el/strings.xml @@ -0,0 +1,24 @@ + + + + + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + diff --git a/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml new file mode 100644 index 0000000000..45647f93f2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml new file mode 100644 index 0000000000..7877074afc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml @@ -0,0 +1,24 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎Additional charges may apply while roaming‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml new file mode 100644 index 0000000000..08edd81a6b --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-es/strings.xml b/Tethering/res/values-mcc310-mnc004-es/strings.xml new file mode 100644 index 0000000000..79f51d00e2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-es/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" + "Puede que se apliquen cargos adicionales en itinerancia" + diff --git a/Tethering/res/values-mcc310-mnc004-et/strings.xml b/Tethering/res/values-mcc310-mnc004-et/strings.xml new file mode 100644 index 0000000000..2da5f8a6d6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-et/strings.xml @@ -0,0 +1,24 @@ + + + + + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" + "Rändluse kasutamisega võivad kaasneda lisatasud" + diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml new file mode 100644 index 0000000000..2073f2806c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" + diff --git a/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/Tethering/res/values-mcc310-mnc004-fa/strings.xml new file mode 100644 index 0000000000..e21b2a0852 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fa/strings.xml @@ -0,0 +1,24 @@ + + + + + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + diff --git a/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/Tethering/res/values-mcc310-mnc004-fi/strings.xml new file mode 100644 index 0000000000..88b0b13eb4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" + "Roaming voi aiheuttaa lisämaksuja" + diff --git a/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml new file mode 100644 index 0000000000..3b781bc8db --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/Tethering/res/values-mcc310-mnc004-fr/strings.xml new file mode 100644 index 0000000000..51d7203c36 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-fr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/Tethering/res/values-mcc310-mnc004-gl/strings.xml new file mode 100644 index 0000000000..008ccb475d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gl/strings.xml @@ -0,0 +1,24 @@ + + + + + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" + "Pódense aplicar cargos adicionais en itinerancia" + diff --git a/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/Tethering/res/values-mcc310-mnc004-gu/strings.xml new file mode 100644 index 0000000000..f2e3b4df78 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-gu/strings.xml @@ -0,0 +1,24 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" + diff --git a/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/Tethering/res/values-mcc310-mnc004-hi/strings.xml new file mode 100644 index 0000000000..b11839d760 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hi/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + diff --git a/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/Tethering/res/values-mcc310-mnc004-hr/strings.xml new file mode 100644 index 0000000000..0a5aca25b1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" + "U roamingu su mogući dodatni troškovi" + diff --git a/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/Tethering/res/values-mcc310-mnc004-hu/strings.xml new file mode 100644 index 0000000000..21c689a44e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" + "Roaming során további díjak léphetnek fel" + diff --git a/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/Tethering/res/values-mcc310-mnc004-hy/strings.xml new file mode 100644 index 0000000000..689d92870e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-hy/strings.xml @@ -0,0 +1,24 @@ + + + + + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + diff --git a/Tethering/res/values-mcc310-mnc004-in/strings.xml b/Tethering/res/values-mcc310-mnc004-in/strings.xml new file mode 100644 index 0000000000..a5f4d19abf --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-in/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" + "Biaya tambahan mungkin berlaku saat roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-is/strings.xml b/Tethering/res/values-mcc310-mnc004-is/strings.xml new file mode 100644 index 0000000000..fc7e8aaf4e --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-is/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" + "Viðbótargjöld kunna að eiga við í reiki" + diff --git a/Tethering/res/values-mcc310-mnc004-it/strings.xml b/Tethering/res/values-mcc310-mnc004-it/strings.xml new file mode 100644 index 0000000000..6456dd1b80 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-it/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/Tethering/res/values-mcc310-mnc004-iw/strings.xml new file mode 100644 index 0000000000..46b24bd3c5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-iw/strings.xml @@ -0,0 +1,24 @@ + + + + + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + diff --git a/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/Tethering/res/values-mcc310-mnc004-ja/strings.xml new file mode 100644 index 0000000000..e6eb277b90 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ja/strings.xml @@ -0,0 +1,24 @@ + + + + + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" + "ローミング時に追加料金が発生することがあります" + diff --git a/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/Tethering/res/values-mcc310-mnc004-ka/strings.xml new file mode 100644 index 0000000000..aeddd7101d --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ka/strings.xml @@ -0,0 +1,24 @@ + + + + + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + diff --git a/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/Tethering/res/values-mcc310-mnc004-kk/strings.xml new file mode 100644 index 0000000000..255f0a276f --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + diff --git a/Tethering/res/values-mcc310-mnc004-km/strings.xml b/Tethering/res/values-mcc310-mnc004-km/strings.xml new file mode 100644 index 0000000000..2bceb1cf77 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-km/strings.xml @@ -0,0 +1,24 @@ + + + + + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + diff --git a/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/Tethering/res/values-mcc310-mnc004-kn/strings.xml new file mode 100644 index 0000000000..ed769305a6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-kn/strings.xml @@ -0,0 +1,24 @@ + + + + + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" + diff --git a/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/Tethering/res/values-mcc310-mnc004-ko/strings.xml new file mode 100644 index 0000000000..6e504941eb --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ko/strings.xml @@ -0,0 +1,24 @@ + + + + + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + diff --git a/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/Tethering/res/values-mcc310-mnc004-ky/strings.xml new file mode 100644 index 0000000000..d68128b9a5 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ky/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + diff --git a/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/Tethering/res/values-mcc310-mnc004-lo/strings.xml new file mode 100644 index 0000000000..03e134a0fc --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lo/strings.xml @@ -0,0 +1,24 @@ + + + + + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" + diff --git a/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/Tethering/res/values-mcc310-mnc004-lt/strings.xml new file mode 100644 index 0000000000..652cedc6e6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lt/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + diff --git a/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/Tethering/res/values-mcc310-mnc004-lv/strings.xml new file mode 100644 index 0000000000..221972298c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-lv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + diff --git a/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/Tethering/res/values-mcc310-mnc004-mk/strings.xml new file mode 100644 index 0000000000..227f9e3466 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" + "При роаминг може да се наплатат дополнителни трошоци" + diff --git a/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/Tethering/res/values-mcc310-mnc004-ml/strings.xml new file mode 100644 index 0000000000..ec43885126 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ml/strings.xml @@ -0,0 +1,24 @@ + + + + + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" + diff --git a/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/Tethering/res/values-mcc310-mnc004-mn/strings.xml new file mode 100644 index 0000000000..e263573799 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + diff --git a/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/Tethering/res/values-mcc310-mnc004-mr/strings.xml new file mode 100644 index 0000000000..adf845d078 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-mr/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + diff --git a/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/Tethering/res/values-mcc310-mnc004-ms/strings.xml new file mode 100644 index 0000000000..f65c451e4c --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ms/strings.xml @@ -0,0 +1,24 @@ + + + + + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + diff --git a/Tethering/res/values-mcc310-mnc004-my/strings.xml b/Tethering/res/values-mcc310-mnc004-my/strings.xml new file mode 100644 index 0000000000..4118e775cd --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-my/strings.xml @@ -0,0 +1,24 @@ + + + + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + diff --git a/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/Tethering/res/values-mcc310-mnc004-nb/strings.xml new file mode 100644 index 0000000000..36853583ce --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nb/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" + "Ytterligere kostnader kan påløpe under roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/Tethering/res/values-mcc310-mnc004-ne/strings.xml new file mode 100644 index 0000000000..d074f15699 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ne/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" + diff --git a/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/Tethering/res/values-mcc310-mnc004-nl/strings.xml new file mode 100644 index 0000000000..1d888942f4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-nl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + diff --git a/Tethering/res/values-mcc310-mnc004-or/strings.xml b/Tethering/res/values-mcc310-mnc004-or/strings.xml new file mode 100644 index 0000000000..8038815fe8 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-or/strings.xml @@ -0,0 +1,24 @@ + + + + + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" + diff --git a/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/Tethering/res/values-mcc310-mnc004-pa/strings.xml new file mode 100644 index 0000000000..819833eab0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pa/strings.xml @@ -0,0 +1,24 @@ + + + + + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" + diff --git a/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/Tethering/res/values-mcc310-mnc004-pl/strings.xml new file mode 100644 index 0000000000..65e4380e39 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml new file mode 100644 index 0000000000..d8866170c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml new file mode 100644 index 0000000000..bfd45ca0a3 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml @@ -0,0 +1,24 @@ + + + + + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" + "Podem aplicar-se custos adicionais em roaming." + diff --git a/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/Tethering/res/values-mcc310-mnc004-pt/strings.xml new file mode 100644 index 0000000000..d8866170c1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-pt/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/Tethering/res/values-mcc310-mnc004-ro/strings.xml new file mode 100644 index 0000000000..8d87a9e516 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ro/strings.xml @@ -0,0 +1,24 @@ + + + + + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" + "Se pot aplica taxe suplimentare pentru roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/Tethering/res/values-mcc310-mnc004-ru/strings.xml new file mode 100644 index 0000000000..dbdb9ebe49 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ru/strings.xml @@ -0,0 +1,24 @@ + + + + + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + diff --git a/Tethering/res/values-mcc310-mnc004-si/strings.xml b/Tethering/res/values-mcc310-mnc004-si/strings.xml new file mode 100644 index 0000000000..d8301e41c2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-si/strings.xml @@ -0,0 +1,24 @@ + + + + + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + diff --git a/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/Tethering/res/values-mcc310-mnc004-sk/strings.xml new file mode 100644 index 0000000000..bef71363f4 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + diff --git a/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/Tethering/res/values-mcc310-mnc004-sl/strings.xml new file mode 100644 index 0000000000..3202c62e8a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + diff --git a/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/Tethering/res/values-mcc310-mnc004-sq/strings.xml new file mode 100644 index 0000000000..37f6ad2868 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sq/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/Tethering/res/values-mcc310-mnc004-sr/strings.xml new file mode 100644 index 0000000000..5566d03ed1 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" + "Можда важе додатни трошкови у ромингу" + diff --git a/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/Tethering/res/values-mcc310-mnc004-sv/strings.xml new file mode 100644 index 0000000000..9765acd0cf --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" + "Ytterligare avgifter kan tillkomma vid roaming" + diff --git a/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/Tethering/res/values-mcc310-mnc004-sw/strings.xml new file mode 100644 index 0000000000..cf850c9cd2 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-sw/strings.xml @@ -0,0 +1,24 @@ + + + + + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + diff --git a/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/Tethering/res/values-mcc310-mnc004-ta/strings.xml new file mode 100644 index 0000000000..f4b15aab19 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ta/strings.xml @@ -0,0 +1,24 @@ + + + + + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" + diff --git a/Tethering/res/values-mcc310-mnc004-te/strings.xml b/Tethering/res/values-mcc310-mnc004-te/strings.xml new file mode 100644 index 0000000000..937d34d520 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-te/strings.xml @@ -0,0 +1,24 @@ + + + + + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" + diff --git a/Tethering/res/values-mcc310-mnc004-th/strings.xml b/Tethering/res/values-mcc310-mnc004-th/strings.xml new file mode 100644 index 0000000000..f781fae525 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-th/strings.xml @@ -0,0 +1,24 @@ + + + + + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + diff --git a/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/Tethering/res/values-mcc310-mnc004-tl/strings.xml new file mode 100644 index 0000000000..8d5d465373 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + diff --git a/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/Tethering/res/values-mcc310-mnc004-tr/strings.xml new file mode 100644 index 0000000000..80cab33ac0 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-tr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + diff --git a/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/Tethering/res/values-mcc310-mnc004-uk/strings.xml new file mode 100644 index 0000000000..c05932a5ae --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" + "У роумінгу може стягуватися додаткова плата" + diff --git a/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/Tethering/res/values-mcc310-mnc004-ur/strings.xml new file mode 100644 index 0000000000..d820eee8ba --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-ur/strings.xml @@ -0,0 +1,24 @@ + + + + + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + diff --git a/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/Tethering/res/values-mcc310-mnc004-uz/strings.xml new file mode 100644 index 0000000000..726148aaee --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-uz/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" + diff --git a/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/Tethering/res/values-mcc310-mnc004-vi/strings.xml new file mode 100644 index 0000000000..b7cb0456b6 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-vi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml new file mode 100644 index 0000000000..af91afff9a --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + + + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" + "漫游时可能会产生额外的费用" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml new file mode 100644 index 0000000000..28e6b80c01 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" + "漫遊時可能需要支付額外費用" + diff --git a/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml new file mode 100644 index 0000000000..528a1e5292 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網路共用連上網際網路" + "裝置無法連線" + "關閉網路共用" + "無線基地台或網路共用已開啟" + "使用漫遊服務可能須支付額外費用" + diff --git a/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/Tethering/res/values-mcc310-mnc004-zu/strings.xml new file mode 100644 index 0000000000..11eb666219 --- /dev/null +++ b/Tethering/res/values-mcc310-mnc004-zu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + diff --git a/Tethering/res/values-mcc311-mnc480-af/strings.xml b/Tethering/res/values-mcc311-mnc480-af/strings.xml new file mode 100644 index 0000000000..9bfa5317a9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-af/strings.xml @@ -0,0 +1,24 @@ + + + + + "Verbinding het nie internet nie" + "Toestelle kan nie koppel nie" + "Skakel verbinding af" + "Warmkol of verbinding is aan" + "Bykomende heffings kan geld terwyl jy swerf" + diff --git a/Tethering/res/values-mcc311-mnc480-am/strings.xml b/Tethering/res/values-mcc311-mnc480-am/strings.xml new file mode 100644 index 0000000000..5949dfa776 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-am/strings.xml @@ -0,0 +1,24 @@ + + + + + "ማስተሳሰር ምንም በይነመረብ የለውም" + "መሣሪያዎችን ማገናኘት አይቻልም" + "ማስተሳሰርን አጥፋ" + "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል" + "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ" + diff --git a/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/Tethering/res/values-mcc311-mnc480-ar/strings.xml new file mode 100644 index 0000000000..8467f9b1f5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ar/strings.xml @@ -0,0 +1,24 @@ + + + + + "ما مِن اتصال بالإنترنت خلال التوصيل" + "تعذّر اتصال الأجهزة" + "إيقاف التوصيل" + "نقطة الاتصال أو التوصيل مفعّلان" + "قد يتم تطبيق رسوم إضافية أثناء التجوال." + diff --git a/Tethering/res/values-mcc311-mnc480-as/strings.xml b/Tethering/res/values-mcc311-mnc480-as/strings.xml new file mode 100644 index 0000000000..9776bd89da --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-as/strings.xml @@ -0,0 +1,24 @@ + + + + + "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই" + "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি" + "টে\'ডাৰিং অফ কৰক" + "হটস্পট অথবা টে\'ডাৰিং অন আছে" + "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে" + diff --git a/Tethering/res/values-mcc311-mnc480-az/strings.xml b/Tethering/res/values-mcc311-mnc480-az/strings.xml new file mode 100644 index 0000000000..e6d3eaf9f0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-az/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemin internetə girişi yoxdur" + "Cihazları qoşmaq mümkün deyil" + "Modemi deaktiv edin" + "Hotspot və ya modem aktivdir" + "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər" + diff --git a/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..4c8a1df8ee --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Privezivanje nema pristup internetu" + "Povezivanje uređaja nije uspelo" + "Isključi privezivanje" + "Uključen je hotspot ili privezivanje" + "Možda važe dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc311-mnc480-be/strings.xml b/Tethering/res/values-mcc311-mnc480-be/strings.xml new file mode 100644 index 0000000000..edfa41e1ff --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-be/strings.xml @@ -0,0 +1,24 @@ + + + + + "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту" + "Не ўдалося падключыць прылады" + "Выключыць рэжым мадэма" + "Хот-спот або рэжым мадэма ўключаны" + "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата" + diff --git a/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/Tethering/res/values-mcc311-mnc480-bg/strings.xml new file mode 100644 index 0000000000..f56398196f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетърингът няма връзка с интернет" + "Устройствата не могат да установят връзка" + "Изключване на тетъринга" + "Точката за достъп или тетърингът са включени" + "Възможно е да ви бъдат начислени допълнителни такси при роуминг" + diff --git a/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/Tethering/res/values-mcc311-mnc480-bn/strings.xml new file mode 100644 index 0000000000..d8ecd2e988 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bn/strings.xml @@ -0,0 +1,24 @@ + + + + + "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই" + "ডিভাইস কানেক্ট করতে পারছে না" + "টিথারিং বন্ধ করুন" + "হটস্পট বা টিথারিং চালু আছে" + "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে" + diff --git a/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/Tethering/res/values-mcc311-mnc480-bs/strings.xml new file mode 100644 index 0000000000..b85fd5e285 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-bs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Povezivanje putem mobitela nema internet" + "Uređaji se ne mogu povezati" + "Isključi povezivanje putem mobitela" + "Pristupna tačka ili povezivanje putem mobitela je uključeno" + "Mogu nastati dodatni troškovi u romingu" + diff --git a/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/Tethering/res/values-mcc311-mnc480-ca/strings.xml new file mode 100644 index 0000000000..a3572151be --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ca/strings.xml @@ -0,0 +1,24 @@ + + + + + "La compartició de xarxa no té accés a Internet" + "No es poden connectar els dispositius" + "Desactiva la compartició de xarxa" + "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa" + "És possible que s\'apliquin costos addicionals en itinerància" + diff --git a/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/Tethering/res/values-mcc311-mnc480-cs/strings.xml new file mode 100644 index 0000000000..91196be9e5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá připojení k internetu" + "Zařízení se nemůžou připojit" + "Vypnout tethering" + "Je zapnutý hotspot nebo tethering" + "Při roamingu mohou být účtovány dodatečné poplatky" + diff --git a/Tethering/res/values-mcc311-mnc480-da/strings.xml b/Tethering/res/values-mcc311-mnc480-da/strings.xml new file mode 100644 index 0000000000..196890011d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-da/strings.xml @@ -0,0 +1,24 @@ + + + + + "Netdeling har ingen internetforbindelse" + "Enheder kan ikke oprette forbindelse" + "Deaktiver netdeling" + "Hotspot eller netdeling er aktiveret" + "Der opkræves muligvis yderligere gebyrer ved roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-de/strings.xml b/Tethering/res/values-mcc311-mnc480-de/strings.xml new file mode 100644 index 0000000000..eb3f8c52c0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-de/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering hat keinen Internetzugriff" + "Geräte können sich nicht verbinden" + "Tethering deaktivieren" + "Hotspot oder Tethering ist aktiviert" + "Für das Roaming können zusätzliche Gebühren anfallen" + diff --git a/Tethering/res/values-mcc311-mnc480-el/strings.xml b/Tethering/res/values-mcc311-mnc480-el/strings.xml new file mode 100644 index 0000000000..56c3d81b63 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-el/strings.xml @@ -0,0 +1,24 @@ + + + + + "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο" + "Δεν είναι δυνατή η σύνδεση των συσκευών" + "Απενεργοποιήστε τη σύνδεση" + "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση" + "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή." + diff --git a/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml new file mode 100644 index 0000000000..dd1a1971cd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering has no Internet" + "Devices can’t connect" + "Turn off tethering" + "Hotspot or tethering is on" + "Additional charges may apply while roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml new file mode 100644 index 0000000000..d3347aae20 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml @@ -0,0 +1,24 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎Tethering has no internet‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎Devices can’t connect‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎Turn off tethering‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎Hotspot or tethering is on‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎Additional charges may apply while roaming‎‏‎‎‏‎" + diff --git a/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml new file mode 100644 index 0000000000..2f0504f07d --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión mediante dispositivo móvil no tiene Internet" + "No se pueden conectar los dispositivos" + "Desactivar conexión mediante dispositivo móvil" + "Se activó el hotspot o la conexión mediante dispositivo móvil" + "Es posible que se apliquen cargos adicionales por roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-es/strings.xml b/Tethering/res/values-mcc311-mnc480-es/strings.xml new file mode 100644 index 0000000000..2d8f882425 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-es/strings.xml @@ -0,0 +1,24 @@ + + + + + "La conexión no se puede compartir, porque no hay acceso a Internet" + "Los dispositivos no se pueden conectar" + "Desactivar conexión compartida" + "Punto de acceso o conexión compartida activados" + "Puede que se apliquen cargos adicionales en itinerancia" + diff --git a/Tethering/res/values-mcc311-mnc480-et/strings.xml b/Tethering/res/values-mcc311-mnc480-et/strings.xml new file mode 100644 index 0000000000..8493c47071 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-et/strings.xml @@ -0,0 +1,24 @@ + + + + + "Jagamisel puudub internetiühendus" + "Seadmed ei saa ühendust luua" + "Lülita jagamine välja" + "Kuumkoht või jagamine on sisse lülitatud" + "Rändluse kasutamisega võivad kaasneda lisatasud" + diff --git a/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/Tethering/res/values-mcc311-mnc480-eu/strings.xml new file mode 100644 index 0000000000..33bccab3e8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Konexioa partekatzeko aukerak ez du Interneteko konexiorik" + "Ezin dira konektatu gailuak" + "Desaktibatu konexioa partekatzeko aukera" + "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago" + "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan" + diff --git a/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/Tethering/res/values-mcc311-mnc480-fa/strings.xml new file mode 100644 index 0000000000..cf8a0cc277 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fa/strings.xml @@ -0,0 +1,24 @@ + + + + + "«اشتراک‌گذاری اینترنت» به اینترنت دسترسی ندارد" + "دستگاه‌ها متصل نمی‌شوند" + "خاموش کردن «اشتراک‌گذاری اینترنت»" + "«نقطه اتصال» یا «اشتراک‌گذاری اینترنت» روشن است" + "ممکن است درحین فراگردی تغییرات دیگر اعمال شود" + diff --git a/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/Tethering/res/values-mcc311-mnc480-fi/strings.xml new file mode 100644 index 0000000000..6a3ab806db --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ei jaettavaa internetyhteyttä" + "Laitteet eivät voi muodostaa yhteyttä" + "Laita yhteyden jakaminen pois päältä" + "Hotspot tai yhteyden jakaminen on päällä" + "Roaming voi aiheuttaa lisämaksuja" + diff --git a/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml new file mode 100644 index 0000000000..ffb9bf6047 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml @@ -0,0 +1,24 @@ + + + + + "Le partage de connexion n\'est pas connecté à Internet" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/Tethering/res/values-mcc311-mnc480-fr/strings.xml new file mode 100644 index 0000000000..768bce3f0a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-fr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Aucune connexion à Internet n\'est disponible pour le partage de connexion" + "Impossible de connecter les appareils" + "Désactiver le partage de connexion" + "Le point d\'accès ou le partage de connexion est activé" + "En itinérance, des frais supplémentaires peuvent s\'appliquer" + diff --git a/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/Tethering/res/values-mcc311-mnc480-gl/strings.xml new file mode 100644 index 0000000000..0c4195a7ca --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gl/strings.xml @@ -0,0 +1,24 @@ + + + + + "A conexión compartida non ten Internet" + "Non se puideron conectar os dispositivos" + "Desactivar conexión compartida" + "Está activada a zona wifi ou a conexión compartida" + "Pódense aplicar cargos adicionais en itinerancia" + diff --git a/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/Tethering/res/values-mcc311-mnc480-gu/strings.xml new file mode 100644 index 0000000000..e9d33a7db2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-gu/strings.xml @@ -0,0 +1,24 @@ + + + + + "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી" + "ડિવાઇસ કનેક્ટ કરી શકાતા નથી" + "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો" + "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે" + "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે" + diff --git a/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/Tethering/res/values-mcc311-mnc480-hi/strings.xml new file mode 100644 index 0000000000..aa418ac5d3 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hi/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंग से इंटरनेट नहीं चल रहा" + "डिवाइस कनेक्ट नहीं हो पा रहे" + "टेदरिंग बंद करें" + "हॉटस्पॉट या टेदरिंग चालू है" + "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है" + diff --git a/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/Tethering/res/values-mcc311-mnc480-hr/strings.xml new file mode 100644 index 0000000000..51c524afbc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modemsko povezivanje nema internet" + "Uređaji se ne mogu povezati" + "Isključivanje modemskog povezivanja" + "Uključena je žarišna točka ili modemsko povezivanje" + "U roamingu su mogući dodatni troškovi" + diff --git a/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/Tethering/res/values-mcc311-mnc480-hu/strings.xml new file mode 100644 index 0000000000..164e45edd1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nincs internetkapcsolat az internet megosztásához" + "Az eszközök nem tudnak csatlakozni" + "Internetmegosztás kikapcsolása" + "A hotspot vagy az internetmegosztás be van kapcsolva" + "Roaming során további díjak léphetnek fel" + diff --git a/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/Tethering/res/values-mcc311-mnc480-hy/strings.xml new file mode 100644 index 0000000000..e76c0a4c80 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-hy/strings.xml @@ -0,0 +1,24 @@ + + + + + "Մոդեմի ռեժիմի կապը բացակայում է" + "Չհաջողվեց միացնել սարքը" + "Անջատել մոդեմի ռեժիմը" + "Թեժ կետը կամ մոդեմի ռեժիմը միացված է" + "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել" + diff --git a/Tethering/res/values-mcc311-mnc480-in/strings.xml b/Tethering/res/values-mcc311-mnc480-in/strings.xml new file mode 100644 index 0000000000..2b817f8abd --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-in/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tidak ada koneksi internet di tethering" + "Perangkat tidak dapat terhubung" + "Nonaktifkan tethering" + "Hotspot atau tethering aktif" + "Biaya tambahan mungkin berlaku saat roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-is/strings.xml b/Tethering/res/values-mcc311-mnc480-is/strings.xml new file mode 100644 index 0000000000..a338d9c7ca --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-is/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tjóðrun er ekki með internettengingu" + "Tæki geta ekki tengst" + "Slökkva á tjóðrun" + "Kveikt er á heitum reit eða tjóðrun" + "Viðbótargjöld kunna að eiga við í reiki" + diff --git a/Tethering/res/values-mcc311-mnc480-it/strings.xml b/Tethering/res/values-mcc311-mnc480-it/strings.xml new file mode 100644 index 0000000000..77769c2ac5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-it/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nessuna connessione a Internet per il tethering" + "Impossibile connettere i dispositivi" + "Disattiva il tethering" + "Hotspot o tethering attivi" + "Potrebbero essere applicati costi aggiuntivi durante il roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/Tethering/res/values-mcc311-mnc480-iw/strings.xml new file mode 100644 index 0000000000..5267b51264 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-iw/strings.xml @@ -0,0 +1,24 @@ + + + + + "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט" + "למכשירים אין אפשרות להתחבר" + "השבתה של שיתוף האינטרנט בין מכשירים" + "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת" + "ייתכנו חיובים נוספים בעת נדידה" + diff --git a/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/Tethering/res/values-mcc311-mnc480-ja/strings.xml new file mode 100644 index 0000000000..66a9a6dd35 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ja/strings.xml @@ -0,0 +1,24 @@ + + + + + "テザリングがインターネットに接続されていません" + "デバイスを接続できません" + "テザリングを OFF にする" + "アクセス ポイントまたはテザリングが ON です" + "ローミング時に追加料金が発生することがあります" + diff --git a/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/Tethering/res/values-mcc311-mnc480-ka/strings.xml new file mode 100644 index 0000000000..d8ad880849 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ka/strings.xml @@ -0,0 +1,24 @@ + + + + + "ტეტერინგს არ აქვს ინტერნეტზე წვდომა" + "მოწყობილობები ვერ ახერხებენ დაკავშირებას" + "ტეტერინგის გამორთვა" + "ჩართულია უსადენო ქსელი ან ტეტერინგი" + "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური" + diff --git a/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/Tethering/res/values-mcc311-mnc480-kk/strings.xml new file mode 100644 index 0000000000..1ddd6b419b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Тетеринг режимі интернет байланысынсыз пайдаланылуда" + "Құрылғыларды байланыстыру мүмкін емес" + "Тетерингіні өшіру" + "Хотспот немесе тетеринг қосулы" + "Роуминг кезінде қосымша ақы алынуы мүмкін." + diff --git a/Tethering/res/values-mcc311-mnc480-km/strings.xml b/Tethering/res/values-mcc311-mnc480-km/strings.xml new file mode 100644 index 0000000000..cf5a1379cc --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-km/strings.xml @@ -0,0 +1,24 @@ + + + + + "ការភ្ជាប់​មិនមានអ៊ីនធឺណិត​ទេ" + "មិនអាច​ភ្ជាប់ឧបករណ៍​បានទេ" + "បិទការភ្ជាប់" + "ហតស្ប៉ត ឬការភ្ជាប់​ត្រូវបានបើក" + "អាចមាន​ការគិតថ្លៃ​បន្ថែម នៅពេល​រ៉ូមីង" + diff --git a/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/Tethering/res/values-mcc311-mnc480-kn/strings.xml new file mode 100644 index 0000000000..68ae68bc19 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-kn/strings.xml @@ -0,0 +1,24 @@ + + + + + "ಟೆಥರಿಂಗ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ" + "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಟೆಥರಿಂಗ್‌ ಆಫ್ ಮಾಡಿ" + "ಹಾಟ್‌ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್‌ ಆನ್ ಆಗಿದೆ" + "ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು" + diff --git a/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/Tethering/res/values-mcc311-mnc480-ko/strings.xml new file mode 100644 index 0000000000..17185ba2d0 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ko/strings.xml @@ -0,0 +1,24 @@ + + + + + "테더링으로 인터넷을 사용할 수 없음" + "기기에서 연결할 수 없음" + "테더링 사용 중지" + "핫스팟 또는 테더링 켜짐" + "로밍 중에는 추가 요금이 발생할 수 있습니다." + diff --git a/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/Tethering/res/values-mcc311-mnc480-ky/strings.xml new file mode 100644 index 0000000000..6a9fb9810c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ky/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модем режими Интернети жок колдонулууда" + "Түзмөктөр туташпай жатат" + "Модем режимин өчүрүү" + "Байланыш түйүнү же модем режими күйүк" + "Роумингде кошумча акы алынышы мүмкүн" + diff --git a/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/Tethering/res/values-mcc311-mnc480-lo/strings.xml new file mode 100644 index 0000000000..bcc4b57626 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lo/strings.xml @@ -0,0 +1,24 @@ + + + + + "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ" + "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້" + "ປິດການປ່ອຍສັນຍານ" + "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່" + "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ" + diff --git a/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/Tethering/res/values-mcc311-mnc480-lt/strings.xml new file mode 100644 index 0000000000..011c2c11fb --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lt/strings.xml @@ -0,0 +1,24 @@ + + + + + "Nėra įrenginio kaip modemo naudojimo interneto ryšio" + "Nepavyko susieti įrenginių" + "Išjungti įrenginio kaip modemo naudojimą" + "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas" + "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai" + diff --git a/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/Tethering/res/values-mcc311-mnc480-lv/strings.xml new file mode 100644 index 0000000000..5cb2f3b7aa --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-lv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Piesaistei nav interneta savienojuma" + "Nevar savienot ierīces" + "Izslēgt piesaisti" + "Ir ieslēgts tīklājs vai piesaiste" + "Viesabonēšanas laikā var tikt piemērota papildu samaksa" + diff --git a/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/Tethering/res/values-mcc311-mnc480-mk/strings.xml new file mode 100644 index 0000000000..4cbfd887c5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Нема интернет преку мобилен" + "Уредите не може да се поврзат" + "Исклучи интернет преку мобилен" + "Точката на пристап или интернетот преку мобилен е вклучен" + "При роаминг може да се наплатат дополнителни трошоци" + diff --git a/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/Tethering/res/values-mcc311-mnc480-ml/strings.xml new file mode 100644 index 0000000000..9cf4eaf34a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ml/strings.xml @@ -0,0 +1,24 @@ + + + + + "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല" + "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല" + "ടെതറിംഗ് ഓഫാക്കുക" + "ഹോട്ട്‌സ്‌പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്" + "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം" + diff --git a/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/Tethering/res/values-mcc311-mnc480-mn/strings.xml new file mode 100644 index 0000000000..47c82c14d9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mn/strings.xml @@ -0,0 +1,24 @@ + + + + + "Модемд интернэт алга байна" + "Төхөөрөмжүүд холбогдох боломжгүй байна" + "Модем болгохыг унтраах" + "Сүлжээний цэг эсвэл модем болгох асаалттай байна" + "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй" + diff --git a/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/Tethering/res/values-mcc311-mnc480-mr/strings.xml new file mode 100644 index 0000000000..ad9e809ab2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-mr/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिंगला इंटरनेट नाही" + "डिव्हाइस कनेक्ट होऊ शकत नाहीत" + "टेदरिंग बंद करा" + "हॉटस्पॉट किंवा टेदरिंग सुरू आहे" + "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात" + diff --git a/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/Tethering/res/values-mcc311-mnc480-ms/strings.xml new file mode 100644 index 0000000000..e708cb8717 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ms/strings.xml @@ -0,0 +1,24 @@ + + + + + "Penambatan tiada Internet" + "Peranti tidak dapat disambungkan" + "Matikan penambatan" + "Tempat liputan atau penambatan dihidupkan" + "Caj tambahan mungkin digunakan semasa perayauan" + diff --git a/Tethering/res/values-mcc311-mnc480-my/strings.xml b/Tethering/res/values-mcc311-mnc480-my/strings.xml new file mode 100644 index 0000000000..ba5462250b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-my/strings.xml @@ -0,0 +1,24 @@ + + + + + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ" + "စက်များ ချိတ်ဆက်၍ မရပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်" + "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်" + "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်" + diff --git a/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/Tethering/res/values-mcc311-mnc480-nb/strings.xml new file mode 100644 index 0000000000..57db484a25 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nb/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internettdeling har ikke internettilgang" + "Enhetene kan ikke koble til" + "Slå av internettdeling" + "Wi-Fi-sone eller internettdeling er på" + "Ytterligere kostnader kan påløpe under roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/Tethering/res/values-mcc311-mnc480-ne/strings.xml new file mode 100644 index 0000000000..1503244f50 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ne/strings.xml @@ -0,0 +1,24 @@ + + + + + "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन" + "यन्त्रहरू कनेक्ट गर्न सकिएन" + "टेदरिङ निष्क्रिय पार्नुहोस्" + "हटस्पट वा टेदरिङ सक्रिय छ" + "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ" + diff --git a/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/Tethering/res/values-mcc311-mnc480-nl/strings.xml new file mode 100644 index 0000000000..b08133f4e5 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-nl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering heeft geen internet" + "Apparaten kunnen niet worden verbonden" + "Tethering uitschakelen" + "Hotspot of tethering is ingeschakeld" + "Er kunnen extra kosten voor roaming in rekening worden gebracht." + diff --git a/Tethering/res/values-mcc311-mnc480-or/strings.xml b/Tethering/res/values-mcc311-mnc480-or/strings.xml new file mode 100644 index 0000000000..1ad4ca354a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-or/strings.xml @@ -0,0 +1,24 @@ + + + + + "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ" + "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ" + "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି" + "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ" + diff --git a/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/Tethering/res/values-mcc311-mnc480-pa/strings.xml new file mode 100644 index 0000000000..88def563d8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pa/strings.xml @@ -0,0 +1,24 @@ + + + + + "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ" + "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ" + "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ" + "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ" + diff --git a/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/Tethering/res/values-mcc311-mnc480-pl/strings.xml new file mode 100644 index 0000000000..f9890abdc2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nie ma internetu" + "Urządzenia nie mogą się połączyć" + "Wyłącz tethering" + "Hotspot lub tethering jest włączony" + "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml new file mode 100644 index 0000000000..ce3b88479f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml new file mode 100644 index 0000000000..7e883ea576 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml @@ -0,0 +1,24 @@ + + + + + "A ligação (à Internet) via telemóvel não tem Internet" + "Não é possível ligar os dispositivos" + "Desativar ligação (à Internet) via telemóvel" + "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada" + "Podem aplicar-se custos adicionais em roaming." + diff --git a/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/Tethering/res/values-mcc311-mnc480-pt/strings.xml new file mode 100644 index 0000000000..ce3b88479f --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-pt/strings.xml @@ -0,0 +1,24 @@ + + + + + "O tethering não tem Internet" + "Não é possível conectar os dispositivos" + "Desativar o tethering" + "Ponto de acesso ou tethering ativado" + "Pode haver cobranças extras durante o roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/Tethering/res/values-mcc311-mnc480-ro/strings.xml new file mode 100644 index 0000000000..1009417316 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ro/strings.xml @@ -0,0 +1,24 @@ + + + + + "Procesul de tethering nu are internet" + "Dispozitivele nu se pot conecta" + "Dezactivați procesul de tethering" + "S-a activat hotspotul sau tethering" + "Se pot aplica taxe suplimentare pentru roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/Tethering/res/values-mcc311-mnc480-ru/strings.xml new file mode 100644 index 0000000000..88683bed95 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ru/strings.xml @@ -0,0 +1,24 @@ + + + + + "Режим модема используется без доступа к Интернету" + "Невозможно подключить устройства." + "Отключить режим модема" + "Включены точка доступа или режим модема" + "За использование услуг связи в роуминге может взиматься дополнительная плата." + diff --git a/Tethering/res/values-mcc311-mnc480-si/strings.xml b/Tethering/res/values-mcc311-mnc480-si/strings.xml new file mode 100644 index 0000000000..176bcdb797 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-si/strings.xml @@ -0,0 +1,24 @@ + + + + + "ටෙදරින් හට අන්තර්ජාලය නැත" + "උපාංගවලට සම්බන්ධ විය නොහැකිය" + "ටෙදරින් ක්‍රියාවිරහිත කරන්න" + "හොට්ස්පොට් හෝ ටෙදරින් ක්‍රියාත්මකයි" + "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය" + diff --git a/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/Tethering/res/values-mcc311-mnc480-sk/strings.xml new file mode 100644 index 0000000000..b9e2127fa8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering nemá internetové pripojenie" + "Zariadenia sa nemôžu pripojiť" + "Vypnúť tethering" + "Je zapnutý hotspot alebo tethering" + "Počas roamingu vám môžu byť účtované ďalšie poplatky" + diff --git a/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/Tethering/res/values-mcc311-mnc480-sl/strings.xml new file mode 100644 index 0000000000..e8140e686a --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Internetna povezava prek mobilnega telefona ni vzpostavljena" + "Napravi se ne moreta povezati" + "Izklopi internetno povezavo prek mobilnega telefona" + "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena" + "Med gostovanjem lahko nastanejo dodatni stroški" + diff --git a/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/Tethering/res/values-mcc311-mnc480-sq/strings.xml new file mode 100644 index 0000000000..61e698d6e8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sq/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ndarja e internetit nuk ka internet" + "Pajisjet nuk mund të lidhen" + "Çaktivizo ndarjen e internetit" + "Zona e qasjes për internet ose ndarja e internetit është aktive" + "Mund të zbatohen tarifime shtesë kur je në roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/Tethering/res/values-mcc311-mnc480-sr/strings.xml new file mode 100644 index 0000000000..b4c411c354 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Привезивање нема приступ интернету" + "Повезивање уређаја није успело" + "Искључи привезивање" + "Укључен је хотспот или привезивање" + "Можда важе додатни трошкови у ромингу" + diff --git a/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/Tethering/res/values-mcc311-mnc480-sv/strings.xml new file mode 100644 index 0000000000..4f543e47b9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sv/strings.xml @@ -0,0 +1,24 @@ + + + + + "Det finns ingen internetanslutning för internetdelningen" + "Enheterna kan inte anslutas" + "Inaktivera internetdelning" + "Surfzon eller internetdelning har aktiverats" + "Ytterligare avgifter kan tillkomma vid roaming" + diff --git a/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/Tethering/res/values-mcc311-mnc480-sw/strings.xml new file mode 100644 index 0000000000..ac347ab485 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-sw/strings.xml @@ -0,0 +1,24 @@ + + + + + "Kipengele cha kusambaza mtandao hakina intaneti" + "Imeshindwa kuunganisha vifaa" + "Zima kipengele cha kusambaza mtandao" + "Umewasha kipengele cha kusambaza mtandao au mtandao pepe" + "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo" + diff --git a/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/Tethering/res/values-mcc311-mnc480-ta/strings.xml new file mode 100644 index 0000000000..2ea2467e58 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ta/strings.xml @@ -0,0 +1,24 @@ + + + + + "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை" + "சாதனங்களால் இணைய முடியவில்லை" + "இணைப்பு முறையை ஆஃப் செய்" + "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது" + "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்" + diff --git a/Tethering/res/values-mcc311-mnc480-te/strings.xml b/Tethering/res/values-mcc311-mnc480-te/strings.xml new file mode 100644 index 0000000000..9360297dd8 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-te/strings.xml @@ -0,0 +1,24 @@ + + + + + "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు" + "పరికరాలు కనెక్ట్ అవ్వడం లేదు" + "టెథరింగ్‌ను ఆఫ్ చేయండి" + "హాట్‌స్పాట్ లేదా టెథరింగ్ ఆన్‌లో ఉంది" + "రోమింగ్‌లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు" + diff --git a/Tethering/res/values-mcc311-mnc480-th/strings.xml b/Tethering/res/values-mcc311-mnc480-th/strings.xml new file mode 100644 index 0000000000..9c4d7e08f2 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-th/strings.xml @@ -0,0 +1,24 @@ + + + + + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต" + "อุปกรณ์เชื่อมต่อไม่ได้" + "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่" + "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง" + diff --git a/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/Tethering/res/values-mcc311-mnc480-tl/strings.xml new file mode 100644 index 0000000000..a7c78a5932 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tl/strings.xml @@ -0,0 +1,24 @@ + + + + + "Walang internet ang pag-tether" + "Hindi makakonekta ang mga device" + "I-off ang pag-tether" + "Naka-on ang Hotspot o pag-tether" + "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam" + diff --git a/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/Tethering/res/values-mcc311-mnc480-tr/strings.xml new file mode 100644 index 0000000000..93da2c3f79 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-tr/strings.xml @@ -0,0 +1,24 @@ + + + + + "Tethering\'in internet bağlantısı yok" + "Cihazlar bağlanamıyor" + "Tethering\'i kapat" + "Hotspot veya tethering açık" + "Dolaşım sırasında ek ücretler uygulanabilir" + diff --git a/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/Tethering/res/values-mcc311-mnc480-uk/strings.xml new file mode 100644 index 0000000000..ee0dcd2c4b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uk/strings.xml @@ -0,0 +1,24 @@ + + + + + "Телефон, який використовується як модем, не підключений до Інтернету" + "Не вдається підключити пристрої" + "Вимкнути використання телефона як модема" + "Увімкнено точку доступу або використання телефона як модема" + "У роумінгу може стягуватися додаткова плата" + diff --git a/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/Tethering/res/values-mcc311-mnc480-ur/strings.xml new file mode 100644 index 0000000000..41cd28eef9 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-ur/strings.xml @@ -0,0 +1,24 @@ + + + + + "ٹیدرنگ میں انٹرنیٹ نہیں ہے" + "آلات منسلک نہیں ہو سکتے" + "ٹیدرنگ آف کریں" + "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے" + "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں" + diff --git a/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/Tethering/res/values-mcc311-mnc480-uz/strings.xml new file mode 100644 index 0000000000..c847bc943b --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-uz/strings.xml @@ -0,0 +1,24 @@ + + + + + "Modem internetga ulanmagan" + "Qurilmalar ulanmadi" + "Modem rejimini faolsizlantirish" + "Hotspot yoki modem rejimi yoniq" + "Rouming vaqtida qoʻshimcha haq olinishi mumkin" + diff --git a/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/Tethering/res/values-mcc311-mnc480-vi/strings.xml new file mode 100644 index 0000000000..a74326f09e --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-vi/strings.xml @@ -0,0 +1,24 @@ + + + + + "Không có Internet để chia sẻ kết Internet" + "Các thiết bị không thể kết nối" + "Tắt tính năng chia sẻ Internet" + "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật" + "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml new file mode 100644 index 0000000000..d7370036e3 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + + + "共享网络未连接到互联网" + "设备无法连接" + "关闭网络共享" + "热点或网络共享已开启" + "漫游时可能会产生额外的费用" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml new file mode 100644 index 0000000000..f378a9dc2c --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網絡共享連線至互聯網" + "裝置無法連接" + "關閉網絡共享" + "熱點或網絡共享已開啟" + "漫遊時可能需要支付額外費用" + diff --git a/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml new file mode 100644 index 0000000000..cd653df1da --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + + + + "無法透過網路共用連上網際網路" + "裝置無法連線" + "關閉網路共用" + "無線基地台或網路共用已開啟" + "使用漫遊服務可能須支付額外費用" + diff --git a/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/Tethering/res/values-mcc311-mnc480-zu/strings.xml new file mode 100644 index 0000000000..32f6df56f1 --- /dev/null +++ b/Tethering/res/values-mcc311-mnc480-zu/strings.xml @@ -0,0 +1,24 @@ + + + + + "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi" + "Amadivayisi awakwazi ukuxhumeka" + "Vala ukusebenzisa ifoni njengemodemu" + "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe" + "Kungaba nezinkokhelo ezengeziwe uma uzula" + diff --git a/Tethering/res/values-mk/strings.xml b/Tethering/res/values-mk/strings.xml index 0fab8aa476..9ad9b9a589 100644 --- a/Tethering/res/values-mk/strings.xml +++ b/Tethering/res/values-mk/strings.xml @@ -1,8 +1,29 @@ + + - "Поврзувањето или точката на пристап се активни" - "Допрете за поставување." - "Врзувањето е оневозможено" - "Контактирајте со администраторот за детали" + "Активно е врзување или точка на пристап" + "Допрете за поставување." + "Врзувањето е оневозможено" + "Контактирајте со администраторот за детали" + "Статус на точката на пристап и врзувањето" + + + + + diff --git a/Tethering/res/values-ml/strings.xml b/Tethering/res/values-ml/strings.xml index fd7e556e38..9db79ce220 100644 --- a/Tethering/res/values-ml/strings.xml +++ b/Tethering/res/values-ml/strings.xml @@ -1,8 +1,29 @@ + + - "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" - "സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക." - "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" - "വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്" + "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക." + "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു" + "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക" + "ഹോട്ട്‌സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില" + + + + + diff --git a/Tethering/res/values-mn/strings.xml b/Tethering/res/values-mn/strings.xml index 4596577c5d..42d1edbace 100644 --- a/Tethering/res/values-mn/strings.xml +++ b/Tethering/res/values-mn/strings.xml @@ -1,8 +1,29 @@ + + - "Модем болгох эсвэл идэвхтэй цэг болгох" - "Тохируулахын тулд товшино уу." - "Модем болгох боломжгүй байна" - "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна" + "Тохируулахын тулд товшино уу." + "Модем болгохыг идэвхгүй болгосон" + "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу" + "Сүлжээний цэг болон модем болгох төлөв" + + + + + diff --git a/Tethering/res/values-mr/strings.xml b/Tethering/res/values-mr/strings.xml index 85c9ade4fe..13995b6b8a 100644 --- a/Tethering/res/values-mr/strings.xml +++ b/Tethering/res/values-mr/strings.xml @@ -1,8 +1,29 @@ + + - "टेदरिंग किंवा हॉटस्पॉट सक्रिय" - "सेट करण्यासाठी टॅप करा." - "टेदरिंग बंद आहे" - "तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा" + "टेदरिंग किंवा हॉटस्पॉट अ‍ॅक्टिव्ह आहे" + "सेट करण्यासाठी टॅप करा." + "टेदरिंग बंद केले आहे" + "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा" + "हॉटस्पॉट आणि टेदरिंगची स्थिती" + + + + + diff --git a/Tethering/res/values-ms/strings.xml b/Tethering/res/values-ms/strings.xml index ec6bdbda08..d6a67f37b1 100644 --- a/Tethering/res/values-ms/strings.xml +++ b/Tethering/res/values-ms/strings.xml @@ -1,8 +1,29 @@ + + - "Penambatan atau titik panas aktif" - "Ketik untuk membuat persediaan." - "Penambatan dilumpuhkan" - "Hubungi pentadbir anda untuk maklumat lanjut" + "Penambatan atau tempat liputan aktif" + "Ketik untuk membuat persediaan." + "Penambatan dilumpuhkan" + "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut" + "Status tempat liputan & penambatan" + + + + + diff --git a/Tethering/res/values-my/strings.xml b/Tethering/res/values-my/strings.xml index 83978b67d4..49f6b88a75 100644 --- a/Tethering/res/values-my/strings.xml +++ b/Tethering/res/values-my/strings.xml @@ -1,8 +1,29 @@ + + - "တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" - "စနစ်ထည့်သွင်းရန် တို့ပါ။" - "မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်" - "အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်" + "စနစ်ထည့်သွင်းရန် တို့ပါ။" + "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်" + "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ" + "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ" + + + + + diff --git a/Tethering/res/values-nb/strings.xml b/Tethering/res/values-nb/strings.xml index 9abf32dd7b..9594e0a70a 100644 --- a/Tethering/res/values-nb/strings.xml +++ b/Tethering/res/values-nb/strings.xml @@ -1,8 +1,29 @@ + + - "Internettdeling eller trådløs sone er aktiv" - "Trykk for å konfigurere." - "Internettdeling er slått av" - "Ta kontakt med administratoren din for å få mer informasjon" + "Internettdeling eller Wi-Fi-sone er aktiv" + "Trykk for å konfigurere." + "Internettdeling er slått av" + "Ta kontakt med administratoren din for å få mer informasjon" + "Status for Wi-Fi-sone og internettdeling" + + + + + diff --git a/Tethering/res/values-ne/strings.xml b/Tethering/res/values-ne/strings.xml index c8869298a5..72ae3a80a9 100644 --- a/Tethering/res/values-ne/strings.xml +++ b/Tethering/res/values-ne/strings.xml @@ -1,8 +1,29 @@ + + - "टेथर गर्ने वा हटस्पट सक्रिय" - "सेटअप गर्न ट्याप गर्नुहोस्।" - "टेदरिङलाई असक्षम पारिएको छ" - "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "टेदरिङ वा हटस्पट सक्रिय छ" + "सेटअप गर्न ट्याप गर्नुहोस्।" + "टेदरिङ सुविधा असक्षम पारिएको छ" + "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्" + "हटस्पट तथा टेदरिङको स्थिति" + + + + + diff --git a/Tethering/res/values-nl/strings.xml b/Tethering/res/values-nl/strings.xml index 0ec4bff621..18b2bbfc76 100644 --- a/Tethering/res/values-nl/strings.xml +++ b/Tethering/res/values-nl/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering of hotspot actief" - "Tik om in te stellen." - "Tethering is uitgeschakeld" - "Neem contact op met je beheerder voor meer informatie" + "Tethering of hotspot actief" + "Tik om in te stellen." + "Tethering is uitgeschakeld" + "Neem contact op met je beheerder voor meer informatie" + "Status van hotspot en tethering" + + + + + diff --git a/Tethering/res/values-or/strings.xml b/Tethering/res/values-or/strings.xml index 457685795a..a15a6db42a 100644 --- a/Tethering/res/values-or/strings.xml +++ b/Tethering/res/values-or/strings.xml @@ -1,8 +1,29 @@ + + - "ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି" - "ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।" - "ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି" - "ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି" + "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।" + "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି" + "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ" + "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି" + + + + + diff --git a/Tethering/res/values-pa/strings.xml b/Tethering/res/values-pa/strings.xml index deddf2ea27..a8235e423e 100644 --- a/Tethering/res/values-pa/strings.xml +++ b/Tethering/res/values-pa/strings.xml @@ -1,8 +1,29 @@ + + - "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" - "ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" - "ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ" - "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ" + "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ" + "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।" + "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ" + "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" + "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ" + + + + + diff --git a/Tethering/res/values-pl/strings.xml b/Tethering/res/values-pl/strings.xml index 48d8468935..ccb017d43f 100644 --- a/Tethering/res/values-pl/strings.xml +++ b/Tethering/res/values-pl/strings.xml @@ -1,8 +1,29 @@ + + - "Aktywny tethering lub punkt dostępu" - "Kliknij, by skonfigurować." - "Tethering został wyłączony" - "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Aktywny tethering lub punkt dostępu" + "Kliknij, by skonfigurować" + "Tethering został wyłączony" + "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem" + "Hotspot i tethering – stan" + + + + + diff --git a/Tethering/res/values-pt-rBR/strings.xml b/Tethering/res/values-pt-rBR/strings.xml index 32c22b8713..a0a4745f93 100644 --- a/Tethering/res/values-pt-rBR/strings.xml +++ b/Tethering/res/values-pt-rBR/strings.xml @@ -1,8 +1,29 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + diff --git a/Tethering/res/values-pt-rPT/strings.xml b/Tethering/res/values-pt-rPT/strings.xml index 641e22f44f..e3f03fcc69 100644 --- a/Tethering/res/values-pt-rPT/strings.xml +++ b/Tethering/res/values-pt-rPT/strings.xml @@ -1,8 +1,29 @@ + + - "Ligação ponto a ponto ou hotspot activos" - "Toque para configurar." - "A ligação (à Internet) via telemóvel está desativada." - "Contacte o gestor para obter detalhes." + "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas" + "Toque para configurar." + "A ligação (à Internet) via telemóvel está desativada." + "Contacte o administrador para obter detalhes." + "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel" + + + + + diff --git a/Tethering/res/values-pt/strings.xml b/Tethering/res/values-pt/strings.xml index 32c22b8713..a0a4745f93 100644 --- a/Tethering/res/values-pt/strings.xml +++ b/Tethering/res/values-pt/strings.xml @@ -1,8 +1,29 @@ + + - "Ponto de acesso ou tethering ativo" - "Toque para configurar." - "Tethering desativado" - "Fale com seu administrador para saber detalhes" + "Ponto de acesso ou tethering ativo" + "Toque para configurar." + "Tethering desativado" + "Fale com seu administrador para saber detalhes" + "Status de ponto de acesso e tethering" + + + + + diff --git a/Tethering/res/values-ro/strings.xml b/Tethering/res/values-ro/strings.xml index f861f733b4..5706a4a69c 100644 --- a/Tethering/res/values-ro/strings.xml +++ b/Tethering/res/values-ro/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering sau hotspot activ" - "Atingeți ca să configurați." - "Tetheringul este dezactivat" - "Contactați administratorul pentru detalii" + "Tethering sau hotspot activ" + "Atingeți ca să configurați." + "Tetheringul este dezactivat" + "Contactați administratorul pentru detalii" + "Starea hotspotului și a tetheringului" + + + + + diff --git a/Tethering/res/values-ru/strings.xml b/Tethering/res/values-ru/strings.xml index 027cb410c5..7cb6f7db3f 100644 --- a/Tethering/res/values-ru/strings.xml +++ b/Tethering/res/values-ru/strings.xml @@ -1,8 +1,29 @@ + + - "Включен режим модема" - "Нажмите, чтобы настроить." - "Включить режим модема нельзя" - "Обратитесь к администратору, чтобы узнать подробности." + "Включен режим модема или точка доступа" + "Нажмите, чтобы настроить." + "Использование телефона в качестве модема запрещено" + "Чтобы узнать подробности, обратитесь к администратору." + "Статус хот-спота и режима модема" + + + + + diff --git a/Tethering/res/values-si/strings.xml b/Tethering/res/values-si/strings.xml index 7d8599f2c2..ec34c22de7 100644 --- a/Tethering/res/values-si/strings.xml +++ b/Tethering/res/values-si/strings.xml @@ -1,8 +1,29 @@ + + - "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" - "පිහිටුවීමට තට්ටු කරන්න." - "ටෙදරින් අබල කර ඇත" - "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි" + "පිහිටුවීමට තට්ටු කරන්න." + "ටෙදරින් අබල කර ඇත" + "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න" + "හොට්ස්පොට් & ටෙදරින් තත්ත්වය" + + + + + diff --git a/Tethering/res/values-sk/strings.xml b/Tethering/res/values-sk/strings.xml index a8fe297c00..43e787c84f 100644 --- a/Tethering/res/values-sk/strings.xml +++ b/Tethering/res/values-sk/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering alebo prístupový bod je aktívny" - "Klepnutím prejdete na nastavenie." - "Tethering je deaktivovaný" - "O podrobnosti požiadajte svojho správcu" + "Tethering alebo prístupový bod je aktívny" + "Klepnutím prejdete na nastavenie." + "Tethering je deaktivovaný" + "O podrobnosti požiadajte svojho správcu" + "Stav hotspotu a tetheringu" + + + + + diff --git a/Tethering/res/values-sl/strings.xml b/Tethering/res/values-sl/strings.xml index b5e5e3856f..59433626a1 100644 --- a/Tethering/res/values-sl/strings.xml +++ b/Tethering/res/values-sl/strings.xml @@ -1,8 +1,29 @@ + + - "Aktivna povezava z internetom ali dostopna točka sta aktivni" - "Dotaknite se, če želite nastaviti." - "Povezava z internetom prek mobilnega telefona je onemogočena" - "Za podrobnosti se obrnite na skrbnika" + "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna" + "Dotaknite se, če želite nastaviti." + "Povezava z internetom prek mobilnega telefona je onemogočena" + "Za podrobnosti se obrnite na skrbnika" + "Stanje dostopne točke in povezave z internetom prek mobilnega telefona" + + + + + diff --git a/Tethering/res/values-sq/strings.xml b/Tethering/res/values-sq/strings.xml index fdd4906cc5..21e11558bb 100644 --- a/Tethering/res/values-sq/strings.xml +++ b/Tethering/res/values-sq/strings.xml @@ -1,8 +1,29 @@ + + - "Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive" - "Trokit për ta konfiguruar." - "Lidhja e çiftimit është çaktivizuar" - "Kontakto me administratorin për detaje" + "Ndarja e internetit ose zona e qasjes së internetit është aktive" + "Trokit për ta konfiguruar." + "Ndarja e internetit është çaktivizuar" + "Kontakto me administratorin për detaje" + "Statusi i zonës së qasjes dhe ndarjes së internetit" + + + + + diff --git a/Tethering/res/values-sr/strings.xml b/Tethering/res/values-sr/strings.xml index 9fab345897..e2e4dc6361 100644 --- a/Tethering/res/values-sr/strings.xml +++ b/Tethering/res/values-sr/strings.xml @@ -1,8 +1,29 @@ + + - "Активно повезивање са интернетом преко мобилног уређаја или хотспот" - "Додирните да бисте подесили." - "Привезивање је онемогућено" - "Потражите детаље од администратора" + "Привезивање или хотспот је активан" + "Додирните да бисте подесили." + "Привезивање је онемогућено" + "Потражите детаље од администратора" + "Статус хотспота и привезивања" + + + + + diff --git a/Tethering/res/values-sv/strings.xml b/Tethering/res/values-sv/strings.xml index 10eeb0fe12..72702c2858 100644 --- a/Tethering/res/values-sv/strings.xml +++ b/Tethering/res/values-sv/strings.xml @@ -1,8 +1,29 @@ + + - "Internetdelning eller surfzon aktiverad" - "Tryck om du vill konfigurera." - "Internetdelning har inaktiverats" - "Kontakta administratören om du vill veta mer" + "Internetdelning eller surfzon har aktiverats" + "Tryck om du vill konfigurera." + "Internetdelning har inaktiverats" + "Kontakta administratören om du vill veta mer" + "Trådlös surfzon och internetdelning har inaktiverats" + + + + + diff --git a/Tethering/res/values-sw/strings.xml b/Tethering/res/values-sw/strings.xml index 3353963077..65e4aa8ceb 100644 --- a/Tethering/res/values-sw/strings.xml +++ b/Tethering/res/values-sw/strings.xml @@ -1,8 +1,29 @@ + + - "Kushiriki au kusambaza intaneti kumewashwa" - "Gusa ili uweke mipangilio." - "Umezima kipengele cha kusambaza mtandao" - "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Kusambaza mtandao au mtandaopepe umewashwa" + "Gusa ili uweke mipangilio." + "Umezima kipengele cha kusambaza mtandao" + "Wasiliana na msimamizi wako ili upate maelezo zaidi" + "Mtandaopepe na hali ya kusambaza mtandao" + + + + + diff --git a/Tethering/res/values-ta/strings.xml b/Tethering/res/values-ta/strings.xml index b1e5cc2413..4aba62d4ab 100644 --- a/Tethering/res/values-ta/strings.xml +++ b/Tethering/res/values-ta/strings.xml @@ -1,8 +1,29 @@ + + - "டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது" - "அமைக்க, தட்டவும்." - "இணைப்பு முறை முடக்கப்பட்டுள்ளது" - "விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது" + "அமைக்க, தட்டவும்." + "டெதெரிங் முடக்கப்பட்டுள்ளது" + "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்" + "ஹாட்ஸ்பாட் & டெதெரிங் நிலை" + + + + + diff --git a/Tethering/res/values-te/strings.xml b/Tethering/res/values-te/strings.xml index aae40dee40..1f91791341 100644 --- a/Tethering/res/values-te/strings.xml +++ b/Tethering/res/values-te/strings.xml @@ -1,8 +1,29 @@ + + - "టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది" - "సెటప్ చేయడానికి నొక్కండి." - "టెథెరింగ్ నిలిపివేయబడింది" - "వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి" + "టెథరింగ్ లేదా హాట్‌స్పాట్ యాక్టివ్‌గా ఉంది" + "సెటప్ చేయడానికి ట్యాప్ చేయండి." + "టెథరింగ్ డిజేబుల్ చేయబడింది" + "వివరాల కోసం మీ అడ్మిన్‌ని సంప్రదించండి" + "హాట్‌స్పాట్ & టెథరింగ్ స్థితి" + + + + + diff --git a/Tethering/res/values-th/strings.xml b/Tethering/res/values-th/strings.xml index 1b800565ad..44171c0db8 100644 --- a/Tethering/res/values-th/strings.xml +++ b/Tethering/res/values-th/strings.xml @@ -1,8 +1,29 @@ + + - "การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่" - "แตะเพื่อตั้งค่า" - "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" - "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่" + "แตะเพื่อตั้งค่า" + "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว" + "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด" + "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ" + + + + + diff --git a/Tethering/res/values-tl/strings.xml b/Tethering/res/values-tl/strings.xml index 12863f90e1..7347dd3e62 100644 --- a/Tethering/res/values-tl/strings.xml +++ b/Tethering/res/values-tl/strings.xml @@ -1,8 +1,29 @@ + + - "Pagsasama o aktibong hotspot" - "I-tap upang i-set up." - "Naka-disable ang pag-tether" - "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Aktibo ang pag-tether o hotspot" + "I-tap para i-set up." + "Naka-disable ang pag-tether" + "Makipag-ugnayan sa iyong admin para sa mga detalye" + "Status ng hotspot at pag-tether" + + + + + diff --git a/Tethering/res/values-tr/strings.xml b/Tethering/res/values-tr/strings.xml index bfcf1ace2c..32030f1765 100644 --- a/Tethering/res/values-tr/strings.xml +++ b/Tethering/res/values-tr/strings.xml @@ -1,8 +1,29 @@ + + - "Tethering veya hotspot etkin" - "Ayarlamak için dokunun." - "Tethering devre dışı bırakıldı" - "Ayrıntılı bilgi için yöneticinize başvurun" + "Tethering veya hotspot etkin" + "Ayarlamak için dokunun." + "Tethering devre dışı bırakıldı" + "Ayrıntılı bilgi için yöneticinize başvurun" + "Hotspot ve tethering durumu" + + + + + diff --git a/Tethering/res/values-uk/strings.xml b/Tethering/res/values-uk/strings.xml index 8e159c0723..1ca89b3f78 100644 --- a/Tethering/res/values-uk/strings.xml +++ b/Tethering/res/values-uk/strings.xml @@ -1,8 +1,29 @@ + + - "Прив\'язка чи точка дост. активна" - "Торкніться, щоб налаштувати." - "Використання телефона в режимі модема вимкнено" - "Щоб дізнатися більше, зв’яжіться з адміністратором" + "Модем чи точка доступу активні" + "Натисніть, щоб налаштувати." + "Використання телефона як модема вимкнено" + "Щоб дізнатися більше, зв\'яжіться з адміністратором" + "Статус точки доступу та модема" + + + + + diff --git a/Tethering/res/values-ur/strings.xml b/Tethering/res/values-ur/strings.xml index 89195d4aae..d72c7d4195 100644 --- a/Tethering/res/values-ur/strings.xml +++ b/Tethering/res/values-ur/strings.xml @@ -1,8 +1,29 @@ + + - "ٹیدرنگ یا ہاٹ اسپاٹ فعال" - "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" - "ٹیدرنگ غیر فعال ہے" - "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ٹیدرنگ یا ہاٹ اسپاٹ فعال" + "سیٹ اپ کرنے کیلئے تھپتھپائیں۔" + "ٹیدرنگ غیر فعال ہے" + "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں" + "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس" + + + + + diff --git a/Tethering/res/values-uz/strings.xml b/Tethering/res/values-uz/strings.xml index 0ac4d4a741..af3b2ebb35 100644 --- a/Tethering/res/values-uz/strings.xml +++ b/Tethering/res/values-uz/strings.xml @@ -1,8 +1,29 @@ + + - "Modem rejimi yoniq" - "Sozlash uchun bosing." - "Modem rejimi faolsizlantirildi" - "Tafsilotlari uchun administratoringizga murojaat qiling" + "Modem rejimi yoki hotspot yoniq" + "Sozlash uchun bosing." + "Modem rejimi faolsizlantirildi" + "Tafsilotlari uchun administratoringizga murojaat qiling" + "Hotspot va modem rejimi holati" + + + + + diff --git a/Tethering/res/values-vi/strings.xml b/Tethering/res/values-vi/strings.xml index 85a4db8aa5..21a0735922 100644 --- a/Tethering/res/values-vi/strings.xml +++ b/Tethering/res/values-vi/strings.xml @@ -1,8 +1,29 @@ + + - "Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động" - "Nhấn để thiết lập." - "Đã tắt tính năng chia sẻ kết nối" - "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động" + "Hãy nhấn để thiết lập." + "Đã tắt tính năng chia sẻ Internet" + "Hãy liên hệ với quản trị viên của bạn để biết chi tiết" + "Trạng thái điểm phát sóng và chia sẻ Internet" + + + + + diff --git a/Tethering/res/values-zh-rCN/strings.xml b/Tethering/res/values-zh-rCN/strings.xml index ff1fe03953..98e3b4b46f 100644 --- a/Tethering/res/values-zh-rCN/strings.xml +++ b/Tethering/res/values-zh-rCN/strings.xml @@ -1,8 +1,29 @@ + + - "网络共享或热点已启用" - "点按即可进行设置。" - "网络共享已停用" - "请与您的管理员联系以了解详情" + "网络共享或热点已启用" + "点按即可设置。" + "网络共享已停用" + "如需了解详情,请与您的管理员联系" + "热点和网络共享状态" + + + + + diff --git a/Tethering/res/values-zh-rHK/strings.xml b/Tethering/res/values-zh-rHK/strings.xml index 0de39fac97..9cafd42dd4 100644 --- a/Tethering/res/values-zh-rHK/strings.xml +++ b/Tethering/res/values-zh-rHK/strings.xml @@ -1,8 +1,29 @@ + + - "已啟用網絡共享或熱點" - "輕按即可設定。" - "網絡共享已停用" - "請聯絡您的管理員以瞭解詳情" + "網絡共享或熱點已啟用" + "輕按即可設定。" + "網絡共享已停用" + "請聯絡您的管理員以瞭解詳情" + "熱點和網絡共享狀態" + + + + + diff --git a/Tethering/res/values-zh-rTW/strings.xml b/Tethering/res/values-zh-rTW/strings.xml index 9a117bbca4..50a50bf7a9 100644 --- a/Tethering/res/values-zh-rTW/strings.xml +++ b/Tethering/res/values-zh-rTW/strings.xml @@ -1,8 +1,29 @@ + + - "網路共用或無線基地台已啟用" - "輕觸即可進行設定。" - "數據連線已停用" - "詳情請洽你的管理員" + "網路共用或無線基地台已啟用" + "輕觸即可進行設定。" + "網路共用已停用" + "詳情請洽你的管理員" + "無線基地台與網路共用狀態" + + + + + diff --git a/Tethering/res/values-zu/strings.xml b/Tethering/res/values-zu/strings.xml index 8fe10d86cb..f210f8726e 100644 --- a/Tethering/res/values-zu/strings.xml +++ b/Tethering/res/values-zu/strings.xml @@ -1,8 +1,29 @@ + + - "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" - "Thepha ukuze usethe." - "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" - "Xhumana nomphathi wakho ukuze uthole imininingwane" + "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe" + "Thepha ukuze usethe." + "Ukusebenzisa ifoni njengemodemu kukhutshaziwe" + "Xhumana nomphathi wakho ukuze uthole imininingwane" + "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu" + + + + + From 9aed13818c6a82f8b1632ea5df53479828f9f704 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Tue, 18 Aug 2020 12:52:51 +0100 Subject: [PATCH 1291/1415] Simplify module visibility post build refactor //visibility:override is no longer needed for impl_library_visibility to override visibility. Removing this allows the defaults module to specify better defaults. - Stub libraries are made publicly visible, via `visibility` - Impl libraries are private by default, but visibility is extended by the modules Bug: 165017290 Test: m Exempt-From-Owner-Approval: build refactor Change-Id: Ibf35bfac5c99a21125f89ba10945f3364217b90f --- Tethering/common/TetheringLib/Android.bp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index c8becce7be..bf643cdcec 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -16,19 +16,9 @@ java_sdk_library { name: "framework-tethering", defaults: ["framework-module-defaults"], + impl_library_visibility: ["//frameworks/base/packages/Tethering:__subpackages__"], - // Allow access to the stubs from anywhere. - visibility: ["//visibility:public"], - - // Restrict access to implementation library. - impl_library_visibility: [ - "//visibility:override", // Ignore the visibility property. - "//frameworks/base/packages/Tethering:__subpackages__", - ], - - srcs: [ - ":framework-tethering-srcs", - ], + srcs: [":framework-tethering-srcs"], jarjar_rules: "jarjar-rules.txt", installable: true, From 56c632caed6dcdec8ae9c99d56d41756f7e3a3f8 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 10 Sep 2020 15:42:58 +0800 Subject: [PATCH 1292/1415] Move BPF offload program from netd to mainline Test: as the follows. $ adb shell ls sys/fs/bpf | grep offload map_offload_tether_ingress_map map_offload_tether_limit_map map_offload_tether_stats_map prog_offload_schedcls_ingress_tether_ether prog_offload_schedcls_ingress_tether_rawip $ adb shell dumpsys netd --short TetherController BPF ingress map: iif(iface) v6addr -> oif(iface) srcmac .. 13(rmnet_data3) 2401:e180:8842:6e3:bc6a:2e45:c30:f418 -> .. BPF stats (downlink): iif(iface) -> packets bytes errors 13(rmnet_data3) -> 7 488 0 BPF limit: iif(iface) -> bytes 13(rmnet_data3) -> 9223372036854775807 Log: bpfloader: Loaded object: /apex/com.android.tethering/etc/bpf/offload.o Change-Id: I71b7efb1f4bd6eb1cd469a0e1e4a56342dc6e579 --- Tethering/apex/Android.bp | 1 + Tethering/bpf_progs/Android.bp | 33 ++++++ Tethering/bpf_progs/offload.c | 207 +++++++++++++++++++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 Tethering/bpf_progs/Android.bp create mode 100644 Tethering/bpf_progs/offload.c diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp index 67097a79e5..05243749f7 100644 --- a/Tethering/apex/Android.bp +++ b/Tethering/apex/Android.bp @@ -19,6 +19,7 @@ apex { updatable: true, min_sdk_version: "current", java_libs: ["framework-tethering"], + bpfs: ["offload.o"], apps: ["Tethering"], manifest: "manifest.json", key: "com.android.tethering.key", diff --git a/Tethering/bpf_progs/Android.bp b/Tethering/bpf_progs/Android.bp new file mode 100644 index 0000000000..d54f861486 --- /dev/null +++ b/Tethering/bpf_progs/Android.bp @@ -0,0 +1,33 @@ +// +// 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. +// + +// +// bpf kernel programs +// +bpf { + name: "offload.o", + srcs: ["offload.c"], + cflags: [ + "-Wall", + "-Werror", + ], + include_dirs: [ + // TODO: get rid of system/netd. + "system/netd/bpf_progs", // for bpf_net_helpers.h + "system/netd/libnetdbpf/include", // for bpf_shared.h + "system/netd/libnetdutils/include", // for UidConstants.h + ], +} diff --git a/Tethering/bpf_progs/offload.c b/Tethering/bpf_progs/offload.c new file mode 100644 index 0000000000..cc5af3127b --- /dev/null +++ b/Tethering/bpf_progs/offload.c @@ -0,0 +1,207 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_net_helpers.h" +#include "netdbpf/bpf_shared.h" + +DEFINE_BPF_MAP_GRW(tether_ingress_map, HASH, TetherIngressKey, TetherIngressValue, 64, + AID_NETWORK_STACK) + +// Tethering stats, indexed by upstream interface. +DEFINE_BPF_MAP_GRW(tether_stats_map, HASH, uint32_t, TetherStatsValue, 16, AID_NETWORK_STACK) + +// Tethering data limit, indexed by upstream interface. +// (tethering allowed when stats[iif].rxBytes + stats[iif].txBytes < limit[iif]) +DEFINE_BPF_MAP_GRW(tether_limit_map, HASH, uint32_t, uint64_t, 16, AID_NETWORK_STACK) + +static inline __always_inline int do_forward(struct __sk_buff* skb, bool is_ethernet) { + int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0; + void* data = (void*)(long)skb->data; + const void* data_end = (void*)(long)skb->data_end; + struct ethhdr* eth = is_ethernet ? data : NULL; // used iff is_ethernet + struct ipv6hdr* ip6 = is_ethernet ? (void*)(eth + 1) : data; + + // Must be meta-ethernet IPv6 frame + if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK; + + // Must have (ethernet and) ipv6 header + if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_OK; + + // Ethertype - if present - must be IPv6 + if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK; + + // IP version must be 6 + if (ip6->version != 6) return TC_ACT_OK; + + // Cannot decrement during forward if already zero or would be zero, + // Let the kernel's stack handle these cases and generate appropriate ICMP errors. + if (ip6->hop_limit <= 1) return TC_ACT_OK; + + // Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness. + __be32 src32 = ip6->saddr.s6_addr32[0]; + if (src32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP + (src32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast + return TC_ACT_OK; + + TetherIngressKey k = { + .iif = skb->ifindex, + .neigh6 = ip6->daddr, + }; + + TetherIngressValue* v = bpf_tether_ingress_map_lookup_elem(&k); + + // If we don't find any offload information then simply let the core stack handle it... + if (!v) return TC_ACT_OK; + + uint32_t stat_and_limit_k = skb->ifindex; + + TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k); + + // If we don't have anywhere to put stats, then abort... + if (!stat_v) return TC_ACT_OK; + + uint64_t* limit_v = bpf_tether_limit_map_lookup_elem(&stat_and_limit_k); + + // If we don't have a limit, then abort... + if (!limit_v) return TC_ACT_OK; + + // Required IPv6 minimum mtu is 1280, below that not clear what we should do, abort... + const int pmtu = v->pmtu; + if (pmtu < IPV6_MIN_MTU) return TC_ACT_OK; + + // Approximate handling of TCP/IPv6 overhead for incoming LRO/GRO packets: default + // outbound path mtu of 1500 is not necessarily correct, but worst case we simply + // undercount, which is still better then not accounting for this overhead at all. + // Note: this really shouldn't be device/path mtu at all, but rather should be + // derived from this particular connection's mss (ie. from gro segment size). + // This would require a much newer kernel with newer ebpf accessors. + // (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header) + uint64_t packets = 1; + uint64_t bytes = skb->len; + if (bytes > pmtu) { + const int tcp_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12; + const int mss = pmtu - tcp_overhead; + const uint64_t payload = bytes - tcp_overhead; + packets = (payload + mss - 1) / mss; + bytes = tcp_overhead * packets + payload; + } + + // Are we past the limit? If so, then abort... + // Note: will not overflow since u64 is 936 years even at 5Gbps. + // Do not drop here. Offload is just that, whenever we fail to handle + // a packet we let the core stack deal with things. + // (The core stack needs to handle limits correctly anyway, + // since we don't offload all traffic in both directions) + if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) return TC_ACT_OK; + + if (!is_ethernet) { + is_ethernet = true; + l2_header_size = sizeof(struct ethhdr); + // Try to inject an ethernet header, and simply return if we fail + if (bpf_skb_change_head(skb, l2_header_size, /*flags*/ 0)) { + __sync_fetch_and_add(&stat_v->rxErrors, 1); + return TC_ACT_OK; + } + + // bpf_skb_change_head() invalidates all pointers - reload them + data = (void*)(long)skb->data; + data_end = (void*)(long)skb->data_end; + eth = data; + ip6 = (void*)(eth + 1); + + // I do not believe this can ever happen, but keep the verifier happy... + if (data + l2_header_size + sizeof(*ip6) > data_end) { + __sync_fetch_and_add(&stat_v->rxErrors, 1); + return TC_ACT_SHOT; + } + }; + + // CHECKSUM_COMPLETE is a 16-bit one's complement sum, + // thus corrections for it need to be done in 16-byte chunks at even offsets. + // IPv6 nexthdr is at offset 6, while hop limit is at offset 7 + uint8_t old_hl = ip6->hop_limit; + --ip6->hop_limit; + uint8_t new_hl = ip6->hop_limit; + + // bpf_csum_update() always succeeds if the skb is CHECKSUM_COMPLETE and returns an error + // (-ENOTSUPP) if it isn't. + bpf_csum_update(skb, 0xFFFF - ntohs(old_hl) + ntohs(new_hl)); + + __sync_fetch_and_add(&stat_v->rxPackets, packets); + __sync_fetch_and_add(&stat_v->rxBytes, bytes); + + // Overwrite any mac header with the new one + *eth = v->macHeader; + + // Redirect to forwarded interface. + // + // Note that bpf_redirect() cannot fail unless you pass invalid flags. + // The redirect actually happens after the ebpf program has already terminated, + // and can fail for example for mtu reasons at that point in time, but there's nothing + // we can do about it here. + return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */); +} + +SEC("schedcls/ingress/tether_ether") +int sched_cls_ingress_tether_ether(struct __sk_buff* skb) { + return do_forward(skb, true); +} + +// Note: section names must be unique to prevent programs from appending to each other, +// so instead the bpf loader will strip everything past the final $ symbol when actually +// pinning the program into the filesystem. +// +// bpf_skb_change_head() is only present on 4.14+ and 2 trivial kernel patches are needed: +// ANDROID: net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head +// ANDROID: net: bpf: permit redirect from ingress L3 to egress L2 devices at near max mtu +// (the first of those has already been upstreamed) +// +// 5.4 kernel support was only added to Android Common Kernel in R, +// and thus a 5.4 kernel always supports this. +// +// Hence, this mandatory (must load successfully) implementation for 5.4+ kernels: +DEFINE_BPF_PROG_KVER("schedcls/ingress/tether_rawip$5_4", AID_ROOT, AID_ROOT, + sched_cls_ingress_tether_rawip_5_4, KVER(5, 4, 0)) +(struct __sk_buff* skb) { + return do_forward(skb, false); +} + +// and this identical optional (may fail to load) implementation for [4.14..5.4) patched kernels: +DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$4_14", AID_ROOT, AID_ROOT, + sched_cls_ingress_tether_rawip_4_14, KVER(4, 14, 0), + KVER(5, 4, 0)) +(struct __sk_buff* skb) { + return do_forward(skb, false); +} + +// and define a no-op stub for [4.9,4.14) and unpatched [4.14,5.4) kernels. +// (if the above real 4.14+ program loaded successfully, then bpfloader will have already pinned +// it at the same location this one would be pinned at and will thus skip loading this stub) +DEFINE_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$stub", AID_ROOT, AID_ROOT, + sched_cls_ingress_tether_rawip_stub, KVER_NONE, KVER(5, 4, 0)) +(struct __sk_buff* skb) { + return TC_ACT_OK; +} + +LICENSE("Apache 2.0"); +CRITICAL("netd"); From ae3412405d68d0a49bebf6cc2e57162c6bf6c84d Mon Sep 17 00:00:00 2001 From: Josh Yang Date: Fri, 11 Sep 2020 15:32:43 -0700 Subject: [PATCH 1293/1415] Skip unsupported hardware for testB141603906 Bug: 168748249 Fix: 168748249 Test: local cts passed. Change-Id: I8af0d5f9716a510322b2bfb0cdf6f05f94b12604 --- .../hostside/app/src/com/android/cts/net/hostside/VpnTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index a451ea8585..d312f18f2b 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -1009,6 +1009,9 @@ public class VpnTest extends InstrumentationTestCase { } public void testB141603906() throws Exception { + if (!supportedHardware()) { + return; + } final InetSocketAddress src = new InetSocketAddress(0); final InetSocketAddress dst = new InetSocketAddress(0); final int NUM_THREADS = 8; From 17ee20dc59061f5a963c4915314e3acde98be849 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 27 Aug 2020 18:02:03 +0800 Subject: [PATCH 1294/1415] Deflake test to ensure airplane mode switches work as expected testSetAirplaneMode verifies the result by checking if intent is broadcasted or not. The working internet may sometimes remain connected if the commands processed fast but sometimes don't. It will leave uncertain network status to the follow-up tests and cause flaky. This behavior specifically breaks testRequestNetworkCallback_onUnavailable. As WiFi is not enabled and still disconnecting, the behavior will confuse test to not to disconnect WiFi. However, test may still get an active WiFi network since the WiFi is not disconneted yet. Thus, verify that working internet should disconnect and reconnect expectedly if airplane mode is updated. Bug: 162323152 Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest\ --rerun-until-failure 20 Change-Id: Id126c43b1f009e7bbce18d75020f25347448b7fb --- .../net/cts/ConnectivityManagerTest.java | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 0790acb54e..455da263ca 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -97,7 +97,9 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.ArrayUtils; +import com.android.testutils.RecorderCallback.CallbackEntry; import com.android.testutils.SkipPresubmit; +import com.android.testutils.TestableNetworkCallback; import libcore.io.Streams; @@ -155,7 +157,7 @@ public class ConnectivityManagerTest { private static final int MIN_NUM_NETWORK_TYPES = 1; // Airplane Mode BroadcastReceiver Timeout - private static final int AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 5000; + private static final long AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 10_000L; // Minimum supported keepalive counts for wifi and cellular. public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1; @@ -473,6 +475,12 @@ public class ConnectivityManagerTest { .build(); } + private NetworkRequest makeCellNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .build(); + } + /** * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to * see if we get a callback for the TRANSPORT_WIFI transport type being available. @@ -1387,11 +1395,19 @@ public class ConnectivityManagerTest { @AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps") @Test public void testSetAirplaneMode() throws Exception{ + final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI); + final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); // store the current state of airplane mode final boolean isAirplaneModeEnabled = isAirplaneModeEnabled(); - + final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); + final TestableNetworkCallback telephonyCb = new TestableNetworkCallback(); // disable airplane mode to reach a known state runShellCommand("cmd connectivity airplane-mode disable"); + // Verify that networks are available as expected if wifi or cell is supported. Continue the + // test if none of them are supported since test should still able to verify the permission + // mechanism. + if (supportWifi) requestAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb); + if (supportTelephony) requestAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb); try { // Verify we cannot set Airplane Mode without correct permission: @@ -1414,6 +1430,11 @@ public class ConnectivityManagerTest { fail("SecurityException should not have been thrown when setAirplaneMode(true) was" + "called whilst holding the NETWORK_AIRPLANE_MODE permission."); } + // Verify that the enabling airplane mode takes effect as expected to prevent flakiness + // caused by fast airplane mode switches. Ensure network lost before turning off + // airplane mode. + if (supportWifi) waitForLost(wifiCb); + if (supportTelephony) waitForLost(telephonyCb); // Verify we can disable Airplane Mode with correct permission: try { @@ -1422,8 +1443,12 @@ public class ConnectivityManagerTest { fail("SecurityException should not have been thrown when setAirplaneMode(false) was" + "called whilst holding the NETWORK_AIRPLANE_MODE permission."); } - + // Verify that turning airplane mode off takes effect as expected. + if (supportWifi) waitForAvailable(wifiCb); + if (supportTelephony) waitForAvailable(telephonyCb); } finally { + if (supportWifi) mCm.unregisterNetworkCallback(wifiCb); + if (supportTelephony) mCm.unregisterNetworkCallback(telephonyCb); // Restore the previous state of airplane mode and permissions: runShellCommand("cmd connectivity airplane-mode " + (isAirplaneModeEnabled ? "enable" : "disable")); @@ -1431,6 +1456,22 @@ public class ConnectivityManagerTest { } } + private void requestAndWaitForAvailable(@NonNull final NetworkRequest request, + @NonNull final TestableNetworkCallback cb) { + mCm.registerNetworkCallback(request, cb); + waitForAvailable(cb); + } + + private void waitForAvailable(@NonNull final TestableNetworkCallback cb) { + cb.eventuallyExpect(CallbackEntry.AVAILABLE, AIRPLANE_MODE_CHANGE_TIMEOUT_MS, + c -> c instanceof CallbackEntry.Available); + } + + private void waitForLost(@NonNull final TestableNetworkCallback cb) { + cb.eventuallyExpect(CallbackEntry.LOST, AIRPLANE_MODE_CHANGE_TIMEOUT_MS, + c -> c instanceof CallbackEntry.Lost); + } + private void setAndVerifyAirplaneMode(Boolean expectedResult) throws Exception { final CompletableFuture actualResult = new CompletableFuture(); From 90e4063fd24e5272159242e8ccf9907ce5b83c1c Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Fri, 13 Mar 2020 11:38:38 -0700 Subject: [PATCH 1295/1415] tethering: DAD Proxy Daemon DAD proxy daemon responsible for forwarding NS/NA between tethered iface and upstream iface. Change-Id: I2e58e10e7fa7dba6a6f63ad03b000549f3afc37e --- .../jni/android_net_util_TetheringUtils.cpp | 52 ++- Tethering/src/android/net/ip/DadProxy.java | 54 +++ Tethering/src/android/net/ip/IpServer.java | 45 ++- .../net/ip/NeighborPacketForwarder.java | 180 ++++++++++ .../net/ip/RouterAdvertisementDaemon.java | 16 +- .../src/android/net/util/TetheringUtils.java | 33 ++ Tethering/tests/privileged/Android.bp | 21 +- .../src/android/net/ip/DadProxyTest.java | 338 ++++++++++++++++++ .../unit/src/android/net/ip/IpServerTest.java | 91 +++++ .../networkstack/tethering/TetheringTest.java | 13 + 10 files changed, 818 insertions(+), 25 deletions(-) create mode 100644 Tethering/src/android/net/ip/DadProxy.java create mode 100644 Tethering/src/android/net/ip/NeighborPacketForwarder.java create mode 100644 Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp index f6eb40a842..94c871d8a3 100644 --- a/Tethering/jni/android_net_util_TetheringUtils.cpp +++ b/Tethering/jni/android_net_util_TetheringUtils.cpp @@ -17,18 +17,63 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include +#include #define LOG_TAG "TetheringUtils" #include namespace android { +static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt); +static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr); +static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type); + +static void android_net_util_setupIcmpFilter(JNIEnv *env, jobject javaFd, uint32_t type) { + sock_filter filter_code[] = { + // Check header is ICMPv6. + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeaderOffset), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3), + + // Check ICMPv6 type. + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, type, 0, 1), + + // Accept or reject. + BPF_STMT(BPF_RET | BPF_K, 0xffff), + BPF_STMT(BPF_RET | BPF_K, 0) + }; + + const sock_fprog filter = { + sizeof(filter_code) / sizeof(filter_code[0]), + filter_code, + }; + + int fd = jniGetFDFromFileDescriptor(env, javaFd); + if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) { + jniThrowExceptionFmt(env, "java/net/SocketException", + "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno)); + } +} + +static void android_net_util_setupNaSocket(JNIEnv *env, jobject clazz, jobject javaFd) +{ + android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_ADVERT); +} + +static void android_net_util_setupNsSocket(JNIEnv *env, jobject clazz, jobject javaFd) +{ + android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_SOLICIT); +} + static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd, jint ifIndex) { @@ -125,7 +170,12 @@ static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject j */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket }, + { "setupNaSocket", "(Ljava/io/FileDescriptor;)V", + (void*) android_net_util_setupNaSocket }, + { "setupNsSocket", "(Ljava/io/FileDescriptor;)V", + (void*) android_net_util_setupNsSocket }, + { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", + (void*) android_net_util_setupRaSocket }, }; int register_android_net_util_TetheringUtils(JNIEnv* env) { diff --git a/Tethering/src/android/net/ip/DadProxy.java b/Tethering/src/android/net/ip/DadProxy.java new file mode 100644 index 0000000000..e2976b7890 --- /dev/null +++ b/Tethering/src/android/net/ip/DadProxy.java @@ -0,0 +1,54 @@ +/* + * 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.ip; + +import android.net.util.InterfaceParams; +import android.os.Handler; + +import androidx.annotation.VisibleForTesting; + +/** + * Basic Duplicate address detection proxy. + * + * @hide + */ +public class DadProxy { + private static final String TAG = DadProxy.class.getSimpleName(); + + @VisibleForTesting + public static NeighborPacketForwarder naForwarder; + public static NeighborPacketForwarder nsForwarder; + + public DadProxy(Handler h, InterfaceParams tetheredIface) { + naForwarder = new NeighborPacketForwarder(h, tetheredIface, + NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT); + nsForwarder = new NeighborPacketForwarder(h, tetheredIface, + NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION); + } + + /** Stop NS/NA Forwarders. */ + public void stop() { + naForwarder.stop(); + nsForwarder.stop(); + } + + /** Set upstream iface on both forwarders. */ + public void setUpstreamIface(InterfaceParams upstreamIface) { + naForwarder.setUpstreamIface(upstreamIface); + nsForwarder.setUpstreamIface(upstreamIface); + } +} diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 673cbf09d2..336124dc1b 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -51,6 +51,7 @@ import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; import android.net.util.SharedLog; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -160,6 +161,15 @@ public class IpServer extends StateMachine { /** Capture IpServer dependencies, for injection. */ public abstract static class Dependencies { + /** + * Create a DadProxy instance to be used by IpServer. + * To support multiple tethered interfaces concurrently DAD Proxy + * needs to be supported per IpServer instead of per upstream. + */ + public DadProxy getDadProxy(Handler handler, InterfaceParams ifParams) { + return new DadProxy(handler, ifParams); + } + /** Create an IpNeighborMonitor to be used by this IpServer */ public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log, IpNeighborMonitor.NeighborEventConsumer consumer) { @@ -256,6 +266,7 @@ public class IpServer extends StateMachine { // Advertisements (otherwise, we do not add them to mLinkProperties at all). private LinkProperties mLastIPv6LinkProperties; private RouterAdvertisementDaemon mRaDaemon; + private DadProxy mDadProxy; // To be accessed only on the handler thread private int mDhcpServerStartIndex = 0; @@ -674,6 +685,13 @@ public class IpServer extends StateMachine { return false; } + // TODO: use ShimUtils instead of explicitly checking the version here. + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R || "S".equals(Build.VERSION.CODENAME) + || "T".equals(Build.VERSION.CODENAME)) { + // DAD Proxy starts forwarding packets after IPv6 upstream is present. + mDadProxy = mDeps.getDadProxy(getHandler(), mInterfaceParams); + } + return true; } @@ -685,6 +703,11 @@ public class IpServer extends StateMachine { mRaDaemon.stop(); mRaDaemon = null; } + + if (mDadProxy != null) { + mDadProxy.stop(); + mDadProxy = null; + } } // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only @@ -702,11 +725,16 @@ public class IpServer extends StateMachine { } RaParams params = null; - int upstreamIfindex = 0; + String upstreamIface = null; + InterfaceParams upstreamIfaceParams = null; + int upstreamIfIndex = 0; if (v6only != null) { - final String upstreamIface = v6only.getInterfaceName(); - + upstreamIface = v6only.getInterfaceName(); + upstreamIfaceParams = mDeps.getInterfaceParams(upstreamIface); + if (upstreamIfaceParams != null) { + upstreamIfIndex = upstreamIfaceParams.index; + } params = new RaParams(); params.mtu = v6only.getMtu(); params.hasDefaultRoute = v6only.hasIpv6DefaultRoute(); @@ -726,15 +754,13 @@ public class IpServer extends StateMachine { } } - upstreamIfindex = mDeps.getIfindex(upstreamIface); - // Add upstream index to name mapping for the tether stats usage in the coordinator. // Although this mapping could be added by both class Tethering and IpServer, adding // mapping from IpServer guarantees that the mapping is added before the adding // forwarding rules. That is because there are different state machines in both // classes. It is hard to guarantee the link property update order between multiple // state machines. - mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface); + mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfIndex, upstreamIface); } // If v6only is null, we pass in null to setRaParams(), which handles @@ -743,8 +769,11 @@ public class IpServer extends StateMachine { setRaParams(params); mLastIPv6LinkProperties = v6only; - updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfindex, null); - mLastIPv6UpstreamIfindex = upstreamIfindex; + updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, null); + mLastIPv6UpstreamIfindex = upstreamIfIndex; + if (mDadProxy != null) { + mDadProxy.setUpstreamIface(upstreamIfaceParams); + } } private void removeRoutesFromLocalNetwork(@NonNull final List toBeRemoved) { diff --git a/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/Tethering/src/android/net/ip/NeighborPacketForwarder.java new file mode 100644 index 0000000000..73fc833fab --- /dev/null +++ b/Tethering/src/android/net/ip/NeighborPacketForwarder.java @@ -0,0 +1,180 @@ +/* + * 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.ip; + +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.AF_PACKET; +import static android.system.OsConstants.ETH_P_IPV6; +import static android.system.OsConstants.IPPROTO_RAW; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOCK_NONBLOCK; +import static android.system.OsConstants.SOCK_RAW; + +import android.net.util.InterfaceParams; +import android.net.util.PacketReader; +import android.net.util.SocketUtils; +import android.net.util.TetheringUtils; +import android.os.Handler; +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Arrays; + +/** + * Basic IPv6 Neighbor Advertisement Forwarder. + * + * Forward NA packets from upstream iface to tethered iface + * and NS packets from tethered iface to upstream iface. + * + * @hide + */ +public class NeighborPacketForwarder extends PacketReader { + private final String mTag; + + private FileDescriptor mFd; + + // TODO: get these from NetworkStackConstants. + private static final int IPV6_ADDR_LEN = 16; + private static final int IPV6_DST_ADDR_OFFSET = 24; + private static final int IPV6_HEADER_LEN = 40; + private static final int ETH_HEADER_LEN = 14; + + private InterfaceParams mListenIfaceParams, mSendIfaceParams; + + private final int mType; + public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136; + public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135; + + public NeighborPacketForwarder(Handler h, InterfaceParams tetheredInterface, int type) { + super(h); + mTag = NeighborPacketForwarder.class.getSimpleName() + "-" + + tetheredInterface.name + "-" + type; + mType = type; + + if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) { + mSendIfaceParams = tetheredInterface; + } else { + mListenIfaceParams = tetheredInterface; + } + } + + /** Set new upstream iface and start/stop based on new params. */ + public void setUpstreamIface(InterfaceParams upstreamParams) { + final InterfaceParams oldUpstreamParams; + + if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) { + oldUpstreamParams = mListenIfaceParams; + mListenIfaceParams = upstreamParams; + } else { + oldUpstreamParams = mSendIfaceParams; + mSendIfaceParams = upstreamParams; + } + + if (oldUpstreamParams == null && upstreamParams != null) { + start(); + } else if (oldUpstreamParams != null && upstreamParams == null) { + stop(); + } else if (oldUpstreamParams != null && upstreamParams != null + && oldUpstreamParams.index != upstreamParams.index) { + stop(); + start(); + } + } + + // TODO: move NetworkStackUtils.closeSocketQuietly to + // frameworks/libs/net/common/device/com/android/net/module/util/[someclass]. + private void closeSocketQuietly(FileDescriptor fd) { + try { + SocketUtils.closeSocket(fd); + } catch (IOException ignored) { + } + } + + @Override + protected FileDescriptor createFd() { + try { + // ICMPv6 packets from modem do not have eth header, so RAW socket cannot be used. + // To keep uniformity in both directions PACKET socket can be used. + mFd = Os.socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0); + + // TODO: convert setup*Socket to setupICMPv6BpfFilter with filter type? + if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) { + TetheringUtils.setupNaSocket(mFd); + } else if (mType == ICMPV6_NEIGHBOR_SOLICITATION) { + TetheringUtils.setupNsSocket(mFd); + } + + SocketAddress bindAddress = SocketUtils.makePacketSocketAddress( + ETH_P_IPV6, mListenIfaceParams.index); + Os.bind(mFd, bindAddress); + } catch (ErrnoException | SocketException e) { + Log.wtf(mTag, "Failed to create socket", e); + closeSocketQuietly(mFd); + return null; + } + + return mFd; + } + + private Inet6Address getIpv6DestinationAddress(byte[] recvbuf) { + Inet6Address dstAddr; + try { + dstAddr = (Inet6Address) Inet6Address.getByAddress(Arrays.copyOfRange(recvbuf, + IPV6_DST_ADDR_OFFSET, IPV6_DST_ADDR_OFFSET + IPV6_ADDR_LEN)); + } catch (UnknownHostException | ClassCastException impossible) { + throw new AssertionError("16-byte array not valid IPv6 address?"); + } + return dstAddr; + } + + @Override + protected void handlePacket(byte[] recvbuf, int length) { + if (mSendIfaceParams == null) { + return; + } + + // The BPF filter should already have checked the length of the packet, but... + if (length < IPV6_HEADER_LEN) { + return; + } + Inet6Address destv6 = getIpv6DestinationAddress(recvbuf); + if (!destv6.isMulticastAddress()) { + return; + } + InetSocketAddress dest = new InetSocketAddress(destv6, 0); + + FileDescriptor fd = null; + try { + fd = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW); + SocketUtils.bindSocketToInterface(fd, mSendIfaceParams.name); + + int ret = Os.sendto(fd, recvbuf, 0, length, 0, dest); + } catch (ErrnoException | SocketException e) { + Log.e(mTag, "handlePacket error: " + e); + } finally { + closeSocketQuietly(fd); + } + } +} diff --git a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java index 6f017dcb62..7c0b7cc751 100644 --- a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java +++ b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java @@ -18,6 +18,7 @@ package android.net.ip; import static android.net.util.NetworkConstants.IPV6_MIN_MTU; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; +import static android.net.util.TetheringUtils.getAllNodesForScopeId; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.SOCK_RAW; @@ -44,7 +45,6 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketException; -import java.net.UnknownHostException; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -92,10 +92,6 @@ public class RouterAdvertisementDaemon { private static final int DAY_IN_SECONDS = 86_400; - private static final byte[] ALL_NODES = new byte[] { - (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 - }; - private final InterfaceParams mInterface; private final InetSocketAddress mAllNodes; @@ -240,7 +236,6 @@ public class RouterAdvertisementDaemon { } } - public RouterAdvertisementDaemon(InterfaceParams ifParams) { mInterface = ifParams; mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0); @@ -363,15 +358,6 @@ public class RouterAdvertisementDaemon { } } - private static Inet6Address getAllNodesForScopeId(int scopeId) { - try { - return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId); - } catch (UnknownHostException uhe) { - Log.wtf(TAG, "Failed to construct ff02::1 InetAddress: " + uhe); - return null; - } - } - private static byte asByte(int value) { return (byte) value; } diff --git a/Tethering/src/android/net/util/TetheringUtils.java b/Tethering/src/android/net/util/TetheringUtils.java index b17b4ba77c..53b54f7de0 100644 --- a/Tethering/src/android/net/util/TetheringUtils.java +++ b/Tethering/src/android/net/util/TetheringUtils.java @@ -17,11 +17,15 @@ package android.net.util; import android.net.TetherStatsParcel; import android.net.TetheringRequestParcel; +import android.util.Log; import androidx.annotation.NonNull; import java.io.FileDescriptor; +import java.net.Inet6Address; import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Arrays; import java.util.Objects; /** @@ -30,6 +34,24 @@ import java.util.Objects; * {@hide} */ public class TetheringUtils { + public static final byte[] ALL_NODES = new byte[] { + (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + }; + + /** + * Configures a socket for receiving and sending ICMPv6 neighbor advertisments. + * @param fd the socket's {@link FileDescriptor}. + */ + public static native void setupNaSocket(FileDescriptor fd) + throws SocketException; + + /** + * Configures a socket for receiving and sending ICMPv6 neighbor solicitations. + * @param fd the socket's {@link FileDescriptor}. + */ + public static native void setupNsSocket(FileDescriptor fd) + throws SocketException; + /** * The object which records offload Tx/Rx forwarded bytes/packets. * TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with @@ -129,4 +151,15 @@ public class TetheringUtils { && request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck && request.showProvisioningUi == otherRequest.showProvisioningUi; } + + /** Get inet6 address for all nodes given scope ID. */ + public static Inet6Address getAllNodesForScopeId(int scopeId) { + try { + return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId); + } catch (UnknownHostException uhe) { + Log.wtf("TetheringUtils", "Failed to construct Inet6Address from " + + Arrays.toString(ALL_NODES) + " and scopedId " + scopeId); + return null; + } + } } diff --git a/Tethering/tests/privileged/Android.bp b/Tethering/tests/privileged/Android.bp index a0fb24603a..9217345dc2 100644 --- a/Tethering/tests/privileged/Android.bp +++ b/Tethering/tests/privileged/Android.bp @@ -14,8 +14,22 @@ // limitations under the License. // +java_defaults { + name: "TetheringPrivilegedTestsJniDefaults", + jni_libs: [ + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + "libtetherutilsjni", + ], + jni_uses_sdk_apis: true, + visibility: ["//visibility:private"], +} + android_test { name: "TetheringPrivilegedTests", + defaults: [ + "TetheringPrivilegedTestsJniDefaults", + ], srcs: [ "src/**/*.java", "src/**/*.kt", @@ -23,8 +37,13 @@ android_test { certificate: "networkstack", platform_apis: true, test_suites: [ - "general-tests", + "device-tests", "mts", ], + static_libs: [ + "androidx.test.rules", + "net-tests-utils", + "TetheringApiCurrentLib", + ], compile_multilib: "both", } diff --git a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java new file mode 100644 index 0000000000..747d3e8030 --- /dev/null +++ b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java @@ -0,0 +1,338 @@ +/* + * 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.ip; + +import static android.system.OsConstants.IPPROTO_ICMPV6; +import static android.system.OsConstants.IPPROTO_TCP; + +import static com.android.internal.util.BitUtils.uint16; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.app.Instrumentation; +import android.content.Context; +import android.net.INetd; +import android.net.InetAddresses; +import android.net.MacAddress; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.util.InterfaceParams; +import android.net.util.IpUtils; +import android.net.util.TetheringUtils; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.system.ErrnoException; +import android.system.Os; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.TapPacketReader; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import java.io.FileDescriptor; +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicReference; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DadProxyTest { + private static final int DATA_BUFFER_LEN = 4096; + private static final int PACKET_TIMEOUT_MS = 5_000; + + // TODO: make NetworkStackConstants accessible to this test and use the constant from there. + private static final int ETHER_SRC_ADDR_OFFSET = 6; + + private DadProxy mProxy; + TestNetworkInterface mUpstreamTestIface, mTetheredTestIface; + private InterfaceParams mUpstreamParams, mTetheredParams; + private HandlerThread mHandlerThread; + private Handler mHandler; + private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader; + private FileDescriptor mUpstreamTapFd, mTetheredTapFd; + + private static INetd sNetd; + + @BeforeClass + public static void setupOnce() { + System.loadLibrary("tetherutilsjni"); + + final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); + final IBinder netdIBinder = + (IBinder) inst.getContext().getSystemService(Context.NETD_SERVICE); + sNetd = INetd.Stub.asInterface(netdIBinder); + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mHandlerThread = new HandlerThread(getClass().getSimpleName()); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + + setupTapInterfaces(); + + // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads. + if (Looper.myLooper() == null) Looper.prepare(); + + DadProxy mProxy = setupProxy(); + } + + @After + public void tearDown() throws Exception { + if (mHandlerThread != null) { + mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket + mHandler.post(mTetheredPacketReader::stop); // Also closes the socket + mUpstreamTapFd = null; + mTetheredTapFd = null; + mHandlerThread.quitSafely(); + } + + if (mTetheredParams != null) { + sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mTetheredParams.name); + } + if (mUpstreamParams != null) { + sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name); + } + + if (mUpstreamTestIface != null) { + try { + Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor()); + } catch (ErrnoException e) { } + } + + if (mTetheredTestIface != null) { + try { + Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor()); + } catch (ErrnoException e) { } + } + } + + private TestNetworkInterface setupTapInterface() { + final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); + AtomicReference iface = new AtomicReference<>(); + + inst.getUiAutomation().adoptShellPermissionIdentity(); + try { + final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService( + Context.TEST_NETWORK_SERVICE); + iface.set(tnm.createTapInterface()); + } finally { + inst.getUiAutomation().dropShellPermissionIdentity(); + } + + return iface.get(); + } + + private void setupTapInterfaces() { + // Create upstream test iface. + mUpstreamTestIface = setupTapInterface(); + mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName()); + assertNotNull(mUpstreamParams); + mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor(); + mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd, + DATA_BUFFER_LEN); + mHandler.post(mUpstreamPacketReader::start); + + // Create tethered test iface. + mTetheredTestIface = setupTapInterface(); + mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName()); + assertNotNull(mTetheredParams); + mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor(); + mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd, + DATA_BUFFER_LEN); + mHandler.post(mTetheredPacketReader::start); + } + + private static final int IPV6_HEADER_LEN = 40; + private static final int ETH_HEADER_LEN = 14; + private static final int ICMPV6_NA_NS_LEN = 24; + private static final int LL_TARGET_OPTION_LEN = 8; + private static final int ICMPV6_CHECKSUM_OFFSET = 2; + private static final int ETHER_TYPE_IPV6 = 0x86dd; + + // TODO: move the IpUtils code to frameworks/lib/net and link it statically. + private static int checksumFold(int sum) { + while (sum > 0xffff) { + sum = (sum >> 16) + (sum & 0xffff); + } + return sum; + } + + // TODO: move the IpUtils code to frameworks/lib/net and link it statically. + private static short checksumAdjust(short checksum, short oldWord, short newWord) { + checksum = (short) ~checksum; + int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord)); + return (short) ~tempSum; + } + + // TODO: move the IpUtils code to frameworks/lib/net and link it statically. + private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset, + int transportLen) { + // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses + // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental + // checksum adjustment for the change in the next header byte. + short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen); + return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6); + } + + private static ByteBuffer createDadPacket(int type) { + // Refer to buildArpPacket() + int icmpLen = ICMPV6_NA_NS_LEN + + (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT + ? LL_TARGET_OPTION_LEN : 0); + final ByteBuffer buf = ByteBuffer.allocate(icmpLen + IPV6_HEADER_LEN + ETH_HEADER_LEN); + + // Ethernet header. + final MacAddress srcMac = MacAddress.fromString("33:33:ff:66:77:88"); + buf.put(srcMac.toByteArray()); + final MacAddress dstMac = MacAddress.fromString("01:02:03:04:05:06"); + buf.put(dstMac.toByteArray()); + buf.putShort((short) ETHER_TYPE_IPV6); + + // IPv6 header + byte[] version = {(byte) 0x60, 0x00, 0x00, 0x00}; + buf.put(version); // Version + buf.putShort((byte) icmpLen); // Length + buf.put((byte) IPPROTO_ICMPV6); // Next header + buf.put((byte) 0xff); // Hop limit + + final byte[] target = + InetAddresses.parseNumericAddress("fe80::1122:3344:5566:7788").getAddress(); + final byte[] src; + final byte[] dst; + if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION) { + src = InetAddresses.parseNumericAddress("::").getAddress(); + dst = InetAddresses.parseNumericAddress("ff02::1:ff66:7788").getAddress(); + } else { + src = target; + dst = TetheringUtils.ALL_NODES; + } + buf.put(src); + buf.put(dst); + + // ICMPv6 Header + buf.put((byte) type); // Type + buf.put((byte) 0x00); // Code + buf.putShort((short) 0); // Checksum + buf.putInt(0); // Reserved + buf.put(target); + + if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT) { + //NA packet has LL target address + //ICMPv6 Option + buf.put((byte) 0x02); // Type + buf.put((byte) 0x01); // Length + byte[] ll_target = MacAddress.fromString("01:02:03:04:05:06").toByteArray(); + buf.put(ll_target); + } + + // Populate checksum field + final int transportOffset = ETH_HEADER_LEN + IPV6_HEADER_LEN; + final short checksum = icmpv6Checksum(buf, ETH_HEADER_LEN, transportOffset, icmpLen); + buf.putShort(transportOffset + ICMPV6_CHECKSUM_OFFSET, checksum); + + buf.flip(); + return buf; + } + + private DadProxy setupProxy() throws Exception { + DadProxy proxy = new DadProxy(mHandler, mTetheredParams); + mHandler.post(() -> proxy.setUpstreamIface(mUpstreamParams)); + + // Upstream iface is added to local network to simplify test case. + // Otherwise the test needs to create and destroy a network for the upstream iface. + sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name); + sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mTetheredParams.name); + + return proxy; + } + + // TODO: change to assert. + private boolean waitForPacket(ByteBuffer packet, TapPacketReader reader) { + byte[] p; + + while ((p = reader.popPacket(PACKET_TIMEOUT_MS)) != null) { + final ByteBuffer buffer = ByteBuffer.wrap(p); + + if (buffer.compareTo(packet) == 0) return true; + } + return false; + } + + private void updateDstMac(ByteBuffer buf, MacAddress mac) { + buf.put(mac.toByteArray()); + buf.rewind(); + } + private void updateSrcMac(ByteBuffer buf, InterfaceParams ifaceParams) { + buf.position(ETHER_SRC_ADDR_OFFSET); + buf.put(ifaceParams.macAddr.toByteArray()); + buf.rewind(); + } + + @Test + public void testNaForwardingFromUpstreamToTether() throws Exception { + ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT); + + mUpstreamPacketReader.sendResponse(na); + updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01")); + updateSrcMac(na, mTetheredParams); + assertTrue(waitForPacket(na, mTetheredPacketReader)); + } + + @Test + // TODO: remove test once DAD works in both directions. + public void testNaForwardingFromTetherToUpstream() throws Exception { + ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT); + + mTetheredPacketReader.sendResponse(na); + updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01")); + updateSrcMac(na, mTetheredParams); + assertFalse(waitForPacket(na, mUpstreamPacketReader)); + } + + @Test + public void testNsForwardingFromTetherToUpstream() throws Exception { + ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION); + + mTetheredPacketReader.sendResponse(ns); + updateSrcMac(ns, mUpstreamParams); + assertTrue(waitForPacket(ns, mUpstreamPacketReader)); + } + + @Test + // TODO: remove test once DAD works in both directions. + public void testNsForwardingFromUpstreamToTether() throws Exception { + ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION); + + mUpstreamPacketReader.sendResponse(ns); + updateSrcMac(ns, mUpstreamParams); + assertFalse(waitForPacket(ns, mTetheredPacketReader)); + } +} diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 3b72b5b471..1a976adc60 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -86,6 +86,7 @@ import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; import android.net.util.SharedLog; +import android.os.Build; import android.os.Handler; import android.os.RemoteException; import android.os.test.TestLooper; @@ -100,8 +101,12 @@ import com.android.networkstack.tethering.BpfCoordinator; import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule; import com.android.networkstack.tethering.PrivateAddressCoordinator; import com.android.networkstack.tethering.TetheringConfiguration; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -120,6 +125,9 @@ import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest public class IpServerTest { + @Rule + public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); + private static final String IFACE_NAME = "testnet1"; private static final String UPSTREAM_IFACE = "upstream0"; private static final String UPSTREAM_IFACE2 = "upstream1"; @@ -132,6 +140,11 @@ public class IpServerTest { private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams( IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */); + private static final InterfaceParams UPSTREAM_IFACE_PARAMS = new InterfaceParams( + UPSTREAM_IFACE, UPSTREAM_IFINDEX, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */); + private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams( + UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.ALL_ZEROS_ADDRESS, + 1500 /* defaultMtu */); private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000; @@ -142,6 +155,7 @@ public class IpServerTest { @Mock private IpServer.Callback mCallback; @Mock private SharedLog mSharedLog; @Mock private IDhcpServer mDhcpServer; + @Mock private DadProxy mDadProxy; @Mock private RouterAdvertisementDaemon mRaDaemon; @Mock private IpNeighborMonitor mIpNeighborMonitor; @Mock private IpServer.Dependencies mDependencies; @@ -165,8 +179,11 @@ public class IpServerTest { private void initStateMachine(int interfaceType, boolean usingLegacyDhcp, boolean usingBpfOffload) throws Exception { + when(mDependencies.getDadProxy(any(), any())).thenReturn(mDadProxy); when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon); when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS); + when(mDependencies.getInterfaceParams(UPSTREAM_IFACE)).thenReturn(UPSTREAM_IFACE_PARAMS); + when(mDependencies.getInterfaceParams(UPSTREAM_IFACE2)).thenReturn(UPSTREAM_IFACE_PARAMS2); when(mDependencies.getIfindex(eq(UPSTREAM_IFACE))).thenReturn(UPSTREAM_IFINDEX); when(mDependencies.getIfindex(eq(UPSTREAM_IFACE2))).thenReturn(UPSTREAM_IFINDEX2); @@ -1103,4 +1120,78 @@ public class IpServerTest { } return true; } + + @Test @IgnoreUpTo(Build.VERSION_CODES.R) + public void dadProxyUpdates() throws Exception { + InOrder inOrder = inOrder(mDadProxy); + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); + inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS); + + // Add an upstream without IPv6. + dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0); + inOrder.verify(mDadProxy).setUpstreamIface(null); + + // Add IPv6 to the upstream. + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(UPSTREAM_IFACE); + dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0); + inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS); + + // Change upstream. + // New linkproperties is needed, otherwise changing the iface has no impact. + LinkProperties lp2 = new LinkProperties(); + lp2.setInterfaceName(UPSTREAM_IFACE2); + dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp2, 0); + inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS2); + + // Lose IPv6 on the upstream... + dispatchTetherConnectionChanged(UPSTREAM_IFACE2, null, 0); + inOrder.verify(mDadProxy).setUpstreamIface(null); + + // ... and regain it on a different upstream. + dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0); + inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS); + + // Lose upstream. + dispatchTetherConnectionChanged(null, null, 0); + inOrder.verify(mDadProxy).setUpstreamIface(null); + + // Regain upstream. + dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0); + inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS); + + // Stop tethering. + mIpServer.stop(); + mLooper.dispatchAll(); + } + + private void checkDadProxyEnabled(boolean expectEnabled) throws Exception { + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); + InOrder inOrder = inOrder(mDadProxy); + // Add IPv6 to the upstream. + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(UPSTREAM_IFACE); + if (expectEnabled) { + inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS); + } else { + inOrder.verifyNoMoreInteractions(); + } + // Stop tethering. + mIpServer.stop(); + mLooper.dispatchAll(); + if (expectEnabled) { + inOrder.verify(mDadProxy).stop(); + } + else { + verify(mDependencies, never()).getDadProxy(any(), any()); + } + } + @Test @IgnoreAfter(Build.VERSION_CODES.R) + public void testDadProxyUpdates_DisabledUpToR() throws Exception { + checkDadProxyEnabled(false); + } + @Test @IgnoreUpTo(Build.VERSION_CODES.R) + public void testDadProxyUpdates_EnabledAfterR() throws Exception { + checkDadProxyEnabled(true); + } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index b0586e30f3..c42a56b4bb 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -110,6 +110,7 @@ import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpServer; +import android.net.ip.DadProxy; import android.net.ip.IpNeighborMonitor; import android.net.ip.IpServer; import android.net.ip.RouterAdvertisementDaemon; @@ -196,6 +197,7 @@ public class TetheringTest { @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor; @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator; + @Mock private DadProxy mDadProxy; @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon; @Mock private IpNeighborMonitor mIpNeighborMonitor; @Mock private IDhcpServer mDhcpServer; @@ -279,6 +281,12 @@ public class TetheringTest { } public class MockIpServerDependencies extends IpServer.Dependencies { + @Override + public DadProxy getDadProxy( + Handler handler, InterfaceParams ifParams) { + return mDadProxy; + } + @Override public RouterAdvertisementDaemon getRouterAdvertisementDaemon( InterfaceParams ifParams) { @@ -832,6 +840,7 @@ public class TetheringTest { verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); + verify(mDadProxy, never()).setUpstreamIface(notNull()); verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull()); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( any(), any()); @@ -858,6 +867,8 @@ public class TetheringTest { verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); + // TODO: add interfaceParams to compare in verify. + verify(mDadProxy, times(1)).setUpstreamIface(notNull()); verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); verify(mNetd, times(1)).tetherApplyDnsInterfaces(); } @@ -874,6 +885,7 @@ public class TetheringTest { any(), any()); sendIPv6TetherUpdates(upstreamState); + verify(mDadProxy, times(1)).setUpstreamIface(notNull()); verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); verify(mNetd, times(1)).tetherApplyDnsInterfaces(); } @@ -891,6 +903,7 @@ public class TetheringTest { verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); + verify(mDadProxy, times(1)).setUpstreamIface(notNull()); verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); verify(mNetd, times(1)).tetherApplyDnsInterfaces(); } From 8f59ec090de7d7d2c852e8cee72ce49bd17d4ee5 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 23 Sep 2020 17:03:33 +0900 Subject: [PATCH 1296/1415] Remove unused testutils lib from tethering tests frameworks-base-testutils is unused in tethering integration tests, so the dependency can be removed. That test library also contains test classes, so removing the dependency allows tethering tests to stop running the associated tests. Also add jarjar rules to the unit tests to zap (remove) the test classes from the output APK. Ideally the unit tests should stop depending on that library too (TestableLooper can be used instead of TestLooper), or the frameworks-base-testutils library should stop including test classes. Bug: 167968946 Test: m CtsTetheringTest TetheringTests Change-Id: Ie950ce5b6181e388a7f71da430fd2dd8ada32e49 --- Tethering/tests/integration/Android.bp | 1 - Tethering/tests/unit/jarjar-rules.txt | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp index ed69b7d63c..02bab9ba35 100644 --- a/Tethering/tests/integration/Android.bp +++ b/Tethering/tests/integration/Android.bp @@ -22,7 +22,6 @@ java_defaults { static_libs: [ "NetworkStackApiStableLib", "androidx.test.rules", - "frameworks-base-testutils", "mockito-target-extended-minus-junit4", "net-tests-utils", "testables", diff --git a/Tethering/tests/unit/jarjar-rules.txt b/Tethering/tests/unit/jarjar-rules.txt index ec2d2b0200..7ed89632a8 100644 --- a/Tethering/tests/unit/jarjar-rules.txt +++ b/Tethering/tests/unit/jarjar-rules.txt @@ -9,3 +9,8 @@ rule com.android.internal.util.StateMachine* com.android.networkstack.tethering. rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1 + +# TODO: either stop using frameworks-base-testutils or remove the unit test classes it contains. +# TestableLooper from "testables" can be used instead of TestLooper from frameworks-base-testutils. +zap android.os.test.TestLooperTest* +zap com.android.test.filters.SelectTestTests* \ No newline at end of file From 84ec4a397a3deb343b08ed03089e5ff26c3e8e04 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 24 Sep 2020 09:50:55 +0800 Subject: [PATCH 1297/1415] Fix TetheredClient callback fail in InProcessTethering TetheredClient callback would additional check whether caller has NETWORK_SETTINGS or {MAINLINE_}NETWORK_STACK permission, but it do not grant for self accessing. InProcessTethering run in system server, so the services in system server would fail to call TetheredClient callback. Grant permission for self process. Bug: 169231588 Test: atest CtsTetheringTest Change-Id: Ic04e44aef4df772c718ff25ed331bf02f5940c1d --- Tethering/src/com/android/networkstack/tethering/Tethering.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 255cf750c0..9a3cecef69 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -2104,7 +2104,7 @@ public class Tethering { } private boolean hasCallingPermission(@NonNull String permission) { - return mContext.checkCallingPermission(permission) == PERMISSION_GRANTED; + return mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED; } /** Unregister tethering event callback */ From 01f9b00e888e945e3921e22b121e7ad0c1c1aefb Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 17 Sep 2020 16:26:46 +0800 Subject: [PATCH 1298/1415] Add CTS to verify DownloadManager permission If DownloadManager doesn't have CONNECTIVITY_USE_RESTRICTED_NETWORKS permission, it can't bind socket to VPN when it is in VPN disallowed list but requested downloading app is in VPN allowed list. Add a new CTS test to verify that DownloadManager can do the download successfully via VPN network. Bug: 165774987 Test: atest HostsideVpnTests Change-Id: Iba9e2f26ad325d0fdb34ab9a06faaaf9cb623166 --- .../com/android/cts/net/hostside/VpnTest.java | 78 ++++++++++++++++++- .../com/android/cts/net/HostsideVpnTests.java | 5 ++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index a451ea8585..57e6b36d18 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -17,13 +17,26 @@ package com.android.cts.net.hostside; import static android.os.Process.INVALID_UID; -import static android.system.OsConstants.*; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.ECONNABORTED; +import static android.system.OsConstants.IPPROTO_ICMP; +import static android.system.OsConstants.IPPROTO_ICMPV6; +import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.POLLIN; +import static android.system.OsConstants.SOCK_DGRAM; import android.annotation.Nullable; +import android.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.database.Cursor; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.LinkProperties; @@ -32,12 +45,13 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.Proxy; import android.net.ProxyInfo; +import android.net.Uri; import android.net.VpnService; import android.net.wifi.WifiManager; -import android.provider.Settings; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.SystemProperties; +import android.provider.Settings; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiSelector; @@ -64,12 +78,12 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; -import java.net.SocketException; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Objects; import java.util.Random; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -1087,4 +1101,62 @@ public class VpnTest extends InstrumentationTestCase { received = true; } } + + /** + * Verifies that DownloadManager has CONNECTIVITY_USE_RESTRICTED_NETWORKS permission that can + * bind socket to VPN when it is in VPN disallowed list but requested downloading app is in VPN + * allowed list. + * See b/165774987. + */ + public void testDownloadWithDownloadManagerDisallowed() throws Exception { + if (!supportedHardware()) return; + + // Start a VPN with DownloadManager package in disallowed list. + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"192.0.2.0/24", "2001:db8::/32"}, + "" /* allowedApps */, "com.android.providers.downloads", null /* proxyInfo */, + null /* underlyingNetworks */, false /* isAlwaysMetered */); + + final Context context = VpnTest.this.getInstrumentation().getContext(); + final DownloadManager dm = context.getSystemService(DownloadManager.class); + final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver(); + try { + context.registerReceiver(receiver, + new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); + + // Enqueue a request and check only one download. + final long id = dm.enqueue(new Request(Uri.parse("https://www.google.com"))); + assertEquals(1, getTotalNumberDownloads(dm, new Query())); + assertEquals(1, getTotalNumberDownloads(dm, new Query().setFilterById(id))); + + // Wait for download complete and check status. + assertEquals(id, receiver.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertEquals(1, getTotalNumberDownloads(dm, + new Query().setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL))); + + // Remove download. + assertEquals(1, dm.remove(id)); + assertEquals(0, getTotalNumberDownloads(dm, new Query())); + } finally { + context.unregisterReceiver(receiver); + } + } + + private static int getTotalNumberDownloads(final DownloadManager dm, final Query query) { + try (Cursor cursor = dm.query(query)) { return cursor.getCount(); } + } + + private static class DownloadCompleteReceiver extends BroadcastReceiver { + private final CompletableFuture future = new CompletableFuture<>(); + + @Override + public void onReceive(Context context, Intent intent) { + future.complete(intent.getLongExtra( + DownloadManager.EXTRA_DOWNLOAD_ID, -1 /* defaultValue */)); + } + + public long get(long timeout, TimeUnit unit) throws Exception { + return future.get(timeout, unit); + } + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java index 62925ad6ab..49b5f9dc96 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -95,4 +95,9 @@ public class HostsideVpnTests extends HostsideNetworkTestCase { public void testB141603906() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testB141603906"); } + + public void testDownloadWithDownloadManagerDisallowed() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", + "testDownloadWithDownloadManagerDisallowed"); + } } From 8ff9c262ca48dbc61c8819ac1532abddb138c5af Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 24 Sep 2020 14:44:32 +0800 Subject: [PATCH 1299/1415] Don't check broadcast intent on connection status check testRequestNetworkCallback_onUnavailable is flaky because the test expects a connectivity broadcast to be sent for the lost network. But after testSetAirplaneMode, the wifi network is not yet default network so a broadcast is never sent but only onUnavailable is triggered. Replace disconnectFromWifi with ensureWifiDisconnected to skip checking the broadcast. Bug: 162323152 Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest\ --rerun-until-failure 20 Change-Id: I88f434798ec83539df9cc6a81446ca37a0081e3b --- tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 455da263ca..70b1bbe8cd 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -607,7 +607,7 @@ public class ConnectivityManagerTest { public void testRequestNetworkCallback_onUnavailable() { final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); if (previousWifiEnabledState) { - mCtsNetUtils.disconnectFromWifi(null); + mCtsNetUtils.ensureWifiDisconnected(null); } final TestNetworkCallback callback = new TestNetworkCallback(); From 050d4a4bb0b9f41f4b80fed93f4ccb5cf71115db Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 19 Aug 2020 16:07:22 +0900 Subject: [PATCH 1300/1415] Move module utils to the module package. Test: builds Change-Id: If5d1e4a58fb2d6d9544e6d01995dabe445cf1f25 (cherry picked from commit 046bf639eb7728504be35e30e3dd49af3d029728) --- Tethering/src/android/net/ip/NeighborPacketForwarder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/Tethering/src/android/net/ip/NeighborPacketForwarder.java index 73fc833fab..084743db03 100644 --- a/Tethering/src/android/net/ip/NeighborPacketForwarder.java +++ b/Tethering/src/android/net/ip/NeighborPacketForwarder.java @@ -25,7 +25,6 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOCK_RAW; import android.net.util.InterfaceParams; -import android.net.util.PacketReader; import android.net.util.SocketUtils; import android.net.util.TetheringUtils; import android.os.Handler; @@ -33,6 +32,8 @@ import android.system.ErrnoException; import android.system.Os; import android.util.Log; +import com.android.net.module.util.PacketReader; + import java.io.FileDescriptor; import java.io.IOException; import java.net.Inet6Address; From f609923b4b108ca81672f5e5997d5a4d512c57e7 Mon Sep 17 00:00:00 2001 From: markchien Date: Sun, 27 Sep 2020 16:56:38 +0800 Subject: [PATCH 1301/1415] Remove double check interface by NetworkInterface NetworkInterface#getByName can not get the interface without IP addresses. When setIncludeTestInterfaces(true) is called, the interface will be placed in client mode, which will delete the link-local address. So calling NetworkInterface#getByName to get test interface may not work before switching to server mode. Bug: 168215721 Test: atest CtsTethering Change-Id: Ice8adcce1c4b2c86bd219c701b2afa9ba2339f24 --- .../tests/integration/src/android/net/EthernetTetheringTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index 64be2d9a55..d206ea0b4d 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -553,7 +553,6 @@ public class EthernetTetheringTest { TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); TestNetworkInterface iface = tnm.createTapInterface(); Log.d(TAG, "Created test interface " + iface.getInterfaceName()); - assertNotNull(NetworkInterface.getByName(iface.getInterfaceName())); return iface; } From 1a2163b972c93d466c367b7b06d649d8f529e52b Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 27 Aug 2020 21:25:37 +0800 Subject: [PATCH 1302/1415] Make PrivateAddressCoordinator ignore vpn network If vpn app make its netmask as 0, PrivateAddressCoordinator would not able to find suitable address for tethering downstream. Since tethering do not support vpn as upstream, just ignore vpn in PrivateAddressCoordinator. Bug: 166365863 Test: atest TetheringTests atest CtsTetheringTest Change-Id: Iabe265467044fea9fa437674ca29ffc7bcdefe3b --- .../tethering/PrivateAddressCoordinator.java | 22 ++-- .../networkstack/tethering/Tethering.java | 12 +- .../PrivateAddressCoordinatorTest.java | 118 ++++++++++-------- 3 files changed, 84 insertions(+), 68 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index fd9e36080c..b285849f9e 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -15,6 +15,7 @@ */ package com.android.networkstack.tethering; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static java.util.Arrays.asList; @@ -23,7 +24,6 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.IpPrefix; import android.net.LinkAddress; -import android.net.LinkProperties; import android.net.Network; import android.net.ip.IpServer; import android.net.util.PrefixUtils; @@ -90,16 +90,24 @@ public class PrivateAddressCoordinator { /** * Record a new upstream IpPrefix which may conflict with tethering downstreams. - * The downstreams will be notified if a conflict is found. + * The downstreams will be notified if a conflict is found. When updateUpstreamPrefix is called, + * UpstreamNetworkState must have an already populated LinkProperties. */ - public void updateUpstreamPrefix(final Network network, final LinkProperties lp) { - final ArrayList ipv4Prefixes = getIpv4Prefixes(lp.getAllLinkAddresses()); - if (ipv4Prefixes.isEmpty()) { - removeUpstreamPrefix(network); + public void updateUpstreamPrefix(final UpstreamNetworkState ns) { + // Do not support VPN as upstream + if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) { + removeUpstreamPrefix(ns.network); return; } - mUpstreamPrefixMap.put(network, ipv4Prefixes); + final ArrayList ipv4Prefixes = getIpv4Prefixes( + ns.linkProperties.getAllLinkAddresses()); + if (ipv4Prefixes.isEmpty()) { + removeUpstreamPrefix(ns.network); + return; + } + + mUpstreamPrefixMap.put(ns.network, ipv4Prefixes); handleMaybePrefixConflict(ipv4Prefixes); } diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 255cf750c0..a6961fad7f 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -1678,14 +1678,6 @@ public class Tethering { } } - private void addUpstreamPrefixes(final UpstreamNetworkState ns) { - mPrivateAddressCoordinator.updateUpstreamPrefix(ns.network, ns.linkProperties); - } - - private void removeUpstreamPrefixes(final UpstreamNetworkState ns) { - mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network); - } - @VisibleForTesting void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) { @@ -1696,10 +1688,10 @@ public class Tethering { final UpstreamNetworkState ns = (UpstreamNetworkState) o; switch (arg1) { case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES: - addUpstreamPrefixes(ns); + mPrivateAddressCoordinator.updateUpstreamPrefix(ns); break; case UpstreamNetworkMonitor.EVENT_ON_LOST: - removeUpstreamPrefixes(ns); + mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network); break; } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 8e93c2e447..7b6632c36f 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -15,6 +15,10 @@ */ package com.android.networkstack.tethering; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; @@ -30,13 +34,12 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.ConnectivityManager; -import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.ip.IpServer; -import android.net.util.NetworkConstants; import android.net.util.PrefixUtils; import androidx.test.filters.SmallTest; @@ -48,13 +51,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.List; - @RunWith(AndroidJUnit4.class) @SmallTest public final class PrivateAddressCoordinatorTest { - private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0"; - private static final String TEST_WIFI_IFNAME = "test_wlan0"; + private static final String TEST_IFNAME = "test0"; @Mock private IpServer mHotspotIpServer; @Mock private IpServer mUsbIpServer; @@ -69,7 +69,8 @@ public final class PrivateAddressCoordinatorTest { private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24"); private final Network mWifiNetwork = new Network(1); private final Network mMobileNetwork = new Network(2); - private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork}; + private final Network mVpnNetwork = new Network(3); + private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork}; private void setUpIpServers() throws Exception { when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB); @@ -184,33 +185,25 @@ public final class PrivateAddressCoordinatorTest { assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix); } - private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6, - boolean isMobile) { - final String testIface; - final String testIpv4Address; - if (isMobile) { - testIface = TEST_MOBILE_IFNAME; - testIpv4Address = "10.0.0.1"; - } else { - testIface = TEST_WIFI_IFNAME; - testIpv4Address = "192.168.43.5"; - } - + private UpstreamNetworkState buildUpstreamNetworkState(final Network network, + final LinkAddress v4Addr, final LinkAddress v6Addr, final NetworkCapabilities cap) { final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(testIface); + prop.setInterfaceName(TEST_IFNAME); + if (v4Addr != null) prop.addLinkAddress(v4Addr); - if (withIPv4) { - prop.addLinkAddress( - new LinkAddress(InetAddresses.parseNumericAddress(testIpv4Address), - NetworkConstants.IPV4_ADDR_BITS)); + if (v6Addr != null) prop.addLinkAddress(v6Addr); + + return new UpstreamNetworkState(prop, cap, network); + } + + private NetworkCapabilities makeNetworkCapabilities(final int transportType) { + final NetworkCapabilities cap = new NetworkCapabilities(); + cap.addTransportType(transportType); + if (transportType == TRANSPORT_VPN) { + cap.removeCapability(NET_CAPABILITY_NOT_VPN); } - if (withIPv6) { - prop.addLinkAddress( - new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"), - NetworkConstants.RFC7421_PREFIX_LENGTH)); - } - return prop; + return cap; } @Test @@ -220,53 +213,76 @@ public final class PrivateAddressCoordinatorTest { final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); // Force always get subAddress "43.5" for conflict testing. when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); - // 1. Enable hotspot with prefix 192.168.43.0/24 + // - Enable hotspot with prefix 192.168.43.0/24 final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer); final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr); assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); - // 2. Update v6 only mobile network, hotspot prefix should not be removed. - List testConflicts; - final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true); - mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp); + // - test mobile network with null NetworkCapabilities. Ideally this should not happen, + // just make sure no crash in this case. + final UpstreamNetworkState noCapUpstream = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("10.0.0.8/24"), null, null); + mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // - test mobile upstream with no address. + final UpstreamNetworkState noAddress = buildUpstreamNetworkState(mMobileNetwork, + null, null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // - Update v6 only mobile network, hotspot prefix should not be removed. + final UpstreamNetworkState v6OnlyMobile = buildUpstreamNetworkState(mMobileNetwork, + null, new LinkAddress("2001:db8::/64"), + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyMobile); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); mPrivateAddressCoordinator.removeUpstreamPrefix(mMobileNetwork); - // 3. Update v4 only mobile network, hotspot prefix should not be removed. - final LinkProperties v4OnlyMobileProp = buildUpstreamLinkProperties(true, false, true); - mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4OnlyMobileProp); + // - Update v4 only mobile network, hotspot prefix should not be removed. + final UpstreamNetworkState v4OnlyMobile = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("10.0.0.8/24"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyMobile); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); - // 4. Update v4v6 mobile network, hotspot prefix should not be removed. - final LinkProperties v4v6MobileProp = buildUpstreamLinkProperties(true, true, true); - mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4v6MobileProp); + // - Update v4v6 mobile network, hotspot prefix should not be removed. + final UpstreamNetworkState v4v6Mobile = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("10.0.0.8/24"), new LinkAddress("2001:db8::/64"), + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4v6Mobile); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); - // 5. Update v6 only wifi network, hotspot prefix should not be removed. - final LinkProperties v6OnlyWifiProp = buildUpstreamLinkProperties(false, true, false); - mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v6OnlyWifiProp); + // - Update v6 only wifi network, hotspot prefix should not be removed. + final UpstreamNetworkState v6OnlyWifi = buildUpstreamNetworkState(mWifiNetwork, + null, new LinkAddress("2001:db8::/64"), makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyWifi); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); - // 6. Update v4 only wifi network, it conflict with hotspot prefix. - final LinkProperties v4OnlyWifiProp = buildUpstreamLinkProperties(true, false, false); - mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); + // - Update vpn network, it conflict with hotspot prefix but VPN networks are ignored. + final UpstreamNetworkState v4OnlyVpn = buildUpstreamNetworkState(mVpnNetwork, + new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_VPN)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyVpn); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // - Update v4 only wifi network, it conflict with hotspot prefix. + final UpstreamNetworkState v4OnlyWifi = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi); verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); reset(mHotspotIpServer); - // 7. Restart hotspot again and its prefix is different previous. + // - Restart hotspot again and its prefix is different previous. mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer); final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2); assertNotEquals(hotspotPrefix, hotspotPrefix2); when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2); - mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); - // 7. Usb tethering can be enabled and its prefix is different with conflict one. + // - Usb tethering can be enabled and its prefix is different with conflict one. final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress( mUsbIpServer); final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr); assertNotEquals(predefinedPrefix, usbPrefix); assertNotEquals(hotspotPrefix2, usbPrefix); when(mUsbIpServer.getAddress()).thenReturn(usbAddr); - // 8. Disable wifi upstream, then wifi's prefix can be selected again. + // - Disable wifi upstream, then wifi's prefix can be selected again. mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress( mEthernetIpServer); From 4613c7e02acad7b67d749507fae8c86880b43504 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 24 Sep 2020 22:46:39 +0900 Subject: [PATCH 1303/1415] Fix a way for this test to flake. While tests are hopefully cleaning up after themselves, there is no guarantee that there is a currently available default network milliseconds after any given test. Some tests need to disconnect to check something, or to change a property of the wifi network that they have to revert at the end for example. Or, a test may fail leaving the device without a default network. To make sure the state is correctly cleaned up, have tearDown make sure the device is connected to a working Internet connection before the test ends, so that the next test can be sure to find established connectivity immediately. It's possible the device needs a few hundred milliseconds to re-establish connectivity, so this patch gives a grace of up to 30 seconds (the default waiting timer for TestCallback) for connectivity to be restored at the end of any test. Bug: 161767594 and others Test: ConnectivityManagerTest Change-Id: I8cf3e6e6c116cabd5b04bf2562da84f7e635ca2a --- .../src/android/net/cts/ConnectivityManagerTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 455da263ca..fb625146b0 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -219,6 +219,16 @@ public class ConnectivityManagerTest { if (mCtsNetUtils.cellConnectAttempted()) { mCtsNetUtils.disconnectFromCell(); } + + // All tests in this class require a working Internet connection as they start. Make + // sure there is still one as they end that's ready to use for the next test to use. + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(callback); + try { + assertNotNull("Couldn't restore Internet connectivity", callback.waitForAvailable()); + } finally { + mCm.unregisterNetworkCallback(callback); + } } /** From 7f70074abcf346c6322e042e07e9e5961c38f171 Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Fri, 11 Sep 2020 11:48:48 -0700 Subject: [PATCH 1304/1415] tethering: offload: Netlink Req NfGen Add the netfilter generic message header to the netlink req. This is needed so the kernel won't ignore the request for invalid params. Bug: 149109043 Test: ConntrackSocketTest Change-Id: I1757fdeb11a0cac5821021a22323cbd74fe22bdc --- .../tethering/OffloadHardwareInterface.java | 28 ++-- .../tethering/ConntrackSocketTest.java | 131 ++++++++++++++++++ .../OffloadHardwareInterfaceTest.java | 2 +- 3 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index 33b9d00e70..da5f25b2a5 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -28,6 +28,7 @@ import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; import android.net.netlink.NetlinkSocket; +import android.net.netlink.StructNfGenMsg; import android.net.netlink.StructNlMsgHdr; import android.net.util.SharedLog; import android.net.util.SocketUtils; @@ -41,11 +42,12 @@ import android.system.OsConstants; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; -import java.io.InterruptedIOException; import java.io.IOException; +import java.io.InterruptedIOException; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; import java.util.NoSuchElementException; @@ -66,11 +68,12 @@ public class OffloadHardwareInterface { private static final String NO_IPV4_ADDRESS = ""; private static final String NO_IPV4_GATEWAY = ""; // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h - private static final int NF_NETLINK_CONNTRACK_NEW = 1; - private static final int NF_NETLINK_CONNTRACK_UPDATE = 2; - private static final int NF_NETLINK_CONNTRACK_DESTROY = 4; + public static final int NF_NETLINK_CONNTRACK_NEW = 1; + public static final int NF_NETLINK_CONNTRACK_UPDATE = 2; + public static final int NF_NETLINK_CONNTRACK_DESTROY = 4; // Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h public static final short NFNL_SUBSYS_CTNETLINK = 1; + public static final short IPCTNL_MSG_CT_NEW = 0; public static final short IPCTNL_MSG_CT_GET = 1; private final long NETLINK_MESSAGE_TIMEOUT_MS = 500; @@ -237,7 +240,7 @@ public class OffloadHardwareInterface { NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); if (h1 == null) return false; - sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET), + sendIpv4NfGenMsg(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET), (short) (NLM_F_REQUEST | NLM_F_DUMP)); final NativeHandle h2 = mDeps.createConntrackSocket( @@ -267,16 +270,23 @@ public class OffloadHardwareInterface { } @VisibleForTesting - public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) { - final int length = StructNlMsgHdr.STRUCT_SIZE; + public void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) { + final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; final byte[] msg = new byte[length]; - final StructNlMsgHdr nlh = new StructNlMsgHdr(); final ByteBuffer byteBuffer = ByteBuffer.wrap(msg); + byteBuffer.order(ByteOrder.nativeOrder()); + + final StructNlMsgHdr nlh = new StructNlMsgHdr(); nlh.nlmsg_len = length; nlh.nlmsg_type = type; nlh.nlmsg_flags = flags; - nlh.nlmsg_seq = 1; + nlh.nlmsg_seq = 0; nlh.pack(byteBuffer); + + // Header needs to be added to buffer since a generic netlink request is being sent. + final StructNfGenMsg nfh = new StructNfGenMsg((byte) OsConstants.AF_INET); + nfh.pack(byteBuffer); + try { NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length, NETLINK_MESSAGE_TIMEOUT_MS); diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java new file mode 100644 index 0000000000..2b272bc040 --- /dev/null +++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java @@ -0,0 +1,131 @@ +/* + * 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 com.android.networkstack.tethering; + +import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; +import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP; +import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; + +import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_GET; +import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_NEW; +import static com.android.networkstack.tethering.OffloadHardwareInterface.NFNL_SUBSYS_CTNETLINK; +import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_DESTROY; +import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_NEW; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.net.netlink.StructNlMsgHdr; +import android.net.util.SharedLog; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.NativeHandle; +import android.system.Os; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ConntrackSocketTest { + private static final long TIMEOUT = 500; + + private HandlerThread mHandlerThread; + private Handler mHandler; + private final SharedLog mLog = new SharedLog("privileged-test"); + + private OffloadHardwareInterface mOffloadHw; + private OffloadHardwareInterface.Dependencies mDeps; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mHandlerThread = new HandlerThread(getClass().getSimpleName()); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + + // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads. + if (Looper.myLooper() == null) Looper.prepare(); + + mDeps = new OffloadHardwareInterface.Dependencies(mLog); + mOffloadHw = new OffloadHardwareInterface(mHandler, mLog, mDeps); + } + + @Test + public void testIpv4ConntrackSocket() throws Exception { + // Set up server and connect. + final InetSocketAddress anyAddress = new InetSocketAddress( + InetAddress.getByName("127.0.0.1"), 0); + final ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(anyAddress); + final SocketAddress theAddress = serverSocket.getLocalSocketAddress(); + + // Make a connection to the server. + final Socket socket = new Socket(); + socket.connect(theAddress); + final Socket acceptedSocket = serverSocket.accept(); + + final NativeHandle handle = mDeps.createConntrackSocket( + NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); + mOffloadHw.sendIpv4NfGenMsg(handle, + (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET), + (short) (NLM_F_REQUEST | NLM_F_DUMP)); + + boolean foundConntrackEntry = false; + ByteBuffer buffer = ByteBuffer.allocate(DEFAULT_RECV_BUFSIZE); + buffer.order(ByteOrder.nativeOrder()); + + try { + while (Os.read(handle.getFileDescriptor(), buffer) > 0) { + buffer.flip(); + + // TODO: ConntrackMessage should get a parse API like StructNlMsgHdr + // so we can confirm that the conntrack added is for the TCP connection above. + final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(buffer); + assertNotNull(nlmsghdr); + + // As long as 1 conntrack entry is found test case will pass, even if it's not + // the from the TCP connection above. + if (nlmsghdr.nlmsg_type == ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW)) { + foundConntrackEntry = true; + break; + } + } + } + finally { + socket.close(); + serverSocket.close(); + } + assertTrue("Did not receive any NFNL_SUBSYS_CTNETLINK/IPCTNL_MSG_CT_NEW message", + foundConntrackEntry); + } +} diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java index c543fad62d..71f8f27d27 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java @@ -229,7 +229,7 @@ public final class OffloadHardwareInterfaceTest { } when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket); - mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS); + mOffloadHw.sendIpv4NfGenMsg(mNativeHandle, TEST_TYPE, TEST_FLAGS); ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE); int read = Os.read(readSocket, buffer); From c99ef48090943918948c49d5b8febe4274f644c3 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 30 Sep 2020 15:05:18 +0900 Subject: [PATCH 1305/1415] Fix OffloadHardwareInterfaceTest. r.android.com/1424920 changed the code but forgot to update the unit test. Also fix some lint errors. Bug: 149109043 Test: atest TetheringTests TetheringPrivilegedTests Change-Id: I53ca4b9877dcb4a759dee6ec63133653315d826f --- .../tethering/ConntrackSocketTest.java | 3 +-- .../OffloadHardwareInterfaceTest.java | 24 +++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java index 2b272bc040..57c28fc67c 100644 --- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java +++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java @@ -120,8 +120,7 @@ public class ConntrackSocketTest { break; } } - } - finally { + } finally { socket.close(); serverSocket.close(); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java index 71f8f27d27..38b19dd3da 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java @@ -17,8 +17,9 @@ package com.android.networkstack.tethering; import static android.net.util.TetheringUtils.uint16; -import static android.system.OsConstants.SOCK_STREAM; +import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_UNIX; +import static android.system.OsConstants.SOCK_STREAM; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -35,14 +36,15 @@ import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; +import android.net.netlink.StructNfGenMsg; import android.net.netlink.StructNlMsgHdr; import android.net.util.SharedLog; import android.os.Handler; import android.os.NativeHandle; import android.os.test.TestLooper; import android.system.ErrnoException; -import android.system.OsConstants; import android.system.Os; +import android.system.OsConstants; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -55,8 +57,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.FileDescriptor; -import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; @RunWith(AndroidJUnit4.class) @@ -218,7 +220,7 @@ public final class OffloadHardwareInterfaceTest { } @Test - public void testNetlinkMessage() throws Exception { + public void testSendIpv4NfGenMsg() throws Exception { FileDescriptor writeSocket = new FileDescriptor(); FileDescriptor readSocket = new FileDescriptor(); try { @@ -231,15 +233,23 @@ public final class OffloadHardwareInterfaceTest { mOffloadHw.sendIpv4NfGenMsg(mNativeHandle, TEST_TYPE, TEST_FLAGS); - ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE); + ByteBuffer buffer = ByteBuffer.allocate(9823); // Arbitrary value > expectedLen. + buffer.order(ByteOrder.nativeOrder()); + int read = Os.read(readSocket, buffer); + final int expectedLen = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; + assertEquals(expectedLen, read); buffer.flip(); - assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt()); + assertEquals(expectedLen, buffer.getInt()); assertEquals(TEST_TYPE, buffer.getShort()); assertEquals(TEST_FLAGS, buffer.getShort()); - assertEquals(1 /* seq */, buffer.getInt()); + assertEquals(0 /* seq */, buffer.getInt()); assertEquals(0 /* pid */, buffer.getInt()); + assertEquals(AF_INET, buffer.get()); // nfgen_family + assertEquals(0 /* error */, buffer.get()); // version + assertEquals(0 /* error */, buffer.getShort()); // res_id + assertEquals(expectedLen, buffer.position()); } private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { From 3d57544fb218fd0d2359272c0cafd049f141cd57 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Thu, 1 Oct 2020 20:12:46 +0000 Subject: [PATCH 1306/1415] Revert "Move module utils to the module package." Revert "Move util classes to their destination package" Revert "Move PacketReader and FdEventReader" Revert "Move static utils to a module package" Revert "Move static utils to a module package" Revert submission 12698912-move_packetreader Reason for revert: Broke presubmit on git_master, b/169861635 Reverted Changes: If5d1e4a58:Move module utils to the module package. I44ffaad3d:Move PacketReader and FdEventReader I93e9cfd96:Move util classes to their destination package Ia84d64130:Move static utils to a module package Iaac2810c7:Move static utils to a module package Change-Id: Ibbe59075cd7bc4c38e0707ea6ae3b3703b40986f --- Tethering/src/android/net/ip/NeighborPacketForwarder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/Tethering/src/android/net/ip/NeighborPacketForwarder.java index 084743db03..73fc833fab 100644 --- a/Tethering/src/android/net/ip/NeighborPacketForwarder.java +++ b/Tethering/src/android/net/ip/NeighborPacketForwarder.java @@ -25,6 +25,7 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOCK_RAW; import android.net.util.InterfaceParams; +import android.net.util.PacketReader; import android.net.util.SocketUtils; import android.net.util.TetheringUtils; import android.os.Handler; @@ -32,8 +33,6 @@ import android.system.ErrnoException; import android.system.Os; import android.util.Log; -import com.android.net.module.util.PacketReader; - import java.io.FileDescriptor; import java.io.IOException; import java.net.Inet6Address; From a773ccbe970ef701fc6f090de4ac9ebcd9cfe9a8 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 25 Jun 2020 03:58:10 +0000 Subject: [PATCH 1307/1415] Move CtsNetTestCasesLatestSdk to presubmit The last 19 runs have been green. This is already in presubmit in other branches. Note that mainline-presubmit is still not supported in some branches. Bug: 158153057 Test: m Merged-In: I9d7954503990902ae807d74de14f4a2874328072 Change-Id: I9d7954503990902ae807d74de14f4a2874328072 --- tests/cts/net/TEST_MAPPING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/TEST_MAPPING b/tests/cts/net/TEST_MAPPING index 3162e22378..9167c98e60 100644 --- a/tests/cts/net/TEST_MAPPING +++ b/tests/cts/net/TEST_MAPPING @@ -1,6 +1,6 @@ { // TODO: move to mainline-presubmit once supported - "postsubmit": [ + "presubmit": [ { "name": "CtsNetTestCasesLatestSdk", "options": [ From fedf95aecc343a0ae78a0a121fb28ca9dc09e7e9 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 16 Jul 2020 19:17:39 +0900 Subject: [PATCH 1308/1415] Add utilities for network validation testing Refactor out TestHttpServer to share it between CaptivePortalApiTest and CaptivePortalTest, move it to frameworks/libs/net, and add a NetworkValidationTestUtil class with utilities to set the test validation URLs. Test: atest CtsNetTestCasesLatestSdk:CaptivePortal[Api]Test Bug: 160617623 Bug: 160656765 Merged-In: Icd7829e680b2dddd1ddaa3dc2d946c14c20b5a15 (cherry picked from commit fe093f509b37eaa9799b4abc6b7c300c14690760) (clean cherry-pick from git, Gerrit could not automerge the rename) Change-Id: Icd7829e680b2dddd1ddaa3dc2d946c14c20b5a15 --- tests/cts/net/Android.bp | 1 - .../src/android/net/cts/CaptivePortalTest.kt | 140 +++++------------- ...talApiTest.kt => NetworkValidationTest.kt} | 66 +++------ .../net/cts/NetworkValidationTestUtil.kt | 79 ++++++++++ 4 files changed, 136 insertions(+), 150 deletions(-) rename tests/cts/net/src/android/net/cts/{CaptivePortalApiTest.kt => NetworkValidationTest.kt} (85%) create mode 100644 tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 7eaf133099..b35b850bc3 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -47,7 +47,6 @@ java_defaults { "ctstestserver", "junit", "junit-params", - "libnanohttpd", "mockwebserver", "net-utils-framework-common", "truth-prebuilt", diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 4a7d38a172..12a966fd31 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -19,7 +19,6 @@ package android.net.cts import android.Manifest.permission.CONNECTIVITY_INTERNAL import android.Manifest.permission.NETWORK_SETTINGS import android.Manifest.permission.READ_DEVICE_CONFIG -import android.Manifest.permission.WRITE_DEVICE_CONFIG import android.content.pm.PackageManager.FEATURE_TELEPHONY import android.content.pm.PackageManager.FEATURE_WIFI import android.net.ConnectivityManager @@ -30,20 +29,25 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkRequest import android.net.Uri +import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig +import android.net.cts.NetworkValidationTestUtil.runAsShell +import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig +import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig +import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig +import com.android.testutils.TestHttpServer.Request import android.net.cts.util.CtsNetUtils +import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL +import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL import android.net.wifi.WifiManager import android.os.Build -import android.os.ConditionVariable import android.platform.test.annotations.AppModeFull import android.provider.DeviceConfig import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY import android.text.TextUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 -import com.android.compatibility.common.util.SystemUtil +import com.android.testutils.TestHttpServer import com.android.testutils.isDevSdkInRange -import fi.iki.elonen.NanoHTTPD -import fi.iki.elonen.NanoHTTPD.Response.IStatus import fi.iki.elonen.NanoHTTPD.Response.Status import junit.framework.AssertionFailedError import org.junit.After @@ -55,15 +59,12 @@ import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException import kotlin.test.Test import kotlin.test.assertNotEquals +import kotlin.test.assertNotNull import kotlin.test.assertTrue -private const val TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING = "test_captive_portal_https_url" -private const val TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING = "test_captive_portal_http_url" -private const val TEST_URL_EXPIRATION_TIME = "test_url_expiration_time" - -private const val TEST_HTTPS_URL_PATH = "https_path" -private const val TEST_HTTP_URL_PATH = "http_path" -private const val TEST_PORTAL_URL_PATH = "portal_path" +private const val TEST_HTTPS_URL_PATH = "/https_path" +private const val TEST_HTTP_URL_PATH = "/http_path" +private const val TEST_PORTAL_URL_PATH = "/portal_path" private const val LOCALHOST_HOSTNAME = "localhost" @@ -88,24 +89,24 @@ class CaptivePortalTest { private val pm by lazy { context.packageManager } private val utils by lazy { CtsNetUtils(context) } - private val server = HttpServer() + private val server = TestHttpServer("localhost") @Before fun setUp() { - doAsShell(READ_DEVICE_CONFIG) { + runAsShell(READ_DEVICE_CONFIG) { // Verify that the test URLs are not normally set on the device, but do not fail if the // test URLs are set to what this test uses (URLs on localhost), in case the test was // interrupted manually and rerun. - assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING) - assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING) + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL) + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL) } - clearTestUrls() + clearValidationTestUrlsDeviceConfig() server.start() } @After fun tearDown() { - clearTestUrls() + clearValidationTestUrlsDeviceConfig() if (pm.hasSystemFeature(FEATURE_WIFI)) { reconnectWifi() } @@ -118,12 +119,6 @@ class CaptivePortalTest { "$urlKey must not be set in production scenarios (current value: $url)") } - private fun clearTestUrls() { - setHttpsUrl(null) - setHttpUrl(null) - setUrlExpiration(null) - } - @Test fun testCaptivePortalIsNotDefaultNetwork() { assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY)) @@ -132,19 +127,15 @@ class CaptivePortalTest { utils.connectToCell() // Have network validation use a local server that serves a HTTPS error / HTTP redirect - server.addResponse(TEST_PORTAL_URL_PATH, Status.OK, + server.addResponse(Request(TEST_PORTAL_URL_PATH), Status.OK, content = "Test captive portal content") - server.addResponse(TEST_HTTPS_URL_PATH, Status.INTERNAL_ERROR) - server.addResponse(TEST_HTTP_URL_PATH, Status.REDIRECT, - locationHeader = server.makeUrl(TEST_PORTAL_URL_PATH)) - setHttpsUrl(server.makeUrl(TEST_HTTPS_URL_PATH)) - setHttpUrl(server.makeUrl(TEST_HTTP_URL_PATH)) + server.addResponse(Request(TEST_HTTPS_URL_PATH), Status.INTERNAL_ERROR) + server.addResponse(Request(TEST_HTTP_URL_PATH), Status.REDIRECT, + locationHeader = makeUrl(TEST_PORTAL_URL_PATH)) + setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH)) + setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH)) // URL expiration needs to be in the next 10 minutes - setUrlExpiration(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)) - - // Expect the portal content to be fetched at some point after detecting the portal. - // Some implementations may fetch the URL before startCaptivePortalApp is called. - val portalContentRequestCv = server.addExpectRequestCv(TEST_PORTAL_URL_PATH) + setUrlExpirationDeviceConfig(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)) // Wait for a captive portal to be detected on the network val wifiNetworkFuture = CompletableFuture() @@ -173,9 +164,14 @@ class CaptivePortalTest { val startPortalAppPermission = if (isDevSdkInRange(0, Build.VERSION_CODES.Q)) CONNECTIVITY_INTERNAL else NETWORK_SETTINGS - doAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } - assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " + - "page was still not fetched ${TEST_TIMEOUT_MS}ms after startCaptivePortalApp.") + runAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } + + // Expect the portal content to be fetched at some point after detecting the portal. + // Some implementations may fetch the URL before startCaptivePortalApp is called. + assertNotNull(server.requestsRecord.poll(TEST_TIMEOUT_MS, pos = 0) { + it.path == TEST_PORTAL_URL_PATH + }, "The captive portal login page was still not fetched ${TEST_TIMEOUT_MS}ms " + + "after startCaptivePortalApp.") assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) } finally { @@ -186,73 +182,13 @@ class CaptivePortalTest { } } - private fun setHttpsUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING, url) - private fun setHttpUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING, url) - private fun setUrlExpiration(timestamp: Long?) = setConfig(TEST_URL_EXPIRATION_TIME, - timestamp?.toString()) - - private fun setConfig(configKey: String, value: String?) { - doAsShell(WRITE_DEVICE_CONFIG) { - DeviceConfig.setProperty( - NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) - } - } - - private fun doAsShell(vararg permissions: String, action: () -> Unit) { - // Wrap the below call to allow for more kotlin-like syntax - SystemUtil.runWithShellPermissionIdentity(action, permissions) - } + /** + * Create a URL string that, when fetched, will hit the test server with the given URL [path]. + */ + private fun makeUrl(path: String) = "http://localhost:${server.listeningPort}" + path private fun reconnectWifi() { utils.ensureWifiDisconnected(null /* wifiNetworkToCheck */) utils.ensureWifiConnected() } - - /** - * A minimal HTTP server running on localhost (loopback), on a random available port. - */ - private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) { - // Map of URL path -> HTTP response code - private val responses = HashMap() - - // Map of path -> CV to open as soon as a request to the path is received - private val waitForRequestCv = HashMap() - - /** - * Create a URL string that, when fetched, will hit this server with the given URL [path]. - */ - fun makeUrl(path: String): String { - return Uri.Builder() - .scheme("http") - .encodedAuthority("localhost:$listeningPort") - .query(path) - .build() - .toString() - } - - fun addResponse( - path: String, - statusCode: IStatus, - locationHeader: String? = null, - content: String = "" - ) { - val response = newFixedLengthResponse(statusCode, "text/plain", content) - locationHeader?.let { response.addHeader("Location", it) } - responses[path] = response - } - - /** - * Create a [ConditionVariable] that will open when a request to [path] is received. - */ - fun addExpectRequestCv(path: String): ConditionVariable { - return ConditionVariable().apply { waitForRequestCv[path] = this } - } - - override fun serve(session: IHTTPSession): Response { - waitForRequestCv[session.queryParameterString]?.open() - return responses[session.queryParameterString] - // Default response is a 404 - ?: super.serve(session) - } - } } \ No newline at end of file diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt similarity index 85% rename from tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt rename to tests/cts/net/src/android/net/cts/NetworkValidationTest.kt index 99fcd4c95d..ec656de653 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt @@ -31,6 +31,7 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.Uri +import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.dhcp.DhcpDiscoverPacket import android.net.dhcp.DhcpPacket import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE @@ -42,18 +43,18 @@ import android.os.HandlerThread import android.platform.test.annotations.AppModeFull import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 -import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity -import com.android.compatibility.common.util.ThrowingRunnable import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY +import com.android.testutils.ArpResponder import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DhcpClientPacketFilter import com.android.testutils.DhcpOptionFilter import com.android.testutils.RecorderCallback.CallbackEntry import com.android.testutils.TapPacketReader +import com.android.testutils.TestHttpServer import com.android.testutils.TestableNetworkCallback -import fi.iki.elonen.NanoHTTPD +import fi.iki.elonen.NanoHTTPD.Response.Status import org.junit.After import org.junit.Assume.assumeFalse import org.junit.Assume.assumeTrue @@ -62,8 +63,6 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import java.net.Inet4Address -import java.util.concurrent.ArrayBlockingQueue -import java.util.concurrent.TimeUnit import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -82,7 +81,7 @@ private const val TEST_MTU = 1500.toShort() @AppModeFull(reason = "Instant apps cannot create test networks") @RunWith(AndroidJUnit4::class) -class CaptivePortalApiTest { +class NetworkValidationTest { @JvmField @Rule val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) @@ -92,10 +91,10 @@ class CaptivePortalApiTest { private val eth by lazy { context.assertHasService(EthernetManager::class.java) } private val cm by lazy { context.assertHasService(ConnectivityManager::class.java) } - private val handlerThread = HandlerThread(CaptivePortalApiTest::class.java.simpleName) + private val handlerThread = HandlerThread(NetworkValidationTest::class.java.simpleName) private val serverIpAddr = InetAddresses.parseNumericAddress("192.0.2.222") as Inet4Address private val clientIpAddr = InetAddresses.parseNumericAddress("192.0.2.111") as Inet4Address - private val httpServer = HttpServer() + private val httpServer = TestHttpServer() private val ethRequest = NetworkRequest.Builder() // ETHERNET|TEST transport networks do not have NET_CAPABILITY_TRUSTED .removeCapability(NET_CAPABILITY_TRUSTED) @@ -156,7 +155,15 @@ class CaptivePortalApiTest { } @Test - fun testApiCallbacks() { + fun testCapportApiCallbacks() { + httpServer.addResponse(capportUrl, Status.OK, content = """ + |{ + | "captive": true, + | "user-portal-url": "$TEST_LOGIN_URL", + | "venue-info-url": "$TEST_VENUE_INFO_URL" + |} + """.trimMargin()) + // Handle the DHCP handshake that includes the capport API URL val discover = reader.assertDhcpPacketReceived( DhcpDiscoverPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER) @@ -168,11 +175,9 @@ class CaptivePortalApiTest { assertEquals(clientIpAddr, request.mRequestedIp) reader.sendResponse(makeAckPacket(request.clientMac, request.transactionId)) - // Expect a request to the capport API - val capportReq = httpServer.recordedRequests.poll(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS) - assertNotNull(capportReq, "The device did not fetch captive portal API data within timeout") - assertEquals(capportUrl.path, capportReq.uri) - assertEquals(capportUrl.query, capportReq.queryParameterString) + // The first request received by the server should be for the portal API + assertTrue(httpServer.requestsRecord.poll(TEST_TIMEOUT_MS, 0)?.matches(capportUrl) ?: false, + "The device did not fetch captive portal API data within timeout") // Expect network callbacks with capport info val testCb = TestableNetworkCallback(TEST_TIMEOUT_MS) @@ -221,30 +226,6 @@ class CaptivePortalApiTest { listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */, serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */, TEST_MTU, false /* rapidCommit */, capportUrl.toString()) - - private fun parseDhcpPacket(bytes: ByteArray) = DhcpPacket.decodeFullPacket( - bytes, MAX_PACKET_LENGTH, DhcpPacket.ENCAP_L2) -} - -/** - * A minimal HTTP server running on localhost (loopback), on a random available port. - * - * The server records each request in [recordedRequests] and will not serve any further request - * until the last one is removed from the queue for verification. - */ -private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) { - val recordedRequests = ArrayBlockingQueue(1 /* capacity */) - - override fun serve(session: IHTTPSession): Response { - recordedRequests.offer(session) - return newFixedLengthResponse(""" - |{ - | "captive": true, - | "user-portal-url": "$TEST_LOGIN_URL", - | "venue-info-url": "$TEST_VENUE_INFO_URL" - |} - """.trimMargin()) - } } private fun TapPacketReader.assertDhcpPacketReceived( @@ -264,12 +245,3 @@ private fun TapPacketReader.assertDhcpPacketReceived( private fun Context.assertHasService(manager: Class): T { return getSystemService(manager) ?: fail("Service $manager not found") } - -/** - * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. - */ -private fun runAsShell(vararg permissions: String, task: () -> T): T { - var ret: T? = null - runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) - return ret ?: fail("ThrowingRunnable was not run") -} diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt new file mode 100644 index 0000000000..5ef185432c --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -0,0 +1,79 @@ +/* + * 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 android.Manifest +import android.net.util.NetworkStackUtils +import android.provider.DeviceConfig +import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import com.android.compatibility.common.util.ThrowingRunnable +import kotlin.test.fail + +/** + * Collection of utility methods for configuring network validation. + */ +internal object NetworkValidationTestUtil { + + /** + * Clear the test network validation URLs. + */ + fun clearValidationTestUrlsDeviceConfig() { + setHttpsUrlDeviceConfig(null) + setHttpUrlDeviceConfig(null) + setUrlExpirationDeviceConfig(null) + } + + /** + * Set the test validation HTTPS URL. + * + * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL + */ + fun setHttpsUrlDeviceConfig(url: String?) = + setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL, url) + + /** + * Set the test validation HTTP URL. + * + * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL + */ + fun setHttpUrlDeviceConfig(url: String?) = + setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL, url) + + /** + * Set the test validation URL expiration. + * + * @see NetworkStackUtils.TEST_URL_EXPIRATION_TIME + */ + fun setUrlExpirationDeviceConfig(timestamp: Long?) = + setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString()) + + private fun setConfig(configKey: String, value: String?) { + runAsShell(Manifest.permission.WRITE_DEVICE_CONFIG) { + DeviceConfig.setProperty( + DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) + } + } + + /** + * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. + */ + fun runAsShell(vararg permissions: String, task: () -> T): T { + var ret: T? = null + runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) + return ret ?: fail("ThrowingRunnable did not return") + } +} \ No newline at end of file From a1b195ee3fbcaf8283dc021fc6af6531921b7ad3 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 18 Sep 2020 10:54:28 +0900 Subject: [PATCH 1309/1415] Add a test for getCaptivePortalServerUrl The API returns a URL that can be used to test the presence of a captive portal. The only requirements are that the URL is valid, and HTTP (as per javadoc). Bug: 168755498 Test: atest CtsNetTestCasesLatestSdk Change-Id: I9a92b422a7df2379fadab79ed49b77e7c2fcc393 --- .../net/cts/ConnectivityManagerTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 70b1bbe8cd..4f42cccf0f 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -17,6 +17,7 @@ package android.net.cts; import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; +import static android.Manifest.permission.NETWORK_SETTINGS; import static android.content.pm.PackageManager.FEATURE_ETHERNET; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.content.pm.PackageManager.FEATURE_USB_HOST; @@ -41,6 +42,7 @@ import static android.system.OsConstants.AF_UNSPEC; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; +import static com.android.testutils.TestPermissionUtil.runAsShell; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -103,6 +105,8 @@ import com.android.testutils.TestableNetworkCallback; import libcore.io.Streams; +import junit.framework.AssertionFailedError; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -118,6 +122,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.MalformedURLException; import java.net.Socket; import java.net.URL; import java.net.UnknownHostException; @@ -1499,4 +1504,17 @@ public class ConnectivityManagerTest { return runShellCommand("cmd connectivity airplane-mode") .trim().equals("enabled"); } + + @Test + public void testGetCaptivePortalServerUrl() { + final String url = runAsShell(NETWORK_SETTINGS, mCm::getCaptivePortalServerUrl); + assertNotNull("getCaptivePortalServerUrl must not be null", url); + try { + final URL parsedUrl = new URL(url); + // As per the javadoc, the URL must be HTTP + assertEquals("Invalid captive portal URL protocol", "http", parsedUrl.getProtocol()); + } catch (MalformedURLException e) { + throw new AssertionFailedError("Captive portal server URL is invalid: " + e); + } + } } From 8b8e27df0689f7eabb62e02994d5ae76ddf65dbf Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 23 Sep 2020 15:18:03 +0900 Subject: [PATCH 1310/1415] Use new test utilities from frameworks/libs/net Use runAsShell from the new TestPermissionUtils, and rename popPacket to poll. Bug: 168868607 Test: atest CtsNetTestCasesLatestSdk Change-Id: I0d938e2967f3adc324dd2bc81138b4b2910af5f8 --- .../net/src/android/net/cts/CaptivePortalTest.kt | 4 ++-- .../src/android/net/cts/NetworkValidationTest.kt | 10 ++++------ .../android/net/cts/NetworkValidationTestUtil.kt | 13 +------------ 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 12a966fd31..f2c5028f96 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -30,11 +30,9 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkRequest import android.net.Uri import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig -import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig -import com.android.testutils.TestHttpServer.Request import android.net.cts.util.CtsNetUtils import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL @@ -47,7 +45,9 @@ import android.text.TextUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 import com.android.testutils.TestHttpServer +import com.android.testutils.TestHttpServer.Request import com.android.testutils.isDevSdkInRange +import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status import junit.framework.AssertionFailedError import org.junit.After diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt index ec656de653..5290f0db28 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt @@ -31,7 +31,6 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.Uri -import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.dhcp.DhcpDiscoverPacket import android.net.dhcp.DhcpPacket import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE @@ -45,8 +44,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address -import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY -import com.android.testutils.ArpResponder +import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DhcpClientPacketFilter import com.android.testutils.DhcpOptionFilter @@ -54,10 +52,10 @@ import com.android.testutils.RecorderCallback.CallbackEntry import com.android.testutils.TapPacketReader import com.android.testutils.TestHttpServer import com.android.testutils.TestableNetworkCallback +import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status import org.junit.After import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -131,7 +129,7 @@ class NetworkValidationTest { handlerThread.threadHandler, iface.fileDescriptor.fileDescriptor, MAX_PACKET_LENGTH) - handlerThread.threadHandler.post { reader.start() } + reader.startAsyncForTest() httpServer.start() // Pad the listening port to make sure it is always of length 5. This ensures the URL has @@ -233,7 +231,7 @@ private fun TapPacketReader.assertDhcpPacketReceived( timeoutMs: Long, type: Byte ): T { - val packetBytes = popPacket(timeoutMs, DhcpClientPacketFilter() + val packetBytes = poll(timeoutMs, DhcpClientPacketFilter() .and(DhcpOptionFilter(DHCP_MESSAGE_TYPE, type))) ?: fail("${packetType.simpleName} not received within timeout") val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2) diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt index 5ef185432c..f6fc75b5f4 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -19,9 +19,7 @@ package android.net.cts import android.Manifest import android.net.util.NetworkStackUtils import android.provider.DeviceConfig -import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity -import com.android.compatibility.common.util.ThrowingRunnable -import kotlin.test.fail +import com.android.testutils.runAsShell /** * Collection of utility methods for configuring network validation. @@ -67,13 +65,4 @@ internal object NetworkValidationTestUtil { DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) } } - - /** - * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. - */ - fun runAsShell(vararg permissions: String, task: () -> T): T { - var ret: T? = null - runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) - return ret ?: fail("ThrowingRunnable did not return") - } } \ No newline at end of file From 2494a06bb394ba08f72489f6d04b3e952d496a3e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 24 Sep 2020 18:31:55 +0900 Subject: [PATCH 1311/1415] Move IpUtils to frameworks/libs/net The utility classes are useful for mainline modules and their tests, for example IpClientIntegrationTest. Bug: 168868607 Test: m && atest NetworkStaticLibTests Change-Id: If2b1613aa18a7990391e2d31cc2951ca93f1cf3c --- Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java index 747d3e8030..95e36fa18f 100644 --- a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java +++ b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java @@ -33,7 +33,6 @@ import android.net.MacAddress; import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.util.InterfaceParams; -import android.net.util.IpUtils; import android.net.util.TetheringUtils; import android.os.Handler; import android.os.HandlerThread; @@ -46,6 +45,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.IpUtils; import com.android.testutils.TapPacketReader; import org.junit.After; From b40f760f8dd8b21432ac8cb9aef78444e763583a Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Mon, 5 Oct 2020 13:52:02 +0800 Subject: [PATCH 1312/1415] Don't wait for unnecessary disconnect broadcast testTetheringUpstream does not require WIFI to be default network since the test disconnects WIFI and verifies that tethering use cellular network to be its upstream. Test only needs to ensure WIFI is disconnected so the broadcast is not necessary. Change to alternative method that does not wait for disconnect broadcast to prevent flaky caused by unvalidated wifi network. Bug: 168217651 Test: atest TetheringManagerTest Change-Id: If74fcad192cb4d4947ac2c99cd9ea2d3971d2cac --- .../src/android/tethering/cts/TetheringManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 65a8c7c76b..92dca3984c 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -757,7 +757,7 @@ public class TetheringManagerTest { if (!isWifiTetheringSupported(tetherEventCallback)) return; if (previousWifiEnabledState) { - mCtsNetUtils.disconnectFromWifi(null); + mCtsNetUtils.ensureWifiDisconnected(null); } final TestNetworkCallback networkCallback = new TestNetworkCallback(); From b8a342e4bc30afecbc6dcf10f4fef43a5f9ad4b4 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Fri, 2 Oct 2020 16:38:21 +0100 Subject: [PATCH 1313/1415] Explicitly reference framework-wifi app build rule This works around a build-system limitation where it does not know which jars to feed r8 to resolve all classes during proguarding. Bug: 160453030 Bug: 169931783 Test: build_mainline_modules.sh (with prebuilt sdk) Change-Id: I3d9f2049cf898b5e551a5c5764df423abaa5e92d Merged-In: I3d9f2049cf898b5e551a5c5764df423abaa5e92d --- Tethering/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 257538d621..5526c657b8 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -101,6 +101,7 @@ java_defaults { ], libs: [ "framework-tethering", + "framework-wifi", ], jarjar_rules: "jarjar-rules.txt", optimize: { From a2ffad84c7fb99a98c232ee0a55620ed76486cf8 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 22 Sep 2020 15:50:43 +0800 Subject: [PATCH 1314/1415] Make the IP subnet persistent till reboot Make the IP subnet persistent if it do not conflict with upstream. It allow client to reuse its IP that usually reduce DHCP procedure. Bug: 168169687 Test: atest TetheringTests Change-Id: Iddc5304730dce7b11c5d124b7eddce057d752bbd --- Tethering/src/android/net/ip/IpServer.java | 8 +- .../tethering/PrivateAddressCoordinator.java | 78 +++++--- .../unit/src/android/net/ip/IpServerTest.java | 18 +- .../PrivateAddressCoordinatorTest.java | 170 ++++++++++-------- 4 files changed, 165 insertions(+), 109 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 336124dc1b..52d59fcdc1 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -616,7 +616,7 @@ public class IpServer extends StateMachine { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (enabled) { - mIpv4Address = requestIpv4Address(); + mIpv4Address = requestIpv4Address(true /* useLastAddress */); } if (mIpv4Address == null) { @@ -661,14 +661,14 @@ public class IpServer extends StateMachine { return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } - private LinkAddress requestIpv4Address() { + private LinkAddress requestIpv4Address(final boolean useLastAddress) { if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) { return new LinkAddress(BLUETOOTH_IFACE_ADDR); } - return mPrivateAddressCoordinator.requestDownstreamAddress(this); + return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress); } private boolean startIPv6() { @@ -957,7 +957,7 @@ public class IpServer extends StateMachine { } final LinkAddress deprecatedLinkAddress = mIpv4Address; - mIpv4Address = requestIpv4Address(); + mIpv4Address = requestIpv4Address(false); if (mIpv4Address == null) { mLog.e("Fail to request a new downstream prefix"); return; diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index b285849f9e..6276c4e2aa 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -16,7 +16,9 @@ package com.android.networkstack.tethering; import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.util.PrefixUtils.asIpPrefix; import static java.util.Arrays.asList; @@ -26,9 +28,9 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.Network; import android.net.ip.IpServer; -import android.net.util.PrefixUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.SparseArray; import androidx.annotation.Nullable; @@ -58,9 +60,6 @@ public class PrivateAddressCoordinator { private static final int MAX_UBYTE = 256; private static final int BYTE_MASK = 0xff; - // reserved for bluetooth tethering. - private static final int BLUETOOTH_RESERVED = 44; - private static final int WIFI_P2P_RESERVED = 49; private static final byte DEFAULT_ID = (byte) 42; // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream @@ -75,9 +74,12 @@ public class PrivateAddressCoordinator { // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers. private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16"; private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24"; + private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24"; private final IpPrefix mTetheringPrefix; private final ConnectivityManager mConnectivityMgr; private final TetheringConfiguration mConfig; + // keyed by downstream type(TetheringManager.TETHERING_*). + private final SparseArray mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { mDownstreams = new ArraySet<>(); @@ -86,6 +88,10 @@ public class PrivateAddressCoordinator { mConnectivityMgr = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); mConfig = config; + mCachedAddresses = new SparseArray<>(); + // Reserved static addresses for bluetooth and wifi p2p. + mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); + mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); } /** @@ -94,7 +100,8 @@ public class PrivateAddressCoordinator { * UpstreamNetworkState must have an already populated LinkProperties. */ public void updateUpstreamPrefix(final UpstreamNetworkState ns) { - // Do not support VPN as upstream + // Do not support VPN as upstream. Normally, networkCapabilities is not expected to be null, + // but just checking to be sure. if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) { removeUpstreamPrefix(ns.network); return; @@ -116,7 +123,7 @@ public class PrivateAddressCoordinator { for (LinkAddress address : linkAddresses) { if (!address.isIpv4()) continue; - list.add(PrefixUtils.asIpPrefix(address)); + list.add(asIpPrefix(address)); } return list; @@ -155,21 +162,23 @@ public class PrivateAddressCoordinator { mUpstreamPrefixMap.removeAll(toBeRemoved); } - private boolean isReservedSubnet(final int subnet) { - return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED; - } - /** * Pick a random available address and mark its prefix as in use for the provided IpServer, * returns null if there is no available address. */ @Nullable - public LinkAddress requestDownstreamAddress(final IpServer ipServer) { + public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { if (mConfig.shouldEnableWifiP2pDedicatedIp() && ipServer.interfaceType() == TETHERING_WIFI_P2P) { return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS); } + final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType()); + if (useLastAddress && cachedAddress != null + && !isConflictWithUpstream(asIpPrefix(cachedAddress))) { + return cachedAddress; + } + // Address would be 192.168.[subAddress]/24. final byte[] bytes = mTetheringPrefix.getRawAddress(); final int subAddress = getRandomSubAddr(); @@ -177,9 +186,8 @@ public class PrivateAddressCoordinator { bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); for (int i = 0; i < MAX_UBYTE; i++) { final int newSubNet = (subNet + i) & BYTE_MASK; - if (isReservedSubnet(newSubNet)) continue; - bytes[2] = (byte) newSubNet; + final InetAddress addr; try { addr = InetAddress.getByAddress(bytes); @@ -187,20 +195,23 @@ public class PrivateAddressCoordinator { throw new IllegalStateException("Invalid address, shouldn't happen.", e); } - final IpPrefix prefix = new IpPrefix(addr, PREFIX_LENGTH); - // Check whether this prefix is in use. - if (isDownstreamPrefixInUse(prefix)) continue; - // Check whether this prefix is conflict with any current upstream network. - if (isConflictWithUpstream(prefix)) continue; + if (isConflict(new IpPrefix(addr, PREFIX_LENGTH))) continue; mDownstreams.add(ipServer); - return new LinkAddress(addr, PREFIX_LENGTH); + final LinkAddress newAddress = new LinkAddress(addr, PREFIX_LENGTH); + mCachedAddresses.put(ipServer.interfaceType(), newAddress); + return newAddress; } // No available address. return null; } + private boolean isConflict(final IpPrefix prefix) { + // Check whether this prefix is in use or conflict with any current upstream network. + return isDownstreamPrefixInUse(prefix) || isConflictWithUpstream(prefix); + } + /** Get random sub address value. Return value is in 0 ~ 0xffff. */ @VisibleForTesting public int getRandomSubAddr() { @@ -244,13 +255,24 @@ public class PrivateAddressCoordinator { return prefix1.contains(prefix2.getAddress()); } - private boolean isDownstreamPrefixInUse(final IpPrefix source) { + // InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last + // downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p). + private boolean isDownstreamPrefixInUse(final IpPrefix prefix) { // This class always generates downstream prefixes with the same prefix length, so // prefixes cannot be contained in each other. They can only be equal to each other. - for (IpServer downstream : mDownstreams) { - final IpPrefix prefix = getDownstreamPrefix(downstream); - if (source.equals(prefix)) return true; + for (int i = 0; i < mCachedAddresses.size(); i++) { + if (prefix.equals(asIpPrefix(mCachedAddresses.valueAt(i)))) return true; } + + // IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include + // in mCachedAddresses. + for (IpServer downstream : mDownstreams) { + final IpPrefix target = getDownstreamPrefix(downstream); + if (target == null) continue; + + if (isConflictPrefix(prefix, target)) return true; + } + return false; } @@ -258,7 +280,7 @@ public class PrivateAddressCoordinator { final LinkAddress address = downstream.getAddress(); if (address == null) return null; - return PrefixUtils.asIpPrefix(address); + return asIpPrefix(address); } void dump(final IndentingPrintWriter pw) { @@ -268,11 +290,19 @@ public class PrivateAddressCoordinator { pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i)); } pw.decreaseIndent(); + pw.println("mDownstreams:"); pw.increaseIndent(); for (IpServer ipServer : mDownstreams) { pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress()); } pw.decreaseIndent(); + + pw.println("mCachedAddresses:"); + pw.increaseIndent(); + for (int i = 0; i < mCachedAddresses.size(); i++) { + pw.println(mCachedAddresses.keyAt(i) + " - " + mCachedAddresses.valueAt(i)); + } + pw.decreaseIndent(); } } diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 1a976adc60..2eb75895ac 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -47,6 +47,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; @@ -230,7 +231,8 @@ public class IpServerTest { dispatchTetherConnectionChanged(upstreamIface, lp, 0); } reset(mNetd, mCallback, mAddressCoordinator); - when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( + mTestAddress); } private void setUpDhcpServer() throws Exception { @@ -250,7 +252,8 @@ public class IpServerTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); - when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( + mTestAddress); when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */); mBpfCoordinator = spy(new BpfCoordinator( @@ -372,7 +375,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); @@ -393,7 +396,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); @@ -607,7 +610,7 @@ public class IpServerTest { final ArgumentCaptor lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); // One for ipv4 route, one for ipv6 link local route. inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), @@ -620,11 +623,12 @@ public class IpServerTest { // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals // onNewPrefixRequest callback. final LinkAddress newAddress = new LinkAddress("192.168.100.125/24"); - when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(newAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( + newAddress); eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); mLooper.dispatchAll(); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false)); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); verifyNoMoreInteractions(mCallback); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 7b6632c36f..191eb6e711 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -23,6 +23,7 @@ import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.util.PrefixUtils.asIpPrefix; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -40,7 +41,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.ip.IpServer; -import android.net.util.PrefixUtils; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -65,7 +65,7 @@ public final class PrivateAddressCoordinatorTest { @Mock private TetheringConfiguration mConfig; private PrivateAddressCoordinator mPrivateAddressCoordinator; - private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24"); + private final LinkAddress mBluetoothAddress = new LinkAddress("192.168.44.1/24"); private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24"); private final Network mWifiNetwork = new Network(1); private final Network mMobileNetwork = new Network(2); @@ -91,98 +91,119 @@ public final class PrivateAddressCoordinatorTest { } @Test - public void testDownstreamPrefixRequest() throws Exception { - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - assertNotEquals(hotspotPrefix, mBluetoothPrefix); + public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception { + final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress); + final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, false /* useLastAddress */); + final IpPrefix hotspotPrefix = asIpPrefix(address); + assertNotEquals(hotspotPrefix, bluetoothPrefix); + when(mHotspotIpServer.getAddress()).thenReturn(address); - address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix testDupRequest = PrefixUtils.asIpPrefix(address); + final LinkAddress newAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, false /* useLastAddress */); + final IpPrefix testDupRequest = asIpPrefix(newAddress); assertNotEquals(hotspotPrefix, testDupRequest); - assertNotEquals(mBluetoothPrefix, testDupRequest); + assertNotEquals(bluetoothPrefix, testDupRequest); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - address = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer); - final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); - assertNotEquals(usbPrefix, mBluetoothPrefix); + final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, false /* useLastAddress */); + final IpPrefix usbPrefix = asIpPrefix(usbAddress); + assertNotEquals(usbPrefix, bluetoothPrefix); assertNotEquals(usbPrefix, hotspotPrefix); mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); } @Test - public void testRequestDownstreamAddress() throws Exception { - LinkAddress expectedAddress = new LinkAddress("192.168.43.42/24"); - int fakeSubAddr = 0x2b00; + public void testSanitizedAddress() throws Exception { + int fakeSubAddr = 0x2b00; // 43.0. when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - assertEquals(actualAddress, expectedAddress); + mHotspotIpServer, false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.43.42/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - fakeSubAddr = 0x2b01; + fakeSubAddr = 0x2d01; // 45.1. when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - assertEquals(actualAddress, expectedAddress); + mHotspotIpServer, false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.45.42/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - fakeSubAddr = 0x2bff; + fakeSubAddr = 0x2eff; // 46.255. when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - assertEquals(actualAddress, expectedAddress); + mHotspotIpServer, false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.46.42/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - expectedAddress = new LinkAddress("192.168.43.5/24"); - fakeSubAddr = 0x2b05; + fakeSubAddr = 0x2f05; // 47.5. when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - assertEquals(actualAddress, expectedAddress); - mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - } - - private int getBluetoothSubAddress() { - final byte[] rawAddress = mBluetoothPrefix.getRawAddress(); - int bluetoothSubNet = rawAddress[2] & 0xff; - return (bluetoothSubNet << 8) + 0x5; - } - - @Test - public void testReserveBluetoothPrefix() throws Exception { - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(getBluetoothSubAddress()); - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - assertNotEquals("Should not get reserved prefix: ", mBluetoothPrefix, hotspotPrefix); + mHotspotIpServer, false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } @Test - public void testNoConflictDownstreamPrefix() throws Exception { + public void testReservedPrefix() throws Exception { + // - Test bluetooth prefix is reserved. + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + getSubAddress(mBluetoothAddress.getAddress().getAddress())); + final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, false /* useLastAddress */); + final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress); + assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix); + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + + // - Test previous enabled hotspot prefix(cached prefix) is reserved. + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + getSubAddress(hotspotAddress.getAddress().getAddress())); + final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, false /* useLastAddress */); + final IpPrefix usbPrefix = asIpPrefix(usbAddress); + assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix); + assertNotEquals(hotspotPrefix, usbPrefix); + mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); + + // - Test wifi p2p prefix is reserved. + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); + final LinkAddress etherAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mEthernetIpServer, false /* useLastAddress */); + final IpPrefix etherPrefix = asIpPrefix(etherAddress); + assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix); + assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix); + assertNotEquals(hotspotPrefix, etherPrefix); + mPrivateAddressCoordinator.releaseDownstream(mEthernetIpServer); + } + + @Test + public void testRequestLastDownstreamAddress() throws Exception { final int fakeHotspotSubAddr = 0x2b05; final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); - when(mHotspotIpServer.getAddress()).thenReturn(address); + final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true /* useLastAddress */); + assertEquals("Wrong wifi prefix: ", predefinedPrefix, asIpPrefix(hotspotAddress)); + when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddress); - address = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer); - final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); - assertNotEquals(predefinedPrefix, usbPrefix); + final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, true /* useLastAddress */); + assertNotEquals(predefinedPrefix, asIpPrefix(usbAddress)); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); - address = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer); - final IpPrefix allowUseFreePrefix = PrefixUtils.asIpPrefix(address); - assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix); + + final int newFakeSubAddr = 0x3c05; + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + + final LinkAddress newHotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true /* useLastAddress */); + assertEquals(hotspotAddress, newHotspotAddress); + final LinkAddress newUsbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, true /* useLastAddress */); + assertEquals(usbAddress, newUsbAddress); } private UpstreamNetworkState buildUpstreamNetworkState(final Network network, @@ -215,12 +236,13 @@ public final class PrivateAddressCoordinatorTest { when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); // - Enable hotspot with prefix 192.168.43.0/24 final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr); + mHotspotIpServer, true /* useLastAddress */); + final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr); assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); - // - test mobile network with null NetworkCapabilities. Ideally this should not happen, - // just make sure no crash in this case. + // - test mobile network with null NetworkCapabilities. Ideally this should not happen + // because NetworkCapabilities update should always happen before LinkProperties update + // and the UpstreamNetworkState update, just make sure no crash in this case. final UpstreamNetworkState noCapUpstream = buildUpstreamNetworkState(mMobileNetwork, new LinkAddress("10.0.0.8/24"), null, null); mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream); @@ -269,24 +291,24 @@ public final class PrivateAddressCoordinatorTest { // - Restart hotspot again and its prefix is different previous. mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2); + mHotspotIpServer, true /* useLastAddress */); + final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2); assertNotEquals(hotspotPrefix, hotspotPrefix2); when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2); mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); // - Usb tethering can be enabled and its prefix is different with conflict one. final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer); - final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr); + mUsbIpServer, true /* useLastAddress */); + final IpPrefix usbPrefix = asIpPrefix(usbAddr); assertNotEquals(predefinedPrefix, usbPrefix); assertNotEquals(hotspotPrefix2, usbPrefix); when(mUsbIpServer.getAddress()).thenReturn(usbAddr); // - Disable wifi upstream, then wifi's prefix can be selected again. mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mEthernetIpServer); - final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr); + mEthernetIpServer, true /* useLastAddress */); + final IpPrefix ethPrefix = asIpPrefix(ethAddr); assertEquals(predefinedPrefix, ethPrefix); } @@ -299,9 +321,9 @@ public final class PrivateAddressCoordinatorTest { private void assertReseveredWifiP2pPrefix() throws Exception { LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress); + mHotspotIpServer, true /* useLastAddress */); + final IpPrefix hotspotPrefix = asIpPrefix(address); + final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress); assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } @@ -319,7 +341,7 @@ public final class PrivateAddressCoordinatorTest { // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address. LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mWifiP2pIpServer); + mWifiP2pIpServer, true /* useLastAddress */); assertEquals(mLegacyWifiP2pAddress, address); mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer); } From cd2fe6e08a4aa3765581d8f1a7c403765f6b94b3 Mon Sep 17 00:00:00 2001 From: David Su Date: Mon, 5 Oct 2020 22:41:42 +0000 Subject: [PATCH 1315/1415] Ensure CONFIGURED_NETWORKS_CHANGED not received without permissions Ensure that the CONFIGURED_NETWORKS_CHANGED_ACTION broadcast is not received without the required permissions. Bug: 159373687 Test: cts-tradefed run cts -m CtsNetTestCases --test android.net.wifi.cts.WifiManagerTest#testWifiManagerNetWork Change-Id: I2e3f38b05d63571e838b148fbbb2ce6f68c19c01 Merged-In: I4669a6ff79b3d2e99795015e42bfa611cffb9070 --- .../android/net/wifi/cts/WifiManagerTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index a2e7f57b9d..9cc5d8199a 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -411,12 +411,33 @@ public class WifiManagerTest extends AndroidTestCase { assertFalse(existSSID(SSID1)); assertTrue(existSSID(SSID2)); + // Need an effectively-final holder because we need to modify inner Intent in callback. + class IntentHolder { + Intent intent; + } + IntentHolder intentHolder = new IntentHolder(); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Log.i(TAG, "Received CONFIGURED_NETWORKS_CHANGED_ACTION broadcast: " + intent); + intentHolder.intent = intent; + } + }, new IntentFilter(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); + // Remove a WifiConfig assertTrue(mWifiManager.removeNetwork(netId)); assertFalse(mWifiManager.removeNetwork(notExist)); assertFalse(existSSID(SSID1)); assertFalse(existSSID(SSID2)); + // wait 10 seconds to ensure that broadcast wasn't received + Thread.sleep(DURATION); + Intent intent = intentHolder.intent; + // Broadcast shouldn't be received because although CtsNetTestCases has + // ACCESS_WIFI_STATE permission, it doesn't have ACCESS_FINE_LOCATION permission. + // Receivers need both permissions to get the broadcast. + assertNull("Unexpected received CONFIGURED_NETWORKS_CHANGED_ACTION broadcast!", intent); + assertTrue(mWifiManager.saveConfiguration()); } finally { reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks()); From 956f4dc23182fb7c42d29546b466e117453f6a75 Mon Sep 17 00:00:00 2001 From: David Su Date: Mon, 5 Oct 2020 22:41:42 +0000 Subject: [PATCH 1316/1415] Ensure CONFIGURED_NETWORKS_CHANGED not received without permissions Ensure that the CONFIGURED_NETWORKS_CHANGED_ACTION broadcast is not received without the required permissions. Bug: 159373687 Test: cts-tradefed run cts -m CtsNetTestCases --test android.net.wifi.cts.WifiManagerTest#testWifiManagerNetWork Change-Id: I2e3f38b05d63571e838b148fbbb2ce6f68c19c01 Merged-In: I4669a6ff79b3d2e99795015e42bfa611cffb9070 --- .../android/net/wifi/cts/WifiManagerTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 44b49c0274..c5d0d4f0ad 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -411,12 +411,33 @@ public class WifiManagerTest extends AndroidTestCase { assertFalse(existSSID(SSID1)); assertTrue(existSSID(SSID2)); + // Need an effectively-final holder because we need to modify inner Intent in callback. + class IntentHolder { + Intent intent; + } + IntentHolder intentHolder = new IntentHolder(); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Log.i(TAG, "Received CONFIGURED_NETWORKS_CHANGED_ACTION broadcast: " + intent); + intentHolder.intent = intent; + } + }, new IntentFilter(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); + // Remove a WifiConfig assertTrue(mWifiManager.removeNetwork(netId)); assertFalse(mWifiManager.removeNetwork(notExist)); assertFalse(existSSID(SSID1)); assertFalse(existSSID(SSID2)); + // wait 10 seconds to ensure that broadcast wasn't received + Thread.sleep(DURATION); + Intent intent = intentHolder.intent; + // Broadcast shouldn't be received because although CtsNetTestCases has + // ACCESS_WIFI_STATE permission, it doesn't have ACCESS_FINE_LOCATION permission. + // Receivers need both permissions to get the broadcast. + assertNull("Unexpected received CONFIGURED_NETWORKS_CHANGED_ACTION broadcast!", intent); + assertTrue(mWifiManager.saveConfiguration()); } finally { reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks()); From 62e162b2844e9cbff42132c23a632296d0d9d422 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 6 Oct 2020 19:10:56 -0700 Subject: [PATCH 1317/1415] Mark testAppIdle(Non)Metered_whitelisted as flaky. Bug: 170180675 Test: atest hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Change-Id: I82c1cebc7ad8f8aac4468f8412216c59ea7a0f71 --- .../cts/net/HostsideRestrictBackgroundNetworkTests.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index ac28c7ab63..f681f3647c 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -16,6 +16,8 @@ package com.android.cts.net; +import android.platform.test.annotations.FlakyTest; + import com.android.ddmlib.Log; import com.android.tradefed.device.DeviceNotAvailableException; @@ -146,6 +148,7 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_disabled"); } + @FlakyTest(bugId=170180675) public void testAppIdleMetered_whitelisted() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", "testBackgroundNetworkAccess_whitelisted"); @@ -176,6 +179,7 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_disabled"); } + @FlakyTest(bugId=170180675) public void testAppIdleNonMetered_whitelisted() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", "testBackgroundNetworkAccess_whitelisted"); From d65405de4b3659f62b6dca5ac44a7d6f29c86a9f Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Tue, 6 Oct 2020 14:58:51 -0700 Subject: [PATCH 1318/1415] Remove vts10 suite setting Bug: 169583551 Test: build Change-Id: I42d38bd2f9e8b1e932571a38c2ebe72861d18fca Exempt-From-Owner-Approval: This CL remove vts10 from test_suites setting. Change-Id: I42d38bd2f9e8b1e932571a38c2ebe72861d18fca --- tests/cts/hostside/Android.bp | 1 - tests/cts/hostside/app/Android.bp | 1 - tests/cts/hostside/app2/Android.bp | 1 - tests/cts/net/Android.bp | 1 - tests/cts/net/api23Test/Android.bp | 1 - tests/cts/net/appForApi23/Android.bp | 1 - tests/cts/net/native/qtaguid/Android.bp | 1 - 7 files changed, 7 deletions(-) diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp index 741c961e5f..47b114b64d 100644 --- a/tests/cts/hostside/Android.bp +++ b/tests/cts/hostside/Android.bp @@ -24,7 +24,6 @@ java_test_host { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts10", "general-tests", ], } diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index e129be7b7d..99037567b5 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp @@ -35,7 +35,6 @@ android_test_helper_app { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts10", "general-tests", ], } diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp index a6e9b118ff..8e279311a8 100644 --- a/tests/cts/hostside/app2/Android.bp +++ b/tests/cts/hostside/app2/Android.bp @@ -23,7 +23,6 @@ android_test_helper_app { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts10", "general-tests", ], certificate: ":cts-net-app", diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 4c00428f71..913380a09c 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -66,7 +66,6 @@ android_test { defaults: ["CtsNetTestCasesDefaults"], test_suites: [ "cts", - "vts10", "general-tests", ], test_config_template: "AndroidTestTemplate.xml", diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index 0ce9826a2b..e43a5e82d0 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -45,7 +45,6 @@ android_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts10", "general-tests", ], diff --git a/tests/cts/net/appForApi23/Android.bp b/tests/cts/net/appForApi23/Android.bp index 399c199508..cec6d7f5a1 100644 --- a/tests/cts/net/appForApi23/Android.bp +++ b/tests/cts/net/appForApi23/Android.bp @@ -26,7 +26,6 @@ android_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts10", "general-tests", ], diff --git a/tests/cts/net/native/qtaguid/Android.bp b/tests/cts/net/native/qtaguid/Android.bp index 23a0cf764d..7c6e19f005 100644 --- a/tests/cts/net/native/qtaguid/Android.bp +++ b/tests/cts/net/native/qtaguid/Android.bp @@ -42,7 +42,6 @@ cc_test { // Tag this module as a cts test artifact test_suites: [ "cts", - "vts10", ], cflags: [ From 06aad059fbe854e25a12a6422c4f20e05ff4aa37 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 8 Oct 2020 15:13:59 +0900 Subject: [PATCH 1319/1415] Update the QUIC packet format. The QUIC packet format has changed again. Update the test to ensure that the GFE can drop support for the old packet format without causing all devices to fail CTS. Packet format changes suggested by dschinazi@. Test: atest --rerun-until-failure 100 CtsNetTestCasesLatestSdk:MultinetworkApiTest#testNativeDatagramTransmission Change-Id: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf --- tests/cts/net/jni/NativeMultinetworkJni.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index cd94709fd5..60e31bc78a 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -458,20 +458,16 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-invariants uint8_t quic_packet[1200] = { - 0x0d, // public flags: - // - version present (0x01), - // - 64bit connection ID (0x0c), - // - 1 byte packet number (0x00) + 0xc0, // long header + 0xaa, 0xda, 0xca, 0xca, // reserved-space version number + 0x08, // destination connection ID length 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number - 1, // 1 byte packet number - 0x00, // private flags - 0x07, // PING frame (cuz why not) + 0x00, // source connection ID length }; - arc4random_buf(quic_packet + 1, 8); // random connection ID + arc4random_buf(quic_packet + 6, 8); // random connection ID uint8_t response[1500]; ssize_t sent, rcvd; @@ -496,7 +492,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < 9) { + if (rcvd < 15) { LOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { LOGD("Does this network block UDP port %s?", kPort); @@ -505,7 +501,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); + int conn_id_cmp = memcmp(quic_packet + 6, response + 7, 8); if (conn_id_cmp != 0) { LOGD("sent and received connection IDs do not match"); close(fd); From 29021f0c643f4827676618a4b936db60346ba494 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 24 Sep 2020 10:27:28 +0000 Subject: [PATCH 1320/1415] Don't check broadcast intent on connection status check testRequestNetworkCallback_onUnavailable is flaky because the test expects a connectivity broadcast to be sent for the lost network. But after testSetAirplaneMode, the wifi network is not yet default network so a broadcast is never sent but only onUnavailable is triggered. Replace disconnectFromWifi with ensureWifiDisconnected to skip checking the broadcast. Bug: 162323152 Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest\ --rerun-until-failure 20 Original-Change: https://android-review.googlesource.com/1435534 Merged-In: I88f434798ec83539df9cc6a81446ca37a0081e3b Change-Id: I88f434798ec83539df9cc6a81446ca37a0081e3b --- tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 3880664827..1961e3da20 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -592,7 +592,7 @@ public class ConnectivityManagerTest { public void testRequestNetworkCallback_onUnavailable() { final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); if (previousWifiEnabledState) { - mCtsNetUtils.disconnectFromWifi(null); + mCtsNetUtils.ensureWifiDisconnected(null); } final TestNetworkCallback callback = new TestNetworkCallback(); From d48265e2013999e94b44135de80863106ed36b9b Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 9 Oct 2020 00:36:13 +0000 Subject: [PATCH 1321/1415] Use new test utilities from frameworks/libs/net Use runAsShell from the new TestPermissionUtils, and rename popPacket to poll. Bug: 168868607 Test: atest CtsNetTestCasesLatestSdk Original-Change: https://android-review.googlesource.com/1433985 Merged-In: I0d938e2967f3adc324dd2bc81138b4b2910af5f8 Change-Id: I0d938e2967f3adc324dd2bc81138b4b2910af5f8 --- .../net/src/android/net/cts/CaptivePortalTest.kt | 4 ++-- .../src/android/net/cts/NetworkValidationTest.kt | 10 ++++------ .../android/net/cts/NetworkValidationTestUtil.kt | 13 +------------ 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 12a966fd31..f2c5028f96 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -30,11 +30,9 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkRequest import android.net.Uri import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig -import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig -import com.android.testutils.TestHttpServer.Request import android.net.cts.util.CtsNetUtils import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL @@ -47,7 +45,9 @@ import android.text.TextUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 import com.android.testutils.TestHttpServer +import com.android.testutils.TestHttpServer.Request import com.android.testutils.isDevSdkInRange +import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status import junit.framework.AssertionFailedError import org.junit.After diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt index ec656de653..5290f0db28 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt @@ -31,7 +31,6 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.Uri -import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.dhcp.DhcpDiscoverPacket import android.net.dhcp.DhcpPacket import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE @@ -45,8 +44,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address -import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY -import com.android.testutils.ArpResponder +import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DhcpClientPacketFilter import com.android.testutils.DhcpOptionFilter @@ -54,10 +52,10 @@ import com.android.testutils.RecorderCallback.CallbackEntry import com.android.testutils.TapPacketReader import com.android.testutils.TestHttpServer import com.android.testutils.TestableNetworkCallback +import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status import org.junit.After import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -131,7 +129,7 @@ class NetworkValidationTest { handlerThread.threadHandler, iface.fileDescriptor.fileDescriptor, MAX_PACKET_LENGTH) - handlerThread.threadHandler.post { reader.start() } + reader.startAsyncForTest() httpServer.start() // Pad the listening port to make sure it is always of length 5. This ensures the URL has @@ -233,7 +231,7 @@ private fun TapPacketReader.assertDhcpPacketReceived( timeoutMs: Long, type: Byte ): T { - val packetBytes = popPacket(timeoutMs, DhcpClientPacketFilter() + val packetBytes = poll(timeoutMs, DhcpClientPacketFilter() .and(DhcpOptionFilter(DHCP_MESSAGE_TYPE, type))) ?: fail("${packetType.simpleName} not received within timeout") val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2) diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt index 5ef185432c..f6fc75b5f4 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -19,9 +19,7 @@ package android.net.cts import android.Manifest import android.net.util.NetworkStackUtils import android.provider.DeviceConfig -import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity -import com.android.compatibility.common.util.ThrowingRunnable -import kotlin.test.fail +import com.android.testutils.runAsShell /** * Collection of utility methods for configuring network validation. @@ -67,13 +65,4 @@ internal object NetworkValidationTestUtil { DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) } } - - /** - * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. - */ - fun runAsShell(vararg permissions: String, task: () -> T): T { - var ret: T? = null - runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) - return ret ?: fail("ThrowingRunnable did not return") - } } \ No newline at end of file From 0d4dee1c1acf890b26e24fcff721859debf53190 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 9 Oct 2020 01:38:44 +0000 Subject: [PATCH 1322/1415] Revert "Use new test utilities from frameworks/libs/net" Revert submission 1440811-iputils_constants_move Reason for revert: Likely broke build in b/170438226 Reverted Changes: Ic382d24e7:Move NetworkStackConstants to frameworks/libs/net I0d938e296:Use new test utilities from frameworks/libs/net Change-Id: Iec4709778ba1b30687df265a2a5c694c536b5456 --- .../net/src/android/net/cts/CaptivePortalTest.kt | 4 ++-- .../src/android/net/cts/NetworkValidationTest.kt | 10 ++++++---- .../android/net/cts/NetworkValidationTestUtil.kt | 13 ++++++++++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index f2c5028f96..12a966fd31 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -30,9 +30,11 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkRequest import android.net.Uri import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig +import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig +import com.android.testutils.TestHttpServer.Request import android.net.cts.util.CtsNetUtils import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL @@ -45,9 +47,7 @@ import android.text.TextUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 import com.android.testutils.TestHttpServer -import com.android.testutils.TestHttpServer.Request import com.android.testutils.isDevSdkInRange -import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status import junit.framework.AssertionFailedError import org.junit.After diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt index 5290f0db28..ec656de653 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt @@ -31,6 +31,7 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.Uri +import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.dhcp.DhcpDiscoverPacket import android.net.dhcp.DhcpPacket import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE @@ -44,7 +45,8 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address -import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY +import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY +import com.android.testutils.ArpResponder import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DhcpClientPacketFilter import com.android.testutils.DhcpOptionFilter @@ -52,10 +54,10 @@ import com.android.testutils.RecorderCallback.CallbackEntry import com.android.testutils.TapPacketReader import com.android.testutils.TestHttpServer import com.android.testutils.TestableNetworkCallback -import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status import org.junit.After import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -129,7 +131,7 @@ class NetworkValidationTest { handlerThread.threadHandler, iface.fileDescriptor.fileDescriptor, MAX_PACKET_LENGTH) - reader.startAsyncForTest() + handlerThread.threadHandler.post { reader.start() } httpServer.start() // Pad the listening port to make sure it is always of length 5. This ensures the URL has @@ -231,7 +233,7 @@ private fun TapPacketReader.assertDhcpPacketReceived( timeoutMs: Long, type: Byte ): T { - val packetBytes = poll(timeoutMs, DhcpClientPacketFilter() + val packetBytes = popPacket(timeoutMs, DhcpClientPacketFilter() .and(DhcpOptionFilter(DHCP_MESSAGE_TYPE, type))) ?: fail("${packetType.simpleName} not received within timeout") val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2) diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt index f6fc75b5f4..5ef185432c 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -19,7 +19,9 @@ package android.net.cts import android.Manifest import android.net.util.NetworkStackUtils import android.provider.DeviceConfig -import com.android.testutils.runAsShell +import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import com.android.compatibility.common.util.ThrowingRunnable +import kotlin.test.fail /** * Collection of utility methods for configuring network validation. @@ -65,4 +67,13 @@ internal object NetworkValidationTestUtil { DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) } } + + /** + * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. + */ + fun runAsShell(vararg permissions: String, task: () -> T): T { + var ret: T? = null + runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) + return ret ?: fail("ThrowingRunnable did not return") + } } \ No newline at end of file From ae04a86b0baae9a1328e57cdd958bf8e9e48b3d2 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 9 Oct 2020 02:17:40 +0000 Subject: [PATCH 1323/1415] Use new test utilities from frameworks/libs/net Use runAsShell from the new TestPermissionUtils, and rename popPacket to poll. This rolls forward the previous change as-is. See change I34bad7ec79ef0fd03e5e40b643f0d85d686c53ec for details on why the previous change was reverted. Bug: 168868607 Test: atest CtsNetTestCasesLatestSdk Change-Id: I7b5176e84ffe08cc5ea1251f66cdcb9b7066ec0a --- .../net/src/android/net/cts/CaptivePortalTest.kt | 4 ++-- .../src/android/net/cts/NetworkValidationTest.kt | 10 ++++------ .../android/net/cts/NetworkValidationTestUtil.kt | 13 +------------ 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 12a966fd31..f2c5028f96 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -30,11 +30,9 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkRequest import android.net.Uri import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig -import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig -import com.android.testutils.TestHttpServer.Request import android.net.cts.util.CtsNetUtils import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL @@ -47,7 +45,9 @@ import android.text.TextUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 import com.android.testutils.TestHttpServer +import com.android.testutils.TestHttpServer.Request import com.android.testutils.isDevSdkInRange +import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status import junit.framework.AssertionFailedError import org.junit.After diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt index ec656de653..5290f0db28 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt @@ -31,7 +31,6 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.Uri -import android.net.cts.NetworkValidationTestUtil.runAsShell import android.net.dhcp.DhcpDiscoverPacket import android.net.dhcp.DhcpPacket import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE @@ -45,8 +44,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address -import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY -import com.android.testutils.ArpResponder +import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DhcpClientPacketFilter import com.android.testutils.DhcpOptionFilter @@ -54,10 +52,10 @@ import com.android.testutils.RecorderCallback.CallbackEntry import com.android.testutils.TapPacketReader import com.android.testutils.TestHttpServer import com.android.testutils.TestableNetworkCallback +import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status import org.junit.After import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -131,7 +129,7 @@ class NetworkValidationTest { handlerThread.threadHandler, iface.fileDescriptor.fileDescriptor, MAX_PACKET_LENGTH) - handlerThread.threadHandler.post { reader.start() } + reader.startAsyncForTest() httpServer.start() // Pad the listening port to make sure it is always of length 5. This ensures the URL has @@ -233,7 +231,7 @@ private fun TapPacketReader.assertDhcpPacketReceived( timeoutMs: Long, type: Byte ): T { - val packetBytes = popPacket(timeoutMs, DhcpClientPacketFilter() + val packetBytes = poll(timeoutMs, DhcpClientPacketFilter() .and(DhcpOptionFilter(DHCP_MESSAGE_TYPE, type))) ?: fail("${packetType.simpleName} not received within timeout") val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2) diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt index 5ef185432c..f6fc75b5f4 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -19,9 +19,7 @@ package android.net.cts import android.Manifest import android.net.util.NetworkStackUtils import android.provider.DeviceConfig -import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity -import com.android.compatibility.common.util.ThrowingRunnable -import kotlin.test.fail +import com.android.testutils.runAsShell /** * Collection of utility methods for configuring network validation. @@ -67,13 +65,4 @@ internal object NetworkValidationTestUtil { DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) } } - - /** - * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax. - */ - fun runAsShell(vararg permissions: String, task: () -> T): T { - var ret: T? = null - runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions) - return ret ?: fail("ThrowingRunnable did not return") - } } \ No newline at end of file From 48ea3b68166c5a0d603262fa07e663d5ec02b0e5 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 12 Oct 2020 17:36:19 +0900 Subject: [PATCH 1324/1415] Do not expect broadcasts in CaptivePortalTest The legacy broadcast may not be sent if wifi does not become the default network within timeout. CaptivePortalTest does not need wifi to be the default network at the start of the test, as it will be disconnected/reconnected immediately after anyway. Bug: 169106352 Test: atest CtsNetTestCasesLatestSdk:CaptivePortalTest Change-Id: Ie4ee6b3c3ed7c0d414fd3cc162d4183248120895 --- tests/cts/net/src/android/net/cts/CaptivePortalTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 12a966fd31..f24053c0fe 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -123,7 +123,7 @@ class CaptivePortalTest { fun testCaptivePortalIsNotDefaultNetwork() { assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY)) assumeTrue(pm.hasSystemFeature(FEATURE_WIFI)) - utils.connectToWifi() + utils.ensureWifiConnected() utils.connectToCell() // Have network validation use a local server that serves a HTTPS error / HTTP redirect From 05c8a1ddd0a0837780e59385b9102d7c58e81964 Mon Sep 17 00:00:00 2001 From: xiamengsen Date: Mon, 12 Oct 2020 10:20:36 +0800 Subject: [PATCH 1325/1415] Verify network state of apps hosting fg-service and in idle state. Test: atest hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Signed-off-by: xiamengsen Change-Id: I0e6e40b714483e51cfee45c155d8ac8b2b356494 --- .../cts/net/hostside/AbstractAppIdleTestCase.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index bb492a1081..f9e30b6b20 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -78,6 +78,17 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork stopForegroundService(); assertAppIdle(true); assertBackgroundNetworkAccess(false); + + // Set Idle after foreground service start. + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); + setAppIdle(true); + addPowerSaveModeWhitelist(TEST_PKG); + removePowerSaveModeWhitelist(TEST_PKG); + assertForegroundServiceNetworkAccess(); + stopForegroundService(); + assertAppIdle(true); + assertBackgroundNetworkAccess(false); + } @Test From 71b9e93a830893a8758a5c66cc1c77ff4df65ad0 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 29 Sep 2020 14:21:58 +0900 Subject: [PATCH 1326/1415] Use IpUtils, NetworkStackConstants in DadProxyTest The test had TODOs to address to use IpUtils and NetworkStackConstants classes once they were moved to frameworks/libs/net. This is now done, so using the new classes. Bug: 158042941 Test: atest TetheringPrivilegedTests Change-Id: I536b4506dbc3b42547ba9cb4e7c3c7a3e9459dd1 --- .../src/android/net/ip/DadProxyTest.java | 104 ++++-------------- 1 file changed, 21 insertions(+), 83 deletions(-) diff --git a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java index 95e36fa18f..42a91aa9ac 100644 --- a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java +++ b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java @@ -17,9 +17,9 @@ package android.net.ip; import static android.system.OsConstants.IPPROTO_ICMPV6; -import static android.system.OsConstants.IPPROTO_TCP; -import static com.android.internal.util.BitUtils.uint16; +import static com.android.net.module.util.IpUtils.icmpv6Checksum; +import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -30,34 +30,29 @@ import android.content.Context; import android.net.INetd; import android.net.InetAddresses; import android.net.MacAddress; -import android.net.TestNetworkInterface; -import android.net.TestNetworkManager; import android.net.util.InterfaceParams; import android.net.util.TetheringUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; -import android.system.ErrnoException; -import android.system.Os; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.IpUtils; import com.android.testutils.TapPacketReader; +import com.android.testutils.TapPacketReaderRule; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; -import java.io.FileDescriptor; import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicReference; @RunWith(AndroidJUnit4.class) @SmallTest @@ -65,16 +60,18 @@ public class DadProxyTest { private static final int DATA_BUFFER_LEN = 4096; private static final int PACKET_TIMEOUT_MS = 5_000; - // TODO: make NetworkStackConstants accessible to this test and use the constant from there. - private static final int ETHER_SRC_ADDR_OFFSET = 6; + // Start the readers manually on a common handler shared with DadProxy, for simplicity + @Rule + public final TapPacketReaderRule mUpstreamReader = new TapPacketReaderRule( + DATA_BUFFER_LEN, false /* autoStart */); + @Rule + public final TapPacketReaderRule mTetheredReader = new TapPacketReaderRule( + DATA_BUFFER_LEN, false /* autoStart */); - private DadProxy mProxy; - TestNetworkInterface mUpstreamTestIface, mTetheredTestIface; private InterfaceParams mUpstreamParams, mTetheredParams; private HandlerThread mHandlerThread; private Handler mHandler; private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader; - private FileDescriptor mUpstreamTapFd, mTetheredTapFd; private static INetd sNetd; @@ -106,12 +103,12 @@ public class DadProxyTest { @After public void tearDown() throws Exception { + mUpstreamReader.stop(); + mTetheredReader.stop(); + if (mHandlerThread != null) { - mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket - mHandler.post(mTetheredPacketReader::stop); // Also closes the socket - mUpstreamTapFd = null; - mTetheredTapFd = null; mHandlerThread.quitSafely(); + mHandlerThread.join(PACKET_TIMEOUT_MS); } if (mTetheredParams != null) { @@ -120,54 +117,20 @@ public class DadProxyTest { if (mUpstreamParams != null) { sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name); } - - if (mUpstreamTestIface != null) { - try { - Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor()); - } catch (ErrnoException e) { } - } - - if (mTetheredTestIface != null) { - try { - Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor()); - } catch (ErrnoException e) { } - } - } - - private TestNetworkInterface setupTapInterface() { - final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); - AtomicReference iface = new AtomicReference<>(); - - inst.getUiAutomation().adoptShellPermissionIdentity(); - try { - final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService( - Context.TEST_NETWORK_SERVICE); - iface.set(tnm.createTapInterface()); - } finally { - inst.getUiAutomation().dropShellPermissionIdentity(); - } - - return iface.get(); } private void setupTapInterfaces() { // Create upstream test iface. - mUpstreamTestIface = setupTapInterface(); - mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName()); + mUpstreamReader.start(mHandler); + mUpstreamParams = InterfaceParams.getByName(mUpstreamReader.iface.getInterfaceName()); assertNotNull(mUpstreamParams); - mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor(); - mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd, - DATA_BUFFER_LEN); - mHandler.post(mUpstreamPacketReader::start); + mUpstreamPacketReader = mUpstreamReader.getReader(); // Create tethered test iface. - mTetheredTestIface = setupTapInterface(); - mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName()); + mTetheredReader.start(mHandler); + mTetheredParams = InterfaceParams.getByName(mTetheredReader.getIface().getInterfaceName()); assertNotNull(mTetheredParams); - mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor(); - mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd, - DATA_BUFFER_LEN); - mHandler.post(mTetheredPacketReader::start); + mTetheredPacketReader = mTetheredReader.getReader(); } private static final int IPV6_HEADER_LEN = 40; @@ -177,31 +140,6 @@ public class DadProxyTest { private static final int ICMPV6_CHECKSUM_OFFSET = 2; private static final int ETHER_TYPE_IPV6 = 0x86dd; - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static int checksumFold(int sum) { - while (sum > 0xffff) { - sum = (sum >> 16) + (sum & 0xffff); - } - return sum; - } - - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static short checksumAdjust(short checksum, short oldWord, short newWord) { - checksum = (short) ~checksum; - int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord)); - return (short) ~tempSum; - } - - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset, - int transportLen) { - // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses - // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental - // checksum adjustment for the change in the next header byte. - short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen); - return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6); - } - private static ByteBuffer createDadPacket(int type) { // Refer to buildArpPacket() int icmpLen = ICMPV6_NA_NS_LEN From d9acdccbd3a47b2ace49c186b3ecda9bd8fdee9b Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 24 Sep 2020 09:48:48 +0800 Subject: [PATCH 1327/1415] Allow tethering pick prefix from all of private address range Currently tethering only pick prefix from 192.168.0.0/16. There is no aviable tethering address if the upstream address is 192.168.x.y/16. This change allow tethering to pick prefix from any private address rnages. Now it still pick from 192.168.0.0/16 only to avoid behavior change. Will have follow up commit to change the configuration. Bug: 166057846 Bug: 170265597 Test: atest TetheringTests atest CtsTetheringTest Change-Id: Ib6304eb8b4788e9196d0af48e72f00a6bda73a5f --- .../tethering/PrivateAddressCoordinator.java | 217 +++++++++++---- .../networkstack/tethering/Tethering.java | 2 +- .../tethering/TetheringDependencies.java | 8 + .../PrivateAddressCoordinatorTest.java | 252 ++++++++++++++++-- .../networkstack/tethering/TetheringTest.java | 74 +++-- 5 files changed, 455 insertions(+), 98 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index 6276c4e2aa..0cf14e3f86 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -20,6 +20,10 @@ import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.util.PrefixUtils.asIpPrefix; +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; + import static java.util.Arrays.asList; import android.content.Context; @@ -37,9 +41,10 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import java.net.Inet4Address; import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Random; @@ -58,10 +63,6 @@ import java.util.Set; public class PrivateAddressCoordinator { public static final int PREFIX_LENGTH = 24; - private static final int MAX_UBYTE = 256; - private static final int BYTE_MASK = 0xff; - private static final byte DEFAULT_ID = (byte) 42; - // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream // address may be requested before coordinator get current upstream notification. To ensure // coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared @@ -69,22 +70,22 @@ public class PrivateAddressCoordinator { // mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprecatedUpstreams(). private final ArrayMap> mUpstreamPrefixMap; private final ArraySet mDownstreams; - // IANA has reserved the following three blocks of the IP address space for private intranets: - // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 - // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers. - private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16"; private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24"; private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24"; - private final IpPrefix mTetheringPrefix; + private final List mTetheringPrefixes; private final ConnectivityManager mConnectivityMgr; private final TetheringConfiguration mConfig; // keyed by downstream type(TetheringManager.TETHERING_*). private final SparseArray mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { + this(context, config, new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16")))); + } + + public PrivateAddressCoordinator(Context context, TetheringConfiguration config, + List prefixPools) { mDownstreams = new ArraySet<>(); mUpstreamPrefixMap = new ArrayMap<>(); - mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX); mConnectivityMgr = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); mConfig = config; @@ -92,6 +93,8 @@ public class PrivateAddressCoordinator { // Reserved static addresses for bluetooth and wifi p2p. mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); + + mTetheringPrefixes = prefixPools; } /** @@ -179,52 +182,148 @@ public class PrivateAddressCoordinator { return cachedAddress; } - // Address would be 192.168.[subAddress]/24. - final byte[] bytes = mTetheringPrefix.getRawAddress(); - final int subAddress = getRandomSubAddr(); - final int subNet = (subAddress >> 8) & BYTE_MASK; - bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); - for (int i = 0; i < MAX_UBYTE; i++) { - final int newSubNet = (subNet + i) & BYTE_MASK; - bytes[2] = (byte) newSubNet; - - final InetAddress addr; - try { - addr = InetAddress.getByAddress(bytes); - } catch (UnknownHostException e) { - throw new IllegalStateException("Invalid address, shouldn't happen.", e); + for (IpPrefix prefixRange : mTetheringPrefixes) { + final LinkAddress newAddress = chooseDownstreamAddress(prefixRange); + if (newAddress != null) { + mDownstreams.add(ipServer); + mCachedAddresses.put(ipServer.interfaceType(), newAddress); + return newAddress; } - - if (isConflict(new IpPrefix(addr, PREFIX_LENGTH))) continue; - - mDownstreams.add(ipServer); - final LinkAddress newAddress = new LinkAddress(addr, PREFIX_LENGTH); - mCachedAddresses.put(ipServer.interfaceType(), newAddress); - return newAddress; } // No available address. return null; } - private boolean isConflict(final IpPrefix prefix) { - // Check whether this prefix is in use or conflict with any current upstream network. - return isDownstreamPrefixInUse(prefix) || isConflictWithUpstream(prefix); + private int getPrefixBaseAddress(final IpPrefix prefix) { + return inet4AddressToIntHTH((Inet4Address) prefix.getAddress()); } - /** Get random sub address value. Return value is in 0 ~ 0xffff. */ - @VisibleForTesting - public int getRandomSubAddr() { - return ((new Random()).nextInt()) & 0xffff; // subNet is in 0 ~ 0xffff. + /** + * Check whether input prefix conflict with upstream prefixes or in-use downstream prefixes. + * If yes, return one of them. + */ + private IpPrefix getConflictPrefix(final IpPrefix prefix) { + final IpPrefix upstream = getConflictWithUpstream(prefix); + if (upstream != null) return upstream; + + return getInUseDownstreamPrefix(prefix); } - private byte getSanitizedAddressSuffix(final int source, byte... excluded) { - final byte subId = (byte) (source & BYTE_MASK); - for (byte value : excluded) { - if (subId == value) return DEFAULT_ID; + // Get the next non-conflict sub prefix. E.g: To get next sub prefix from 10.0.0.0/8, if the + // previously selected prefix is 10.20.42.0/24(subPrefix: 0.20.42.0) and the conflicting prefix + // is 10.16.0.0/20 (10.16.0.0 ~ 10.16.15.255), then the max address under subPrefix is + // 0.16.15.255 and the next subPrefix is 0.16.16.255/24 (0.16.15.255 + 0.0.1.0). + // Note: the sub address 0.0.0.255 here is fine to be any value that it will be replaced as + // selected random sub address later. + private int getNextSubPrefix(final IpPrefix conflictPrefix, final int prefixRangeMask) { + final int suffixMask = ~prefixLengthToV4NetmaskIntHTH(conflictPrefix.getPrefixLength()); + // The largest offset within the prefix assignment block that still conflicts with + // conflictPrefix. + final int maxConflict = + (getPrefixBaseAddress(conflictPrefix) | suffixMask) & ~prefixRangeMask; + + final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH); + // Pick a sub prefix a full prefix (1 << (32 - PREFIX_LENGTH) addresses) greater than + // maxConflict. This ensures that the selected prefix never overlaps with conflictPrefix. + // There is no need to mask the result with PREFIX_LENGTH bits because this is done by + // findAvailablePrefixFromRange when it constructs the prefix. + return maxConflict + (1 << (32 - PREFIX_LENGTH)); + } + + private LinkAddress chooseDownstreamAddress(final IpPrefix prefixRange) { + // The netmask of the prefix assignment block (e.g., 0xfff00000 for 172.16.0.0/12). + final int prefixRangeMask = prefixLengthToV4NetmaskIntHTH(prefixRange.getPrefixLength()); + + // The zero address in the block (e.g., 0xac100000 for 172.16.0.0/12). + final int baseAddress = getPrefixBaseAddress(prefixRange); + + // The subnet mask corresponding to PREFIX_LENGTH. + final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH); + + // The offset within prefixRange of a randomly-selected prefix of length PREFIX_LENGTH. + // This may not be the prefix of the address returned by this method: + // - If it is already in use, the method will return an address in another prefix. + // - If all prefixes within prefixRange are in use, the method will return null. For + // example, for a /24 prefix within 172.26.0.0/12, this will be a multiple of 256 in + // [0, 1048576). In other words, a random 32-bit number with mask 0x000fff00. + // + // prefixRangeMask is required to ensure no wrapping. For example, consider: + // - prefixRange 127.0.0.0/8 + // - randomPrefixStart 127.255.255.0 + // - A conflicting prefix of 127.255.254.0/23 + // In this case without prefixRangeMask, getNextSubPrefix would return 128.0.0.0, which + // means the "start < end" check in findAvailablePrefixFromRange would not reject the prefix + // because Java doesn't have unsigned integers, so 128.0.0.0 = 0x80000000 = -2147483648 + // is less than 127.0.0.0 = 0x7f000000 = 2130706432. + // + // Additionally, it makes debug output easier to read by making the numbers smaller. + final int randomPrefixStart = getRandomInt() & ~prefixRangeMask & prefixMask; + + // A random offset within the prefix. Used to determine the local address once the prefix + // is selected. It does not result in an IPv4 address ending in .0, .1, or .255 + // For a PREFIX_LENGTH of 255, this is a number between 2 and 254. + final int subAddress = getSanitizedSubAddr(~prefixMask); + + // Find a prefix length PREFIX_LENGTH between randomPrefixStart and the end of the block, + // such that the prefix does not conflict with any upstream. + IpPrefix downstreamPrefix = findAvailablePrefixFromRange( + randomPrefixStart, (~prefixRangeMask) + 1, baseAddress, prefixRangeMask); + if (downstreamPrefix != null) return getLinkAddress(downstreamPrefix, subAddress); + + // If that failed, do the same, but between 0 and randomPrefixStart. + downstreamPrefix = findAvailablePrefixFromRange( + 0, randomPrefixStart, baseAddress, prefixRangeMask); + + return getLinkAddress(downstreamPrefix, subAddress); + } + + private LinkAddress getLinkAddress(final IpPrefix prefix, final int subAddress) { + if (prefix == null) return null; + + final InetAddress address = intToInet4AddressHTH(getPrefixBaseAddress(prefix) | subAddress); + return new LinkAddress(address, PREFIX_LENGTH); + } + + private IpPrefix findAvailablePrefixFromRange(final int start, final int end, + final int baseAddress, final int prefixRangeMask) { + int newSubPrefix = start; + while (newSubPrefix < end) { + final InetAddress address = intToInet4AddressHTH(baseAddress | newSubPrefix); + final IpPrefix prefix = new IpPrefix(address, PREFIX_LENGTH); + + final IpPrefix conflictPrefix = getConflictPrefix(prefix); + + if (conflictPrefix == null) return prefix; + + newSubPrefix = getNextSubPrefix(conflictPrefix, prefixRangeMask); } - return subId; + return null; + } + + /** Get random int which could be used to generate random address. */ + @VisibleForTesting + public int getRandomInt() { + return (new Random()).nextInt(); + } + + /** Get random subAddress and avoid selecting x.x.x.0, x.x.x.1 and x.x.x.255 address. */ + private int getSanitizedSubAddr(final int subAddrMask) { + final int randomSubAddr = getRandomInt() & subAddrMask; + // If prefix length > 30, the selecting speace would be less than 4 which may be hard to + // avoid 3 consecutive address. + if (PREFIX_LENGTH > 30) return randomSubAddr; + + // TODO: maybe it is not necessary to avoid .0, .1 and .255 address because tethering + // address would not be conflicted. This code only works because PREFIX_LENGTH is not longer + // than 24 + final int candidate = randomSubAddr & 0xff; + if (candidate == 0 || candidate == 1 || candidate == 255) { + return (randomSubAddr & 0xfffffffc) + 2; + } + + return randomSubAddr; } /** Release downstream record for IpServer. */ @@ -237,14 +336,18 @@ public class PrivateAddressCoordinator { mUpstreamPrefixMap.clear(); } - private boolean isConflictWithUpstream(final IpPrefix source) { + private IpPrefix getConflictWithUpstream(final IpPrefix prefix) { for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { final List list = mUpstreamPrefixMap.valueAt(i); - for (IpPrefix target : list) { - if (isConflictPrefix(source, target)) return true; + for (IpPrefix upstream : list) { + if (isConflictPrefix(prefix, upstream)) return upstream; } } - return false; + return null; + } + + private boolean isConflictWithUpstream(final IpPrefix prefix) { + return getConflictWithUpstream(prefix) != null; } private boolean isConflictPrefix(final IpPrefix prefix1, final IpPrefix prefix2) { @@ -257,11 +360,10 @@ public class PrivateAddressCoordinator { // InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last // downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p). - private boolean isDownstreamPrefixInUse(final IpPrefix prefix) { - // This class always generates downstream prefixes with the same prefix length, so - // prefixes cannot be contained in each other. They can only be equal to each other. + private IpPrefix getInUseDownstreamPrefix(final IpPrefix prefix) { for (int i = 0; i < mCachedAddresses.size(); i++) { - if (prefix.equals(asIpPrefix(mCachedAddresses.valueAt(i)))) return true; + final IpPrefix downstream = asIpPrefix(mCachedAddresses.valueAt(i)); + if (isConflictPrefix(prefix, downstream)) return downstream; } // IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include @@ -270,10 +372,10 @@ public class PrivateAddressCoordinator { final IpPrefix target = getDownstreamPrefix(downstream); if (target == null) continue; - if (isConflictPrefix(prefix, target)) return true; + if (isConflictPrefix(prefix, target)) return target; } - return false; + return null; } private IpPrefix getDownstreamPrefix(final IpServer downstream) { @@ -284,6 +386,13 @@ public class PrivateAddressCoordinator { } void dump(final IndentingPrintWriter pw) { + pw.println("mTetheringPrefixes:"); + pw.increaseIndent(); + for (IpPrefix prefix : mTetheringPrefixes) { + pw.println(prefix); + } + pw.decreaseIndent(); + pw.println("mUpstreamPrefixMap:"); pw.increaseIndent(); for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 474f4e8b60..5a0c5b0cff 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -326,7 +326,7 @@ public class Tethering { // It is OK for the configuration to be passed to the PrivateAddressCoordinator at // construction time because the only part of the configuration it uses is // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that. - mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig); + mPrivateAddressCoordinator = mDeps.getPrivateAddressCoordinator(mContext, mConfig); // Must be initialized after tethering configuration is loaded because BpfCoordinator // constructor needs to use the configuration. diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 131a5fbf2a..45b914178e 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -156,4 +156,12 @@ public abstract class TetheringDependencies { public boolean isTetheringDenied() { return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true"); } + + /** + * Get a reference to PrivateAddressCoordinator to be used by Tethering. + */ + public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx, + TetheringConfiguration cfg) { + return new PrivateAddressCoordinator(ctx, cfg); + } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 191eb6e711..86e6f11659 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -51,6 +51,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.Arrays; + @RunWith(AndroidJUnit4.class) @SmallTest public final class PrivateAddressCoordinatorTest { @@ -70,7 +73,17 @@ public final class PrivateAddressCoordinatorTest { private final Network mWifiNetwork = new Network(1); private final Network mMobileNetwork = new Network(2); private final Network mVpnNetwork = new Network(3); - private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork}; + private final Network mMobileNetwork2 = new Network(4); + private final Network mMobileNetwork3 = new Network(5); + private final Network mMobileNetwork4 = new Network(6); + private final Network mMobileNetwork5 = new Network(7); + private final Network mMobileNetwork6 = new Network(8); + private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork, + mMobileNetwork2, mMobileNetwork3, mMobileNetwork4, mMobileNetwork5, mMobileNetwork6}; + private final ArrayList mTetheringPrefixes = new ArrayList<>(Arrays.asList( + new IpPrefix("192.168.0.0/16"), + new IpPrefix("172.16.0.0/12"), + new IpPrefix("10.0.0.0/8"))); private void setUpIpServers() throws Exception { when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB); @@ -87,7 +100,8 @@ public final class PrivateAddressCoordinatorTest { when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks); when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false); setUpIpServers(); - mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig)); + mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig, + mTetheringPrefixes)); } @Test @@ -117,28 +131,28 @@ public final class PrivateAddressCoordinatorTest { @Test public void testSanitizedAddress() throws Exception { int fakeSubAddr = 0x2b00; // 43.0. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); - assertEquals(new LinkAddress("192.168.43.42/24"), actualAddress); + assertEquals(new LinkAddress("192.168.43.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2d01; // 45.1. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); - assertEquals(new LinkAddress("192.168.45.42/24"), actualAddress); + assertEquals(new LinkAddress("192.168.45.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2eff; // 46.255. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); - assertEquals(new LinkAddress("192.168.46.42/24"), actualAddress); + assertEquals(new LinkAddress("192.168.46.254/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2f05; // 47.5. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress); @@ -148,7 +162,7 @@ public final class PrivateAddressCoordinatorTest { @Test public void testReservedPrefix() throws Exception { // - Test bluetooth prefix is reserved. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mBluetoothAddress.getAddress().getAddress())); final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); @@ -157,7 +171,7 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); // - Test previous enabled hotspot prefix(cached prefix) is reserved. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(hotspotAddress.getAddress().getAddress())); final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mUsbIpServer, false /* useLastAddress */); @@ -167,7 +181,7 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); // - Test wifi p2p prefix is reserved. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); final LinkAddress etherAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mEthernetIpServer, false /* useLastAddress */); @@ -182,7 +196,7 @@ public final class PrivateAddressCoordinatorTest { public void testRequestLastDownstreamAddress() throws Exception { final int fakeHotspotSubAddr = 0x2b05; final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, true /* useLastAddress */); assertEquals("Wrong wifi prefix: ", predefinedPrefix, asIpPrefix(hotspotAddress)); @@ -196,7 +210,7 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); final int newFakeSubAddr = 0x3c05; - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress newHotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, true /* useLastAddress */); @@ -229,11 +243,10 @@ public final class PrivateAddressCoordinatorTest { @Test public void testNoConflictUpstreamPrefix() throws Exception { - final int fakeHotspotSubId = 43; - final int fakeHotspotSubAddr = 0x2b05; + final int fakeHotspotSubAddr = 0x2b05; // 43.5 final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); // Force always get subAddress "43.5" for conflict testing. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); // - Enable hotspot with prefix 192.168.43.0/24 final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, true /* useLastAddress */); @@ -312,6 +325,209 @@ public final class PrivateAddressCoordinatorTest { assertEquals(predefinedPrefix, ethPrefix); } + @Test + public void testChooseAvailablePrefix() throws Exception { + final int randomAddress = 0x8605; // 134.5 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); + final LinkAddress addr0 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.134.5. + assertEquals("Wrong prefix: ", new LinkAddress("192.168.134.5/24"), addr0); + when(mHotspotIpServer.getAddress()).thenReturn(addr0); + final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.134.13/26"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); + + // Check whether return address is next prefix of 192.168.134.0/24. + final LinkAddress addr1 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.135.5/24"), addr1); + when(mHotspotIpServer.getAddress()).thenReturn(addr1); + final UpstreamNetworkState wifiUpstream2 = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.149.16/19"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream2); + + + // The conflict range is 128 ~ 159, so the address is 192.168.160.5/24. + final LinkAddress addr2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.160.5/24"), addr2); + when(mHotspotIpServer.getAddress()).thenReturn(addr2); + final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("192.168.129.53/18"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + // Update another conflict upstream which is covered by the previous one (but not the first + // one) and verify whether this would affect the result. + final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, + new LinkAddress("192.168.170.7/19"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2); + + // The conflict range are 128 ~ 159 and 159 ~ 191, so the address is 192.168.192.5/24. + final LinkAddress addr3 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.192.5/24"), addr3); + when(mHotspotIpServer.getAddress()).thenReturn(addr3); + final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, + new LinkAddress("192.168.188.133/17"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream3); + + // Conflict range: 128 ~ 255. The next available address is 192.168.0.5 because + // 192.168.134/24 ~ 192.168.255.255/24 is not available. + final LinkAddress addr4 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.0.5/24"), addr4); + when(mHotspotIpServer.getAddress()).thenReturn(addr4); + final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, + new LinkAddress("192.168.3.59/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4); + + // Conflict ranges: 128 ~ 255 and 0 ~ 7, so the address is 192.168.8.5/24. + final LinkAddress addr5 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr5); + when(mHotspotIpServer.getAddress()).thenReturn(addr5); + final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, + new LinkAddress("192.168.68.43/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream5); + + // Update an upstream that does *not* conflict, check whether return the same address + // 192.168.5/24. + final LinkAddress addr6 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr6); + when(mHotspotIpServer.getAddress()).thenReturn(addr6); + final UpstreamNetworkState mobileUpstream6 = buildUpstreamNetworkState(mMobileNetwork6, + new LinkAddress("192.168.10.97/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream6); + + // Conflict ranges: 0 ~ 15 and 128 ~ 255, so the address is 192.168.16.5/24. + final LinkAddress addr7 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.16.5/24"), addr7); + when(mHotspotIpServer.getAddress()).thenReturn(addr7); + final UpstreamNetworkState mobileUpstream7 = buildUpstreamNetworkState(mMobileNetwork6, + new LinkAddress("192.168.0.0/17"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream7); + + // Choose prefix from next range(172.16.0.0/12) when no available prefix in 192.168.0.0/16. + final LinkAddress addr8 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.134.5/24"), addr8); + when(mHotspotIpServer.getAddress()).thenReturn(addr6); + } + + @Test + public void testChoosePrefixFromDifferentRanges() throws Exception { + final int randomAddress = 0x1f2b2a; // 31.43.42 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); + final LinkAddress classC1 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.43.42. + assertEquals("Wrong prefix: ", new LinkAddress("192.168.43.42/24"), classC1); + when(mHotspotIpServer.getAddress()).thenReturn(classC1); + final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.88.23/17"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // Check whether return address is next address of prefix 192.168.128.0/17. + final LinkAddress classC2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.128.42/24"), classC2); + when(mHotspotIpServer.getAddress()).thenReturn(classC2); + final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("192.1.2.3/8"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // Check whether return address is under prefix 172.16.0.0/12. + final LinkAddress classB1 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.31.43.42/24"), classB1); + when(mHotspotIpServer.getAddress()).thenReturn(classB1); + final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, + new LinkAddress("172.28.123.100/14"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // 172.28.0.0 ~ 172.31.255.255 is not available. + // Check whether return address is next address of prefix 172.16.0.0/14. + final LinkAddress classB2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.0.42/24"), classB2); + when(mHotspotIpServer.getAddress()).thenReturn(classB2); + + // Check whether new downstream is next address of address 172.16.0.42/24. + final LinkAddress classB3 = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.1.42/24"), classB3); + when(mUsbIpServer.getAddress()).thenReturn(classB3); + final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, + new LinkAddress("172.16.0.1/24"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream3); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verify(mUsbIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + + // Check whether return address is next address of prefix 172.16.1.42/24. + final LinkAddress classB4 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.2.42/24"), classB4); + when(mHotspotIpServer.getAddress()).thenReturn(classB4); + final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, + new LinkAddress("172.16.0.1/13"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verifyNotifyConflictAndRelease(mUsbIpServer); + + // Check whether return address is next address of prefix 172.16.0.1/13. + final LinkAddress classB5 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.24.0.42/24"), classB5); + when(mHotspotIpServer.getAddress()).thenReturn(classB5); + // Check whether return address is next address of prefix 172.24.0.42/24. + final LinkAddress classB6 = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.24.1.42/24"), classB6); + when(mUsbIpServer.getAddress()).thenReturn(classB6); + final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, + new LinkAddress("172.24.0.1/12"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream5); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verifyNotifyConflictAndRelease(mUsbIpServer); + + // Check whether return address is prefix 10.0.0.0/8 + subAddress 0.31.43.42. + final LinkAddress classA1 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("10.31.43.42/24"), classA1); + when(mHotspotIpServer.getAddress()).thenReturn(classA1); + // Check whether new downstream is next address of address 10.31.43.42/24. + final LinkAddress classA2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("10.31.44.42/24"), classA2); + } + + private void verifyNotifyConflictAndRelease(final IpServer ipServer) throws Exception { + verify(ipServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + mPrivateAddressCoordinator.releaseDownstream(ipServer); + reset(ipServer); + setUpIpServers(); + } + private int getSubAddress(final byte... ipv4Address) { assertEquals(4, ipv4Address.length); @@ -330,7 +546,7 @@ public final class PrivateAddressCoordinatorTest { @Test public void testEnableLegacyWifiP2PAddress() throws Exception { - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); // No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix // is resevered. diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index df570206e3..20e94b256a 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -24,6 +24,9 @@ import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; @@ -179,6 +182,7 @@ public class TetheringTest { private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0"; private static final String TEST_NCM_IFNAME = "test_ncm0"; private static final String TEST_ETH_IFNAME = "test_eth0"; + private static final String TEST_BT_IFNAME = "test_pan0"; private static final String TETHERING_NAME = "Tethering"; private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; @@ -230,6 +234,7 @@ public class TetheringTest { private TetheringConfiguration mConfig; private EntitlementManager mEntitleMgr; private OffloadController mOffloadCtrl; + private PrivateAddressCoordinator mPrivateAddressCoordinator; private class TestContext extends BroadcastInterceptingContext { TestContext(Context base) { @@ -446,6 +451,18 @@ public class TetheringTest { public boolean isTetheringDenied() { return false; } + + + @Override + public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx, + TetheringConfiguration cfg) { + final ArrayList prefixPool = new ArrayList<>(Arrays.asList( + new IpPrefix("192.168.0.0/16"), + new IpPrefix("172.16.0.0/12"), + new IpPrefix("10.0.0.0/8"))); + mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(ctx, cfg, prefixPool)); + return mPrivateAddressCoordinator; + } } private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4, @@ -1875,27 +1892,36 @@ public class TetheringTest { sendConfigurationChanged(); } - private static UpstreamNetworkState buildV4WifiUpstreamState(final String ipv4Address, - final int prefixLength, final Network network) { + private static UpstreamNetworkState buildV4UpstreamState(final LinkAddress address, + final Network network, final String iface, final int transportType) { final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(TEST_WIFI_IFNAME); + prop.setInterfaceName(iface); - prop.addLinkAddress( - new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address), - prefixLength)); + prop.addLinkAddress(address); final NetworkCapabilities capabilities = new NetworkCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + .addTransportType(transportType); return new UpstreamNetworkState(prop, capabilities, network); } + private void updateV4Upstream(final LinkAddress ipv4Address, final Network network, + final String iface, final int transportType) { + final UpstreamNetworkState upstream = buildV4UpstreamState(ipv4Address, network, iface, + transportType); + mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( + Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, + UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, + 0, + upstream); + mLooper.dispatchAll(); + } + @Test public void testHandleIpConflict() throws Exception { final Network wifiNetwork = new Network(200); final Network[] allNetworks = { wifiNetwork }; when(mCm.getAllNetworks()).thenReturn(allNetworks); - UpstreamNetworkState upstreamNetwork = null; - runUsbTethering(upstreamNetwork); + runUsbTethering(null); final ArgumentCaptor ifaceConfigCaptor = ArgumentCaptor.forClass(InterfaceConfigurationParcel.class); verify(mNetd).interfaceSetCfg(ifaceConfigCaptor.capture()); @@ -1903,13 +1929,10 @@ public class TetheringTest { verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( any(), any()); reset(mNetd, mUsbManager); - upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork); - mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( - Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, - UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, - 0, - upstreamNetwork); - mLooper.dispatchAll(); + + // Cause a prefix conflict by assigning a /30 out of the downstream's /24 to the upstream. + updateV4Upstream(new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address), 30), + wifiNetwork, TEST_WIFI_IFNAME, TRANSPORT_WIFI); // verify turn off usb tethering verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); mTethering.interfaceRemoved(TEST_USB_IFNAME); @@ -1921,9 +1944,10 @@ public class TetheringTest { @Test public void testNoAddressAvailable() throws Exception { final Network wifiNetwork = new Network(200); - final Network[] allNetworks = { wifiNetwork }; + final Network btNetwork = new Network(201); + final Network mobileNetwork = new Network(202); + final Network[] allNetworks = { wifiNetwork, btNetwork, mobileNetwork }; when(mCm.getAllNetworks()).thenReturn(allNetworks); - final String upstreamAddress = "192.168.0.100"; runUsbTethering(null); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( any(), any()); @@ -1940,13 +1964,13 @@ public class TetheringTest { mLooper.dispatchAll(); reset(mUsbManager, mEm); - final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState( - upstreamAddress, 16, wifiNetwork); - mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( - Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, - UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, - 0, - upstreamNetwork); + updateV4Upstream(new LinkAddress("192.168.0.100/16"), wifiNetwork, TEST_WIFI_IFNAME, + TRANSPORT_WIFI); + updateV4Upstream(new LinkAddress("172.16.0.0/12"), btNetwork, TEST_BT_IFNAME, + TRANSPORT_BLUETOOTH); + updateV4Upstream(new LinkAddress("10.0.0.0/8"), mobileNetwork, TEST_MOBILE_IFNAME, + TRANSPORT_CELLULAR); + mLooper.dispatchAll(); // verify turn off usb tethering verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); From 7056d02dd74c68d73a0f6a3a3d5ee8918bbe9cf4 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 13 Oct 2020 23:40:57 +0900 Subject: [PATCH 1328/1415] Update the QUIC packet format. The QUIC packet format has changed again. Update the test to ensure that the GFE can drop support for the old packet format without causing all devices to fail CTS. Packet format changes suggested by dschinazi@. Bug: 170724836 Test: atest --rerun-until-failure 100 CtsNetTestCasesLatestSdk:MultinetworkApiTest#testNativeDatagramTransmission Change-Id: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf Merged-In: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf (cherry picked from commit c2b9b83bf353a1fe0669e327fa03ddb024e4f21d) --- tests/cts/net/jni/NativeMultinetworkJni.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index 4531f822eb..b269a8bfb6 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -177,20 +177,16 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-invariants uint8_t quic_packet[1200] = { - 0x0d, // public flags: - // - version present (0x01), - // - 64bit connection ID (0x0c), - // - 1 byte packet number (0x00) + 0xc0, // long header + 0xaa, 0xda, 0xca, 0xca, // reserved-space version number + 0x08, // destination connection ID length 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number - 1, // 1 byte packet number - 0x00, // private flags - 0x07, // PING frame (cuz why not) + 0x00, // source connection ID length }; - arc4random_buf(quic_packet + 1, 8); // random connection ID + arc4random_buf(quic_packet + 6, 8); // random connection ID uint8_t response[1500]; ssize_t sent, rcvd; @@ -215,7 +211,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < 9) { + if (rcvd < 15) { ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { ALOGD("Does this network block UDP port %s?", kPort); @@ -224,7 +220,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); + int conn_id_cmp = memcmp(quic_packet + 6, response + 7, 8); if (conn_id_cmp != 0) { ALOGD("sent and received connection IDs do not match"); close(fd); From 25da49b7ff8700cc1f631fc26fa0dbdc20e5742f Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 13 Oct 2020 23:40:57 +0900 Subject: [PATCH 1329/1415] Update the QUIC packet format. The QUIC packet format has changed again. Update the test to ensure that the GFE can drop support for the old packet format without causing all devices to fail CTS. Packet format changes suggested by dschinazi@. Bug: 170724836 Test: atest --rerun-until-failure 100 CtsNetTestCasesLatestSdk:MultinetworkApiTest#testNativeDatagramTransmission Change-Id: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf Merged-In: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf (cherry picked from commit c2b9b83bf353a1fe0669e327fa03ddb024e4f21d) --- tests/cts/net/jni/NativeMultinetworkJni.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.c b/tests/cts/net/jni/NativeMultinetworkJni.c index 4531f822eb..b269a8bfb6 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.c +++ b/tests/cts/net/jni/NativeMultinetworkJni.c @@ -177,20 +177,16 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-invariants uint8_t quic_packet[1200] = { - 0x0d, // public flags: - // - version present (0x01), - // - 64bit connection ID (0x0c), - // - 1 byte packet number (0x00) + 0xc0, // long header + 0xaa, 0xda, 0xca, 0xca, // reserved-space version number + 0x08, // destination connection ID length 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number - 1, // 1 byte packet number - 0x00, // private flags - 0x07, // PING frame (cuz why not) + 0x00, // source connection ID length }; - arc4random_buf(quic_packet + 1, 8); // random connection ID + arc4random_buf(quic_packet + 6, 8); // random connection ID uint8_t response[1500]; ssize_t sent, rcvd; @@ -215,7 +211,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < 9) { + if (rcvd < 15) { ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { ALOGD("Does this network block UDP port %s?", kPort); @@ -224,7 +220,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); + int conn_id_cmp = memcmp(quic_packet + 6, response + 7, 8); if (conn_id_cmp != 0) { ALOGD("sent and received connection IDs do not match"); close(fd); From 8b5d18fe90e387853569dc7e01e432f2f445dab9 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Mon, 12 Oct 2020 12:27:34 +0000 Subject: [PATCH 1330/1415] Update the QUIC packet format. The QUIC packet format has changed again. Update the test to ensure that the GFE can drop support for the old packet format without causing all devices to fail CTS. Packet format changes suggested by dschinazi@. Bug: 170724836 Test: atest --rerun-until-failure 100 CtsNetTestCasesLatestSdk:MultinetworkApiTest#testNativeDatagramTransmission Change-Id: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf Merged-In: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf --- tests/cts/net/jni/NativeMultinetworkJni.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index cd94709fd5..60e31bc78a 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -458,20 +458,16 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-invariants uint8_t quic_packet[1200] = { - 0x0d, // public flags: - // - version present (0x01), - // - 64bit connection ID (0x0c), - // - 1 byte packet number (0x00) + 0xc0, // long header + 0xaa, 0xda, 0xca, 0xca, // reserved-space version number + 0x08, // destination connection ID length 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number - 1, // 1 byte packet number - 0x00, // private flags - 0x07, // PING frame (cuz why not) + 0x00, // source connection ID length }; - arc4random_buf(quic_packet + 1, 8); // random connection ID + arc4random_buf(quic_packet + 6, 8); // random connection ID uint8_t response[1500]; ssize_t sent, rcvd; @@ -496,7 +492,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < 9) { + if (rcvd < 15) { LOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { LOGD("Does this network block UDP port %s?", kPort); @@ -505,7 +501,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); + int conn_id_cmp = memcmp(quic_packet + 6, response + 7, 8); if (conn_id_cmp != 0) { LOGD("sent and received connection IDs do not match"); close(fd); From a4eeed0833b39c050a65dd0a3ae18e948d457a7e Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Mon, 12 Oct 2020 12:27:34 +0000 Subject: [PATCH 1331/1415] Update the QUIC packet format. The QUIC packet format has changed again. Update the test to ensure that the GFE can drop support for the old packet format without causing all devices to fail CTS. Packet format changes suggested by dschinazi@. Bug: 170724836 Test: atest --rerun-until-failure 100 CtsNetTestCasesLatestSdk:MultinetworkApiTest#testNativeDatagramTransmission Change-Id: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf Merged-In: I8625ac9a58c55fc19dfb9fdb5f34a89cee40caaf --- tests/cts/net/jni/NativeMultinetworkJni.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index 5bd3013819..ef06d75157 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -455,20 +455,16 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-invariants uint8_t quic_packet[1200] = { - 0x0d, // public flags: - // - version present (0x01), - // - 64bit connection ID (0x0c), - // - 1 byte packet number (0x00) + 0xc0, // long header + 0xaa, 0xda, 0xca, 0xca, // reserved-space version number + 0x08, // destination connection ID length 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number - 1, // 1 byte packet number - 0x00, // private flags - 0x07, // PING frame (cuz why not) + 0x00, // source connection ID length }; - arc4random_buf(quic_packet + 1, 8); // random connection ID + arc4random_buf(quic_packet + 6, 8); // random connection ID uint8_t response[1500]; ssize_t sent, rcvd; @@ -493,7 +489,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < 9) { + if (rcvd < 15) { ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { ALOGD("Does this network block UDP port %s?", kPort); @@ -502,7 +498,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); + int conn_id_cmp = memcmp(quic_packet + 6, response + 7, 8); if (conn_id_cmp != 0) { ALOGD("sent and received connection IDs do not match"); close(fd); From ccf07b1dd6790208993ce638aeb57b9f0ebb595f Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 14 Oct 2020 16:24:15 +0800 Subject: [PATCH 1332/1415] Test conflict notification work when using cached address This test catch the regression introduced in r.android.com/1432958. Bug: 1432958 Test: atest TetheringTest Change-Id: Id0c1afb5563954ffee1f598a3a5de6a245d77a0e --- .../PrivateAddressCoordinatorTest.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 86e6f11659..da13e341fb 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -194,17 +194,16 @@ public final class PrivateAddressCoordinatorTest { @Test public void testRequestLastDownstreamAddress() throws Exception { - final int fakeHotspotSubAddr = 0x2b05; - final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); + final int fakeHotspotSubAddr = 0x2b05; // 43.5 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, true /* useLastAddress */); - assertEquals("Wrong wifi prefix: ", predefinedPrefix, asIpPrefix(hotspotAddress)); + assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress); when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddress); final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mUsbIpServer, true /* useLastAddress */); - assertNotEquals(predefinedPrefix, asIpPrefix(usbAddress)); + assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.45.5/24"), usbAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); @@ -218,6 +217,18 @@ public final class PrivateAddressCoordinatorTest { final LinkAddress newUsbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mUsbIpServer, true /* useLastAddress */); assertEquals(usbAddress, newUsbAddress); + + // BUG: the code should detect a conflict, but it doesn't. + // Regression introduced in r.android.com/168169687. + // Ensure conflict notification works when using cached address. + when(mHotspotIpServer.getAddress()).thenReturn(newHotspotAddress); + when(mUsbIpServer.getAddress()).thenReturn(usbAddress); + final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.88.23/16"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + verify(mUsbIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); } private UpstreamNetworkState buildUpstreamNetworkState(final Network network, From 87b8363cb9e227a564ea60f110203fce843d4cc6 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Wed, 14 Oct 2020 12:32:38 +0100 Subject: [PATCH 1333/1415] Remove Tethering @TestApi Modules shouldn't have TestApis, as documented in go/android-api-types. Additionally, nothing depends on these TestApis existing. Bug: 170395679 Test: m checkapi Change-Id: I6e2c8298e90b4b54f0264be974d036fa08cd5632 Merged-In: I6e2c8298e90b4b54f0264be974d036fa08cd5632 --- .../common/TetheringLib/src/android/net/TetheredClient.java | 2 -- .../common/TetheringLib/src/android/net/TetheringManager.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/Tethering/common/TetheringLib/src/android/net/TetheredClient.java index 645b000013..0b223f42b9 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheredClient.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheredClient.java @@ -19,7 +19,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -34,7 +33,6 @@ import java.util.Objects; * @hide */ @SystemApi -@TestApi public final class TetheredClient implements Parcelable { @NonNull private final MacAddress mMacAddress; diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 88e0b42534..97fb4974d0 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -23,7 +23,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.content.Context; import android.os.Bundle; import android.os.ConditionVariable; @@ -55,7 +54,6 @@ import java.util.function.Supplier; * @hide */ @SystemApi -@TestApi public class TetheringManager { private static final String TAG = TetheringManager.class.getSimpleName(); private static final int DEFAULT_TIMEOUT_MS = 60_000; From b4d5a4b66fcda861e39f83a2a6f095cc5eb60bd4 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 12 Oct 2020 15:45:01 -0700 Subject: [PATCH 1334/1415] Migrate IPsec CTS out of tests/tests/net Bug: 170487836 Test: atest CtsIkeTestCases Change-Id: I08f069c2a11f3daa3f0332c631055a1e0be7ce7b --- tests/cts/net/ipsec/Android.bp | 48 -- tests/cts/net/ipsec/AndroidManifest.xml | 39 -- tests/cts/net/ipsec/AndroidTest.xml | 33 - tests/cts/net/ipsec/OWNERS | 3 - .../ipsec/assets/key/client-a-private-key.key | 28 - .../ipsec/assets/pem/client-a-end-cert.pem | 21 - .../pem/client-a-intermediate-ca-one.pem | 21 - .../pem/client-a-intermediate-ca-two.pem | 21 - .../assets/pem/server-a-self-signed-ca.pem | 20 - .../net/eap/cts/EapSessionConfigTest.java | 98 --- .../ipsec/ike/cts/ChildSessionParamsTest.java | 230 ------- .../ipsec/ike/cts/IkeIdentificationTest.java | 75 --- .../cts/IkeSessionDigitalSignatureTest.java | 211 ------ .../ipsec/ike/cts/IkeSessionMschapV2Test.java | 220 ------- .../ipsec/ike/cts/IkeSessionParamsTest.java | 414 ------------ .../net/ipsec/ike/cts/IkeSessionPskTest.java | 371 ----------- .../ipsec/ike/cts/IkeSessionRekeyTest.java | 265 -------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 598 ------------------ .../net/ipsec/ike/cts/IkeTestBase.java | 144 ----- .../net/ipsec/ike/cts/IkeTunUtils.java | 377 ----------- .../net/ipsec/ike/cts/PacketUtils.java | 467 -------------- .../net/ipsec/ike/cts/SaProposalTest.java | 256 -------- .../net/ipsec/ike/cts/TestNetworkUtils.java | 87 --- .../android/net/ipsec/ike/cts/TunUtils.java | 264 -------- 24 files changed, 4311 deletions(-) delete mode 100644 tests/cts/net/ipsec/Android.bp delete mode 100644 tests/cts/net/ipsec/AndroidManifest.xml delete mode 100644 tests/cts/net/ipsec/AndroidTest.xml delete mode 100644 tests/cts/net/ipsec/OWNERS delete mode 100644 tests/cts/net/ipsec/assets/key/client-a-private-key.key delete mode 100644 tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem delete mode 100644 tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem delete mode 100644 tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem delete mode 100644 tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem delete mode 100644 tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp deleted file mode 100644 index 948cc05d76..0000000000 --- a/tests/cts/net/ipsec/Android.bp +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - -android_test { - name: "CtsIkeTestCases", - defaults: ["cts_defaults"], - - // Include both the 32 and 64 bit versions - compile_multilib: "both", - - libs: [ - "android.net.ipsec.ike.stubs.system", - "android.test.base", - ], - - srcs: [ - "src/**/*.java", - ":ike-test-utils", - ], - - static_libs: [ - "androidx.test.ext.junit", - "compatibility-device-util-axt", - "ctstestrunner-axt", - "net-tests-utils", - ], - - platform_apis: true, - - // Tag this module as a cts test artifact - test_suites: [ - "cts", - "mts", - "vts", - "general-tests", - ], -} diff --git a/tests/cts/net/ipsec/AndroidManifest.xml b/tests/cts/net/ipsec/AndroidManifest.xml deleted file mode 100644 index de7d23cbd5..0000000000 --- a/tests/cts/net/ipsec/AndroidManifest.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/tests/cts/net/ipsec/AndroidTest.xml b/tests/cts/net/ipsec/AndroidTest.xml deleted file mode 100644 index cd5c118dd6..0000000000 --- a/tests/cts/net/ipsec/AndroidTest.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/tests/cts/net/ipsec/OWNERS b/tests/cts/net/ipsec/OWNERS deleted file mode 100644 index 26407ff253..0000000000 --- a/tests/cts/net/ipsec/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -lorenzo@google.com -nharold@google.com -satk@google.com diff --git a/tests/cts/net/ipsec/assets/key/client-a-private-key.key b/tests/cts/net/ipsec/assets/key/client-a-private-key.key deleted file mode 100644 index 22736e98e0..0000000000 --- a/tests/cts/net/ipsec/assets/key/client-a-private-key.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL -8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu -7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K -Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i -pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS -jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK -a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub -G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n -zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo -zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL -gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc -9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf -spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL -ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms -TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy -GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK -QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ -+K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE -i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh -fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU -ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+ -NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN -mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR -wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G -xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf -idNFcaIrC52PtZIH7QCzdDY= ------END PRIVATE KEY----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem b/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem deleted file mode 100644 index e82da85c50..0000000000 --- a/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE -BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu -ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG -A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0 -LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE -CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc -6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw -D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC -25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG -R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL -bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu -bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK -I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio -4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP -ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab -SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7 -T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy -rmkYV2MAWguFeckh ------END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem deleted file mode 100644 index 707e575bc3..0000000000 --- a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDaDCCAlCgAwIBAgIIIbjMyRn2770wDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE -BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h -bmRyb2lkLm5ldDAeFw0xOTA5MzAxODQzMThaFw0yNDA5MjgxODQzMThaMEExCzAJ -BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSAwHgYDVQQDExdvbmUuY2EudGVz -dC5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNN -sRr5Z30rAEw2jrAh/BIekbEy/MvOucAr1w0lxH71p+ybRBx5Bj7G07UGXbL659gm -meMV6nabY4HjQXNMq22POiJBZj+U+rw34br6waljBttxCmmJac1VvgqNsSspXjRy -NbiVQdFjyKSX0NOPcEkwANk15mZbOgJBaYYc8jQCY2G/p8eARVBTLJCy8LEwEU6j -XRv/4eYST79qpBFc7gQQj2FLmh9oppDIvcIVBHwtd1tBoVuehRSud1o8vQRkl/HJ -Mrwp24nO5YYhmVNSFRtBpmWMSu1KknFUwkOebINUNsKXXHebVa7cP4XIQUL8mRT3 -5X9rFJFSQJE01S3NjNMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B -Af8EBAMCAQYwHQYDVR0OBBYEFHK3FIm7g8dxEIwK9zMAO8EWhRYxMB8GA1UdIwQY -MBaAFEmfqEeF14Nj91ekIpR+sVhCEoAaMA0GCSqGSIb3DQEBCwUAA4IBAQAeMlXT -TnxZo8oz0204gKZ63RzlgDpJ7SqA3qFG+pV+TiqGfSuVkXuIdOskjxJnA9VxUzrr -LdMTCn5e0FK6wCYjZ2GT/CD7oD3vSMkzGbLGNcNJhhDHUq8BOLPkPzz/rwQFPBSb -zr6hsiVXphEt/psGoN7Eu9blPeQaIwMfWnaufAwF664S/3dmCRbNMWSam1qzzz8q -jr0cDOIMa//ZIAcM16cvoBK6pFGnUmuoJYYRtfpY5MmfCWz0sCJxENIX/lxyhd7N -FdRALA1ZP3E//Tn2vQoeFjbKaAba527RE26HgHJ9zZDo1nn8J8J/YwYRJdBWM/3S -LYebNiMtcyB5nIkj ------END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem deleted file mode 100644 index 39808f885e..0000000000 --- a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDZzCCAk+gAwIBAgIIKWCREnNCs+wwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE -BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF29uZS5jYS50ZXN0LmFu -ZHJvaWQubmV0MB4XDTE5MDkzMDE4NDQwMloXDTI0MDkyODE4NDQwMlowQTELMAkG -A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0 -LmFuZHJvaWQubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLUa -RqkYl2m7lUmMnkooqO0DNNY1aN9r7mJc3ndYn5gjkpb3yLgOYPDNLcQerV6uWk/u -qKudNHed2dInGonl3oxwwv7++6oUvvtrSWLDZlRg16GsdIE1Y98DSMQWkSxevYy9 -Nh6FGTdlBFQVMpiMa8qHEkrOyKsy85yCW1sgzlpGTIBwbDAqYtwe3rgbwyHwUtfy -0EU++DBcR4ll/pDqB0OQtW5E3AOq2GH1iaGeFLKSUQ5KAbdI8y4/b8IkSDffvxcc -kXig7S54aLrNlL/ZjQ+H4Chgjj2A5wMucd81+Fb60Udej73ICL9PpMPnXQ1+BVYd -MJ/txjLNmrOJG9yEHQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwIBBjAdBgNVHQ4EFgQUcqSu1uRYT/DLbLoDNUz38nGvCKQwHwYDVR0jBBgw -FoAUcrcUibuDx3EQjAr3MwA7wRaFFjEwDQYJKoZIhvcNAQELBQADggEBADY461GT -Rw0dGnD07xaGJcI0i0pV+WnGSrl1s1PAIdMYihJAqYnh10fXbFXLm2WMWVmv/pxs -FI/xDJno+pd4mCa/sIhm63ar/Nv+lFQmcpIlvSlKnhhV4SLNBeqbVhPBGTCHfrG4 -aIyCwm1KJsnkWbf03crhSskR/2CXIjX6lcAy7K3fE2u1ELpAdH0kMJR7VXkLFLUm -gqe9YCluR0weMpe2sCaOGzdVzQSmMMCzGP5cxeFR5U6K40kMOpiW11JNmQ06xI/m -YVkMNwoiV/ITT0/C/g9FxJmkO0mVSLEqxaLS/hNiQNDlroVM0rbxhzviXLI3R3AO -50VvlOQYGxWed/I= ------END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem b/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem deleted file mode 100644 index 972fd55372..0000000000 --- a/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDSDCCAjCgAwIBAgIITJQJ6HC1rjwwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE -BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h -bmRyb2lkLm5ldDAeFw0xOTA5MzAxNzU1NTJaFw0yOTA5MjcxNzU1NTJaMEIxCzAJ -BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSEwHwYDVQQDExhyb290LmNhLnRl -c3QuYW5kcm9pZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCT -q3hGF+JvLaB1xW7KGKmaxiQ7BxX2Sn7cbp7ggoVYXsFlBUuPPv3+Vg5PfPCPhsJ8 -/7w4HyKo3uc/vHs5HpQ7rSd9blhAkfmJci2ULLq73FB8Mix4CzPwMx29RrN1X9bU -z4G0vJMczIBGxbZ0uw7n8bKcXBV7AIeax+J8lseEZ3k8iSuBkUJqGIpPFKTqByFZ -A1Lvt47xkON5SZh6c/Oe+o6291wXaCOJUSAKv6PAWZkq9HeD2fqKA/ck9dBaz1M3 -YvzQ9V/7so3/dECjAfKia388h1I6XSGNUM+d5hpxMXpAFgG42eUXHpJ10OjDvSwd -7ZSC91/kRQewUomEKBK1AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P -AQH/BAQDAgEGMB0GA1UdDgQWBBRJn6hHhdeDY/dXpCKUfrFYQhKAGjANBgkqhkiG -9w0BAQsFAAOCAQEAig/94aGfHBhZuvbbhwAK4rUNpizmR567u0ZJ+QUEKyAlo9lT -ZWYHSm7qTAZYvPEjzTQIptnAlxCHePXh3Cfwgo+r82lhG2rcdI03iRyvHWjM8gyk -BXCJTi0Q08JHHpTP6GnAqpz58qEIFkk8P766zNXdhYrGPOydF+p7MFcb1Zv1gum3 -zmRLt0XUAMfjPUv1Bl8kTKFxH5lkMBLR1E0jnoJoTTfgRPrf9CuFSoh48n7YhoBT -KV75xZY8b8+SuB0v6BvQmkpKZGoxBjuVsShyG7q1+4JTAtwhiP7BlkDvVkaBEi7t -WIMFp2r2ZDisHgastNaeYFyzHYz9g1FCCrHQ4w== ------END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java b/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java deleted file mode 100644 index c24379dae0..0000000000 --- a/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.eap.cts; - -import static android.telephony.TelephonyManager.APPTYPE_USIM; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.net.eap.EapSessionConfig; -import android.net.eap.EapSessionConfig.EapAkaConfig; -import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; -import android.net.eap.EapSessionConfig.EapMsChapV2Config; -import android.net.eap.EapSessionConfig.EapSimConfig; -import android.net.eap.EapSessionConfig.EapUiccConfig; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class EapSessionConfigTest { - // These constants are IANA-defined values and are copies of hidden constants in - // frameworks/opt/net/ike/src/java/com/android/internal/net/eap/message/EapData.java. - private static final int EAP_TYPE_SIM = 18; - private static final int EAP_TYPE_AKA = 23; - private static final int EAP_TYPE_MSCHAP_V2 = 26; - private static final int EAP_TYPE_AKA_PRIME = 50; - - private static final int SUB_ID = 1; - private static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); - private static final String NETWORK_NAME = "android.net"; - private static final String EAP_MSCHAPV2_USERNAME = "username"; - private static final String EAP_MSCHAPV2_PASSWORD = "password"; - - @Test - public void testBuildWithAllEapMethods() { - EapSessionConfig result = - new EapSessionConfig.Builder() - .setEapIdentity(EAP_IDENTITY) - .setEapSimConfig(SUB_ID, APPTYPE_USIM) - .setEapAkaConfig(SUB_ID, APPTYPE_USIM) - .setEapAkaPrimeConfig( - SUB_ID, - APPTYPE_USIM, - NETWORK_NAME, - true /* allowMismatchedNetworkNames */) - .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) - .build(); - - assertArrayEquals(EAP_IDENTITY, result.getEapIdentity()); - - EapSimConfig eapSimConfig = result.getEapSimConfig(); - assertNotNull(eapSimConfig); - assertEquals(EAP_TYPE_SIM, eapSimConfig.getMethodType()); - verifyEapUiccConfigCommon(eapSimConfig); - - EapAkaConfig eapAkaConfig = result.getEapAkaConfig(); - assertNotNull(eapAkaConfig); - assertEquals(EAP_TYPE_AKA, eapAkaConfig.getMethodType()); - verifyEapUiccConfigCommon(eapAkaConfig); - - EapAkaPrimeConfig eapAkaPrimeConfig = result.getEapAkaPrimeConfig(); - assertNotNull(eapAkaPrimeConfig); - assertEquals(EAP_TYPE_AKA_PRIME, eapAkaPrimeConfig.getMethodType()); - assertEquals(NETWORK_NAME, eapAkaPrimeConfig.getNetworkName()); - assertTrue(NETWORK_NAME, eapAkaPrimeConfig.allowsMismatchedNetworkNames()); - verifyEapUiccConfigCommon(eapAkaPrimeConfig); - - EapMsChapV2Config eapMsChapV2Config = result.getEapMsChapV2onfig(); - assertNotNull(eapMsChapV2Config); - assertEquals(EAP_TYPE_MSCHAP_V2, eapMsChapV2Config.getMethodType()); - assertEquals(EAP_MSCHAPV2_USERNAME, eapMsChapV2Config.getUsername()); - assertEquals(EAP_MSCHAPV2_PASSWORD, eapMsChapV2Config.getPassword()); - } - - private void verifyEapUiccConfigCommon(EapUiccConfig config) { - assertEquals(SUB_ID, config.getSubId()); - assertEquals(APPTYPE_USIM, config.getAppType()); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java deleted file mode 100644 index 7fb1b6dc43..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import android.net.LinkAddress; -import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.ChildSessionParams; -import android.net.ipsec.ike.TransportModeChildSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer; -import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -@RunWith(AndroidJUnit4.class) -public class ChildSessionParamsTest extends IkeTestBase { - private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(3L); - private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(1L); - - // Random proposal. Content doesn't matter - private final ChildSaProposal mSaProposal = - SaProposalTest.buildChildSaProposalWithCombinedModeCipher(); - - private void verifyTunnelModeChildParamsWithDefaultValues(ChildSessionParams childParams) { - assertTrue(childParams instanceof TunnelModeChildSessionParams); - verifyChildParamsWithDefaultValues(childParams); - } - - private void verifyTunnelModeChildParamsWithCustomizedValues(ChildSessionParams childParams) { - assertTrue(childParams instanceof TunnelModeChildSessionParams); - verifyChildParamsWithCustomizedValues(childParams); - } - - private void verifyTransportModeChildParamsWithDefaultValues(ChildSessionParams childParams) { - assertTrue(childParams instanceof TransportModeChildSessionParams); - verifyChildParamsWithDefaultValues(childParams); - } - - private void verifyTransportModeChildParamsWithCustomizedValues( - ChildSessionParams childParams) { - assertTrue(childParams instanceof TransportModeChildSessionParams); - verifyChildParamsWithCustomizedValues(childParams); - } - - private void verifyChildParamsWithDefaultValues(ChildSessionParams childParams) { - assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals()); - - // Do not do assertEquals to the default values to be avoid being a change-detector test - assertTrue(childParams.getHardLifetimeSeconds() > childParams.getSoftLifetimeSeconds()); - assertTrue(childParams.getSoftLifetimeSeconds() > 0); - - assertEquals( - Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS), - childParams.getInboundTrafficSelectors()); - assertEquals( - Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS), - childParams.getOutboundTrafficSelectors()); - } - - private void verifyChildParamsWithCustomizedValues(ChildSessionParams childParams) { - assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals()); - - assertEquals(HARD_LIFETIME_SECONDS, childParams.getHardLifetimeSeconds()); - assertEquals(SOFT_LIFETIME_SECONDS, childParams.getSoftLifetimeSeconds()); - - assertEquals( - Arrays.asList(INBOUND_V4_TS, INBOUND_V6_TS), - childParams.getInboundTrafficSelectors()); - assertEquals( - Arrays.asList(OUTBOUND_V4_TS, OUTBOUND_V6_TS), - childParams.getOutboundTrafficSelectors()); - } - - @Test - public void testBuildTransportModeParamsWithDefaultValues() { - TransportModeChildSessionParams childParams = - new TransportModeChildSessionParams.Builder().addSaProposal(mSaProposal).build(); - - verifyTransportModeChildParamsWithDefaultValues(childParams); - } - - @Test - public void testBuildTunnelModeParamsWithDefaultValues() { - TunnelModeChildSessionParams childParams = - new TunnelModeChildSessionParams.Builder().addSaProposal(mSaProposal).build(); - - verifyTunnelModeChildParamsWithDefaultValues(childParams); - assertTrue(childParams.getConfigurationRequests().isEmpty()); - } - - @Test - public void testBuildTransportModeParamsWithCustomizedValues() { - TransportModeChildSessionParams childParams = - new TransportModeChildSessionParams.Builder() - .addSaProposal(mSaProposal) - .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) - .addInboundTrafficSelectors(INBOUND_V4_TS) - .addInboundTrafficSelectors(INBOUND_V6_TS) - .addOutboundTrafficSelectors(OUTBOUND_V4_TS) - .addOutboundTrafficSelectors(OUTBOUND_V6_TS) - .build(); - - verifyTransportModeChildParamsWithCustomizedValues(childParams); - } - - @Test - public void testBuildTunnelModeParamsWithCustomizedValues() { - TunnelModeChildSessionParams childParams = - new TunnelModeChildSessionParams.Builder() - .addSaProposal(mSaProposal) - .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) - .addInboundTrafficSelectors(INBOUND_V4_TS) - .addInboundTrafficSelectors(INBOUND_V6_TS) - .addOutboundTrafficSelectors(OUTBOUND_V4_TS) - .addOutboundTrafficSelectors(OUTBOUND_V6_TS) - .build(); - - verifyTunnelModeChildParamsWithCustomizedValues(childParams); - } - - @Test - public void testBuildChildSessionParamsWithConfigReq() { - TunnelModeChildSessionParams childParams = - new TunnelModeChildSessionParams.Builder() - .addSaProposal(mSaProposal) - .addInternalAddressRequest(AF_INET) - .addInternalAddressRequest(AF_INET6) - .addInternalAddressRequest(AF_INET6) - .addInternalAddressRequest(IPV4_ADDRESS_REMOTE) - .addInternalAddressRequest(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN) - .addInternalDnsServerRequest(AF_INET) - .addInternalDnsServerRequest(AF_INET6) - .addInternalDhcpServerRequest(AF_INET) - .addInternalDhcpServerRequest(AF_INET) - .build(); - - verifyTunnelModeChildParamsWithDefaultValues(childParams); - - // Verify config request types and number of requests for each type - Map, Integer> expectedAttributeCounts = - new HashMap<>(); - expectedAttributeCounts.put(ConfigRequestIpv4Address.class, 2); - expectedAttributeCounts.put(ConfigRequestIpv6Address.class, 3); - expectedAttributeCounts.put(ConfigRequestIpv4Netmask.class, 1); - expectedAttributeCounts.put(ConfigRequestIpv4DnsServer.class, 1); - expectedAttributeCounts.put(ConfigRequestIpv6DnsServer.class, 1); - expectedAttributeCounts.put(ConfigRequestIpv4DhcpServer.class, 2); - verifyConfigRequestTypes(expectedAttributeCounts, childParams.getConfigurationRequests()); - - // Verify specific IPv4 address request - Set expectedV4Addresses = new HashSet<>(); - expectedV4Addresses.add(IPV4_ADDRESS_REMOTE); - verifySpecificV4AddrConfigReq(expectedV4Addresses, childParams); - - // Verify specific IPv6 address request - Set expectedV6Addresses = new HashSet<>(); - expectedV6Addresses.add(new LinkAddress(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN)); - verifySpecificV6AddrConfigReq(expectedV6Addresses, childParams); - } - - protected void verifySpecificV4AddrConfigReq( - Set expectedAddresses, TunnelModeChildSessionParams childParams) { - for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) { - if (req instanceof ConfigRequestIpv4Address - && ((ConfigRequestIpv4Address) req).getAddress() != null) { - Inet4Address address = ((ConfigRequestIpv4Address) req).getAddress(); - - // Fail if expectedAddresses does not contain this address - assertTrue(expectedAddresses.remove(address)); - } - } - - // Fail if any expected address is not found in result - assertTrue(expectedAddresses.isEmpty()); - } - - protected void verifySpecificV6AddrConfigReq( - Set expectedAddresses, TunnelModeChildSessionParams childParams) { - for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) { - if (req instanceof ConfigRequestIpv6Address - && ((ConfigRequestIpv6Address) req).getAddress() != null) { - ConfigRequestIpv6Address ipv6AddrReq = (ConfigRequestIpv6Address) req; - - // Fail if expectedAddresses does not contain this address - LinkAddress address = - new LinkAddress(ipv6AddrReq.getAddress(), ipv6AddrReq.getPrefixLength()); - assertTrue(expectedAddresses.remove(address)); - } - } - - // Fail if any expected address is not found in result - assertTrue(expectedAddresses.isEmpty()); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java deleted file mode 100644 index 0317def92e..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import android.net.ipsec.ike.IkeDerAsn1DnIdentification; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeIpv4AddrIdentification; -import android.net.ipsec.ike.IkeIpv6AddrIdentification; -import android.net.ipsec.ike.IkeKeyIdIdentification; -import android.net.ipsec.ike.IkeRfc822AddrIdentification; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import javax.security.auth.x500.X500Principal; - -@RunWith(AndroidJUnit4.class) -public final class IkeIdentificationTest extends IkeTestBase { - @Test - public void testIkeDerAsn1DnIdentification() throws Exception { - X500Principal asn1Dn = new X500Principal(LOCAL_ASN1_DN_STRING); - - IkeDerAsn1DnIdentification ikeId = new IkeDerAsn1DnIdentification(asn1Dn); - assertEquals(asn1Dn, ikeId.derAsn1Dn); - } - - @Test - public void testIkeFqdnIdentification() throws Exception { - IkeFqdnIdentification ikeId = new IkeFqdnIdentification(LOCAL_HOSTNAME); - assertEquals(LOCAL_HOSTNAME, ikeId.fqdn); - } - - @Test - public void testIkeIpv4AddrIdentification() throws Exception { - IkeIpv4AddrIdentification ikeId = new IkeIpv4AddrIdentification(IPV4_ADDRESS_LOCAL); - assertEquals(IPV4_ADDRESS_LOCAL, ikeId.ipv4Address); - } - - @Test - public void testIkeIpv6AddrIdentification() throws Exception { - IkeIpv6AddrIdentification ikeId = new IkeIpv6AddrIdentification(IPV6_ADDRESS_LOCAL); - assertEquals(IPV6_ADDRESS_LOCAL, ikeId.ipv6Address); - } - - @Test - public void testIkeKeyIdIdentification() throws Exception { - IkeKeyIdIdentification ikeId = new IkeKeyIdIdentification(LOCAL_KEY_ID); - assertArrayEquals(LOCAL_KEY_ID, ikeId.keyId); - } - - @Test - public void testIkeRfc822AddrIdentification() throws Exception { - IkeRfc822AddrIdentification ikeId = new IkeRfc822AddrIdentification(LOCAL_RFC822_NAME); - assertEquals(LOCAL_RFC822_NAME, ikeId.rfc822Name); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java deleted file mode 100644 index 9be1dc72cf..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import android.net.InetAddresses; -import android.net.LinkAddress; -import android.net.ipsec.ike.IkeDerAsn1DnIdentification; -import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeTrafficSelector; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.internal.net.ipsec.ike.testutils.CertUtils; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.util.ArrayList; -import java.util.Arrays; - -import javax.security.auth.x500.X500Principal; - -/** - * Explicitly test setting up transport mode Child SA so that devices do not have - * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in - * IkeSessionPskTest and authentication method is orthogonal to Child mode. - */ -@RunWith(AndroidJUnit4.class) -public class IkeSessionDigitalSignatureTest extends IkeSessionTestBase { - private static final int EXPECTED_AUTH_REQ_FRAG_COUNT = 3; - - private static final String IKE_INIT_RESP = - "46B8ECA1E0D72A18BF3FA1C2CB1EE86F21202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0100030000080300000503000008" - + "0200000400000008040000022800008800020000328451C8A976CE69E407966A" - + "50D7320C4197A15A07267CE1B16BAFF9BDBBDEC1FDCDAAF7175ADF9AA8DB55DB" - + "2D70C012D01D914C4EDEF6E8B226868EA1D01B2ED0C4C5C86E6BFE566010EC0C" - + "33BA1C93666430B88BDA0470D82CC4F4416F49E3E361E3017C9F27811A66718B" - + "389E1800915D776D59AA528A7E1D1B7815D35144290000249FE8FABE7F43D917" - + "CE370DE2FD9C22BBC082951AC26C1BA26DE795470F2C25BC2900001C00004004" - + "AE388EC86D6D1A470D44142D01AB2E85A7AC14182900001C0000400544A235A4" - + "171C884286B170F48FFC181DB428D87D290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - private static final String IKE_AUTH_RESP_FRAG_1 = - "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000004E0240004C4" - + "00010002DF6750A2D1D5675006F9F6230BB886FFD20CFB973FD04963CFD7A528" - + "560598C58CC44178B2FCBBBBB271387AC81A664B7E7F1055B912F8C686E287C9" - + "D31684C66339151AB86DA3CF1DA664052FA97687634558A1E9E6B37E16A86BD1" - + "68D76DA5E2E1E0B7E98EB662D80D542307015D2BF134EBBBE425D6954FE8C2C4" - + "D31D16C16AA0521C3C481F873ECF25BB8B05AC6083775C1821CAAB1E35A3955D" - + "85ACC599574142E1DD5B262D6E5365CBF6EBE92FFCC16BC29EC3239456F3B202" - + "492551C0F6D752ADCCA56D506D50CC8809EF6BC56EAD005586F7168F76445FD3" - + "1366CC62D32C0C19B28210B8F813F97CD6A447C3857EFD6EC483DDA8ACD9870E" - + "5A21B9C66F0FA44496C0C3D05E8859A1A4CFC88155D0C411BABC13033DD41FA4" - + "AF08CE7734A146687F374F95634D1F26843203CA1FFD05CA3EB150CEA02FBF14" - + "712B7A1C9BC7616A086E7FCA059E7D64EFF98DB895B32F8F7002762AF7D12F23" - + "31E9DD25174C4CE273E5392BBB48F50B7A3E0187181216265F6A4FC7B91BE0AB" - + "C601A580149D4B07411AE99DDB1944B977E86ADC9746605C60A92B569EEFAFFC" - + "3A888D187B75D8F13249689FC28EBCD62B5E03AF171F3A561F0DEA3B1A75F531" - + "971157DCE1E7BC6E7789FF3E8156015BC9C521EFE48996B41471D33BF09864E4" - + "2436E8D7EB6218CDE7716DA754A924B123A63E25585BF27F4AC043A0C4AECE38" - + "BB59DD62F5C0EC657206A76CED1BD26262237DA1CA6815435992A825758DEBEC" - + "DDF598A22B8242AC4E34E70704DBA7B7B73DC3E067C1C98764F8791F84C99156" - + "947D1FFC875F36FCE24B89369C1B5BF1D4C999DCA28E72A528D0E0163C66C067" - + "E71B5E0025C13DA93313942F9EDA230B3ADC254821A4CB1A5DC9D0C5F4DC4E8E" - + "CE46B7B8C72D3C5923C9B30DF1EF7B4EDEDA8BD05C86CA0162AE1BF8F277878E" - + "607401BAA8F06E3EA873FA4C137324C4E0699277CDF649FE7F0F01945EE25FA7" - + "0E4A89737E58185B11B4CB52FD5B0497D3E3CD1CEE7B1FBB3E969DB6F4C324A1" - + "32DC6A0EA21F41332435FD99140C286F8ABBBA926953ADBEED17D30AAD953909" - + "1347EF6D87163D6B1FF32D8B11FFB2E69FAEE7FE913D3826FBA7F9D11E0E3C57" - + "27625B37D213710B5DD8965DAEFD3F491E8C029E2BF361039949BADEC31D60AC" - + "355F26EE41339C03CC9D9B01C3C7F288F0E9D6DFEE78231BDA9AC10FED135913" - + "2836B1A17CE060742B7E5B738A7177CCD59F70337BA251409C377A0FA5333204" - + "D8622BA8C06DE0BEF4F32B6D4D77BE9DE977445D8A2A08C5C38341CB7974FBFB" - + "22C8F983A7D6CEF068DDB2281E6673453521C831C1826861005AE5F37649BC64" - + "0A6360B23284861441A440F1C5AADE1AB53CA63DB17F4C314D493C4C44DE5F20" - + "75E084D080F92791F30BDD88373D50AB5A07BC72B0E7FFFA593103964E55603E" - + "F7FEB7CA0762A1A7B86B6CCAD88CD6CBC7C6935D21F5F06B2700588A2530E619" - + "DA1648AC809F3DDF56ACE5951737568FFEC7E2AB1AA0AE01B03A7F5A29CE73C0" - + "5D2801B17CAAD0121082E9952FAB16BA1C386336C62D4CF3A5019CF61609433E" - + "1C083237D47C4CF575097F7BF9000EF6B6C497A44E6480154A35669AD276BF05" - + "6CC730B4E5962B6AF96CC6D236AE85CEFDA6877173F72D2F614F6696D1F9DF07" - + "E107758B0978F69BC9DBE0CCBF252C40A3FDF7CE9104D3344F7B73593CCD73E0"; - private static final String IKE_AUTH_RESP_FRAG_2 = - "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000000F0000000D4" - + "00020002155211EA41B37BC5F20568A6AE57038EEE208F94F9B444004F1EF391" - + "2CABFCF857B9CD95FAAA9489ED10A3F5C93510820E22E23FC55ED8049E067D72" - + "3645C00E1E08611916CE72D7F0A84123B63A8F3B9E78DBBE39967B7BB074AF4D" - + "BF2178D991EDBDD01908A14A266D09236DB963B14AC33D894F0F83A580209EFD" - + "61875BB56273AA336C22D6A4D890B93E0D42435667830CC32E4F608500E18569" - + "3E6C1D88C0B5AE427333C86468E3474DAA4D1506AAB2A4021309A33DD759D0D0" - + "A8C98BF7FBEA8109361A9F194D0FD756"; - private static final String DELETE_IKE_RESP = - "46B8ECA1E0D72A18BF3FA1C2CB1EE86F2E202520000000020000004C00000030" - + "342842D8DA37C8EFB92ED37C4FBB23CBDC90445137D6A0AF489F9F03641DBA9D" - + "02F6F59FD8A7A78C7261CEB8"; - - // Using IPv4 for transport mode Child SA. IPv6 is currently infeasible because the IKE server - // that generates the test vectors is running in an IPv4 only network. - private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("172.58.35.103"), - InetAddresses.parseNumericAddress("172.58.35.103")); - - // TODO(b/157510502): Add test for IKE Session setup with transport mode Child in IPv6 network - - private static final String LOCAL_ID_ASN1_DN = - "CN=client.test.ike.android.net, O=Android, C=US"; - private static final String REMOTE_ID_ASN1_DN = - "CN=server.test.ike.android.net, O=Android, C=US"; - - private static X509Certificate sServerCaCert; - private static X509Certificate sClientEndCert; - private static X509Certificate sClientIntermediateCaCertOne; - private static X509Certificate sClientIntermediateCaCertTwo; - private static RSAPrivateKey sClientPrivateKey; - - @BeforeClass - public static void setUpCertsBeforeClass() throws Exception { - sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); - sClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); - sClientIntermediateCaCertOne = - CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem"); - sClientIntermediateCaCertTwo = - CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem"); - sClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); - } - - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { - IkeSessionParams ikeParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(remoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification( - new IkeDerAsn1DnIdentification(new X500Principal(LOCAL_ID_ASN1_DN))) - .setRemoteIdentification( - new IkeDerAsn1DnIdentification( - new X500Principal(REMOTE_ID_ASN1_DN))) - .setAuthDigitalSignature( - sServerCaCert, - sClientEndCert, - Arrays.asList( - sClientIntermediateCaCertOne, sClientIntermediateCaCertTwo), - sClientPrivateKey) - .build(); - - return new IkeSession( - sContext, - ikeParams, - buildTransportModeChildParamsWithTs( - TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), - mUserCbExecutor, - mIkeSessionCallback, - mFirstChildSessionCallback); - } - - @Test - public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception { - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - performSetupIkeAndFirstChildBlocking( - IKE_INIT_RESP, - EXPECTED_AUTH_REQ_FRAG_COUNT /* expectedReqPktCnt */, - true /* expectedAuthUseEncap */, - IKE_AUTH_RESP_FRAG_1, - IKE_AUTH_RESP_FRAG_2); - - // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 - int expectedMsgId = 2; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TRANSPORT_MODE_INBOUND_TS), - Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Close IKE Session - ikeSession.close(); - performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP); - verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java deleted file mode 100644 index cb771276dc..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import android.net.InetAddresses; -import android.net.LinkAddress; -import android.net.eap.EapSessionConfig; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeTrafficSelector; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.internal.net.ipsec.ike.testutils.CertUtils; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Explicitly test setting up transport mode Child SA so that devices do not have - * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in - * IkeSessionPskTest and authentication method is orthogonal to Child mode. - */ -@RunWith(AndroidJUnit4.class) -public class IkeSessionMschapV2Test extends IkeSessionTestBase { - private static final String IKE_INIT_RESP = - "46B8ECA1E0D72A1873F643FF94D249A921202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0080030000080300000203000008" - + "0200000200000008040000022800008800020000CC6E71E67E32CED6BCE33FBD" - + "A74113867E3FA3AE21C7C9AB44A7F8835DF602BFD6F6528B67FEE39821232380" - + "C99E8FFC0A5D767F8F38906DA41946C2299DF18C15FA69BAC08D3EDB32E8C8CA" - + "28431831561C04CB0CDE393F817151CD8DAF7A311838411F1C39BFDB5EBCF6A6" - + "1DF66DEB067362649D64607D599B56C4227819D0290000241197004CF31AD00F" - + "5E0C92E198488D8A2B6F6A25C82762AA49F565BCE9D857D72900001C00004004" - + "A0D98FEABBFB92A6C0976EE83D2AACFCCF969A6B2900001C0000400575EBF73F" - + "8EE5CC73917DE9D3F91FCD4A16A0444D290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - private static final String IKE_AUTH_RESP_1_FRAG_1 = - "46B8ECA1E0D72A1873F643FF94D249A93520232000000001000004E0240004C4" - + "00010002C4159CB756773B3F1911F4595107BC505D7A28C72F05182966076679" - + "CA68ED92E4BC5CD441C9CB315F2F449A8A521CAFED3C5F285E295FC3791D3415" - + "E3BACF66A08410DF4E35F7D88FE40DA28851C91C77A6549E186AC1B7846DF3FA" - + "0A347A5ABBCAEE19E70F0EE5966DC6242A115F29523709302EDAD2E36C8F0395" - + "CF5C42EC2D2898ECDD8A6AEDD686A70B589A981558667647F32F41E0D8913E94" - + "A6693F53E59EA8938037F562CF1DC5E6E2CDC630B5FFB08949E3172249422F7D" - + "EA069F9BAD5F96E48BADC7164A9269669AD0DF295A80C54D1D23CEA3F28AC485" - + "86D2A9850DA23823037AB7D1577B7B2364C92C36B84238357129EB4A64D33310" - + "B95DCD50CD53E78C32EFE7DC1627D9432E9BFDEE130045DE967B19F92A9D1270" - + "F1E2C6BFBAA56802F3E63510578EF1ECB6872852F286EEC790AA1FE0CAF391CB" - + "E276554922713BA4770CFE71E23F043DC620E22CC02A74F60725D18331B7F2C9" - + "276EB6FBB7CBDAA040046D7ECBE1A5D7064E04E542807C5101B941D1C81B9D5E" - + "90347B22BD4E638E2EDC98E369B51AA29BDB2CF8AA610D4B893EB83A4650717C" - + "38B4D145EE939C18DCEDF6C79933CEB3D7C116B1F188DF9DDD560951B54E4A7D" - + "80C999A32AB02BF39D7B498DAD36F1A5CBE2F64557D6401AE9DD6E0CEADA3F90" - + "540FE9114BB6B8719C9064796354F4A180A6600CAD092F8302564E409B71ACB7" - + "590F19B3AC88E7A606C718D0B97F7E4B4830F11D851C59F2255846DA22E2C805" - + "0CA2AF2ACF3B6C769D11B75B5AC9AB82ED3D90014994B1BF6FED58FBEF2D72EF" - + "8BDFE51F9A101393A7CA1ACF78FAEBF3E3CC25E09407D1E14AF351A159A13EE3" - + "9B919BA8B49942792E7527C2FB6D418C4DF427669A4BF5A1AFBBB973BAF17918" - + "9C9D520CAC2283B89A539ECE785EBE48FBB77D880A17D55C84A51F46068A4B87" - + "FF48FEEE50E1E034CC8AFF5DA92105F55EC4823E67BDFE942CA8BE0DAECBBD52" - + "E8AAF306049DC6C4CF87D987B0AC54FCE92E6AE8507965AAAC6AB8BD3405712F" - + "EE170B70BC64BDCBD86D80C7AAAF341131F9A1210D7430B17218413AE1363183" - + "5C98FA2428B1E9E987ADC9070E232310A28F4C3163E18366FFB112BADD7C5E0F" - + "D13093A7C1428F87856BA0A7E46955589ACA267CE7A04320C4BCDBB60C672404" - + "778F8D511AAB09349DAB482445D7F606F28E7FBBB18FC0F4EC0AF04F44C282F9" - + "39C6E3B955C84DADEA350667236583069B74F492D600127636FA31F63E560851" - + "2FC28B8EA5B4D01D110990B6EA46B9C2E7C7C856C240EF7A8147BA2C4344B85A" - + "453C862024B5B6814D13CDEAEF7683D539BB50CAFFC0416F269F2F9EDEC5FA30" - + "022FD7B4B186CD2020E7ED8D81ED90822EDD8B76F840DD68F09694CFF9B4F33E" - + "11DF4E601A4212881A6D4E9259001705C41E9E23D18A7F3D4A3463649A38211A" - + "5A90D0F17739A677C74E23F31C01D60B5A0F1E6A4D44FED9D25BF1E63418E1FC" - + "0B19F6F4B71DE53C62B14B82279538A82DD4BE19AB6E00AFC20F124AAB7DF21A" - + "42259BE4F40EC69B16917256F23E2C37376311D62E0A3A0EF8C2AD0C090221D5" - + "C5ECA08F08178A4D31FFDB150C609827D18AD83C7B0A43AEE0406BD3FB494B53" - + "A279FDD6447E234C926AD8CE47FFF779BB45B1FC8457C6E7D257D1359959D977" - + "CEF6906A3367DC4D454993EFDC6F1EA94E17EB3DCB00A289346B4CFD7F19B16E"; - private static final String IKE_AUTH_RESP_1_FRAG_2 = - "46B8ECA1E0D72A1873F643FF94D249A935202320000000010000008000000064" - + "00020002C61F66025E821A5E69A4DE1F591A2C32C983C3154A5003660137D685" - + "A5262B9FDF5EDC699DE4D8BD38F549E3CBD12024B45B4C86561C36C3EED839DA" - + "9860C6AA0B764C662D08F1B6A98F68CF6E3038F737C0B415AD8A8B7D702BD92A"; - private static final String IKE_AUTH_RESP_2 = - "46B8ECA1E0D72A1873F643FF94D249A92E202320000000020000008C30000070" - + "62B90C2229FD23025BC2FD7FE6341E9EE04B17264CD619BCE18975A5F88BE438" - + "D4AD4A5310057255AF568C293A29B10107E3EE3675C10AA2B26404D90C0528CC" - + "F7605A86C96A1F2635CCC6CFC90EE65E5C2A2262EB33FE520EB708423A83CB63" - + "274ECCBB102AF5DF35742657"; - private static final String IKE_AUTH_RESP_3 = - "46B8ECA1E0D72A1873F643FF94D249A92E202320000000030000004C30000030" - + "AB52C3C80123D3432C05AF457CE93C352395F73E861CD49561BA528CFE68D17D" - + "78BBF6FC41E81C2B9EA051A2"; - private static final String IKE_AUTH_RESP_4 = - "46B8ECA1E0D72A1873F643FF94D249A92E20232000000004000000CC270000B0" - + "8D3342A7AB2666AC754F4B55C5C6B1A61255E62FBCA53D5CDEEDE60DADB7915C" - + "7F962076A58BF7D39A05ED1B60FF349B6DE311AF7CEBC72B4BB9723A728A5D3E" - + "9E508B2D7A11843D279B56ADA07E608D61F5CA7638F10372A440AD1DCE44E190" - + "7B7B7A68B126EBBB86638D667D5B528D233BA8D32D7E0FAC4E1448E87396EEE6" - + "0985B79841E1229D7962AACFD8F872722EC8D5B19D4C82D6C4ADCB276127A1A7" - + "3FC84CDF85B2299BC96B64AC"; - private static final String DELETE_IKE_RESP = - "46B8ECA1E0D72A1873F643FF94D249A92E202520000000050000004C00000030" - + "622CE06C8CB132AA00567E9BC83F58B32BD7DB5130C76E385B306434DA227361" - + "D50CC19D408A8D4F36F9697F"; - - // This value is align with the test vectors hex that are generated in an IPv4 environment - private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("172.58.35.67"), - InetAddresses.parseNumericAddress("172.58.35.67")); - - private static final EapSessionConfig EAP_CONFIG = - new EapSessionConfig.Builder() - .setEapIdentity(EAP_IDENTITY) - .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) - .build(); - - private static X509Certificate sServerCaCert; - - @BeforeClass - public static void setUpCertBeforeClass() throws Exception { - sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); - } - - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { - IkeSessionParams ikeParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(remoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) - .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) - .setAuthEap(sServerCaCert, EAP_CONFIG) - .build(); - return new IkeSession( - sContext, - ikeParams, - buildTransportModeChildParamsWithTs( - TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), - mUserCbExecutor, - mIkeSessionCallback, - mFirstChildSessionCallback); - } - - @Test - public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception { - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - IKE_INIT_RESP); - - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - IKE_AUTH_RESP_1_FRAG_1, - IKE_AUTH_RESP_1_FRAG_2); - - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - IKE_AUTH_RESP_2); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - IKE_AUTH_RESP_3); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - IKE_AUTH_RESP_4); - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TRANSPORT_MODE_INBOUND_TS), - Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Close IKE Session - ikeSession.close(); - performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP); - verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java deleted file mode 100644 index c767b78120..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID; -import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.telephony.TelephonyManager.APPTYPE_USIM; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import android.net.eap.EapSessionConfig; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeIdentification; -import android.net.ipsec.ike.IkeSaProposal; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer; -import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer; -import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.internal.net.ipsec.ike.testutils.CertUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -@RunWith(AndroidJUnit4.class) -public final class IkeSessionParamsTest extends IkeSessionTestBase { - private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(20L); - private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(10L); - private static final int DPD_DELAY_SECONDS = (int) TimeUnit.MINUTES.toSeconds(10L); - private static final int[] RETRANS_TIMEOUT_MS_LIST = new int[] {500, 500, 500, 500, 500, 500}; - - private static final Map, Integer> EXPECTED_REQ_COUNT = - new HashMap<>(); - private static final HashSet EXPECTED_PCSCF_SERVERS = new HashSet<>(); - - static { - EXPECTED_REQ_COUNT.put(ConfigRequestIpv4PcscfServer.class, 3); - EXPECTED_REQ_COUNT.put(ConfigRequestIpv6PcscfServer.class, 3); - - EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_1); - EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_2); - EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_1); - EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_2); - } - - // Arbitrary proposal and remote ID. Local ID is chosen to match the client end cert in the - // following CL - private static final IkeSaProposal SA_PROPOSAL = - SaProposalTest.buildIkeSaProposalWithNormalModeCipher(); - private static final IkeIdentification LOCAL_ID = new IkeFqdnIdentification(LOCAL_HOSTNAME); - private static final IkeIdentification REMOTE_ID = new IkeFqdnIdentification(REMOTE_HOSTNAME); - - private static final EapSessionConfig EAP_ALL_METHODS_CONFIG = - createEapOnlySafeMethodsBuilder() - .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) - .build(); - private static final EapSessionConfig EAP_ONLY_SAFE_METHODS_CONFIG = - createEapOnlySafeMethodsBuilder().build(); - - private X509Certificate mServerCaCert; - private X509Certificate mClientEndCert; - private X509Certificate mClientIntermediateCaCertOne; - private X509Certificate mClientIntermediateCaCertTwo; - private RSAPrivateKey mClientPrivateKey; - - @Before - public void setUp() throws Exception { - // This address is never used except for setting up the test network - setUpTestNetwork(IPV4_ADDRESS_LOCAL); - - mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); - mClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); - mClientIntermediateCaCertOne = - CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem"); - mClientIntermediateCaCertTwo = - CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem"); - mClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); - } - - @After - public void tearDown() throws Exception { - tearDownTestNetwork(); - } - - private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() { - return new EapSessionConfig.Builder() - .setEapIdentity(EAP_IDENTITY) - .setEapSimConfig(SUB_ID, APPTYPE_USIM) - .setEapAkaConfig(SUB_ID, APPTYPE_USIM) - .setEapAkaPrimeConfig( - SUB_ID, APPTYPE_USIM, NETWORK_NAME, true /* allowMismatchedNetworkNames */); - } - - /** - * Create a Builder that has minimum configurations to build an IkeSessionParams. - * - *

    Authentication method is arbitrarily selected. Using other method (e.g. setAuthEap) also - * works. - */ - private IkeSessionParams.Builder createIkeParamsBuilderMinimum() { - return new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) - .addSaProposal(SA_PROPOSAL) - .setLocalIdentification(LOCAL_ID) - .setRemoteIdentification(REMOTE_ID) - .setAuthPsk(IKE_PSK); - } - - /** - * Verify the minimum configurations to build an IkeSessionParams. - * - * @see #createIkeParamsBuilderMinimum - */ - private void verifyIkeParamsMinimum(IkeSessionParams sessionParams) { - assertEquals(mTunNetwork, sessionParams.getNetwork()); - assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); - assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); - assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); - assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthPskConfig); - assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk()); - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthPskConfig); - assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); - } - - @Test - public void testBuildWithMinimumSet() throws Exception { - IkeSessionParams sessionParams = createIkeParamsBuilderMinimum().build(); - - verifyIkeParamsMinimum(sessionParams); - - // Verify default values that do not need explicit configuration. Do not do assertEquals - // to be avoid being a change-detector test - assertTrue(sessionParams.getHardLifetimeSeconds() > sessionParams.getSoftLifetimeSeconds()); - assertTrue(sessionParams.getSoftLifetimeSeconds() > 0); - assertTrue(sessionParams.getDpdDelaySeconds() > 0); - assertTrue(sessionParams.getRetransmissionTimeoutsMillis().length > 0); - for (int timeout : sessionParams.getRetransmissionTimeoutsMillis()) { - assertTrue(timeout > 0); - } - assertTrue(sessionParams.getConfigurationRequests().isEmpty()); - assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); - } - - @Test - public void testSetLifetimes() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) - .build(); - - verifyIkeParamsMinimum(sessionParams); - assertEquals(HARD_LIFETIME_SECONDS, sessionParams.getHardLifetimeSeconds()); - assertEquals(SOFT_LIFETIME_SECONDS, sessionParams.getSoftLifetimeSeconds()); - } - - @Test - public void testSetDpdDelay() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum().setDpdDelaySeconds(DPD_DELAY_SECONDS).build(); - - verifyIkeParamsMinimum(sessionParams); - assertEquals(DPD_DELAY_SECONDS, sessionParams.getDpdDelaySeconds()); - } - - @Test - public void testSetRetransmissionTimeouts() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST) - .build(); - - verifyIkeParamsMinimum(sessionParams); - assertArrayEquals(RETRANS_TIMEOUT_MS_LIST, sessionParams.getRetransmissionTimeoutsMillis()); - } - - @Test - public void testSetPcscfConfigRequests() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST) - .addPcscfServerRequest(AF_INET) - .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_1) - .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_1) - .addPcscfServerRequest(AF_INET6) - .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_2) - .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_2) - .build(); - - verifyIkeParamsMinimum(sessionParams); - verifyConfigRequestTypes(EXPECTED_REQ_COUNT, sessionParams.getConfigurationRequests()); - - Set resultAddresses = new HashSet<>(); - for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) { - if (req instanceof ConfigRequestIpv4PcscfServer - && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) { - resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress()); - } else if (req instanceof ConfigRequestIpv6PcscfServer - && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) { - resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress()); - } - } - assertEquals(EXPECTED_PCSCF_SERVERS, resultAddresses); - } - - @Test - public void testAddIkeOption() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) - .build(); - - verifyIkeParamsMinimum(sessionParams); - assertTrue(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); - } - - @Test - public void testRemoveIkeOption() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) - .removeIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) - .build(); - - verifyIkeParamsMinimum(sessionParams); - assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); - } - - /** - * Create a Builder that has minimum configurations to build an IkeSessionParams, except for - * authentication method. - */ - private IkeSessionParams.Builder createIkeParamsBuilderMinimumWithoutAuth() { - return new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) - .addSaProposal(SA_PROPOSAL) - .setLocalIdentification(LOCAL_ID) - .setRemoteIdentification(REMOTE_ID); - } - - /** - * Verify the minimum configurations to build an IkeSessionParams, except for authentication - * method. - * - * @see #createIkeParamsBuilderMinimumWithoutAuth - */ - private void verifyIkeParamsMinimumWithoutAuth(IkeSessionParams sessionParams) { - assertEquals(mTunNetwork, sessionParams.getNetwork()); - assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); - assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); - assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); - assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); - } - - @Test - public void testBuildWithPsk() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth().setAuthPsk(IKE_PSK).build(); - - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthPskConfig); - assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk()); - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthPskConfig); - assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); - } - - @Test - public void testBuildWithEap() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG) - .build(); - - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthEapConfig); - assertEquals(EAP_ALL_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig()); - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); - assertEquals( - mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); - } - - @Test - public void testBuildWithEapOnlyAuth() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthEap(mServerCaCert, EAP_ONLY_SAFE_METHODS_CONFIG) - .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH) - .build(); - - assertTrue(sessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH)); - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthEapConfig); - assertEquals(EAP_ONLY_SAFE_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig()); - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); - assertEquals( - mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); - } - - @Test - public void testThrowBuildEapOnlyAuthWithUnsafeMethod() throws Exception { - try { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG) - .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH) - .build(); - fail("Expected to fail because EAP only unsafe method is proposed"); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testBuildWithDigitalSignature() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthDigitalSignature(mServerCaCert, mClientEndCert, mClientPrivateKey) - .build(); - - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); - IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig; - assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate()); - assertEquals(Collections.EMPTY_LIST, localSignConfig.getIntermediateCertificates()); - assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey()); - - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); - assertEquals( - mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); - } - - @Test - public void testBuildWithDigitalSignatureAndIntermediateCerts() throws Exception { - List intermediateCerts = - Arrays.asList(mClientIntermediateCaCertOne, mClientIntermediateCaCertTwo); - - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthDigitalSignature( - mServerCaCert, mClientEndCert, intermediateCerts, mClientPrivateKey) - .build(); - - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); - IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig; - assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate()); - assertEquals(intermediateCerts, localSignConfig.getIntermediateCertificates()); - assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey()); - - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); - assertEquals( - mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java deleted file mode 100644 index 13f953a50d..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; -import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; -import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; -import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import android.net.LinkAddress; -import android.net.ipsec.ike.ChildSessionParams; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.exceptions.IkeProtocolException; -import android.platform.test.annotations.AppModeFull; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; - -@RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_IPSEC_TUNNELS permission can't be granted to instant apps") -public class IkeSessionPskTest extends IkeSessionTestBase { - // Test vectors for success workflow - private static final String SUCCESS_IKE_INIT_RESP = - "46B8ECA1E0D72A18B45427679F9245D421202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0080030000080300000203000008" - + "0200000200000008040000022800008800020000A7AA3435D088EC1A2B7C2A47" - + "1FA1B85F1066C9B2006E7C353FB5B5FDBC2A88347ED2C6F5B7A265D03AE34039" - + "6AAC0145CFCC93F8BDB219DDFF22A603B8856A5DC59B6FAB7F17C5660CF38670" - + "8794FC72F273ADEB7A4F316519794AED6F8AB61F95DFB360FAF18C6C8CABE471" - + "6E18FE215348C2E582171A57FC41146B16C4AFE429000024A634B61C0E5C90C6" - + "8D8818B0955B125A9B1DF47BBD18775710792E651083105C2900001C00004004" - + "406FA3C5685A16B9B72C7F2EEE9993462C619ABE2900001C00004005AF905A87" - + "0A32222AA284A7070585601208A282F0290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - private static final String SUCCESS_IKE_AUTH_RESP = - "46B8ECA1E0D72A18B45427679F9245D42E20232000000001000000EC240000D0" - + "0D06D37198F3F0962DE8170D66F1A9008267F98CDD956D984BDCED2FC7FAF84A" - + "A6664EF25049B46B93C9ED420488E0C172AA6635BF4011C49792EF2B88FE7190" - + "E8859FEEF51724FD20C46E7B9A9C3DC4708EF7005707A18AB747C903ABCEAC5C" - + "6ECF5A5FC13633DCE3844A920ED10EF202F115DBFBB5D6D2D7AB1F34EB08DE7C" - + "A54DCE0A3A582753345CA2D05A0EFDB9DC61E81B2483B7D13EEE0A815D37252C" - + "23D2F29E9C30658227D2BB0C9E1A481EAA80BC6BE9006BEDC13E925A755A0290" - + "AEC4164D29997F52ED7DCC2E"; - private static final String SUCCESS_CREATE_CHILD_RESP = - "46B8ECA1E0D72A18B45427679F9245D42E20242000000002000000CC210000B0" - + "484565D4AF6546274674A8DE339E9C9584EE2326AB9260F41C4D0B6C5B02D1D" - + "2E8394E3CDE3094895F2ACCABCDCA8E82960E5196E9622BD13745FC8D6A2BED" - + "E561FF5D9975421BC463C959A3CBA3478256B6D278159D99B512DDF56AC1658" - + "63C65A986F395FE8B1476124B91F83FD7865304EB95B22CA4DD9601DA7A2533" - + "ABF4B36EB1B8CD09522F6A600032316C74E562E6756D9D49D945854E2ABDC4C" - + "3AF36305353D60D40B58BE44ABF82"; - private static final String SUCCESS_DELETE_CHILD_RESP = - "46B8ECA1E0D72A18B45427679F9245D42E202520000000030000004C2A000030" - + "0C5CEB882DBCA65CE32F4C53909335F1365C91C555316C5E9D9FB553F7AA916" - + "EF3A1D93460B7FABAF0B4B854"; - private static final String SUCCESS_DELETE_IKE_RESP = - "46B8ECA1E0D72A18B45427679F9245D42E202520000000040000004C00000030" - + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" - + "6743A7CEB2BE34AC00095A5B8"; - - private IkeSession openIkeSessionWithTunnelModeChild(InetAddress remoteAddress) { - return openIkeSession(remoteAddress, buildTunnelModeChildSessionParams()); - } - - private IkeSession openIkeSessionWithTransportModeChild(InetAddress remoteAddress) { - return openIkeSession(remoteAddress, buildTransportModeChildParamsWithDefaultTs()); - } - - private IkeSession openIkeSession(InetAddress remoteAddress, ChildSessionParams childParams) { - IkeSessionParams ikeParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(remoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) - .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) - .setAuthPsk(IKE_PSK) - .build(); - return new IkeSession( - sContext, - ikeParams, - childParams, - mUserCbExecutor, - mIkeSessionCallback, - mFirstChildSessionCallback); - } - - @BeforeClass - public static void setUpTunnelPermissionBeforeClass() throws Exception { - // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and - // a standard permission is insufficient. So we shell out the appop, to give us the - // right appop permissions. - setAppOp(OP_MANAGE_IPSEC_TUNNELS, true); - } - - // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass - // methods. - @AfterClass - public static void tearDownTunnelPermissionAfterClass() throws Exception { - setAppOp(OP_MANAGE_IPSEC_TUNNELS, false); - } - - @Test - public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception { - if (!hasTunnelsFeature()) return; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); - - // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 - int expectedMsgId = 2; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TUNNEL_MODE_INBOUND_TS), - Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), - Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR)); - - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Open additional Child Session - TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); - ikeSession.openChildSession(buildTunnelModeChildSessionParams(), additionalChildCb); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - SUCCESS_CREATE_CHILD_RESP); - - // Verify opening additional Child Session - verifyChildSessionSetupBlocking( - additionalChildCb, - Arrays.asList(TUNNEL_MODE_INBOUND_TS), - Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord additionalTransformRecordA = - additionalChildCb.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord additionalTransformRecordB = - additionalChildCb.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(additionalTransformRecordA, additionalTransformRecordB); - - // Close additional Child Session - ikeSession.closeChildSession(additionalChildCb); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - SUCCESS_DELETE_CHILD_RESP); - - verifyDeleteIpSecTransformPair( - additionalChildCb, additionalTransformRecordA, additionalTransformRecordB); - additionalChildCb.awaitOnClosed(); - - // Close IKE Session - ikeSession.close(); - performCloseIkeBlocking(expectedMsgId++, SUCCESS_DELETE_IKE_RESP); - verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); - } - - @Test - public void testIkeSessionSetupAndChildSessionSetupWithTunnelModeV6() throws Exception { - if (!hasTunnelsFeature()) return; - - final String ikeInitResp = - "46B8ECA1E0D72A186F7B6C2CEB77EB9021202220000000000000011822000030" - + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" - + "0200000500000008040000022800008800020000DABAA04B38B491E2403F2125" - + "96ECF1C8EF7B1DC19A422FDD46E1756C826BB3A16404361B775D9950577B5CDF" - + "6AAA1642BD1427BDA8BC55354A97C1025E19C1E2EE2DF8A0C9406E545D829F52" - + "75695008E3B742984B8DD1770F3514213B0DF3EE8B199416DF200D248115C057" - + "1C193E4F96802E5EF48DD99CAC251882A8F7CCC329000024BC6F0F1D3653C2C7" - + "679E02CDB6A3B32B2FEE9AF52F0326D4D9AE073D56CE8922290000080000402E" - + "290000100000402F00020003000400050000000800004014"; - final String ikeAuthResp = - "46B8ECA1E0D72A186F7B6C2CEB77EB902E202320000000010000015024000134" - + "4D115AFDCDAD0310760BB664EB7D405A340869AD6EDF0AAEAD0663A9253DADCB" - + "73EBE5CD29D4FA1CDEADE0B94391B5C4CF77BCC1596ACE3CE6A7891E44888FA5" - + "46632C0EF4E6193C023C9DC59142C37D1C49D6EF5CD324EC6FC35C89E1721C78" - + "91FDCDB723D8062709950F4AA9273D26A54C9C7E86862DBC15F7B6641D2B9BAD" - + "E55069008201D12968D97B537B1518FE87B0FFA03C3EE6012C06721B1E2A3F68" - + "92108BC4A4F7063F7F94562D8B60F291A1377A836CF12BCDA7E15C1A8F3C77BB" - + "6DB7F2C833CCE4CDDED7506536621A3356CE2BC1874E7B1A1A9B447D7DF6AB09" - + "638B8AD94A781B28BB91B514B611B24DF8E8A047A10AE27BBF15C754D3D2F792" - + "D3E1CCADDAE934C98AE53A8FC3419C88AFF0355564F82A629C998012DA7BB704" - + "5307270DF326377E3E1994476902035B"; - final String deleteIkeResp = - "46B8ECA1E0D72A186F7B6C2CEB77EB902E202520000000020000005000000034" - + "CF15C299F35688E5140A48B61C95F004121BF8236201415E5CD45BA41AAB16D4" - + "90B44B9E6D5D92B5B97D24196A58C73F"; - - mLocalAddress = IPV6_ADDRESS_LOCAL; - mRemoteAddress = IPV6_ADDRESS_REMOTE; - - // Teardown current test network that uses IPv4 address and set up new network with IPv6 - // address. - tearDownTestNetwork(); - setUpTestNetwork(mLocalAddress); - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking( - ikeInitResp, - 1 /* expectedAuthReqPktCnt */, - false /* expectedAuthUseEncap */, - ikeAuthResp); - - // Local request message ID starts from 2 because there is one IKE_INIT message and a single - // IKE_AUTH message. - int expectedMsgId = 2; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TUNNEL_MODE_INBOUND_TS_V6), - Arrays.asList(TUNNEL_MODE_OUTBOUND_TS_V6), - Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR_V6), - Arrays.asList(EXPECTED_DNS_SERVERS_ONE, EXPECTED_DNS_SERVERS_TWO)); - - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Close IKE Session - ikeSession.close(); - performCloseIkeBlocking(expectedMsgId++, false /* expectedUseEncap */, deleteIkeResp); - verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); - } - - @Test - public void testIkeSessionKillWithTunnelMode() throws Exception { - if (!hasTunnelsFeature()) return; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); - - ikeSession.kill(); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); - } - - @Test - public void testIkeInitFail() throws Exception { - final String ikeInitFailRespHex = - "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - ikeInitFailRespHex); - - mFirstChildSessionCallback.awaitOnClosed(); - - IkeProtocolException protocolException = - (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException(); - assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, protocolException.getErrorType()); - assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); - } - - @Test - public void testIkeAuthHandlesAuthFailNotification() throws Exception { - final String ikeInitRespHex = - "46B8ECA1E0D72A18CF94CE3159486F002120222000000000000001502200" - + "00300000002C010100040300000C0100000C800E01000300000803000005" - + "0300000802000004000000080400000228000088000200001821AA854691" - + "FA3292DF710F0AC149ACBD0CB421608B8796C1912AF04C5B4B23936FDEC4" - + "7CB640E3EAFB56BBB562825E87AF68B40E4BAB80A49BAD44407450A4195A" - + "1DD54BD99F48D28C9F0FBA315A3401C1C3C4AD55911F514A8DF2D2467C46" - + "A73DDC1452AE81336E0F0D5EC896D2E7A77628AF2F9089F48943399DF216" - + "EFCD2900002418D2B7E4E6AF0FEFF5962CF8D68F7793B1293FEDE13331D4" - + "AB0CE9436C2EE1EC2900001C0000400457BD9AEF5B362A83DD7F3DDAA4A9" - + "9B6B4041DAF32900001C000040055A81893582701E44D4B6729A22FE06DE" - + "82A03A36290000080000402E290000100000402F00020003000400050000" - + "000800004014"; - final String ikeAuthFailRespHex = - "46B8ECA1E0D72A18CF94CE3159486F002E202320000000010000004C2900" - + "00301B9E4C8242D3BE62E7F0A537FE8B92C6EAB7153105DA421DCE43A06D" - + "AB6E4808BAC0CA1DAD6ADD0A126A41BD"; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthFailRespHex); - - mFirstChildSessionCallback.awaitOnClosed(); - IkeProtocolException protocolException = - (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException(); - assertEquals(ERROR_TYPE_AUTHENTICATION_FAILED, protocolException.getErrorType()); - assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); - } - - @Test - public void testIkeAuthHandlesFirstChildCreationFail() throws Exception { - final String ikeInitRespHex = - "46B8ECA1E0D72A18F5ABBF896A1240BE2120222000000000000001502200" - + "00300000002C010100040300000C0100000C800E0100030000080300000C" - + "03000008020000050000000804000002280000880002000074950F016B85" - + "605E57E24651843AB70E41B552EDEE227DFE51E6CBEC00E75FFEFC7D5453" - + "109B15F721FCD811FC9F113BE06050882F2FC5F5FF25857E555CCFB5AB64" - + "8B0D1D7A819A3B05DE1FE89A4A627C60D5AA06CD0F66ACD3748722F9CD4F" - + "F30AE7477CBC12049821F07AD6C9F0ED732321A6A36FA817722E025AC34B" - + "ABE62900002432E3807F595070E95EDA341A787599B24B1151B535B0222B" - + "65C003401B9B38F82900001C000040043BB760DB3037B51768DFFAB4B21D" - + "B1716EA1C1382900001C0000400531098EB04DF1BE3F304606BD59B454A8" - + "CC7E7311290000080000402E290000100000402F00020003000400050000" - + "000800004014"; - final String ikeAuthCreateChildFailHex = - "46B8ECA1E0D72A18F5ABBF896A1240BE2E20232000000001000000B02400" - + "009400B0861242E0C88ECB3848D772B560CAD65B6AC9DFFDC8622A394B8E" - + "64E550BDD69FCD7E768129787ED9062992C1D6DB0F0631C2E05765B403CF" - + "EF1D0A055B32F6698FF7DB5B8FB1B6A83A81634D00E22C86E35B3BFBEC73" - + "EAC6806678926945BC7A57003DC1A3528A1EC423EE56C1075B36C0B57A6B" - + "C6DD990182F6FABFFA167D199C7D629E5B830AAD2AFBD31CEBA6"; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthCreateChildFailHex); - - // Even though the child creation failed, the authentication succeeded, so the IKE Session's - // onOpened() callback is still expected - verifyIkeSessionSetupBlocking(); - - // Verify Child Creation failed - IkeProtocolException protocolException = - (IkeProtocolException) mFirstChildSessionCallback.awaitOnClosedException(); - assertEquals(ERROR_TYPE_TS_UNACCEPTABLE, protocolException.getErrorType()); - assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); - - ikeSession.kill(); - mIkeSessionCallback.awaitOnClosed(); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java deleted file mode 100644 index f954fcd031..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static com.android.internal.util.HexDump.hexStringToByteArray; - -import android.net.InetAddresses; -import android.net.LinkAddress; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeTrafficSelector; -import android.net.ipsec.ike.cts.IkeTunUtils.PortPair; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Explicitly test transport mode Child SA so that devices without FEATURE_IPSEC_TUNNELS can be test - * covered. Tunnel mode Child SA setup has been tested in IkeSessionPskTest. Rekeying process is - * independent from Child SA mode. - */ -@RunWith(AndroidJUnit4.class) -public class IkeSessionRekeyTest extends IkeSessionTestBase { - // This value is align with the test vectors hex that are generated in an IPv4 environment - private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("172.58.35.40"), - InetAddresses.parseNumericAddress("172.58.35.40")); - - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { - IkeSessionParams ikeParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(remoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) - .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) - .setAuthPsk(IKE_PSK) - .build(); - return new IkeSession( - sContext, - ikeParams, - buildTransportModeChildParamsWithTs( - TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), - mUserCbExecutor, - mIkeSessionCallback, - mFirstChildSessionCallback); - } - - private byte[] buildInboundPkt(PortPair outPktSrcDestPortPair, String inboundDataHex) - throws Exception { - // Build inbound packet by flipping the outbound packet addresses and ports - return IkeTunUtils.buildIkePacket( - mRemoteAddress, - mLocalAddress, - outPktSrcDestPortPair.dstPort, - outPktSrcDestPortPair.srcPort, - true /* useEncap */, - hexStringToByteArray(inboundDataHex)); - } - - @Test - public void testRekeyIke() throws Exception { - final String ikeInitResp = - "46B8ECA1E0D72A1866B5248CF6C7472D21202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" - + "0200000500000008040000022800008800020000920D3E830E7276908209212D" - + "E5A7F2A48706CFEF1BE8CB6E3B173B8B4E0D8C2DC626271FF1B13A88619E569E" - + "7B03C3ED2C127390749CDC7CDC711D0A8611E4457FFCBC4F0981B3288FBF58EA" - + "3E8B70E27E76AE70117FBBCB753660ADDA37EB5EB3A81BED6A374CCB7E132C2A" - + "94BFCE402DC76B19C158B533F6B1F2ABF01ACCC329000024B302CA2FB85B6CF4" - + "02313381246E3C53828D787F6DFEA6BD62D6405254AEE6242900001C00004004" - + "7A1682B06B58596533D00324886EF1F20EF276032900001C00004005BF633E31" - + "F9984B29A62E370BB2770FC09BAEA665290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - final String ikeAuthResp = - "46B8ECA1E0D72A1866B5248CF6C7472D2E20232000000001000000F0240000D4" - + "10166CA8647F56123DE74C17FA5E256043ABF73216C812EE32EE1BB01EAF4A82" - + "DC107AB3ADBFEE0DEA5EEE10BDD5D43178F4C975C7C775D252273BB037283C7F" - + "236FE34A6BCE4833816897075DB2055B9FFD66DFA45A0A89A8F70AFB59431EED" - + "A20602FB614369D12906D3355CF7298A5D25364ABBCC75A9D88E0E6581449FCD" - + "4E361A39E00EFD1FD0A69651F63DB46C12470226AA21BA5EFF48FAF0B6DDF61C" - + "B0A69392CE559495EEDB4D1C1D80688434D225D57210A424C213F7C993D8A456" - + "38153FBD194C5E247B592D1D048DB4C8"; - final String rekeyIkeCreateReq = - "46B8ECA1E0D72A1866B5248CF6C7472D2E202400000000000000013021000114" - + "13743670039E308A8409BA5FD47B67F956B36FEE88AC3B70BB5D789B8218A135" - + "1B3D83E260E87B3EDB1BF064F09D4DC2611AEDBC99951B4B2DE767BD4AA2ACC3" - + "3653549CFC66B75869DF003CDC9A137A9CC27776AD5732B34203E74BE8CA4858" - + "1D5C0D9C9CA52D680EB299B4B21C7FA25FFEE174D57015E0FF2EAED653AAD95C" - + "071ABE269A8C2C9FBC1188E07550EB992F910D4CA9689E44BA66DE0FABB2BDF9" - + "8DD377186DBB25EF9B68B027BB2A27981779D8303D88D7CE860010A42862D50B" - + "1E0DBFD3D27C36F14809D7F493B2B96A65534CF98B0C32AD5219AD77F681AC04" - + "9D5CB89A0230A91A243FA7F16251B0D9B4B65E7330BEEAC9663EF4578991EAC8" - + "46C19EBB726E7D113F1D0D601102C05E"; - final String rekeyIkeDeleteReq = - "46B8ECA1E0D72A1866B5248CF6C7472D2E20250000000001000000502A000034" - + "02E40C0C7B1ED977729F705BB9B643FAC513A1070A6EB28ECD2AEA8A441ADC05" - + "7841382A7967BBF116AE52496590B2AD"; - final String deleteIkeReq = - "7D3DEDC65407D1FC9361C8CF8C47162A2E20250800000000000000502A000034" - + "201915C9E4E9173AA9EE79F3E02FE2D4954B22085C66D164762C34D347C16E9F" - + "FC5F7F114428C54D8D915860C57B1BC1"; - final long newIkeDeterministicInitSpi = Long.parseLong("7D3DEDC65407D1FC", 16); - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp); - - // Local request message ID starts from 2 because there is one IKE_INIT message and a single - // IKE_AUTH message. - int expectedReqMsgId = 2; - int expectedRespMsgId = 0; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TRANSPORT_MODE_INBOUND_TS), - Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Inject rekey IKE requests - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeCreateReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeDeleteReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - - // IKE has been rekeyed, reset message IDs - expectedReqMsgId = 0; - expectedRespMsgId = 0; - - // Inject delete IKE request - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq)); - mTunUtils.awaitResp( - newIkeDeterministicInitSpi, expectedRespMsgId++, true /* expectedUseEncap */); - - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); - } - - @Test - public void testRekeyTransportModeChildSa() throws Exception { - final String ikeInitResp = - "46B8ECA1E0D72A18CECD871146CF83A121202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" - + "0200000500000008040000022800008800020000C4904458957746BCF1C12972" - + "1D4E19EB8A584F78DE673053396D167CE0F34552DBC69BA63FE7C673B4CF4A99" - + "62481518EE985357876E8C47BAAA0DBE9C40AE47B12E52165874703586E8F786" - + "045F72EEEB238C5D1823352BED44B71B3214609276ADC0B3D42DAC820168C4E2" - + "660730DAAC92492403288805EBB9053F1AB060DA290000242D9364ACB93519FF" - + "8F8B019BAA43A40D699F59714B327B8382216EF427ED52282900001C00004004" - + "06D91438A0D6B734E152F76F5CC55A72A2E38A0A2900001C000040052EFF78B3" - + "55B37F3CE75AFF26C721B050F892C0D6290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - final String ikeAuthResp = - "46B8ECA1E0D72A18CECD871146CF83A12E20232000000001000000F0240000D4" - + "A17BC258BA2714CF536663639DD5F665A60C75E93557CD5141990A8CEEDD2017" - + "93F5B181C8569FBCD6C2A00198EC2B62D42BEFAC016B8B6BF6A7BC9CEDE3413A" - + "6C495A6B8EC941864DC3E08F57D015EA6520C4B05884960B85478FCA53DA5F17" - + "9628BB1097DA77461C71837207A9EB80720B3E6E661816EE4E14AC995B5E8441" - + "A4C3F9097CC148142BA300076C94A23EC4ADE82B1DD2B121F7E9102860A8C3BF" - + "58DDC207285A3176E924C44DE820322524E1AA438EFDFBA781B36084AED80846" - + "3B77FCED9682B6E4E476408EF3F1037E"; - final String rekeyChildCreateReq = - "46B8ECA1E0D72A18CECD871146CF83A12E202400000000000000015029000134" - + "319D74B6B155B86942143CEC1D29D21F073F24B7BEDC9BFE0F0FDD8BDB5458C0" - + "8DB93506E1A43DD0640FE7370C97F9B34FF4EC9B2DB7257A87B75632301FB68A" - + "86B54871249534CA3D01C9BEB127B669F46470E1C8AAF72574C3CEEC15B901CF" - + "5A0D6ADAE59C3CA64AC8C86689C860FAF9500E608DFE63F2DCD30510FD6FFCD5" - + "A50838574132FD1D069BCACD4C7BAF45C9B1A7689FAD132E3F56DBCFAF905A8C" - + "4145D4BA1B74A54762F8F43308D94DE05649C49D885121CE30681D51AC1E3E68" - + "AB82F9A19B99579AFE257F32DBD1037814DA577379E4F42DEDAC84502E49C933" - + "9EA83F6F5DB4401B660CB1681B023B8603D205DFDD1DE86AD8DE22B6B754F30D" - + "05EAE81A709C2CEE81386133DC3DC7B5EF8F166E48E54A0722DD0C64F4D00638" - + "40F272144C47F6ECED72A248180645DB"; - final String rekeyChildDeleteReq = - "46B8ECA1E0D72A18CECD871146CF83A12E20250000000001000000502A000034" - + "02D98DAF0432EBD991CA4F2D89C1E0EFABC6E91A3327A85D8914FB2F1485BE1B" - + "8D3415D548F7CE0DC4224E7E9D0D3355"; - final String deleteIkeReq = - "46B8ECA1E0D72A18CECD871146CF83A12E20250000000002000000502A000034" - + "095041F4026B4634F04B0AB4F9349484F7BE9AEF03E3733EEE293330043B75D2" - + "ABF5F965ED51127629585E1B1BBA787F"; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp); - - // IKE INIT and IKE AUTH takes two exchanges. Local request message ID starts from 2 - int expectedReqMsgId = 2; - int expectedRespMsgId = 0; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TRANSPORT_MODE_INBOUND_TS), - Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord oldTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord oldTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(oldTransformRecordA, oldTransformRecordB); - - // Inject rekey Child requests - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildCreateReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildDeleteReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - - // Verify IpSecTransforms are renewed - IpSecTransformCallRecord newTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord newTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(newTransformRecordA, newTransformRecordB); - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, oldTransformRecordA, oldTransformRecordB); - - // Inject delete IKE request - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, newTransformRecordA, newTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java deleted file mode 100644 index 6264ceab99..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ /dev/null @@ -1,598 +0,0 @@ -/* - * 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 - * - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.annotation.NonNull; -import android.app.AppOpsManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.InetAddresses; -import android.net.IpSecManager; -import android.net.IpSecTransform; -import android.net.LinkAddress; -import android.net.Network; -import android.net.TestNetworkInterface; -import android.net.TestNetworkManager; -import android.net.annotations.PolicyDirection; -import android.net.ipsec.ike.ChildSessionCallback; -import android.net.ipsec.ike.ChildSessionConfiguration; -import android.net.ipsec.ike.IkeSessionCallback; -import android.net.ipsec.ike.IkeSessionConfiguration; -import android.net.ipsec.ike.IkeSessionConnectionInfo; -import android.net.ipsec.ike.IkeTrafficSelector; -import android.net.ipsec.ike.TransportModeChildSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams; -import android.net.ipsec.ike.cts.IkeTunUtils.PortPair; -import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; -import android.net.ipsec.ike.exceptions.IkeException; -import android.net.ipsec.ike.exceptions.IkeProtocolException; -import android.os.Binder; -import android.os.ParcelFileDescriptor; -import android.platform.test.annotations.AppModeFull; - -import androidx.test.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.compatibility.common.util.SystemUtil; -import com.android.net.module.util.ArrayTrackRecord; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -/** - * Package private base class for testing IkeSessionParams and IKE exchanges. - * - *

    Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use - * the test network - * - *

    All IKE Sessions running in test mode will generate SPIs deterministically. That is to say - * each IKE Session will always generate the same IKE INIT SPI and test vectors are generated based - * on this deterministic IKE SPI. Each test will use different local and remote addresses to avoid - * the case that the next test try to allocate the same SPI before the previous test has released - * it, since SPI resources are not released in testing thread. Similarly, each test MUST use - * different Network instances to avoid sharing the same IkeSocket and hitting IKE SPI collision. - */ -@RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") -abstract class IkeSessionTestBase extends IkeTestBase { - // Package-wide common expected results that will be shared by all IKE/Child SA creation tests - static final String EXPECTED_REMOTE_APP_VERSION_EMPTY = ""; - static final byte[] EXPECTED_PROTOCOL_ERROR_DATA_NONE = new byte[0]; - - static final InetAddress EXPECTED_DNS_SERVERS_ONE = - InetAddresses.parseNumericAddress("8.8.8.8"); - static final InetAddress EXPECTED_DNS_SERVERS_TWO = - InetAddresses.parseNumericAddress("8.8.4.4"); - - static final InetAddress EXPECTED_INTERNAL_ADDR = - InetAddresses.parseNumericAddress("198.51.100.10"); - static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR = - new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN); - static final InetAddress EXPECTED_INTERNAL_ADDR_V6 = - InetAddresses.parseNumericAddress("2001:db8::2"); - static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR_V6 = - new LinkAddress(EXPECTED_INTERNAL_ADDR_V6, IP6_PREFIX_LEN); - - static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); - static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS; - static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS_V6 = - new IkeTrafficSelector( - MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR_V6, EXPECTED_INTERNAL_ADDR_V6); - static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS_V6 = DEFAULT_V6_TS; - - // This value is align with the test vectors hex that are generated in an IPv4 environment - static final IkeTrafficSelector TRANSPORT_MODE_OUTBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("10.138.0.2"), - InetAddresses.parseNumericAddress("10.138.0.2")); - - static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); - - // Static state to reduce setup/teardown - static Context sContext = InstrumentationRegistry.getContext(); - static ConnectivityManager sCM = - (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); - static TestNetworkManager sTNM; - - private static final int TIMEOUT_MS = 500; - - // Constants to be used for providing different IP addresses for each tests - private static final byte IP_ADDR_LAST_BYTE_MAX = (byte) 100; - private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_LOCAL = - InetAddresses.parseNumericAddress("192.0.2.1").getAddress(); - private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_REMOTE = - InetAddresses.parseNumericAddress("198.51.100.1").getAddress(); - private static final byte[] NEXT_AVAILABLE_IP4_ADDR_LOCAL = INITIAL_AVAILABLE_IP4_ADDR_LOCAL; - private static final byte[] NEXT_AVAILABLE_IP4_ADDR_REMOTE = INITIAL_AVAILABLE_IP4_ADDR_REMOTE; - - ParcelFileDescriptor mTunFd; - TestNetworkCallback mTunNetworkCallback; - Network mTunNetwork; - IkeTunUtils mTunUtils; - - InetAddress mLocalAddress; - InetAddress mRemoteAddress; - - Executor mUserCbExecutor; - TestIkeSessionCallback mIkeSessionCallback; - TestChildSessionCallback mFirstChildSessionCallback; - - // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass - // methods. - @BeforeClass - public static void setUpPermissionBeforeClass() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(); - sTNM = sContext.getSystemService(TestNetworkManager.class); - } - - // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass - // methods. - @AfterClass - public static void tearDownPermissionAfterClass() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .dropShellPermissionIdentity(); - } - - @Before - public void setUp() throws Exception { - mLocalAddress = getNextAvailableIpv4AddressLocal(); - mRemoteAddress = getNextAvailableIpv4AddressRemote(); - setUpTestNetwork(mLocalAddress); - - mUserCbExecutor = Executors.newSingleThreadExecutor(); - mIkeSessionCallback = new TestIkeSessionCallback(); - mFirstChildSessionCallback = new TestChildSessionCallback(); - } - - @After - public void tearDown() throws Exception { - tearDownTestNetwork(); - } - - void setUpTestNetwork(InetAddress localAddr) throws Exception { - int prefixLen = localAddr instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN; - - TestNetworkInterface testIface = - sTNM.createTunInterface(new LinkAddress[] {new LinkAddress(localAddr, prefixLen)}); - - mTunFd = testIface.getFileDescriptor(); - mTunNetworkCallback = - TestNetworkUtils.setupAndGetTestNetwork( - sCM, sTNM, testIface.getInterfaceName(), new Binder()); - mTunNetwork = mTunNetworkCallback.getNetworkBlocking(); - mTunUtils = new IkeTunUtils(mTunFd); - } - - void tearDownTestNetwork() throws Exception { - sCM.unregisterNetworkCallback(mTunNetworkCallback); - - sTNM.teardownTestNetwork(mTunNetwork); - mTunFd.close(); - } - - static void setAppOp(int appop, boolean allow) { - String opName = AppOpsManager.opToName(appop); - for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { - String cmd = - String.format( - "appops set %s %s %s", - pkg, // Package name - opName, // Appop - (allow ? "allow" : "deny")); // Action - - SystemUtil.runShellCommand(cmd); - } - } - - Inet4Address getNextAvailableIpv4AddressLocal() throws Exception { - return (Inet4Address) - getNextAvailableAddress( - NEXT_AVAILABLE_IP4_ADDR_LOCAL, - INITIAL_AVAILABLE_IP4_ADDR_LOCAL, - false /* isIp6 */); - } - - Inet4Address getNextAvailableIpv4AddressRemote() throws Exception { - return (Inet4Address) - getNextAvailableAddress( - NEXT_AVAILABLE_IP4_ADDR_REMOTE, - INITIAL_AVAILABLE_IP4_ADDR_REMOTE, - false /* isIp6 */); - } - - InetAddress getNextAvailableAddress( - byte[] nextAddressBytes, byte[] initialAddressBytes, boolean isIp6) throws Exception { - int addressLen = isIp6 ? IP6_ADDRESS_LEN : IP4_ADDRESS_LEN; - - synchronized (nextAddressBytes) { - if (nextAddressBytes[addressLen - 1] == IP_ADDR_LAST_BYTE_MAX) { - resetNextAvailableAddress(nextAddressBytes, initialAddressBytes); - } - - InetAddress address = InetAddress.getByAddress(nextAddressBytes); - nextAddressBytes[addressLen - 1]++; - return address; - } - } - - private void resetNextAvailableAddress(byte[] nextAddressBytes, byte[] initialAddressBytes) { - synchronized (nextAddressBytes) { - System.arraycopy( - nextAddressBytes, 0, initialAddressBytes, 0, initialAddressBytes.length); - } - } - - TransportModeChildSessionParams buildTransportModeChildParamsWithTs( - IkeTrafficSelector inboundTs, IkeTrafficSelector outboundTs) { - return new TransportModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .addInboundTrafficSelectors(inboundTs) - .addOutboundTrafficSelectors(outboundTs) - .build(); - } - - TransportModeChildSessionParams buildTransportModeChildParamsWithDefaultTs() { - return new TransportModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .build(); - } - - TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { - return new TunnelModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addInternalAddressRequest(AF_INET) - .addInternalAddressRequest(AF_INET6) - .build(); - } - - PortPair performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) - throws Exception { - return performSetupIkeAndFirstChildBlocking( - ikeInitRespHex, - 1 /* expectedAuthReqPktCnt */, - true /*expectedAuthUseEncap*/, - ikeAuthRespHexes); - } - - PortPair performSetupIkeAndFirstChildBlocking( - String ikeInitRespHex, boolean expectedAuthUseEncap, String... ikeAuthRespHexes) - throws Exception { - return performSetupIkeAndFirstChildBlocking( - ikeInitRespHex, - 1 /* expectedAuthReqPktCnt */, - expectedAuthUseEncap, - ikeAuthRespHexes); - } - - PortPair performSetupIkeAndFirstChildBlocking( - String ikeInitRespHex, - int expectedAuthReqPktCnt, - boolean expectedAuthUseEncap, - String... ikeAuthRespHexes) - throws Exception { - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 0 /* expectedMsgId */, - false /* expectedUseEncap */, - ikeInitRespHex); - - byte[] ikeAuthReqPkt = - mTunUtils - .awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 1 /* expectedMsgId */, - expectedAuthUseEncap, - expectedAuthReqPktCnt, - ikeAuthRespHexes) - .get(0); - return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt); - } - - void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { - performCloseIkeBlocking(expectedMsgId, true /* expectedUseEncap*/, deleteIkeRespHex); - } - - void performCloseIkeBlocking( - int expectedMsgId, boolean expectedUseEncap, String deleteIkeRespHex) throws Exception { - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId, expectedUseEncap, deleteIkeRespHex); - } - - /** Testing callback that allows caller to block current thread until a method get called */ - static class TestIkeSessionCallback implements IkeSessionCallback { - private CompletableFuture mFutureIkeConfig = - new CompletableFuture<>(); - private CompletableFuture mFutureOnClosedCall = new CompletableFuture<>(); - private CompletableFuture mFutureOnClosedException = - new CompletableFuture<>(); - - private int mOnErrorExceptionsCount = 0; - private ArrayTrackRecord mOnErrorExceptionsTrackRecord = - new ArrayTrackRecord<>(); - - @Override - public void onOpened(@NonNull IkeSessionConfiguration sessionConfiguration) { - mFutureIkeConfig.complete(sessionConfiguration); - } - - @Override - public void onClosed() { - mFutureOnClosedCall.complete(true /* unused */); - } - - @Override - public void onClosedExceptionally(@NonNull IkeException exception) { - mFutureOnClosedException.complete(exception); - } - - @Override - public void onError(@NonNull IkeProtocolException exception) { - mOnErrorExceptionsTrackRecord.add(exception); - } - - public IkeSessionConfiguration awaitIkeConfig() throws Exception { - return mFutureIkeConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - public IkeException awaitOnClosedException() throws Exception { - return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - public IkeProtocolException awaitNextOnErrorException() { - return mOnErrorExceptionsTrackRecord.poll( - (long) TIMEOUT_MS, - mOnErrorExceptionsCount++, - (transform) -> { - return true; - }); - } - - public void awaitOnClosed() throws Exception { - mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - } - - /** Testing callback that allows caller to block current thread until a method get called */ - static class TestChildSessionCallback implements ChildSessionCallback { - private CompletableFuture mFutureChildConfig = - new CompletableFuture<>(); - private CompletableFuture mFutureOnClosedCall = new CompletableFuture<>(); - private CompletableFuture mFutureOnClosedException = - new CompletableFuture<>(); - - private int mCreatedIpSecTransformCount = 0; - private int mDeletedIpSecTransformCount = 0; - private ArrayTrackRecord mCreatedIpSecTransformsTrackRecord = - new ArrayTrackRecord<>(); - private ArrayTrackRecord mDeletedIpSecTransformsTrackRecord = - new ArrayTrackRecord<>(); - - @Override - public void onOpened(@NonNull ChildSessionConfiguration sessionConfiguration) { - mFutureChildConfig.complete(sessionConfiguration); - } - - @Override - public void onClosed() { - mFutureOnClosedCall.complete(true /* unused */); - } - - @Override - public void onClosedExceptionally(@NonNull IkeException exception) { - mFutureOnClosedException.complete(exception); - } - - @Override - public void onIpSecTransformCreated(@NonNull IpSecTransform ipSecTransform, int direction) { - mCreatedIpSecTransformsTrackRecord.add( - new IpSecTransformCallRecord(ipSecTransform, direction)); - } - - @Override - public void onIpSecTransformDeleted(@NonNull IpSecTransform ipSecTransform, int direction) { - mDeletedIpSecTransformsTrackRecord.add( - new IpSecTransformCallRecord(ipSecTransform, direction)); - } - - public ChildSessionConfiguration awaitChildConfig() throws Exception { - return mFutureChildConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - public IkeException awaitOnClosedException() throws Exception { - return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - public IpSecTransformCallRecord awaitNextCreatedIpSecTransform() { - return mCreatedIpSecTransformsTrackRecord.poll( - (long) TIMEOUT_MS, - mCreatedIpSecTransformCount++, - (transform) -> { - return true; - }); - } - - public IpSecTransformCallRecord awaitNextDeletedIpSecTransform() { - return mDeletedIpSecTransformsTrackRecord.poll( - (long) TIMEOUT_MS, - mDeletedIpSecTransformCount++, - (transform) -> { - return true; - }); - } - - public void awaitOnClosed() throws Exception { - mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - } - - /** - * This class represents a created or deleted IpSecTransfrom that is provided by - * ChildSessionCallback - */ - static class IpSecTransformCallRecord { - public final IpSecTransform ipSecTransform; - public final int direction; - - IpSecTransformCallRecord(IpSecTransform ipSecTransform, @PolicyDirection int direction) { - this.ipSecTransform = ipSecTransform; - this.direction = direction; - } - - @Override - public int hashCode() { - return Objects.hash(ipSecTransform, direction); - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof IpSecTransformCallRecord)) return false; - - IpSecTransformCallRecord record = (IpSecTransformCallRecord) o; - return ipSecTransform.equals(record.ipSecTransform) && direction == record.direction; - } - } - - void verifyIkeSessionSetupBlocking() throws Exception { - IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); - assertNotNull(ikeConfig); - assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); - assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); - assertTrue(ikeConfig.getPcscfServers().isEmpty()); - assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); - - IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); - assertNotNull(ikeConnectInfo); - assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); - assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); - assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); - } - - void verifyChildSessionSetupBlocking( - TestChildSessionCallback childCallback, - List expectedInboundTs, - List expectedOutboundTs, - List expectedInternalAddresses) - throws Exception { - verifyChildSessionSetupBlocking( - childCallback, - expectedInboundTs, - expectedOutboundTs, - expectedInternalAddresses, - new ArrayList() /* expectedDnsServers */); - } - - void verifyChildSessionSetupBlocking( - TestChildSessionCallback childCallback, - List expectedInboundTs, - List expectedOutboundTs, - List expectedInternalAddresses, - List expectedDnsServers) - throws Exception { - ChildSessionConfiguration childConfig = childCallback.awaitChildConfig(); - assertNotNull(childConfig); - assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors()); - assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors()); - assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses()); - assertEquals(expectedDnsServers, childConfig.getInternalDnsServers()); - assertTrue(childConfig.getInternalSubnets().isEmpty()); - assertTrue(childConfig.getInternalDhcpServers().isEmpty()); - } - - void verifyCloseIkeAndChildBlocking( - IpSecTransformCallRecord expectedTransformRecordA, - IpSecTransformCallRecord expectedTransformRecordB) - throws Exception { - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, expectedTransformRecordA, expectedTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); - } - - static void verifyCreateIpSecTransformPair( - IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) { - IpSecTransform transformA = transformRecordA.ipSecTransform; - IpSecTransform transformB = transformRecordB.ipSecTransform; - - assertNotNull(transformA); - assertNotNull(transformB); - - Set expectedDirections = new HashSet<>(); - expectedDirections.add(IpSecManager.DIRECTION_IN); - expectedDirections.add(IpSecManager.DIRECTION_OUT); - - Set resultDirections = new HashSet<>(); - resultDirections.add(transformRecordA.direction); - resultDirections.add(transformRecordB.direction); - - assertEquals(expectedDirections, resultDirections); - } - - static void verifyDeleteIpSecTransformPair( - TestChildSessionCallback childCb, - IpSecTransformCallRecord expectedTransformRecordA, - IpSecTransformCallRecord expectedTransformRecordB) { - Set expectedTransforms = new HashSet<>(); - expectedTransforms.add(expectedTransformRecordA); - expectedTransforms.add(expectedTransformRecordB); - - Set resultTransforms = new HashSet<>(); - resultTransforms.add(childCb.awaitNextDeletedIpSecTransform()); - resultTransforms.add(childCb.awaitNextDeletedIpSecTransform()); - - assertEquals(expectedTransforms, resultTransforms); - } - - /** Package private method to check if device has IPsec tunnels feature */ - static boolean hasTunnelsFeature() { - return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); - } - - // TODO(b/148689509): Verify hostname based creation -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java deleted file mode 100644 index c70e5372ec..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.net.InetAddresses; -import android.net.ipsec.ike.IkeTrafficSelector; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** Shared parameters and util methods for testing different components of IKE */ -abstract class IkeTestBase { - static final int MIN_PORT = 0; - static final int MAX_PORT = 65535; - private static final int INBOUND_TS_START_PORT = MIN_PORT; - private static final int INBOUND_TS_END_PORT = 65520; - private static final int OUTBOUND_TS_START_PORT = 16; - private static final int OUTBOUND_TS_END_PORT = MAX_PORT; - - static final int IP4_ADDRESS_LEN = 4; - static final int IP6_ADDRESS_LEN = 16; - static final int IP4_PREFIX_LEN = 32; - static final int IP6_PREFIX_LEN = 64; - - static final byte[] IKE_PSK = "ikeAndroidPsk".getBytes(); - - static final String LOCAL_HOSTNAME = "client.test.ike.android.net"; - static final String REMOTE_HOSTNAME = "server.test.ike.android.net"; - static final String LOCAL_ASN1_DN_STRING = "CN=client.test.ike.android.net, O=Android, C=US"; - static final String LOCAL_RFC822_NAME = "client.test.ike@example.com"; - static final byte[] LOCAL_KEY_ID = "Local Key ID".getBytes(); - - static final int SUB_ID = 1; - static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); - static final String NETWORK_NAME = "android.net"; - static final String EAP_MSCHAPV2_USERNAME = "mschapv2user"; - static final String EAP_MSCHAPV2_PASSWORD = "password"; - - static final Inet4Address IPV4_ADDRESS_LOCAL = - (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); - static final Inet4Address IPV4_ADDRESS_REMOTE = - (Inet4Address) (InetAddresses.parseNumericAddress("198.51.100.100")); - static final Inet6Address IPV6_ADDRESS_LOCAL = - (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8::100")); - static final Inet6Address IPV6_ADDRESS_REMOTE = - (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8:255::100")); - - static final InetAddress PCSCF_IPV4_ADDRESS_1 = InetAddresses.parseNumericAddress("192.0.2.1"); - static final InetAddress PCSCF_IPV4_ADDRESS_2 = InetAddresses.parseNumericAddress("192.0.2.2"); - static final InetAddress PCSCF_IPV6_ADDRESS_1 = - InetAddresses.parseNumericAddress("2001:DB8::1"); - static final InetAddress PCSCF_IPV6_ADDRESS_2 = - InetAddresses.parseNumericAddress("2001:DB8::2"); - - static final IkeTrafficSelector DEFAULT_V4_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("0.0.0.0"), - InetAddresses.parseNumericAddress("255.255.255.255")); - static final IkeTrafficSelector DEFAULT_V6_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("::"), - InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - static final IkeTrafficSelector INBOUND_V4_TS = - new IkeTrafficSelector( - INBOUND_TS_START_PORT, - INBOUND_TS_END_PORT, - InetAddresses.parseNumericAddress("192.0.2.10"), - InetAddresses.parseNumericAddress("192.0.2.20")); - static final IkeTrafficSelector OUTBOUND_V4_TS = - new IkeTrafficSelector( - OUTBOUND_TS_START_PORT, - OUTBOUND_TS_END_PORT, - InetAddresses.parseNumericAddress("198.51.100.0"), - InetAddresses.parseNumericAddress("198.51.100.255")); - - static final IkeTrafficSelector INBOUND_V6_TS = - new IkeTrafficSelector( - INBOUND_TS_START_PORT, - INBOUND_TS_END_PORT, - InetAddresses.parseNumericAddress("2001:db8::10"), - InetAddresses.parseNumericAddress("2001:db8::128")); - static final IkeTrafficSelector OUTBOUND_V6_TS = - new IkeTrafficSelector( - OUTBOUND_TS_START_PORT, - OUTBOUND_TS_END_PORT, - InetAddresses.parseNumericAddress("2001:db8:255::64"), - InetAddresses.parseNumericAddress("2001:db8:255::255")); - - // Verify Config requests in TunnelModeChildSessionParams and IkeSessionParams - void verifyConfigRequestTypes( - Map, Integer> expectedReqCntMap, List resultReqList) { - Map, Integer> resultReqCntMap = new HashMap<>(); - - // Verify that every config request type in resultReqList is expected, and build - // resultReqCntMap at the same time - for (T resultReq : resultReqList) { - boolean isResultReqExpected = false; - - for (Class expectedReqInterface : expectedReqCntMap.keySet()) { - if (expectedReqInterface.isInstance(resultReq)) { - isResultReqExpected = true; - - resultReqCntMap.put( - expectedReqInterface, - resultReqCntMap.getOrDefault(expectedReqInterface, 0) + 1); - } - } - - if (!isResultReqExpected) { - fail("Failed due to unexpected config request " + resultReq); - } - } - - assertEquals(expectedReqCntMap, resultReqCntMap); - - // TODO: Think of a neat way to validate both counts and values in this method. Probably can - // build Runnables as validators for count and values. - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java deleted file mode 100644 index 41cbf0baa1..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.cts.PacketUtils.BytePayload; -import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.Ip4Header; -import static android.net.ipsec.ike.cts.PacketUtils.Ip6Header; -import static android.net.ipsec.ike.cts.PacketUtils.IpHeader; -import static android.net.ipsec.ike.cts.PacketUtils.Payload; -import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader; -import static android.system.OsConstants.IPPROTO_UDP; - -import static com.android.internal.util.HexDump.hexStringToByteArray; - -import static org.junit.Assert.fail; - -import android.os.ParcelFileDescriptor; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.Predicate; - -public class IkeTunUtils extends TunUtils { - private static final int PORT_LEN = 2; - - private static final int NON_ESP_MARKER_LEN = 4; - private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN]; - - private static final int IKE_INIT_SPI_OFFSET = 0; - private static final int IKE_FIRST_PAYLOAD_OFFSET = 16; - private static final int IKE_IS_RESP_BYTE_OFFSET = 19; - private static final int IKE_MSG_ID_OFFSET = 20; - private static final int IKE_HEADER_LEN = 28; - private static final int IKE_FRAG_NUM_OFFSET = 32; - private static final int IKE_PAYLOAD_TYPE_SKF = 53; - - private static final int RSP_FLAG_MASK = 0x20; - - public IkeTunUtils(ParcelFileDescriptor tunFd) { - super(tunFd); - } - - /** - * Await the expected IKE request inject an IKE response (or a list of response fragments) - * - * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without - * IP/UDP headers or NON ESP MARKER. - */ - public byte[] awaitReqAndInjectResp( - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedUseEncap, - String... ikeRespDataFragmentsHex) - throws Exception { - return awaitReqAndInjectResp( - expectedInitIkeSpi, - expectedMsgId, - expectedUseEncap, - 1 /* expectedReqPktCnt */, - ikeRespDataFragmentsHex) - .get(0); - } - - /** - * Await the expected IKE request (or the list of IKE request fragments) and inject an IKE - * response (or a list of response fragments) - * - * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without - * IP/UDP headers or NON ESP MARKER. - */ - public List awaitReqAndInjectResp( - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedUseEncap, - int expectedReqPktCnt, - String... ikeRespDataFragmentsHex) - throws Exception { - List reqList = new ArrayList<>(expectedReqPktCnt); - if (expectedReqPktCnt == 1) { - // Expecting one complete IKE packet - byte[] req = - awaitIkePacket( - (pkt) -> { - return isExpectedIkePkt( - pkt, - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap); - }); - reqList.add(req); - } else { - // Expecting "expectedReqPktCnt" number of request fragments - for (int i = 0; i < expectedReqPktCnt; i++) { - // IKE Fragment number always starts from 1 - int expectedFragNum = i + 1; - byte[] req = - awaitIkePacket( - (pkt) -> { - return isExpectedIkeFragPkt( - pkt, - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap, - expectedFragNum); - }); - reqList.add(req); - } - } - - // All request fragments have the same addresses and ports - byte[] request = reqList.get(0); - - // Build response header by flipping address and port - InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); - InetAddress dstAddr = getAddress(request, true /* shouldGetSource */); - int srcPort = getPort(request, false /* shouldGetSource */); - int dstPort = getPort(request, true /* shouldGetSource */); - for (String resp : ikeRespDataFragmentsHex) { - byte[] response = - buildIkePacket( - srcAddr, - dstAddr, - srcPort, - dstPort, - expectedUseEncap, - hexStringToByteArray(resp)); - injectPacket(response); - } - - return reqList; - } - - /** Await the expected IKE response */ - public byte[] awaitResp(long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap) - throws Exception { - return awaitIkePacket( - (pkt) -> { - return isExpectedIkePkt( - pkt, - expectedInitIkeSpi, - expectedMsgId, - true /* expectedResp*/, - expectedUseEncap); - }); - } - - private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { - long endTime = System.currentTimeMillis() + TIMEOUT; - int startIndex = 0; - synchronized (mPackets) { - while (System.currentTimeMillis() < endTime) { - byte[] ikePkt = getFirstMatchingPacket(pktVerifier, startIndex); - if (ikePkt != null) { - return ikePkt; // We've found the packet we're looking for. - } - - startIndex = mPackets.size(); - - // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout - long waitTimeout = endTime - System.currentTimeMillis(); - if (waitTimeout > 0) { - mPackets.wait(waitTimeout); - } - } - - fail("No matching packet found"); - } - - throw new IllegalStateException( - "Hit an impossible case where fail() didn't throw an exception"); - } - - private static boolean isExpectedIkePkt( - byte[] pkt, - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp, - boolean expectedUseEncap) { - int ipProtocolOffset = isIpv6(pkt) ? IP6_PROTO_OFFSET : IP4_PROTO_OFFSET; - int ikeOffset = getIkeOffset(pkt, expectedUseEncap); - - return pkt[ipProtocolOffset] == IPPROTO_UDP - && expectedUseEncap == hasNonEspMarker(pkt) - && isExpectedSpiAndMsgId( - pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); - } - - private static boolean isExpectedIkeFragPkt( - byte[] pkt, - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp, - boolean expectedUseEncap, - int expectedFragNum) { - return isExpectedIkePkt( - pkt, expectedInitIkeSpi, expectedMsgId, expectedResp, expectedUseEncap) - && isExpectedFragNum(pkt, getIkeOffset(pkt, expectedUseEncap), expectedFragNum); - } - - private static int getIkeOffset(byte[] pkt, boolean useEncap) { - if (isIpv6(pkt)) { - // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap. - return IP6_HDRLEN + UDP_HDRLEN; - } else { - // Use default IPv4 header length (assuming no options) - int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; - return useEncap ? ikeOffset + NON_ESP_MARKER_LEN : ikeOffset; - } - } - - private static boolean hasNonEspMarker(byte[] pkt) { - ByteBuffer buffer = ByteBuffer.wrap(pkt); - int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; - if (buffer.remaining() < ikeOffset) return false; - - buffer.get(new byte[ikeOffset]); // Skip IP and UDP header - byte[] nonEspMarker = new byte[NON_ESP_MARKER_LEN]; - if (buffer.remaining() < NON_ESP_MARKER_LEN) return false; - - buffer.get(nonEspMarker); - return Arrays.equals(NON_ESP_MARKER, nonEspMarker); - } - - private static boolean isExpectedSpiAndMsgId( - byte[] pkt, - int ikeOffset, - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp) { - if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false; - - ByteBuffer buffer = ByteBuffer.wrap(pkt); - buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER) - buffer.mark(); // Mark this position so that later we can reset back here - - // Check SPI - buffer.get(new byte[IKE_INIT_SPI_OFFSET]); - long initSpi = buffer.getLong(); - if (expectedInitIkeSpi != initSpi) { - return false; - } - - // Check direction - buffer.reset(); - buffer.get(new byte[IKE_IS_RESP_BYTE_OFFSET]); - byte flagsByte = buffer.get(); - boolean isResp = ((flagsByte & RSP_FLAG_MASK) != 0); - if (expectedResp != isResp) { - return false; - } - - // Check message ID - buffer.reset(); - buffer.get(new byte[IKE_MSG_ID_OFFSET]); - - // Both the expected message ID and the packet's msgId are signed integers, so directly - // compare them. - int msgId = buffer.getInt(); - if (expectedMsgId != msgId) { - return false; - } - - return true; - } - - private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) { - ByteBuffer buffer = ByteBuffer.wrap(pkt); - buffer.get(new byte[ikeOffset]); - buffer.mark(); // Mark this position so that later we can reset back here - - // Check if it is a fragment packet - buffer.get(new byte[IKE_FIRST_PAYLOAD_OFFSET]); - int firstPayload = Byte.toUnsignedInt(buffer.get()); - if (firstPayload != IKE_PAYLOAD_TYPE_SKF) { - return false; - } - - // Check fragment number - buffer.reset(); - buffer.get(new byte[IKE_FRAG_NUM_OFFSET]); - int fragNum = Short.toUnsignedInt(buffer.getShort()); - return expectedFragNum == fragNum; - } - - public static class PortPair { - public final int srcPort; - public final int dstPort; - - public PortPair(int sourcePort, int destinationPort) { - srcPort = sourcePort; - dstPort = destinationPort; - } - } - - public static PortPair getSrcDestPortPair(byte[] outboundIkePkt) throws Exception { - return new PortPair( - getPort(outboundIkePkt, true /* shouldGetSource */), - getPort(outboundIkePkt, false /* shouldGetSource */)); - } - - private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { - int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; - int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; - int ipOffset = shouldGetSource ? srcIpOffset : srcIpOffset + ipLen; - - ByteBuffer buffer = ByteBuffer.wrap(pkt); - buffer.get(new byte[ipOffset]); - byte[] ipAddrBytes = new byte[ipLen]; - buffer.get(ipAddrBytes); - return InetAddress.getByAddress(ipAddrBytes); - } - - private static int getPort(byte[] pkt, boolean shouldGetSource) { - ByteBuffer buffer = ByteBuffer.wrap(pkt); - int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; - int portOffset = shouldGetSource ? srcPortOffset : srcPortOffset + PORT_LEN; - - buffer.get(new byte[portOffset]); - return Short.toUnsignedInt(buffer.getShort()); - } - - public static byte[] buildIkePacket( - InetAddress srcAddr, - InetAddress dstAddr, - int srcPort, - int dstPort, - boolean useEncap, - byte[] ikePacket) - throws Exception { - if (useEncap) { - ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER_LEN + ikePacket.length); - buffer.put(NON_ESP_MARKER); - buffer.put(ikePacket); - ikePacket = buffer.array(); - } - - UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(ikePacket)); - IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt); - return ipPkt.getPacketBytes(); - } - - private static IpHeader getIpHeader( - int protocol, InetAddress src, InetAddress dst, Payload payload) { - if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { - throw new IllegalArgumentException("Invalid src/dst address combination"); - } - - if (src instanceof Inet6Address) { - return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); - } else { - return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); - } - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java deleted file mode 100644 index 35e6719fb7..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java +++ /dev/null @@ -1,467 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.system.OsConstants.IPPROTO_IPV6; -import static android.system.OsConstants.IPPROTO_UDP; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ShortBuffer; -import java.security.GeneralSecurityException; -import java.security.SecureRandom; -import java.util.Arrays; - -import javax.crypto.Cipher; -import javax.crypto.Mac; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -/** - * This code is a exact copy of {@link PacketUtils} in - * cts/tests/tests/net/src/android/net/cts/PacketUtils.java. - * - *

    TODO(b/148689509): Statically include the PacketUtils source file instead of copying it. - */ -public class PacketUtils { - private static final String TAG = PacketUtils.class.getSimpleName(); - - private static final int DATA_BUFFER_LEN = 4096; - - static final int IP4_HDRLEN = 20; - static final int IP6_HDRLEN = 40; - static final int UDP_HDRLEN = 8; - static final int TCP_HDRLEN = 20; - static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12; - - // Not defined in OsConstants - static final int IPPROTO_IPV4 = 4; - static final int IPPROTO_ESP = 50; - - // Encryption parameters - static final int AES_GCM_IV_LEN = 8; - static final int AES_CBC_IV_LEN = 16; - static final int AES_GCM_BLK_SIZE = 4; - static final int AES_CBC_BLK_SIZE = 16; - - // Encryption algorithms - static final String AES = "AES"; - static final String AES_CBC = "AES/CBC/NoPadding"; - static final String HMAC_SHA_256 = "HmacSHA256"; - - public interface Payload { - byte[] getPacketBytes(IpHeader header) throws Exception; - - void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception; - - short length(); - - int getProtocolId(); - } - - public abstract static class IpHeader { - - public final byte proto; - public final InetAddress srcAddr; - public final InetAddress dstAddr; - public final Payload payload; - - public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) { - this.proto = (byte) proto; - this.srcAddr = src; - this.dstAddr = dst; - this.payload = payload; - } - - public abstract byte[] getPacketBytes() throws Exception; - - public abstract int getProtocolId(); - } - - public static class Ip4Header extends IpHeader { - private short checksum; - - public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) { - super(proto, src, dst, payload); - } - - public byte[] getPacketBytes() throws Exception { - ByteBuffer resultBuffer = buildHeader(); - payload.addPacketBytes(this, resultBuffer); - - return getByteArrayFromBuffer(resultBuffer); - } - - public ByteBuffer buildHeader() { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - // Version, IHL - bb.put((byte) (0x45)); - - // DCSP, ECN - bb.put((byte) 0); - - // Total Length - bb.putShort((short) (IP4_HDRLEN + payload.length())); - - // Empty for Identification, Flags and Fragment Offset - bb.putShort((short) 0); - bb.put((byte) 0x40); - bb.put((byte) 0x00); - - // TTL - bb.put((byte) 64); - - // Protocol - bb.put(proto); - - // Header Checksum - final int ipChecksumOffset = bb.position(); - bb.putShort((short) 0); - - // Src/Dst addresses - bb.put(srcAddr.getAddress()); - bb.put(dstAddr.getAddress()); - - bb.putShort(ipChecksumOffset, calculateChecksum(bb)); - - return bb; - } - - private short calculateChecksum(ByteBuffer bb) { - int checksum = 0; - - // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit - // aligned, so no special cases needed for unaligned values. - ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer(); - while (shortBuffer.hasRemaining()) { - short val = shortBuffer.get(); - - // Wrap as needed - checksum = addAndWrapForChecksum(checksum, val); - } - - return onesComplement(checksum); - } - - public int getProtocolId() { - return IPPROTO_IPV4; - } - } - - public static class Ip6Header extends IpHeader { - public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) { - super(nextHeader, src, dst, payload); - } - - public byte[] getPacketBytes() throws Exception { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - // Version | Traffic Class (First 4 bits) - bb.put((byte) 0x60); - - // Traffic class (Last 4 bits), Flow Label - bb.put((byte) 0); - bb.put((byte) 0); - bb.put((byte) 0); - - // Payload Length - bb.putShort((short) payload.length()); - - // Next Header - bb.put(proto); - - // Hop Limit - bb.put((byte) 64); - - // Src/Dst addresses - bb.put(srcAddr.getAddress()); - bb.put(dstAddr.getAddress()); - - // Payload - payload.addPacketBytes(this, bb); - - return getByteArrayFromBuffer(bb); - } - - public int getProtocolId() { - return IPPROTO_IPV6; - } - } - - public static class BytePayload implements Payload { - public final byte[] payload; - - public BytePayload(byte[] payload) { - this.payload = payload; - } - - public int getProtocolId() { - return -1; - } - - public byte[] getPacketBytes(IpHeader header) { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - addPacketBytes(header, bb); - return getByteArrayFromBuffer(bb); - } - - public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) { - resultBuffer.put(payload); - } - - public short length() { - return (short) payload.length; - } - } - - public static class UdpHeader implements Payload { - - public final short srcPort; - public final short dstPort; - public final Payload payload; - - public UdpHeader(int srcPort, int dstPort, Payload payload) { - this.srcPort = (short) srcPort; - this.dstPort = (short) dstPort; - this.payload = payload; - } - - public int getProtocolId() { - return IPPROTO_UDP; - } - - public short length() { - return (short) (payload.length() + 8); - } - - public byte[] getPacketBytes(IpHeader header) throws Exception { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - addPacketBytes(header, bb); - return getByteArrayFromBuffer(bb); - } - - public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { - // Source, Destination port - resultBuffer.putShort(srcPort); - resultBuffer.putShort(dstPort); - - // Payload Length - resultBuffer.putShort(length()); - - // Get payload bytes for checksum + payload - ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); - payload.addPacketBytes(header, payloadBuffer); - byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer); - - // Checksum - resultBuffer.putShort(calculateChecksum(header, payloadBytes)); - - // Payload - resultBuffer.put(payloadBytes); - } - - private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception { - int newChecksum = 0; - ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer(); - ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer(); - - while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) { - short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get(); - - // Wrap as needed - newChecksum = addAndWrapForChecksum(newChecksum, val); - } - - // Add pseudo-header values. Proto is 0-padded, so just use the byte. - newChecksum = addAndWrapForChecksum(newChecksum, header.proto); - newChecksum = addAndWrapForChecksum(newChecksum, length()); - newChecksum = addAndWrapForChecksum(newChecksum, srcPort); - newChecksum = addAndWrapForChecksum(newChecksum, dstPort); - newChecksum = addAndWrapForChecksum(newChecksum, length()); - - ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer(); - while (payloadShortBuffer.hasRemaining()) { - newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get()); - } - if (payload.length() % 2 != 0) { - newChecksum = - addAndWrapForChecksum( - newChecksum, (payloadBytes[payloadBytes.length - 1] << 8)); - } - - return onesComplement(newChecksum); - } - } - - public static class EspHeader implements Payload { - public final int nextHeader; - public final int spi; - public final int seqNum; - public final byte[] key; - public final byte[] payload; - - /** - * Generic constructor for ESP headers. - * - *

    For Tunnel mode, payload will be a full IP header + attached payloads - * - *

    For Transport mode, payload will be only the attached payloads, but with the checksum - * calculated using the pre-encryption IP header - */ - public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) { - this.nextHeader = nextHeader; - this.spi = spi; - this.seqNum = seqNum; - this.key = key; - this.payload = payload; - } - - public int getProtocolId() { - return IPPROTO_ESP; - } - - public short length() { - // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len) - return (short) - calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128); - } - - public byte[] getPacketBytes(IpHeader header) throws Exception { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - addPacketBytes(header, bb); - return getByteArrayFromBuffer(bb); - } - - public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { - ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); - espPayloadBuffer.putInt(spi); - espPayloadBuffer.putInt(seqNum); - espPayloadBuffer.put(getCiphertext(key)); - - espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16); - resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer)); - } - - private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException { - Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256); - SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256); - sha256HMAC.init(authKey); - - return sha256HMAC.doFinal(authenticatedSection); - } - - /** - * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks - * - *

    The ciphertext does NOT include the SPI/Sequence numbers, or the ICV. - */ - private byte[] getCiphertext(byte[] key) throws GeneralSecurityException { - int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE); - ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen); - paddedPayload.put(payload); - - // Add padding - consecutive integers from 0x01 - int pad = 1; - while (paddedPayload.position() < paddedPayload.limit()) { - paddedPayload.put((byte) pad++); - } - - paddedPayload.position(paddedPayload.limit() - 2); - paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length - paddedPayload.put((byte) nextHeader); - - // Generate Initialization Vector - byte[] iv = new byte[AES_CBC_IV_LEN]; - new SecureRandom().nextBytes(iv); - IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); - SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); - - // Encrypt payload - Cipher cipher = Cipher.getInstance(AES_CBC); - cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); - byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload)); - - // Build ciphertext - ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length); - cipherText.put(iv); - cipherText.put(encrypted); - - return getByteArrayFromBuffer(cipherText); - } - } - - private static int addAndWrapForChecksum(int currentChecksum, int value) { - currentChecksum += value & 0x0000ffff; - - // Wrap anything beyond the first 16 bits, and add to lower order bits - return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff); - } - - private static short onesComplement(int val) { - val = (val >>> 16) + (val & 0xffff); - - if (val == 0) return 0; - return (short) ((~val) & 0xffff); - } - - public static int calculateEspPacketSize( - int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { - final int ESP_HDRLEN = 4 + 4; // SPI + Seq# - final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length - payloadLen += cryptIvLength; // Initialization Vector - - // Align to block size of encryption algorithm - payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize); - return payloadLen + ESP_HDRLEN + ICV_LEN; - } - - private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) { - payloadLen += 2; // ESP trailer - - // Align to block size of encryption algorithm - return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize); - } - - private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) { - return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; - } - - private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) { - return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); - } - - /* - * Debug printing - */ - private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); - - public static String bytesToHex(byte[] bytes) { - StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { - sb.append(hexArray[b >>> 4]); - sb.append(hexArray[b & 0x0F]); - sb.append(' '); - } - return sb.toString(); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java deleted file mode 100644 index e0d3be0540..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP; -import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; -import static android.net.ipsec.ike.SaProposal.DH_GROUP_NONE; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE; -import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; -import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192; -import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256; -import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.IkeSaProposal; -import android.util.Pair; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -@RunWith(AndroidJUnit4.class) -public class SaProposalTest { - private static final List> NORMAL_MODE_CIPHERS = new ArrayList<>(); - private static final List> COMBINED_MODE_CIPHERS = new ArrayList<>(); - private static final List INTEGRITY_ALGOS = new ArrayList<>(); - private static final List DH_GROUPS = new ArrayList<>(); - private static final List DH_GROUPS_WITH_NONE = new ArrayList<>(); - private static final List PRFS = new ArrayList<>(); - - static { - NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)); - NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128)); - NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192)); - NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)); - - COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128)); - COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192)); - COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256)); - - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96); - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_AES_XCBC_96); - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128); - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192); - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256); - - DH_GROUPS.add(DH_GROUP_1024_BIT_MODP); - DH_GROUPS.add(DH_GROUP_2048_BIT_MODP); - - DH_GROUPS_WITH_NONE.add(DH_GROUP_NONE); - DH_GROUPS_WITH_NONE.addAll(DH_GROUPS); - - PRFS.add(PSEUDORANDOM_FUNCTION_HMAC_SHA1); - PRFS.add(PSEUDORANDOM_FUNCTION_AES128_XCBC); - PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_256); - PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_384); - PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_512); - } - - // Package private - static IkeSaProposal buildIkeSaProposalWithNormalModeCipher() { - return buildIkeSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, PRFS, DH_GROUPS); - } - - // Package private - static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher() { - return buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); - } - - private static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher( - boolean hasIntegrityNone) { - List integerAlgos = new ArrayList<>(); - if (hasIntegrityNone) { - integerAlgos.add(INTEGRITY_ALGORITHM_NONE); - } - return buildIkeSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, PRFS, DH_GROUPS); - } - - private static IkeSaProposal buildIkeSaProposal( - List> ciphers, - List integrityAlgos, - List prfs, - List dhGroups) { - IkeSaProposal.Builder builder = new IkeSaProposal.Builder(); - - for (Pair pair : ciphers) { - builder.addEncryptionAlgorithm(pair.first, pair.second); - } - for (int algo : integrityAlgos) { - builder.addIntegrityAlgorithm(algo); - } - for (int algo : prfs) { - builder.addPseudorandomFunction(algo); - } - for (int algo : dhGroups) { - builder.addDhGroup(algo); - } - - return builder.build(); - } - - // Package private - static ChildSaProposal buildChildSaProposalWithNormalModeCipher() { - return buildChildSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, DH_GROUPS_WITH_NONE); - } - - // Package private - static ChildSaProposal buildChildSaProposalWithCombinedModeCipher() { - return buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); - } - - private static ChildSaProposal buildChildSaProposalWithCombinedModeCipher( - boolean hasIntegrityNone) { - List integerAlgos = new ArrayList<>(); - if (hasIntegrityNone) { - integerAlgos.add(INTEGRITY_ALGORITHM_NONE); - } - - return buildChildSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, DH_GROUPS_WITH_NONE); - } - - private static ChildSaProposal buildChildSaProposal( - List> ciphers, - List integrityAlgos, - List dhGroups) { - ChildSaProposal.Builder builder = new ChildSaProposal.Builder(); - - for (Pair pair : ciphers) { - builder.addEncryptionAlgorithm(pair.first, pair.second); - } - for (int algo : integrityAlgos) { - builder.addIntegrityAlgorithm(algo); - } - for (int algo : dhGroups) { - builder.addDhGroup(algo); - } - - return builder.build(); - } - - // Package private - static ChildSaProposal buildChildSaProposalWithOnlyCiphers() { - return buildChildSaProposal( - COMBINED_MODE_CIPHERS, Collections.EMPTY_LIST, Collections.EMPTY_LIST); - } - - @Test - public void testBuildIkeSaProposalWithNormalModeCipher() { - IkeSaProposal saProposal = buildIkeSaProposalWithNormalModeCipher(); - - assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms()); - assertEquals(PRFS, saProposal.getPseudorandomFunctions()); - assertEquals(DH_GROUPS, saProposal.getDhGroups()); - } - - @Test - public void testBuildIkeSaProposalWithCombinedModeCipher() { - IkeSaProposal saProposal = - buildIkeSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(PRFS, saProposal.getPseudorandomFunctions()); - assertEquals(DH_GROUPS, saProposal.getDhGroups()); - assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); - } - - @Test - public void testBuildIkeSaProposalWithCombinedModeCipherAndIntegrityNone() { - IkeSaProposal saProposal = - buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(PRFS, saProposal.getPseudorandomFunctions()); - assertEquals(DH_GROUPS, saProposal.getDhGroups()); - assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms()); - } - - @Test - public void testBuildChildSaProposalWithNormalModeCipher() { - ChildSaProposal saProposal = buildChildSaProposalWithNormalModeCipher(); - - assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms()); - assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); - } - - @Test - public void testBuildChildProposalWithCombinedModeCipher() { - ChildSaProposal saProposal = - buildChildSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); - assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); - } - - @Test - public void testBuildChildProposalWithCombinedModeCipherAndIntegrityNone() { - ChildSaProposal saProposal = - buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms()); - assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); - } - - @Test - public void testBuildChildSaProposalWithOnlyCiphers() { - ChildSaProposal saProposal = buildChildSaProposalWithOnlyCiphers(); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); - assertTrue(saProposal.getDhGroups().isEmpty()); - } - - // TODO(b/148689509): Test throwing exception when algorithm combination is invalid -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java deleted file mode 100644 index 5b08cdc8f2..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; -import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; -import static android.net.NetworkCapabilities.TRANSPORT_TEST; - -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkRequest; -import android.net.TestNetworkManager; -import android.os.IBinder; -import android.os.RemoteException; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -// TODO(b/148689509): Share this class with net CTS test (e.g. IpSecManagerTunnelTest) -public class TestNetworkUtils { - private static final int TIMEOUT_MS = 500; - - /** Callback to receive requested test network. */ - public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CompletableFuture futureNetwork = new CompletableFuture<>(); - - @Override - public void onAvailable(Network network) { - futureNetwork.complete(network); - } - - public Network getNetworkBlocking() throws Exception { - return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - } - - /** - * Set up test network. - * - *

    Caller MUST have MANAGE_TEST_NETWORKS permission to use this method. - * - * @param connMgr ConnectivityManager to request network. - * @param testNetworkMgr TestNetworkManager to set up test network. - * @param ifname the name of the interface to be used for the Network LinkProperties. - * @param binder a binder object guarding the lifecycle of this test network. - * @return TestNetworkCallback to retrieve the test network. - * @throws RemoteException if test network setup failed. - * @see android.net.TestNetworkManager - */ - public static TestNetworkCallback setupAndGetTestNetwork( - ConnectivityManager connMgr, - TestNetworkManager testNetworkMgr, - String ifname, - IBinder binder) - throws RemoteException { - NetworkRequest nr = - new NetworkRequest.Builder() - .addTransportType(TRANSPORT_TEST) - .removeCapability(NET_CAPABILITY_TRUSTED) - .removeCapability(NET_CAPABILITY_NOT_VPN) - .setNetworkSpecifier(ifname) - .build(); - - TestNetworkCallback cb = new TestNetworkCallback(); - connMgr.requestNetwork(nr, cb); - - // Setup the test network after network request is filed to prevent Network from being - // reaped due to no requests matching it. - testNetworkMgr.setupTestNetwork(ifname, binder); - - return cb; - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java deleted file mode 100644 index 5539dbca23..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.IPPROTO_ESP; -import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; -import static android.system.OsConstants.IPPROTO_UDP; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; - -import android.os.ParcelFileDescriptor; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.function.Predicate; - -/** - * This code is a exact copy of {@link TunUtils} in - * cts/tests/tests/net/src/android/net/cts/TunUtils.java, except the import path of PacketUtils is - * the path to the copy of PacktUtils. - * - *

    TODO(b/148689509): Statically include the TunUtils source file instead of copying it. - */ -public class TunUtils { - private static final String TAG = TunUtils.class.getSimpleName(); - - private static final int DATA_BUFFER_LEN = 4096; - static final int TIMEOUT = 500; - - static final int IP4_PROTO_OFFSET = 9; - static final int IP6_PROTO_OFFSET = 6; - - static final int IP4_ADDR_OFFSET = 12; - static final int IP4_ADDR_LEN = 4; - static final int IP6_ADDR_OFFSET = 8; - static final int IP6_ADDR_LEN = 16; - - final List mPackets = new ArrayList<>(); - private final ParcelFileDescriptor mTunFd; - private final Thread mReaderThread; - - public TunUtils(ParcelFileDescriptor tunFd) { - mTunFd = tunFd; - - // Start background reader thread - mReaderThread = - new Thread( - () -> { - try { - // Loop will exit and thread will quit when tunFd is closed. - // Receiving either EOF or an exception will exit this reader loop. - // FileInputStream in uninterruptable, so there's no good way to - // ensure that this thread shuts down except upon FD closure. - while (true) { - byte[] intercepted = receiveFromTun(); - if (intercepted == null) { - // Exit once we've hit EOF - return; - } else if (intercepted.length > 0) { - // Only save packet if we've received any bytes. - synchronized (mPackets) { - mPackets.add(intercepted); - mPackets.notifyAll(); - } - } - } - } catch (IOException ignored) { - // Simply exit this reader thread - return; - } - }); - mReaderThread.start(); - } - - private byte[] receiveFromTun() throws IOException { - FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor()); - byte[] inBytes = new byte[DATA_BUFFER_LEN]; - int bytesRead = in.read(inBytes); - - if (bytesRead < 0) { - return null; // return null for EOF - } else if (bytesRead >= DATA_BUFFER_LEN) { - throw new IllegalStateException("Too big packet. Fragmentation unsupported"); - } - return Arrays.copyOf(inBytes, bytesRead); - } - - byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { - synchronized (mPackets) { - for (int i = startIndex; i < mPackets.size(); i++) { - byte[] pkt = mPackets.get(i); - if (verifier.test(pkt)) { - return pkt; - } - } - } - return null; - } - - /** - * Checks if the specified bytes were ever sent in plaintext. - * - *

    Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like - * - * @param plaintext the plaintext bytes to check for - * @param startIndex the index in the list to check for - */ - public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { - Predicate verifier = - (pkt) -> { - return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) - != -1; - }; - return getFirstMatchingPacket(verifier, startIndex) != null; - } - - public byte[] getEspPacket(int spi, boolean encap, int startIndex) { - return getFirstMatchingPacket( - (pkt) -> { - return isEsp(pkt, spi, encap); - }, - startIndex); - } - - public byte[] awaitEspPacketNoPlaintext( - int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { - long endTime = System.currentTimeMillis() + TIMEOUT; - int startIndex = 0; - - synchronized (mPackets) { - while (System.currentTimeMillis() < endTime) { - byte[] espPkt = getEspPacket(spi, useEncap, startIndex); - if (espPkt != null) { - // Validate packet size - assertEquals(expectedPacketSize, espPkt.length); - - // Always check plaintext from start - assertFalse(hasPlaintextPacket(plaintext, 0)); - return espPkt; // We've found the packet we're looking for. - } - - startIndex = mPackets.size(); - - // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout - long waitTimeout = endTime - System.currentTimeMillis(); - if (waitTimeout > 0) { - mPackets.wait(waitTimeout); - } - } - - fail("No such ESP packet found with SPI " + spi); - } - return null; - } - - private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { - // Check SPI byte by byte. - return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) - && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) - && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) - && pkt[espOffset + 3] == (byte) (spi & 0xff); - } - - private static boolean isEsp(byte[] pkt, int spi, boolean encap) { - if (isIpv6(pkt)) { - // IPv6 UDP encap not supported by kernels; assume non-encap. - return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); - } else { - // Use default IPv4 header length (assuming no options) - if (encap) { - return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP - && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi); - } else { - return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi); - } - } - } - - static boolean isIpv6(byte[] pkt) { - // First nibble shows IP version. 0x60 for IPv6 - return (pkt[0] & (byte) 0xF0) == (byte) 0x60; - } - - private static byte[] getReflectedPacket(byte[] pkt) { - byte[] reflected = Arrays.copyOf(pkt, pkt.length); - - if (isIpv6(pkt)) { - // Set reflected packet's dst to that of the original's src - System.arraycopy( - pkt, // src - IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset - reflected, // dst - IP6_ADDR_OFFSET, // dst offset - IP6_ADDR_LEN); // len - // Set reflected packet's src IP to that of the original's dst IP - System.arraycopy( - pkt, // src - IP6_ADDR_OFFSET, // src offset - reflected, // dst - IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset - IP6_ADDR_LEN); // len - } else { - // Set reflected packet's dst to that of the original's src - System.arraycopy( - pkt, // src - IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset - reflected, // dst - IP4_ADDR_OFFSET, // dst offset - IP4_ADDR_LEN); // len - // Set reflected packet's src IP to that of the original's dst IP - System.arraycopy( - pkt, // src - IP4_ADDR_OFFSET, // src offset - reflected, // dst - IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset - IP4_ADDR_LEN); // len - } - return reflected; - } - - /** Takes all captured packets, flips the src/dst, and re-injects them. */ - public void reflectPackets() throws IOException { - synchronized (mPackets) { - for (byte[] pkt : mPackets) { - injectPacket(getReflectedPacket(pkt)); - } - } - } - - public void injectPacket(byte[] pkt) throws IOException { - FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor()); - out.write(pkt); - out.flush(); - } - - /** Resets the intercepted packets. */ - public void reset() throws IOException { - synchronized (mPackets) { - mPackets.clear(); - } - } -} From 44b2ebcf340685e808cb3e663eb192739eb1a32d Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Wed, 14 Oct 2020 12:32:38 +0100 Subject: [PATCH 1335/1415] Remove Tethering @TestApi Modules shouldn't have TestApis, as documented in go/android-api-types. Additionally, nothing depends on these TestApis existing. Bug: 170395679 Test: m checkapi Exempt-From-Owner-Approval: cherry-pick Change-Id: I6e2c8298e90b4b54f0264be974d036fa08cd5632 --- .../common/TetheringLib/src/android/net/TetheredClient.java | 2 -- .../common/TetheringLib/src/android/net/TetheringManager.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/Tethering/common/TetheringLib/src/android/net/TetheredClient.java index 645b000013..0b223f42b9 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheredClient.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheredClient.java @@ -19,7 +19,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -34,7 +33,6 @@ import java.util.Objects; * @hide */ @SystemApi -@TestApi public final class TetheredClient implements Parcelable { @NonNull private final MacAddress mMacAddress; diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index db84368592..13b05a841d 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -23,7 +23,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.content.Context; import android.os.Bundle; import android.os.ConditionVariable; @@ -55,7 +54,6 @@ import java.util.function.Supplier; * @hide */ @SystemApi -@TestApi public class TetheringManager { private static final String TAG = TetheringManager.class.getSimpleName(); private static final int DEFAULT_TIMEOUT_MS = 60_000; From 52723ecd91654b61a5b6ba2c5f85df6dd58cf627 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 9 Oct 2020 04:53:54 +0000 Subject: [PATCH 1336/1415] Fix a way for this test to flake. While tests are hopefully cleaning up after themselves, there is no guarantee that there is a currently available default network milliseconds after any given test. Some tests need to disconnect to check something, or to change a property of the wifi network that they have to revert at the end for example. Or, a test may fail leaving the device without a default network. To make sure the state is correctly cleaned up, have tearDown make sure the device is connected to a working Internet connection before the test ends, so that the next test can be sure to find established connectivity immediately. It's possible the device needs a few hundred milliseconds to re-establish connectivity, so this patch gives a grace of up to 30 seconds (the default waiting timer for TestCallback) for connectivity to be restored at the end of any test. Bug: 161767594 and others Test: ConnectivityManagerTest Original change: https://android-review.googlesource.com/c/platform/cts/+/1436794 Change-Id: I2318a6d1a6d6ac4b142fc998f0c5efbe93b68707 (cherry picked from commit ff47147c3a881a11f03f87c75bc2a7cf68f85857) --- .../src/android/net/cts/ConnectivityManagerTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 3880664827..109034fd92 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -210,6 +210,16 @@ public class ConnectivityManagerTest { if (mCtsNetUtils.cellConnectAttempted()) { mCtsNetUtils.disconnectFromCell(); } + + // All tests in this class require a working Internet connection as they start. Make + // sure there is still one as they end that's ready to use for the next test to use. + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(callback); + try { + assertNotNull("Couldn't restore Internet connectivity", callback.waitForAvailable()); + } finally { + mCm.unregisterNetworkCallback(callback); + } } /** From 634f0a8ec170496ae57afc985156b6c5a9237d50 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 14 Oct 2020 15:11:43 +0800 Subject: [PATCH 1337/1415] Fix miss tracking downstream problem in PrivateAddressCoordinator The downstream do not be tracked if PrivateAddressCoordinator just return cached address. Then, PrivateAddressCoordinator would not notify that downstream if conflict happen. Also remove the null check in getDownstreamPrefix because: - An IpServer is only added to mDownstreams by requestDownstreamAddress. - That method will only add the IpServer to mDownstreams if it has an IPv4 address. - As soon as that method returns, the IpServer sets mIpv4Address to the address that was returned. - When an IpServer is torn down, mIpv4Address is set to null after releaseDownstream is called. So it should never be possible for this to return null. Bug: 168169687 Test: atest CtsTetheringTest atest TetheringTests Change-Id: Ide5206b013acdc499344e1c839a830c5b245af41 --- .../tethering/PrivateAddressCoordinator.java | 6 +- .../PrivateAddressCoordinatorTest.java | 192 ++++++++---------- 2 files changed, 87 insertions(+), 111 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index 0cf14e3f86..9fc1d7e5bc 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -36,6 +36,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.SparseArray; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; @@ -135,7 +136,6 @@ public class PrivateAddressCoordinator { private void handleMaybePrefixConflict(final List prefixes) { for (IpServer downstream : mDownstreams) { final IpPrefix target = getDownstreamPrefix(downstream); - if (target == null) continue; for (IpPrefix source : prefixes) { if (isConflictPrefix(source, target)) { @@ -179,6 +179,7 @@ public class PrivateAddressCoordinator { final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType()); if (useLastAddress && cachedAddress != null && !isConflictWithUpstream(asIpPrefix(cachedAddress))) { + mDownstreams.add(ipServer); return cachedAddress; } @@ -370,7 +371,6 @@ public class PrivateAddressCoordinator { // in mCachedAddresses. for (IpServer downstream : mDownstreams) { final IpPrefix target = getDownstreamPrefix(downstream); - if (target == null) continue; if (isConflictPrefix(prefix, target)) return target; } @@ -378,9 +378,9 @@ public class PrivateAddressCoordinator { return null; } + @NonNull private IpPrefix getDownstreamPrefix(final IpServer downstream) { final LinkAddress address = downstream.getAddress(); - if (address == null) return null; return asIpPrefix(address); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index da13e341fb..8cb80bad80 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -104,24 +104,30 @@ public final class PrivateAddressCoordinatorTest { mTetheringPrefixes)); } + private LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { + final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( + ipServer, useLastAddress); + when(ipServer.getAddress()).thenReturn(address); + return address; + } + @Test public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception { final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress); - final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, false /* useLastAddress */); + final LinkAddress address = requestDownstreamAddress(mHotspotIpServer, + false /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(address); assertNotEquals(hotspotPrefix, bluetoothPrefix); - when(mHotspotIpServer.getAddress()).thenReturn(address); - final LinkAddress newAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, false /* useLastAddress */); + final LinkAddress newAddress = requestDownstreamAddress(mHotspotIpServer, + false /* useLastAddress */); final IpPrefix testDupRequest = asIpPrefix(newAddress); assertNotEquals(hotspotPrefix, testDupRequest); assertNotEquals(bluetoothPrefix, testDupRequest); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer, false /* useLastAddress */); + final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, + false /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddress); assertNotEquals(usbPrefix, bluetoothPrefix); assertNotEquals(usbPrefix, hotspotPrefix); @@ -132,29 +138,26 @@ public final class PrivateAddressCoordinatorTest { public void testSanitizedAddress() throws Exception { int fakeSubAddr = 0x2b00; // 43.0. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, false /* useLastAddress */); + LinkAddress actualAddress = requestDownstreamAddress(mHotspotIpServer, + false /* useLastAddress */); assertEquals(new LinkAddress("192.168.43.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2d01; // 45.1. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.45.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2eff; // 46.255. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.46.254/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2f05; // 47.5. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } @@ -164,8 +167,8 @@ public final class PrivateAddressCoordinatorTest { // - Test bluetooth prefix is reserved. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mBluetoothAddress.getAddress().getAddress())); - final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, false /* useLastAddress */); + final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, + false /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress); assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); @@ -173,8 +176,8 @@ public final class PrivateAddressCoordinatorTest { // - Test previous enabled hotspot prefix(cached prefix) is reserved. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(hotspotAddress.getAddress().getAddress())); - final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer, false /* useLastAddress */); + final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, + false /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddress); assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix); assertNotEquals(hotspotPrefix, usbPrefix); @@ -183,8 +186,8 @@ public final class PrivateAddressCoordinatorTest { // - Test wifi p2p prefix is reserved. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); - final LinkAddress etherAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mEthernetIpServer, false /* useLastAddress */); + final LinkAddress etherAddress = requestDownstreamAddress(mEthernetIpServer, + false /* useLastAddress */); final IpPrefix etherPrefix = asIpPrefix(etherAddress); assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix); assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix); @@ -196,13 +199,12 @@ public final class PrivateAddressCoordinatorTest { public void testRequestLastDownstreamAddress() throws Exception { final int fakeHotspotSubAddr = 0x2b05; // 43.5 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); - final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true /* useLastAddress */); + final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress); - when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddress); - final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer, true /* useLastAddress */); + final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.45.5/24"), usbAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); @@ -211,24 +213,19 @@ public final class PrivateAddressCoordinatorTest { final int newFakeSubAddr = 0x3c05; when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); - final LinkAddress newHotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true /* useLastAddress */); + final LinkAddress newHotspotAddress = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals(hotspotAddress, newHotspotAddress); - final LinkAddress newUsbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer, true /* useLastAddress */); + final LinkAddress newUsbAddress = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); assertEquals(usbAddress, newUsbAddress); - // BUG: the code should detect a conflict, but it doesn't. - // Regression introduced in r.android.com/168169687. - // Ensure conflict notification works when using cached address. - when(mHotspotIpServer.getAddress()).thenReturn(newHotspotAddress); - when(mUsbIpServer.getAddress()).thenReturn(usbAddress); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, new LinkAddress("192.168.88.23/16"), null, makeNetworkCapabilities(TRANSPORT_WIFI)); mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); - verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); - verify(mUsbIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + verify(mUsbIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); } private UpstreamNetworkState buildUpstreamNetworkState(final Network network, @@ -259,11 +256,10 @@ public final class PrivateAddressCoordinatorTest { // Force always get subAddress "43.5" for conflict testing. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); // - Enable hotspot with prefix 192.168.43.0/24 - final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true /* useLastAddress */); + final LinkAddress hotspotAddr = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr); assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); - when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); // - test mobile network with null NetworkCapabilities. Ideally this should not happen // because NetworkCapabilities update should always happen before LinkProperties update // and the UpstreamNetworkState update, just make sure no crash in this case. @@ -314,24 +310,22 @@ public final class PrivateAddressCoordinatorTest { reset(mHotspotIpServer); // - Restart hotspot again and its prefix is different previous. mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true /* useLastAddress */); + final LinkAddress hotspotAddr2 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2); assertNotEquals(hotspotPrefix, hotspotPrefix2); - when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2); mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); // - Usb tethering can be enabled and its prefix is different with conflict one. - final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer, true /* useLastAddress */); + final LinkAddress usbAddr = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddr); assertNotEquals(predefinedPrefix, usbPrefix); assertNotEquals(hotspotPrefix2, usbPrefix); - when(mUsbIpServer.getAddress()).thenReturn(usbAddr); // - Disable wifi upstream, then wifi's prefix can be selected again. mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); - final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mEthernetIpServer, true /* useLastAddress */); + final LinkAddress ethAddr = requestDownstreamAddress(mEthernetIpServer, + true /* useLastAddress */); final IpPrefix ethPrefix = asIpPrefix(ethAddr); assertEquals(predefinedPrefix, ethPrefix); } @@ -340,21 +334,19 @@ public final class PrivateAddressCoordinatorTest { public void testChooseAvailablePrefix() throws Exception { final int randomAddress = 0x8605; // 134.5 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); - final LinkAddress addr0 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr0 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.134.5. assertEquals("Wrong prefix: ", new LinkAddress("192.168.134.5/24"), addr0); - when(mHotspotIpServer.getAddress()).thenReturn(addr0); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, new LinkAddress("192.168.134.13/26"), null, makeNetworkCapabilities(TRANSPORT_WIFI)); mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); // Check whether return address is next prefix of 192.168.134.0/24. - final LinkAddress addr1 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr1 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.135.5/24"), addr1); - when(mHotspotIpServer.getAddress()).thenReturn(addr1); final UpstreamNetworkState wifiUpstream2 = buildUpstreamNetworkState(mWifiNetwork, new LinkAddress("192.168.149.16/19"), null, makeNetworkCapabilities(TRANSPORT_WIFI)); @@ -362,10 +354,9 @@ public final class PrivateAddressCoordinatorTest { // The conflict range is 128 ~ 159, so the address is 192.168.160.5/24. - final LinkAddress addr2 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr2 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.160.5/24"), addr2); - when(mHotspotIpServer.getAddress()).thenReturn(addr2); final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, new LinkAddress("192.168.129.53/18"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); @@ -378,10 +369,9 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2); // The conflict range are 128 ~ 159 and 159 ~ 191, so the address is 192.168.192.5/24. - final LinkAddress addr3 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr3 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.192.5/24"), addr3); - when(mHotspotIpServer.getAddress()).thenReturn(addr3); final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, new LinkAddress("192.168.188.133/17"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); @@ -389,20 +379,18 @@ public final class PrivateAddressCoordinatorTest { // Conflict range: 128 ~ 255. The next available address is 192.168.0.5 because // 192.168.134/24 ~ 192.168.255.255/24 is not available. - final LinkAddress addr4 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr4 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.0.5/24"), addr4); - when(mHotspotIpServer.getAddress()).thenReturn(addr4); final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, new LinkAddress("192.168.3.59/21"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4); // Conflict ranges: 128 ~ 255 and 0 ~ 7, so the address is 192.168.8.5/24. - final LinkAddress addr5 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr5 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr5); - when(mHotspotIpServer.getAddress()).thenReturn(addr5); final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, new LinkAddress("192.168.68.43/21"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); @@ -410,41 +398,37 @@ public final class PrivateAddressCoordinatorTest { // Update an upstream that does *not* conflict, check whether return the same address // 192.168.5/24. - final LinkAddress addr6 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr6 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr6); - when(mHotspotIpServer.getAddress()).thenReturn(addr6); final UpstreamNetworkState mobileUpstream6 = buildUpstreamNetworkState(mMobileNetwork6, new LinkAddress("192.168.10.97/21"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream6); // Conflict ranges: 0 ~ 15 and 128 ~ 255, so the address is 192.168.16.5/24. - final LinkAddress addr7 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr7 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.16.5/24"), addr7); - when(mHotspotIpServer.getAddress()).thenReturn(addr7); final UpstreamNetworkState mobileUpstream7 = buildUpstreamNetworkState(mMobileNetwork6, new LinkAddress("192.168.0.0/17"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream7); // Choose prefix from next range(172.16.0.0/12) when no available prefix in 192.168.0.0/16. - final LinkAddress addr8 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress addr8 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.134.5/24"), addr8); - when(mHotspotIpServer.getAddress()).thenReturn(addr6); } @Test public void testChoosePrefixFromDifferentRanges() throws Exception { final int randomAddress = 0x1f2b2a; // 31.43.42 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); - final LinkAddress classC1 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress classC1 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.43.42. assertEquals("Wrong prefix: ", new LinkAddress("192.168.43.42/24"), classC1); - when(mHotspotIpServer.getAddress()).thenReturn(classC1); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, new LinkAddress("192.168.88.23/17"), null, makeNetworkCapabilities(TRANSPORT_WIFI)); @@ -452,10 +436,9 @@ public final class PrivateAddressCoordinatorTest { verifyNotifyConflictAndRelease(mHotspotIpServer); // Check whether return address is next address of prefix 192.168.128.0/17. - final LinkAddress classC2 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress classC2 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.128.42/24"), classC2); - when(mHotspotIpServer.getAddress()).thenReturn(classC2); final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, new LinkAddress("192.1.2.3/8"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); @@ -463,10 +446,9 @@ public final class PrivateAddressCoordinatorTest { verifyNotifyConflictAndRelease(mHotspotIpServer); // Check whether return address is under prefix 172.16.0.0/12. - final LinkAddress classB1 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress classB1 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.31.43.42/24"), classB1); - when(mHotspotIpServer.getAddress()).thenReturn(classB1); final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, new LinkAddress("172.28.123.100/14"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); @@ -475,16 +457,14 @@ public final class PrivateAddressCoordinatorTest { // 172.28.0.0 ~ 172.31.255.255 is not available. // Check whether return address is next address of prefix 172.16.0.0/14. - final LinkAddress classB2 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress classB2 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.0.42/24"), classB2); - when(mHotspotIpServer.getAddress()).thenReturn(classB2); // Check whether new downstream is next address of address 172.16.0.42/24. - final LinkAddress classB3 = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer, true/* useLastAddress */); + final LinkAddress classB3 = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.1.42/24"), classB3); - when(mUsbIpServer.getAddress()).thenReturn(classB3); final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, new LinkAddress("172.16.0.1/24"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); @@ -493,10 +473,9 @@ public final class PrivateAddressCoordinatorTest { verify(mUsbIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); // Check whether return address is next address of prefix 172.16.1.42/24. - final LinkAddress classB4 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress classB4 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.2.42/24"), classB4); - when(mHotspotIpServer.getAddress()).thenReturn(classB4); final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, new LinkAddress("172.16.0.1/13"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); @@ -505,15 +484,13 @@ public final class PrivateAddressCoordinatorTest { verifyNotifyConflictAndRelease(mUsbIpServer); // Check whether return address is next address of prefix 172.16.0.1/13. - final LinkAddress classB5 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress classB5 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.24.0.42/24"), classB5); - when(mHotspotIpServer.getAddress()).thenReturn(classB5); // Check whether return address is next address of prefix 172.24.0.42/24. - final LinkAddress classB6 = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer, true/* useLastAddress */); + final LinkAddress classB6 = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.24.1.42/24"), classB6); - when(mUsbIpServer.getAddress()).thenReturn(classB6); final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, new LinkAddress("172.24.0.1/12"), null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); @@ -522,13 +499,12 @@ public final class PrivateAddressCoordinatorTest { verifyNotifyConflictAndRelease(mUsbIpServer); // Check whether return address is prefix 10.0.0.0/8 + subAddress 0.31.43.42. - final LinkAddress classA1 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true/* useLastAddress */); + final LinkAddress classA1 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("10.31.43.42/24"), classA1); - when(mHotspotIpServer.getAddress()).thenReturn(classA1); // Check whether new downstream is next address of address 10.31.43.42/24. - final LinkAddress classA2 = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer, true/* useLastAddress */); + final LinkAddress classA2 = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("10.31.44.42/24"), classA2); } @@ -547,8 +523,8 @@ public final class PrivateAddressCoordinatorTest { } private void assertReseveredWifiP2pPrefix() throws Exception { - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer, true /* useLastAddress */); + LinkAddress address = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(address); final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress); assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix); @@ -567,8 +543,8 @@ public final class PrivateAddressCoordinatorTest { assertReseveredWifiP2pPrefix(); // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address. - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mWifiP2pIpServer, true /* useLastAddress */); + LinkAddress address = requestDownstreamAddress(mWifiP2pIpServer, + true /* useLastAddress */); assertEquals(mLegacyWifiP2pAddress, address); mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer); } From b93dd8145ece78a3d5daa66d5d8b9b9acec7a10e Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Wed, 14 Oct 2020 14:26:46 -0700 Subject: [PATCH 1338/1415] Fix DeviceConfig resetting. DeviceConfig.resetToDefaults is designed to only be used by RescueParty to reset flags and ban values after a disaster (e.g. bootloop). It's not designed to be used to clear up local changes and causes CTS tests to break/be flaky. Switching to reading existing values, changing them, and reverting to the pre-existing values to avoid further test breakages. Bug: 165943447 Test: atest CtsAlarmManagerTestCases Test: atest CtsBatterySavingTestCases Test: atest CtsHostsideNetworkTests Test: atest CtsJobSchedulerTestCases Test: atest CtsPermissionTestCases:LocationAccessCheckTest Change-Id: I237d2cd2b862a826f7e871b7a7c31840a3470d0a --- ...tractRestrictBackgroundNetworkTestCase.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 0883b1aaa6..2b4594e5c8 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -50,11 +50,10 @@ import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; import android.provider.DeviceConfig; -import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.util.Log; -import com.android.compatibility.common.util.SystemUtil; +import com.android.compatibility.common.util.DeviceConfigStateHelper; import org.junit.Rule; import org.junit.rules.RuleChain; @@ -131,18 +130,20 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { protected int mUid; private int mMyUid; private MyServiceClient mServiceClient; + private DeviceConfigStateHelper mDeviceIdleDeviceConfigStateHelper; @Rule public final RuleChain mRuleChain = RuleChain.outerRule(new RequiredPropertiesRule()) .around(new MeterednessConfigurationRule()); protected void setUp() throws Exception { - PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null); mInstrumentation = getInstrumentation(); mContext = getContext(); mCm = getConnectivityManager(); + mDeviceIdleDeviceConfigStateHelper = + new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_DEVICE_IDLE); mUid = getUid(TEST_APP2_PKG); mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); @@ -721,17 +722,12 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { } protected void setPendingIntentAllowlistDuration(long durationMs) { - SystemUtil.runWithShellPermissionIdentity(() -> { - DeviceConfig.setProperty( - DeviceConfig.NAMESPACE_DEVICE_IDLE, "notification_allowlist_duration_ms", - String.valueOf(durationMs), /* makeDefault */ false); - }); + mDeviceIdleDeviceConfigStateHelper.set("notification_allowlist_duration_ms", + String.valueOf(durationMs)); } protected void resetDeviceIdleSettings() { - SystemUtil.runWithShellPermissionIdentity(() -> - DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS, - DeviceConfig.NAMESPACE_DEVICE_IDLE)); + mDeviceIdleDeviceConfigStateHelper.restoreOriginalValues(); } protected void launchComponentAndAssertNetworkAccess(int type) throws Exception { From b8c683784ce84a0a45aae02d455fbf76b05c73c1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 12 Oct 2020 15:45:01 -0700 Subject: [PATCH 1339/1415] Migrate IPsec CTS out of tests/tests/net Bug: 170487836 Test: atest CtsIkeTestCases Change-Id: I08f069c2a11f3daa3f0332c631055a1e0be7ce7b Merged-In: I08f069c2a11f3daa3f0332c631055a1e0be7ce7b (cherry picked from commit b4d5a4b66fcda861e39f83a2a6f095cc5eb60bd4) --- tests/cts/net/ipsec/Android.bp | 48 -- tests/cts/net/ipsec/AndroidManifest.xml | 39 -- tests/cts/net/ipsec/AndroidTest.xml | 33 - tests/cts/net/ipsec/OWNERS | 3 - .../ipsec/assets/key/client-a-private-key.key | 28 - .../ipsec/assets/pem/client-a-end-cert.pem | 21 - .../pem/client-a-intermediate-ca-one.pem | 21 - .../pem/client-a-intermediate-ca-two.pem | 21 - .../assets/pem/server-a-self-signed-ca.pem | 20 - .../net/eap/cts/EapSessionConfigTest.java | 98 --- .../ipsec/ike/cts/ChildSessionParamsTest.java | 230 ------- .../ipsec/ike/cts/IkeIdentificationTest.java | 75 --- .../cts/IkeSessionDigitalSignatureTest.java | 211 ------ .../ipsec/ike/cts/IkeSessionMschapV2Test.java | 220 ------- .../ipsec/ike/cts/IkeSessionParamsTest.java | 414 ------------ .../net/ipsec/ike/cts/IkeSessionPskTest.java | 371 ----------- .../ipsec/ike/cts/IkeSessionRekeyTest.java | 265 -------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 598 ------------------ .../net/ipsec/ike/cts/IkeTestBase.java | 144 ----- .../net/ipsec/ike/cts/IkeTunUtils.java | 377 ----------- .../net/ipsec/ike/cts/PacketUtils.java | 467 -------------- .../net/ipsec/ike/cts/SaProposalTest.java | 256 -------- .../net/ipsec/ike/cts/TestNetworkUtils.java | 87 --- .../android/net/ipsec/ike/cts/TunUtils.java | 264 -------- 24 files changed, 4311 deletions(-) delete mode 100644 tests/cts/net/ipsec/Android.bp delete mode 100644 tests/cts/net/ipsec/AndroidManifest.xml delete mode 100644 tests/cts/net/ipsec/AndroidTest.xml delete mode 100644 tests/cts/net/ipsec/OWNERS delete mode 100644 tests/cts/net/ipsec/assets/key/client-a-private-key.key delete mode 100644 tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem delete mode 100644 tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem delete mode 100644 tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem delete mode 100644 tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem delete mode 100644 tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java delete mode 100644 tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp deleted file mode 100644 index 124e93c650..0000000000 --- a/tests/cts/net/ipsec/Android.bp +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - -android_test { - name: "CtsIkeTestCases", - defaults: ["cts_defaults"], - - // Include both the 32 and 64 bit versions - compile_multilib: "both", - - libs: [ - "android.net.ipsec.ike.stubs.system", - "android.test.base.stubs", - ], - - srcs: [ - "src/**/*.java", - ":ike-test-utils", - ], - - static_libs: [ - "androidx.test.ext.junit", - "compatibility-device-util-axt", - "ctstestrunner-axt", - "net-tests-utils", - ], - - platform_apis: true, - - // Tag this module as a cts test artifact - test_suites: [ - "cts", - "mts", - "vts", - "general-tests", - ], -} diff --git a/tests/cts/net/ipsec/AndroidManifest.xml b/tests/cts/net/ipsec/AndroidManifest.xml deleted file mode 100644 index de7d23cbd5..0000000000 --- a/tests/cts/net/ipsec/AndroidManifest.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/tests/cts/net/ipsec/AndroidTest.xml b/tests/cts/net/ipsec/AndroidTest.xml deleted file mode 100644 index cd5c118dd6..0000000000 --- a/tests/cts/net/ipsec/AndroidTest.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/tests/cts/net/ipsec/OWNERS b/tests/cts/net/ipsec/OWNERS deleted file mode 100644 index 26407ff253..0000000000 --- a/tests/cts/net/ipsec/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -lorenzo@google.com -nharold@google.com -satk@google.com diff --git a/tests/cts/net/ipsec/assets/key/client-a-private-key.key b/tests/cts/net/ipsec/assets/key/client-a-private-key.key deleted file mode 100644 index 22736e98e0..0000000000 --- a/tests/cts/net/ipsec/assets/key/client-a-private-key.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL -8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu -7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K -Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i -pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS -jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK -a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub -G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n -zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo -zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL -gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc -9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf -spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL -ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms -TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy -GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK -QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ -+K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE -i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh -fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU -ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+ -NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN -mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR -wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G -xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf -idNFcaIrC52PtZIH7QCzdDY= ------END PRIVATE KEY----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem b/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem deleted file mode 100644 index e82da85c50..0000000000 --- a/tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE -BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu -ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG -A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0 -LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE -CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc -6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw -D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC -25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG -R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL -bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu -bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK -I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio -4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP -ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab -SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7 -T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy -rmkYV2MAWguFeckh ------END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem deleted file mode 100644 index 707e575bc3..0000000000 --- a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDaDCCAlCgAwIBAgIIIbjMyRn2770wDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE -BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h -bmRyb2lkLm5ldDAeFw0xOTA5MzAxODQzMThaFw0yNDA5MjgxODQzMThaMEExCzAJ -BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSAwHgYDVQQDExdvbmUuY2EudGVz -dC5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNN -sRr5Z30rAEw2jrAh/BIekbEy/MvOucAr1w0lxH71p+ybRBx5Bj7G07UGXbL659gm -meMV6nabY4HjQXNMq22POiJBZj+U+rw34br6waljBttxCmmJac1VvgqNsSspXjRy -NbiVQdFjyKSX0NOPcEkwANk15mZbOgJBaYYc8jQCY2G/p8eARVBTLJCy8LEwEU6j -XRv/4eYST79qpBFc7gQQj2FLmh9oppDIvcIVBHwtd1tBoVuehRSud1o8vQRkl/HJ -Mrwp24nO5YYhmVNSFRtBpmWMSu1KknFUwkOebINUNsKXXHebVa7cP4XIQUL8mRT3 -5X9rFJFSQJE01S3NjNMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B -Af8EBAMCAQYwHQYDVR0OBBYEFHK3FIm7g8dxEIwK9zMAO8EWhRYxMB8GA1UdIwQY -MBaAFEmfqEeF14Nj91ekIpR+sVhCEoAaMA0GCSqGSIb3DQEBCwUAA4IBAQAeMlXT -TnxZo8oz0204gKZ63RzlgDpJ7SqA3qFG+pV+TiqGfSuVkXuIdOskjxJnA9VxUzrr -LdMTCn5e0FK6wCYjZ2GT/CD7oD3vSMkzGbLGNcNJhhDHUq8BOLPkPzz/rwQFPBSb -zr6hsiVXphEt/psGoN7Eu9blPeQaIwMfWnaufAwF664S/3dmCRbNMWSam1qzzz8q -jr0cDOIMa//ZIAcM16cvoBK6pFGnUmuoJYYRtfpY5MmfCWz0sCJxENIX/lxyhd7N -FdRALA1ZP3E//Tn2vQoeFjbKaAba527RE26HgHJ9zZDo1nn8J8J/YwYRJdBWM/3S -LYebNiMtcyB5nIkj ------END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem b/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem deleted file mode 100644 index 39808f885e..0000000000 --- a/tests/cts/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDZzCCAk+gAwIBAgIIKWCREnNCs+wwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE -BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF29uZS5jYS50ZXN0LmFu -ZHJvaWQubmV0MB4XDTE5MDkzMDE4NDQwMloXDTI0MDkyODE4NDQwMlowQTELMAkG -A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0 -LmFuZHJvaWQubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLUa -RqkYl2m7lUmMnkooqO0DNNY1aN9r7mJc3ndYn5gjkpb3yLgOYPDNLcQerV6uWk/u -qKudNHed2dInGonl3oxwwv7++6oUvvtrSWLDZlRg16GsdIE1Y98DSMQWkSxevYy9 -Nh6FGTdlBFQVMpiMa8qHEkrOyKsy85yCW1sgzlpGTIBwbDAqYtwe3rgbwyHwUtfy -0EU++DBcR4ll/pDqB0OQtW5E3AOq2GH1iaGeFLKSUQ5KAbdI8y4/b8IkSDffvxcc -kXig7S54aLrNlL/ZjQ+H4Chgjj2A5wMucd81+Fb60Udej73ICL9PpMPnXQ1+BVYd -MJ/txjLNmrOJG9yEHQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwIBBjAdBgNVHQ4EFgQUcqSu1uRYT/DLbLoDNUz38nGvCKQwHwYDVR0jBBgw -FoAUcrcUibuDx3EQjAr3MwA7wRaFFjEwDQYJKoZIhvcNAQELBQADggEBADY461GT -Rw0dGnD07xaGJcI0i0pV+WnGSrl1s1PAIdMYihJAqYnh10fXbFXLm2WMWVmv/pxs -FI/xDJno+pd4mCa/sIhm63ar/Nv+lFQmcpIlvSlKnhhV4SLNBeqbVhPBGTCHfrG4 -aIyCwm1KJsnkWbf03crhSskR/2CXIjX6lcAy7K3fE2u1ELpAdH0kMJR7VXkLFLUm -gqe9YCluR0weMpe2sCaOGzdVzQSmMMCzGP5cxeFR5U6K40kMOpiW11JNmQ06xI/m -YVkMNwoiV/ITT0/C/g9FxJmkO0mVSLEqxaLS/hNiQNDlroVM0rbxhzviXLI3R3AO -50VvlOQYGxWed/I= ------END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem b/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem deleted file mode 100644 index 972fd55372..0000000000 --- a/tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDSDCCAjCgAwIBAgIITJQJ6HC1rjwwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE -BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h -bmRyb2lkLm5ldDAeFw0xOTA5MzAxNzU1NTJaFw0yOTA5MjcxNzU1NTJaMEIxCzAJ -BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSEwHwYDVQQDExhyb290LmNhLnRl -c3QuYW5kcm9pZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCT -q3hGF+JvLaB1xW7KGKmaxiQ7BxX2Sn7cbp7ggoVYXsFlBUuPPv3+Vg5PfPCPhsJ8 -/7w4HyKo3uc/vHs5HpQ7rSd9blhAkfmJci2ULLq73FB8Mix4CzPwMx29RrN1X9bU -z4G0vJMczIBGxbZ0uw7n8bKcXBV7AIeax+J8lseEZ3k8iSuBkUJqGIpPFKTqByFZ -A1Lvt47xkON5SZh6c/Oe+o6291wXaCOJUSAKv6PAWZkq9HeD2fqKA/ck9dBaz1M3 -YvzQ9V/7so3/dECjAfKia388h1I6XSGNUM+d5hpxMXpAFgG42eUXHpJ10OjDvSwd -7ZSC91/kRQewUomEKBK1AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P -AQH/BAQDAgEGMB0GA1UdDgQWBBRJn6hHhdeDY/dXpCKUfrFYQhKAGjANBgkqhkiG -9w0BAQsFAAOCAQEAig/94aGfHBhZuvbbhwAK4rUNpizmR567u0ZJ+QUEKyAlo9lT -ZWYHSm7qTAZYvPEjzTQIptnAlxCHePXh3Cfwgo+r82lhG2rcdI03iRyvHWjM8gyk -BXCJTi0Q08JHHpTP6GnAqpz58qEIFkk8P766zNXdhYrGPOydF+p7MFcb1Zv1gum3 -zmRLt0XUAMfjPUv1Bl8kTKFxH5lkMBLR1E0jnoJoTTfgRPrf9CuFSoh48n7YhoBT -KV75xZY8b8+SuB0v6BvQmkpKZGoxBjuVsShyG7q1+4JTAtwhiP7BlkDvVkaBEi7t -WIMFp2r2ZDisHgastNaeYFyzHYz9g1FCCrHQ4w== ------END CERTIFICATE----- \ No newline at end of file diff --git a/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java b/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java deleted file mode 100644 index c24379dae0..0000000000 --- a/tests/cts/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.eap.cts; - -import static android.telephony.TelephonyManager.APPTYPE_USIM; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.net.eap.EapSessionConfig; -import android.net.eap.EapSessionConfig.EapAkaConfig; -import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; -import android.net.eap.EapSessionConfig.EapMsChapV2Config; -import android.net.eap.EapSessionConfig.EapSimConfig; -import android.net.eap.EapSessionConfig.EapUiccConfig; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class EapSessionConfigTest { - // These constants are IANA-defined values and are copies of hidden constants in - // frameworks/opt/net/ike/src/java/com/android/internal/net/eap/message/EapData.java. - private static final int EAP_TYPE_SIM = 18; - private static final int EAP_TYPE_AKA = 23; - private static final int EAP_TYPE_MSCHAP_V2 = 26; - private static final int EAP_TYPE_AKA_PRIME = 50; - - private static final int SUB_ID = 1; - private static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); - private static final String NETWORK_NAME = "android.net"; - private static final String EAP_MSCHAPV2_USERNAME = "username"; - private static final String EAP_MSCHAPV2_PASSWORD = "password"; - - @Test - public void testBuildWithAllEapMethods() { - EapSessionConfig result = - new EapSessionConfig.Builder() - .setEapIdentity(EAP_IDENTITY) - .setEapSimConfig(SUB_ID, APPTYPE_USIM) - .setEapAkaConfig(SUB_ID, APPTYPE_USIM) - .setEapAkaPrimeConfig( - SUB_ID, - APPTYPE_USIM, - NETWORK_NAME, - true /* allowMismatchedNetworkNames */) - .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) - .build(); - - assertArrayEquals(EAP_IDENTITY, result.getEapIdentity()); - - EapSimConfig eapSimConfig = result.getEapSimConfig(); - assertNotNull(eapSimConfig); - assertEquals(EAP_TYPE_SIM, eapSimConfig.getMethodType()); - verifyEapUiccConfigCommon(eapSimConfig); - - EapAkaConfig eapAkaConfig = result.getEapAkaConfig(); - assertNotNull(eapAkaConfig); - assertEquals(EAP_TYPE_AKA, eapAkaConfig.getMethodType()); - verifyEapUiccConfigCommon(eapAkaConfig); - - EapAkaPrimeConfig eapAkaPrimeConfig = result.getEapAkaPrimeConfig(); - assertNotNull(eapAkaPrimeConfig); - assertEquals(EAP_TYPE_AKA_PRIME, eapAkaPrimeConfig.getMethodType()); - assertEquals(NETWORK_NAME, eapAkaPrimeConfig.getNetworkName()); - assertTrue(NETWORK_NAME, eapAkaPrimeConfig.allowsMismatchedNetworkNames()); - verifyEapUiccConfigCommon(eapAkaPrimeConfig); - - EapMsChapV2Config eapMsChapV2Config = result.getEapMsChapV2onfig(); - assertNotNull(eapMsChapV2Config); - assertEquals(EAP_TYPE_MSCHAP_V2, eapMsChapV2Config.getMethodType()); - assertEquals(EAP_MSCHAPV2_USERNAME, eapMsChapV2Config.getUsername()); - assertEquals(EAP_MSCHAPV2_PASSWORD, eapMsChapV2Config.getPassword()); - } - - private void verifyEapUiccConfigCommon(EapUiccConfig config) { - assertEquals(SUB_ID, config.getSubId()); - assertEquals(APPTYPE_USIM, config.getAppType()); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java deleted file mode 100644 index 7fb1b6dc43..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import android.net.LinkAddress; -import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.ChildSessionParams; -import android.net.ipsec.ike.TransportModeChildSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address; -import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer; -import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -@RunWith(AndroidJUnit4.class) -public class ChildSessionParamsTest extends IkeTestBase { - private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(3L); - private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(1L); - - // Random proposal. Content doesn't matter - private final ChildSaProposal mSaProposal = - SaProposalTest.buildChildSaProposalWithCombinedModeCipher(); - - private void verifyTunnelModeChildParamsWithDefaultValues(ChildSessionParams childParams) { - assertTrue(childParams instanceof TunnelModeChildSessionParams); - verifyChildParamsWithDefaultValues(childParams); - } - - private void verifyTunnelModeChildParamsWithCustomizedValues(ChildSessionParams childParams) { - assertTrue(childParams instanceof TunnelModeChildSessionParams); - verifyChildParamsWithCustomizedValues(childParams); - } - - private void verifyTransportModeChildParamsWithDefaultValues(ChildSessionParams childParams) { - assertTrue(childParams instanceof TransportModeChildSessionParams); - verifyChildParamsWithDefaultValues(childParams); - } - - private void verifyTransportModeChildParamsWithCustomizedValues( - ChildSessionParams childParams) { - assertTrue(childParams instanceof TransportModeChildSessionParams); - verifyChildParamsWithCustomizedValues(childParams); - } - - private void verifyChildParamsWithDefaultValues(ChildSessionParams childParams) { - assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals()); - - // Do not do assertEquals to the default values to be avoid being a change-detector test - assertTrue(childParams.getHardLifetimeSeconds() > childParams.getSoftLifetimeSeconds()); - assertTrue(childParams.getSoftLifetimeSeconds() > 0); - - assertEquals( - Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS), - childParams.getInboundTrafficSelectors()); - assertEquals( - Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS), - childParams.getOutboundTrafficSelectors()); - } - - private void verifyChildParamsWithCustomizedValues(ChildSessionParams childParams) { - assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals()); - - assertEquals(HARD_LIFETIME_SECONDS, childParams.getHardLifetimeSeconds()); - assertEquals(SOFT_LIFETIME_SECONDS, childParams.getSoftLifetimeSeconds()); - - assertEquals( - Arrays.asList(INBOUND_V4_TS, INBOUND_V6_TS), - childParams.getInboundTrafficSelectors()); - assertEquals( - Arrays.asList(OUTBOUND_V4_TS, OUTBOUND_V6_TS), - childParams.getOutboundTrafficSelectors()); - } - - @Test - public void testBuildTransportModeParamsWithDefaultValues() { - TransportModeChildSessionParams childParams = - new TransportModeChildSessionParams.Builder().addSaProposal(mSaProposal).build(); - - verifyTransportModeChildParamsWithDefaultValues(childParams); - } - - @Test - public void testBuildTunnelModeParamsWithDefaultValues() { - TunnelModeChildSessionParams childParams = - new TunnelModeChildSessionParams.Builder().addSaProposal(mSaProposal).build(); - - verifyTunnelModeChildParamsWithDefaultValues(childParams); - assertTrue(childParams.getConfigurationRequests().isEmpty()); - } - - @Test - public void testBuildTransportModeParamsWithCustomizedValues() { - TransportModeChildSessionParams childParams = - new TransportModeChildSessionParams.Builder() - .addSaProposal(mSaProposal) - .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) - .addInboundTrafficSelectors(INBOUND_V4_TS) - .addInboundTrafficSelectors(INBOUND_V6_TS) - .addOutboundTrafficSelectors(OUTBOUND_V4_TS) - .addOutboundTrafficSelectors(OUTBOUND_V6_TS) - .build(); - - verifyTransportModeChildParamsWithCustomizedValues(childParams); - } - - @Test - public void testBuildTunnelModeParamsWithCustomizedValues() { - TunnelModeChildSessionParams childParams = - new TunnelModeChildSessionParams.Builder() - .addSaProposal(mSaProposal) - .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) - .addInboundTrafficSelectors(INBOUND_V4_TS) - .addInboundTrafficSelectors(INBOUND_V6_TS) - .addOutboundTrafficSelectors(OUTBOUND_V4_TS) - .addOutboundTrafficSelectors(OUTBOUND_V6_TS) - .build(); - - verifyTunnelModeChildParamsWithCustomizedValues(childParams); - } - - @Test - public void testBuildChildSessionParamsWithConfigReq() { - TunnelModeChildSessionParams childParams = - new TunnelModeChildSessionParams.Builder() - .addSaProposal(mSaProposal) - .addInternalAddressRequest(AF_INET) - .addInternalAddressRequest(AF_INET6) - .addInternalAddressRequest(AF_INET6) - .addInternalAddressRequest(IPV4_ADDRESS_REMOTE) - .addInternalAddressRequest(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN) - .addInternalDnsServerRequest(AF_INET) - .addInternalDnsServerRequest(AF_INET6) - .addInternalDhcpServerRequest(AF_INET) - .addInternalDhcpServerRequest(AF_INET) - .build(); - - verifyTunnelModeChildParamsWithDefaultValues(childParams); - - // Verify config request types and number of requests for each type - Map, Integer> expectedAttributeCounts = - new HashMap<>(); - expectedAttributeCounts.put(ConfigRequestIpv4Address.class, 2); - expectedAttributeCounts.put(ConfigRequestIpv6Address.class, 3); - expectedAttributeCounts.put(ConfigRequestIpv4Netmask.class, 1); - expectedAttributeCounts.put(ConfigRequestIpv4DnsServer.class, 1); - expectedAttributeCounts.put(ConfigRequestIpv6DnsServer.class, 1); - expectedAttributeCounts.put(ConfigRequestIpv4DhcpServer.class, 2); - verifyConfigRequestTypes(expectedAttributeCounts, childParams.getConfigurationRequests()); - - // Verify specific IPv4 address request - Set expectedV4Addresses = new HashSet<>(); - expectedV4Addresses.add(IPV4_ADDRESS_REMOTE); - verifySpecificV4AddrConfigReq(expectedV4Addresses, childParams); - - // Verify specific IPv6 address request - Set expectedV6Addresses = new HashSet<>(); - expectedV6Addresses.add(new LinkAddress(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN)); - verifySpecificV6AddrConfigReq(expectedV6Addresses, childParams); - } - - protected void verifySpecificV4AddrConfigReq( - Set expectedAddresses, TunnelModeChildSessionParams childParams) { - for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) { - if (req instanceof ConfigRequestIpv4Address - && ((ConfigRequestIpv4Address) req).getAddress() != null) { - Inet4Address address = ((ConfigRequestIpv4Address) req).getAddress(); - - // Fail if expectedAddresses does not contain this address - assertTrue(expectedAddresses.remove(address)); - } - } - - // Fail if any expected address is not found in result - assertTrue(expectedAddresses.isEmpty()); - } - - protected void verifySpecificV6AddrConfigReq( - Set expectedAddresses, TunnelModeChildSessionParams childParams) { - for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) { - if (req instanceof ConfigRequestIpv6Address - && ((ConfigRequestIpv6Address) req).getAddress() != null) { - ConfigRequestIpv6Address ipv6AddrReq = (ConfigRequestIpv6Address) req; - - // Fail if expectedAddresses does not contain this address - LinkAddress address = - new LinkAddress(ipv6AddrReq.getAddress(), ipv6AddrReq.getPrefixLength()); - assertTrue(expectedAddresses.remove(address)); - } - } - - // Fail if any expected address is not found in result - assertTrue(expectedAddresses.isEmpty()); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java deleted file mode 100644 index 0317def92e..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import android.net.ipsec.ike.IkeDerAsn1DnIdentification; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeIpv4AddrIdentification; -import android.net.ipsec.ike.IkeIpv6AddrIdentification; -import android.net.ipsec.ike.IkeKeyIdIdentification; -import android.net.ipsec.ike.IkeRfc822AddrIdentification; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import javax.security.auth.x500.X500Principal; - -@RunWith(AndroidJUnit4.class) -public final class IkeIdentificationTest extends IkeTestBase { - @Test - public void testIkeDerAsn1DnIdentification() throws Exception { - X500Principal asn1Dn = new X500Principal(LOCAL_ASN1_DN_STRING); - - IkeDerAsn1DnIdentification ikeId = new IkeDerAsn1DnIdentification(asn1Dn); - assertEquals(asn1Dn, ikeId.derAsn1Dn); - } - - @Test - public void testIkeFqdnIdentification() throws Exception { - IkeFqdnIdentification ikeId = new IkeFqdnIdentification(LOCAL_HOSTNAME); - assertEquals(LOCAL_HOSTNAME, ikeId.fqdn); - } - - @Test - public void testIkeIpv4AddrIdentification() throws Exception { - IkeIpv4AddrIdentification ikeId = new IkeIpv4AddrIdentification(IPV4_ADDRESS_LOCAL); - assertEquals(IPV4_ADDRESS_LOCAL, ikeId.ipv4Address); - } - - @Test - public void testIkeIpv6AddrIdentification() throws Exception { - IkeIpv6AddrIdentification ikeId = new IkeIpv6AddrIdentification(IPV6_ADDRESS_LOCAL); - assertEquals(IPV6_ADDRESS_LOCAL, ikeId.ipv6Address); - } - - @Test - public void testIkeKeyIdIdentification() throws Exception { - IkeKeyIdIdentification ikeId = new IkeKeyIdIdentification(LOCAL_KEY_ID); - assertArrayEquals(LOCAL_KEY_ID, ikeId.keyId); - } - - @Test - public void testIkeRfc822AddrIdentification() throws Exception { - IkeRfc822AddrIdentification ikeId = new IkeRfc822AddrIdentification(LOCAL_RFC822_NAME); - assertEquals(LOCAL_RFC822_NAME, ikeId.rfc822Name); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java deleted file mode 100644 index 9be1dc72cf..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import android.net.InetAddresses; -import android.net.LinkAddress; -import android.net.ipsec.ike.IkeDerAsn1DnIdentification; -import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeTrafficSelector; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.internal.net.ipsec.ike.testutils.CertUtils; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.util.ArrayList; -import java.util.Arrays; - -import javax.security.auth.x500.X500Principal; - -/** - * Explicitly test setting up transport mode Child SA so that devices do not have - * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in - * IkeSessionPskTest and authentication method is orthogonal to Child mode. - */ -@RunWith(AndroidJUnit4.class) -public class IkeSessionDigitalSignatureTest extends IkeSessionTestBase { - private static final int EXPECTED_AUTH_REQ_FRAG_COUNT = 3; - - private static final String IKE_INIT_RESP = - "46B8ECA1E0D72A18BF3FA1C2CB1EE86F21202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0100030000080300000503000008" - + "0200000400000008040000022800008800020000328451C8A976CE69E407966A" - + "50D7320C4197A15A07267CE1B16BAFF9BDBBDEC1FDCDAAF7175ADF9AA8DB55DB" - + "2D70C012D01D914C4EDEF6E8B226868EA1D01B2ED0C4C5C86E6BFE566010EC0C" - + "33BA1C93666430B88BDA0470D82CC4F4416F49E3E361E3017C9F27811A66718B" - + "389E1800915D776D59AA528A7E1D1B7815D35144290000249FE8FABE7F43D917" - + "CE370DE2FD9C22BBC082951AC26C1BA26DE795470F2C25BC2900001C00004004" - + "AE388EC86D6D1A470D44142D01AB2E85A7AC14182900001C0000400544A235A4" - + "171C884286B170F48FFC181DB428D87D290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - private static final String IKE_AUTH_RESP_FRAG_1 = - "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000004E0240004C4" - + "00010002DF6750A2D1D5675006F9F6230BB886FFD20CFB973FD04963CFD7A528" - + "560598C58CC44178B2FCBBBBB271387AC81A664B7E7F1055B912F8C686E287C9" - + "D31684C66339151AB86DA3CF1DA664052FA97687634558A1E9E6B37E16A86BD1" - + "68D76DA5E2E1E0B7E98EB662D80D542307015D2BF134EBBBE425D6954FE8C2C4" - + "D31D16C16AA0521C3C481F873ECF25BB8B05AC6083775C1821CAAB1E35A3955D" - + "85ACC599574142E1DD5B262D6E5365CBF6EBE92FFCC16BC29EC3239456F3B202" - + "492551C0F6D752ADCCA56D506D50CC8809EF6BC56EAD005586F7168F76445FD3" - + "1366CC62D32C0C19B28210B8F813F97CD6A447C3857EFD6EC483DDA8ACD9870E" - + "5A21B9C66F0FA44496C0C3D05E8859A1A4CFC88155D0C411BABC13033DD41FA4" - + "AF08CE7734A146687F374F95634D1F26843203CA1FFD05CA3EB150CEA02FBF14" - + "712B7A1C9BC7616A086E7FCA059E7D64EFF98DB895B32F8F7002762AF7D12F23" - + "31E9DD25174C4CE273E5392BBB48F50B7A3E0187181216265F6A4FC7B91BE0AB" - + "C601A580149D4B07411AE99DDB1944B977E86ADC9746605C60A92B569EEFAFFC" - + "3A888D187B75D8F13249689FC28EBCD62B5E03AF171F3A561F0DEA3B1A75F531" - + "971157DCE1E7BC6E7789FF3E8156015BC9C521EFE48996B41471D33BF09864E4" - + "2436E8D7EB6218CDE7716DA754A924B123A63E25585BF27F4AC043A0C4AECE38" - + "BB59DD62F5C0EC657206A76CED1BD26262237DA1CA6815435992A825758DEBEC" - + "DDF598A22B8242AC4E34E70704DBA7B7B73DC3E067C1C98764F8791F84C99156" - + "947D1FFC875F36FCE24B89369C1B5BF1D4C999DCA28E72A528D0E0163C66C067" - + "E71B5E0025C13DA93313942F9EDA230B3ADC254821A4CB1A5DC9D0C5F4DC4E8E" - + "CE46B7B8C72D3C5923C9B30DF1EF7B4EDEDA8BD05C86CA0162AE1BF8F277878E" - + "607401BAA8F06E3EA873FA4C137324C4E0699277CDF649FE7F0F01945EE25FA7" - + "0E4A89737E58185B11B4CB52FD5B0497D3E3CD1CEE7B1FBB3E969DB6F4C324A1" - + "32DC6A0EA21F41332435FD99140C286F8ABBBA926953ADBEED17D30AAD953909" - + "1347EF6D87163D6B1FF32D8B11FFB2E69FAEE7FE913D3826FBA7F9D11E0E3C57" - + "27625B37D213710B5DD8965DAEFD3F491E8C029E2BF361039949BADEC31D60AC" - + "355F26EE41339C03CC9D9B01C3C7F288F0E9D6DFEE78231BDA9AC10FED135913" - + "2836B1A17CE060742B7E5B738A7177CCD59F70337BA251409C377A0FA5333204" - + "D8622BA8C06DE0BEF4F32B6D4D77BE9DE977445D8A2A08C5C38341CB7974FBFB" - + "22C8F983A7D6CEF068DDB2281E6673453521C831C1826861005AE5F37649BC64" - + "0A6360B23284861441A440F1C5AADE1AB53CA63DB17F4C314D493C4C44DE5F20" - + "75E084D080F92791F30BDD88373D50AB5A07BC72B0E7FFFA593103964E55603E" - + "F7FEB7CA0762A1A7B86B6CCAD88CD6CBC7C6935D21F5F06B2700588A2530E619" - + "DA1648AC809F3DDF56ACE5951737568FFEC7E2AB1AA0AE01B03A7F5A29CE73C0" - + "5D2801B17CAAD0121082E9952FAB16BA1C386336C62D4CF3A5019CF61609433E" - + "1C083237D47C4CF575097F7BF9000EF6B6C497A44E6480154A35669AD276BF05" - + "6CC730B4E5962B6AF96CC6D236AE85CEFDA6877173F72D2F614F6696D1F9DF07" - + "E107758B0978F69BC9DBE0CCBF252C40A3FDF7CE9104D3344F7B73593CCD73E0"; - private static final String IKE_AUTH_RESP_FRAG_2 = - "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000000F0000000D4" - + "00020002155211EA41B37BC5F20568A6AE57038EEE208F94F9B444004F1EF391" - + "2CABFCF857B9CD95FAAA9489ED10A3F5C93510820E22E23FC55ED8049E067D72" - + "3645C00E1E08611916CE72D7F0A84123B63A8F3B9E78DBBE39967B7BB074AF4D" - + "BF2178D991EDBDD01908A14A266D09236DB963B14AC33D894F0F83A580209EFD" - + "61875BB56273AA336C22D6A4D890B93E0D42435667830CC32E4F608500E18569" - + "3E6C1D88C0B5AE427333C86468E3474DAA4D1506AAB2A4021309A33DD759D0D0" - + "A8C98BF7FBEA8109361A9F194D0FD756"; - private static final String DELETE_IKE_RESP = - "46B8ECA1E0D72A18BF3FA1C2CB1EE86F2E202520000000020000004C00000030" - + "342842D8DA37C8EFB92ED37C4FBB23CBDC90445137D6A0AF489F9F03641DBA9D" - + "02F6F59FD8A7A78C7261CEB8"; - - // Using IPv4 for transport mode Child SA. IPv6 is currently infeasible because the IKE server - // that generates the test vectors is running in an IPv4 only network. - private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("172.58.35.103"), - InetAddresses.parseNumericAddress("172.58.35.103")); - - // TODO(b/157510502): Add test for IKE Session setup with transport mode Child in IPv6 network - - private static final String LOCAL_ID_ASN1_DN = - "CN=client.test.ike.android.net, O=Android, C=US"; - private static final String REMOTE_ID_ASN1_DN = - "CN=server.test.ike.android.net, O=Android, C=US"; - - private static X509Certificate sServerCaCert; - private static X509Certificate sClientEndCert; - private static X509Certificate sClientIntermediateCaCertOne; - private static X509Certificate sClientIntermediateCaCertTwo; - private static RSAPrivateKey sClientPrivateKey; - - @BeforeClass - public static void setUpCertsBeforeClass() throws Exception { - sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); - sClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); - sClientIntermediateCaCertOne = - CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem"); - sClientIntermediateCaCertTwo = - CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem"); - sClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); - } - - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { - IkeSessionParams ikeParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(remoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification( - new IkeDerAsn1DnIdentification(new X500Principal(LOCAL_ID_ASN1_DN))) - .setRemoteIdentification( - new IkeDerAsn1DnIdentification( - new X500Principal(REMOTE_ID_ASN1_DN))) - .setAuthDigitalSignature( - sServerCaCert, - sClientEndCert, - Arrays.asList( - sClientIntermediateCaCertOne, sClientIntermediateCaCertTwo), - sClientPrivateKey) - .build(); - - return new IkeSession( - sContext, - ikeParams, - buildTransportModeChildParamsWithTs( - TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), - mUserCbExecutor, - mIkeSessionCallback, - mFirstChildSessionCallback); - } - - @Test - public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception { - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - performSetupIkeAndFirstChildBlocking( - IKE_INIT_RESP, - EXPECTED_AUTH_REQ_FRAG_COUNT /* expectedReqPktCnt */, - true /* expectedAuthUseEncap */, - IKE_AUTH_RESP_FRAG_1, - IKE_AUTH_RESP_FRAG_2); - - // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 - int expectedMsgId = 2; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TRANSPORT_MODE_INBOUND_TS), - Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Close IKE Session - ikeSession.close(); - performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP); - verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java deleted file mode 100644 index cb771276dc..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import android.net.InetAddresses; -import android.net.LinkAddress; -import android.net.eap.EapSessionConfig; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeTrafficSelector; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.internal.net.ipsec.ike.testutils.CertUtils; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Explicitly test setting up transport mode Child SA so that devices do not have - * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in - * IkeSessionPskTest and authentication method is orthogonal to Child mode. - */ -@RunWith(AndroidJUnit4.class) -public class IkeSessionMschapV2Test extends IkeSessionTestBase { - private static final String IKE_INIT_RESP = - "46B8ECA1E0D72A1873F643FF94D249A921202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0080030000080300000203000008" - + "0200000200000008040000022800008800020000CC6E71E67E32CED6BCE33FBD" - + "A74113867E3FA3AE21C7C9AB44A7F8835DF602BFD6F6528B67FEE39821232380" - + "C99E8FFC0A5D767F8F38906DA41946C2299DF18C15FA69BAC08D3EDB32E8C8CA" - + "28431831561C04CB0CDE393F817151CD8DAF7A311838411F1C39BFDB5EBCF6A6" - + "1DF66DEB067362649D64607D599B56C4227819D0290000241197004CF31AD00F" - + "5E0C92E198488D8A2B6F6A25C82762AA49F565BCE9D857D72900001C00004004" - + "A0D98FEABBFB92A6C0976EE83D2AACFCCF969A6B2900001C0000400575EBF73F" - + "8EE5CC73917DE9D3F91FCD4A16A0444D290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - private static final String IKE_AUTH_RESP_1_FRAG_1 = - "46B8ECA1E0D72A1873F643FF94D249A93520232000000001000004E0240004C4" - + "00010002C4159CB756773B3F1911F4595107BC505D7A28C72F05182966076679" - + "CA68ED92E4BC5CD441C9CB315F2F449A8A521CAFED3C5F285E295FC3791D3415" - + "E3BACF66A08410DF4E35F7D88FE40DA28851C91C77A6549E186AC1B7846DF3FA" - + "0A347A5ABBCAEE19E70F0EE5966DC6242A115F29523709302EDAD2E36C8F0395" - + "CF5C42EC2D2898ECDD8A6AEDD686A70B589A981558667647F32F41E0D8913E94" - + "A6693F53E59EA8938037F562CF1DC5E6E2CDC630B5FFB08949E3172249422F7D" - + "EA069F9BAD5F96E48BADC7164A9269669AD0DF295A80C54D1D23CEA3F28AC485" - + "86D2A9850DA23823037AB7D1577B7B2364C92C36B84238357129EB4A64D33310" - + "B95DCD50CD53E78C32EFE7DC1627D9432E9BFDEE130045DE967B19F92A9D1270" - + "F1E2C6BFBAA56802F3E63510578EF1ECB6872852F286EEC790AA1FE0CAF391CB" - + "E276554922713BA4770CFE71E23F043DC620E22CC02A74F60725D18331B7F2C9" - + "276EB6FBB7CBDAA040046D7ECBE1A5D7064E04E542807C5101B941D1C81B9D5E" - + "90347B22BD4E638E2EDC98E369B51AA29BDB2CF8AA610D4B893EB83A4650717C" - + "38B4D145EE939C18DCEDF6C79933CEB3D7C116B1F188DF9DDD560951B54E4A7D" - + "80C999A32AB02BF39D7B498DAD36F1A5CBE2F64557D6401AE9DD6E0CEADA3F90" - + "540FE9114BB6B8719C9064796354F4A180A6600CAD092F8302564E409B71ACB7" - + "590F19B3AC88E7A606C718D0B97F7E4B4830F11D851C59F2255846DA22E2C805" - + "0CA2AF2ACF3B6C769D11B75B5AC9AB82ED3D90014994B1BF6FED58FBEF2D72EF" - + "8BDFE51F9A101393A7CA1ACF78FAEBF3E3CC25E09407D1E14AF351A159A13EE3" - + "9B919BA8B49942792E7527C2FB6D418C4DF427669A4BF5A1AFBBB973BAF17918" - + "9C9D520CAC2283B89A539ECE785EBE48FBB77D880A17D55C84A51F46068A4B87" - + "FF48FEEE50E1E034CC8AFF5DA92105F55EC4823E67BDFE942CA8BE0DAECBBD52" - + "E8AAF306049DC6C4CF87D987B0AC54FCE92E6AE8507965AAAC6AB8BD3405712F" - + "EE170B70BC64BDCBD86D80C7AAAF341131F9A1210D7430B17218413AE1363183" - + "5C98FA2428B1E9E987ADC9070E232310A28F4C3163E18366FFB112BADD7C5E0F" - + "D13093A7C1428F87856BA0A7E46955589ACA267CE7A04320C4BCDBB60C672404" - + "778F8D511AAB09349DAB482445D7F606F28E7FBBB18FC0F4EC0AF04F44C282F9" - + "39C6E3B955C84DADEA350667236583069B74F492D600127636FA31F63E560851" - + "2FC28B8EA5B4D01D110990B6EA46B9C2E7C7C856C240EF7A8147BA2C4344B85A" - + "453C862024B5B6814D13CDEAEF7683D539BB50CAFFC0416F269F2F9EDEC5FA30" - + "022FD7B4B186CD2020E7ED8D81ED90822EDD8B76F840DD68F09694CFF9B4F33E" - + "11DF4E601A4212881A6D4E9259001705C41E9E23D18A7F3D4A3463649A38211A" - + "5A90D0F17739A677C74E23F31C01D60B5A0F1E6A4D44FED9D25BF1E63418E1FC" - + "0B19F6F4B71DE53C62B14B82279538A82DD4BE19AB6E00AFC20F124AAB7DF21A" - + "42259BE4F40EC69B16917256F23E2C37376311D62E0A3A0EF8C2AD0C090221D5" - + "C5ECA08F08178A4D31FFDB150C609827D18AD83C7B0A43AEE0406BD3FB494B53" - + "A279FDD6447E234C926AD8CE47FFF779BB45B1FC8457C6E7D257D1359959D977" - + "CEF6906A3367DC4D454993EFDC6F1EA94E17EB3DCB00A289346B4CFD7F19B16E"; - private static final String IKE_AUTH_RESP_1_FRAG_2 = - "46B8ECA1E0D72A1873F643FF94D249A935202320000000010000008000000064" - + "00020002C61F66025E821A5E69A4DE1F591A2C32C983C3154A5003660137D685" - + "A5262B9FDF5EDC699DE4D8BD38F549E3CBD12024B45B4C86561C36C3EED839DA" - + "9860C6AA0B764C662D08F1B6A98F68CF6E3038F737C0B415AD8A8B7D702BD92A"; - private static final String IKE_AUTH_RESP_2 = - "46B8ECA1E0D72A1873F643FF94D249A92E202320000000020000008C30000070" - + "62B90C2229FD23025BC2FD7FE6341E9EE04B17264CD619BCE18975A5F88BE438" - + "D4AD4A5310057255AF568C293A29B10107E3EE3675C10AA2B26404D90C0528CC" - + "F7605A86C96A1F2635CCC6CFC90EE65E5C2A2262EB33FE520EB708423A83CB63" - + "274ECCBB102AF5DF35742657"; - private static final String IKE_AUTH_RESP_3 = - "46B8ECA1E0D72A1873F643FF94D249A92E202320000000030000004C30000030" - + "AB52C3C80123D3432C05AF457CE93C352395F73E861CD49561BA528CFE68D17D" - + "78BBF6FC41E81C2B9EA051A2"; - private static final String IKE_AUTH_RESP_4 = - "46B8ECA1E0D72A1873F643FF94D249A92E20232000000004000000CC270000B0" - + "8D3342A7AB2666AC754F4B55C5C6B1A61255E62FBCA53D5CDEEDE60DADB7915C" - + "7F962076A58BF7D39A05ED1B60FF349B6DE311AF7CEBC72B4BB9723A728A5D3E" - + "9E508B2D7A11843D279B56ADA07E608D61F5CA7638F10372A440AD1DCE44E190" - + "7B7B7A68B126EBBB86638D667D5B528D233BA8D32D7E0FAC4E1448E87396EEE6" - + "0985B79841E1229D7962AACFD8F872722EC8D5B19D4C82D6C4ADCB276127A1A7" - + "3FC84CDF85B2299BC96B64AC"; - private static final String DELETE_IKE_RESP = - "46B8ECA1E0D72A1873F643FF94D249A92E202520000000050000004C00000030" - + "622CE06C8CB132AA00567E9BC83F58B32BD7DB5130C76E385B306434DA227361" - + "D50CC19D408A8D4F36F9697F"; - - // This value is align with the test vectors hex that are generated in an IPv4 environment - private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("172.58.35.67"), - InetAddresses.parseNumericAddress("172.58.35.67")); - - private static final EapSessionConfig EAP_CONFIG = - new EapSessionConfig.Builder() - .setEapIdentity(EAP_IDENTITY) - .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) - .build(); - - private static X509Certificate sServerCaCert; - - @BeforeClass - public static void setUpCertBeforeClass() throws Exception { - sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); - } - - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { - IkeSessionParams ikeParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(remoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) - .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) - .setAuthEap(sServerCaCert, EAP_CONFIG) - .build(); - return new IkeSession( - sContext, - ikeParams, - buildTransportModeChildParamsWithTs( - TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), - mUserCbExecutor, - mIkeSessionCallback, - mFirstChildSessionCallback); - } - - @Test - public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception { - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - IKE_INIT_RESP); - - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - IKE_AUTH_RESP_1_FRAG_1, - IKE_AUTH_RESP_1_FRAG_2); - - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - IKE_AUTH_RESP_2); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - IKE_AUTH_RESP_3); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - IKE_AUTH_RESP_4); - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TRANSPORT_MODE_INBOUND_TS), - Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Close IKE Session - ikeSession.close(); - performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP); - verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java deleted file mode 100644 index c767b78120..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID; -import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; -import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.telephony.TelephonyManager.APPTYPE_USIM; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import android.net.eap.EapSessionConfig; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeIdentification; -import android.net.ipsec.ike.IkeSaProposal; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer; -import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer; -import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.internal.net.ipsec.ike.testutils.CertUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -@RunWith(AndroidJUnit4.class) -public final class IkeSessionParamsTest extends IkeSessionTestBase { - private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(20L); - private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(10L); - private static final int DPD_DELAY_SECONDS = (int) TimeUnit.MINUTES.toSeconds(10L); - private static final int[] RETRANS_TIMEOUT_MS_LIST = new int[] {500, 500, 500, 500, 500, 500}; - - private static final Map, Integer> EXPECTED_REQ_COUNT = - new HashMap<>(); - private static final HashSet EXPECTED_PCSCF_SERVERS = new HashSet<>(); - - static { - EXPECTED_REQ_COUNT.put(ConfigRequestIpv4PcscfServer.class, 3); - EXPECTED_REQ_COUNT.put(ConfigRequestIpv6PcscfServer.class, 3); - - EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_1); - EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_2); - EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_1); - EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_2); - } - - // Arbitrary proposal and remote ID. Local ID is chosen to match the client end cert in the - // following CL - private static final IkeSaProposal SA_PROPOSAL = - SaProposalTest.buildIkeSaProposalWithNormalModeCipher(); - private static final IkeIdentification LOCAL_ID = new IkeFqdnIdentification(LOCAL_HOSTNAME); - private static final IkeIdentification REMOTE_ID = new IkeFqdnIdentification(REMOTE_HOSTNAME); - - private static final EapSessionConfig EAP_ALL_METHODS_CONFIG = - createEapOnlySafeMethodsBuilder() - .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD) - .build(); - private static final EapSessionConfig EAP_ONLY_SAFE_METHODS_CONFIG = - createEapOnlySafeMethodsBuilder().build(); - - private X509Certificate mServerCaCert; - private X509Certificate mClientEndCert; - private X509Certificate mClientIntermediateCaCertOne; - private X509Certificate mClientIntermediateCaCertTwo; - private RSAPrivateKey mClientPrivateKey; - - @Before - public void setUp() throws Exception { - // This address is never used except for setting up the test network - setUpTestNetwork(IPV4_ADDRESS_LOCAL); - - mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem"); - mClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem"); - mClientIntermediateCaCertOne = - CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem"); - mClientIntermediateCaCertTwo = - CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem"); - mClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key"); - } - - @After - public void tearDown() throws Exception { - tearDownTestNetwork(); - } - - private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() { - return new EapSessionConfig.Builder() - .setEapIdentity(EAP_IDENTITY) - .setEapSimConfig(SUB_ID, APPTYPE_USIM) - .setEapAkaConfig(SUB_ID, APPTYPE_USIM) - .setEapAkaPrimeConfig( - SUB_ID, APPTYPE_USIM, NETWORK_NAME, true /* allowMismatchedNetworkNames */); - } - - /** - * Create a Builder that has minimum configurations to build an IkeSessionParams. - * - *

    Authentication method is arbitrarily selected. Using other method (e.g. setAuthEap) also - * works. - */ - private IkeSessionParams.Builder createIkeParamsBuilderMinimum() { - return new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) - .addSaProposal(SA_PROPOSAL) - .setLocalIdentification(LOCAL_ID) - .setRemoteIdentification(REMOTE_ID) - .setAuthPsk(IKE_PSK); - } - - /** - * Verify the minimum configurations to build an IkeSessionParams. - * - * @see #createIkeParamsBuilderMinimum - */ - private void verifyIkeParamsMinimum(IkeSessionParams sessionParams) { - assertEquals(mTunNetwork, sessionParams.getNetwork()); - assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); - assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); - assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); - assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthPskConfig); - assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk()); - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthPskConfig); - assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); - } - - @Test - public void testBuildWithMinimumSet() throws Exception { - IkeSessionParams sessionParams = createIkeParamsBuilderMinimum().build(); - - verifyIkeParamsMinimum(sessionParams); - - // Verify default values that do not need explicit configuration. Do not do assertEquals - // to be avoid being a change-detector test - assertTrue(sessionParams.getHardLifetimeSeconds() > sessionParams.getSoftLifetimeSeconds()); - assertTrue(sessionParams.getSoftLifetimeSeconds() > 0); - assertTrue(sessionParams.getDpdDelaySeconds() > 0); - assertTrue(sessionParams.getRetransmissionTimeoutsMillis().length > 0); - for (int timeout : sessionParams.getRetransmissionTimeoutsMillis()) { - assertTrue(timeout > 0); - } - assertTrue(sessionParams.getConfigurationRequests().isEmpty()); - assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); - } - - @Test - public void testSetLifetimes() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS) - .build(); - - verifyIkeParamsMinimum(sessionParams); - assertEquals(HARD_LIFETIME_SECONDS, sessionParams.getHardLifetimeSeconds()); - assertEquals(SOFT_LIFETIME_SECONDS, sessionParams.getSoftLifetimeSeconds()); - } - - @Test - public void testSetDpdDelay() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum().setDpdDelaySeconds(DPD_DELAY_SECONDS).build(); - - verifyIkeParamsMinimum(sessionParams); - assertEquals(DPD_DELAY_SECONDS, sessionParams.getDpdDelaySeconds()); - } - - @Test - public void testSetRetransmissionTimeouts() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST) - .build(); - - verifyIkeParamsMinimum(sessionParams); - assertArrayEquals(RETRANS_TIMEOUT_MS_LIST, sessionParams.getRetransmissionTimeoutsMillis()); - } - - @Test - public void testSetPcscfConfigRequests() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST) - .addPcscfServerRequest(AF_INET) - .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_1) - .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_1) - .addPcscfServerRequest(AF_INET6) - .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_2) - .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_2) - .build(); - - verifyIkeParamsMinimum(sessionParams); - verifyConfigRequestTypes(EXPECTED_REQ_COUNT, sessionParams.getConfigurationRequests()); - - Set resultAddresses = new HashSet<>(); - for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) { - if (req instanceof ConfigRequestIpv4PcscfServer - && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) { - resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress()); - } else if (req instanceof ConfigRequestIpv6PcscfServer - && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) { - resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress()); - } - } - assertEquals(EXPECTED_PCSCF_SERVERS, resultAddresses); - } - - @Test - public void testAddIkeOption() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) - .build(); - - verifyIkeParamsMinimum(sessionParams); - assertTrue(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); - } - - @Test - public void testRemoveIkeOption() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimum() - .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) - .removeIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID) - .build(); - - verifyIkeParamsMinimum(sessionParams); - assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)); - } - - /** - * Create a Builder that has minimum configurations to build an IkeSessionParams, except for - * authentication method. - */ - private IkeSessionParams.Builder createIkeParamsBuilderMinimumWithoutAuth() { - return new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress()) - .addSaProposal(SA_PROPOSAL) - .setLocalIdentification(LOCAL_ID) - .setRemoteIdentification(REMOTE_ID); - } - - /** - * Verify the minimum configurations to build an IkeSessionParams, except for authentication - * method. - * - * @see #createIkeParamsBuilderMinimumWithoutAuth - */ - private void verifyIkeParamsMinimumWithoutAuth(IkeSessionParams sessionParams) { - assertEquals(mTunNetwork, sessionParams.getNetwork()); - assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname()); - assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals()); - assertEquals(LOCAL_ID, sessionParams.getLocalIdentification()); - assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification()); - } - - @Test - public void testBuildWithPsk() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth().setAuthPsk(IKE_PSK).build(); - - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthPskConfig); - assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk()); - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthPskConfig); - assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk()); - } - - @Test - public void testBuildWithEap() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG) - .build(); - - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthEapConfig); - assertEquals(EAP_ALL_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig()); - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); - assertEquals( - mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); - } - - @Test - public void testBuildWithEapOnlyAuth() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthEap(mServerCaCert, EAP_ONLY_SAFE_METHODS_CONFIG) - .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH) - .build(); - - assertTrue(sessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH)); - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthEapConfig); - assertEquals(EAP_ONLY_SAFE_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig()); - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); - assertEquals( - mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); - } - - @Test - public void testThrowBuildEapOnlyAuthWithUnsafeMethod() throws Exception { - try { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG) - .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH) - .build(); - fail("Expected to fail because EAP only unsafe method is proposed"); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testBuildWithDigitalSignature() throws Exception { - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthDigitalSignature(mServerCaCert, mClientEndCert, mClientPrivateKey) - .build(); - - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); - IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig; - assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate()); - assertEquals(Collections.EMPTY_LIST, localSignConfig.getIntermediateCertificates()); - assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey()); - - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); - assertEquals( - mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); - } - - @Test - public void testBuildWithDigitalSignatureAndIntermediateCerts() throws Exception { - List intermediateCerts = - Arrays.asList(mClientIntermediateCaCertOne, mClientIntermediateCaCertTwo); - - IkeSessionParams sessionParams = - createIkeParamsBuilderMinimumWithoutAuth() - .setAuthDigitalSignature( - mServerCaCert, mClientEndCert, intermediateCerts, mClientPrivateKey) - .build(); - - verifyIkeParamsMinimumWithoutAuth(sessionParams); - - IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig(); - assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); - IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig; - assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate()); - assertEquals(intermediateCerts, localSignConfig.getIntermediateCertificates()); - assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey()); - - IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig(); - assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); - assertEquals( - mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert()); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java deleted file mode 100644 index 13f953a50d..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; -import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; -import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; -import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import android.net.LinkAddress; -import android.net.ipsec.ike.ChildSessionParams; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.exceptions.IkeProtocolException; -import android.platform.test.annotations.AppModeFull; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; - -@RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_IPSEC_TUNNELS permission can't be granted to instant apps") -public class IkeSessionPskTest extends IkeSessionTestBase { - // Test vectors for success workflow - private static final String SUCCESS_IKE_INIT_RESP = - "46B8ECA1E0D72A18B45427679F9245D421202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0080030000080300000203000008" - + "0200000200000008040000022800008800020000A7AA3435D088EC1A2B7C2A47" - + "1FA1B85F1066C9B2006E7C353FB5B5FDBC2A88347ED2C6F5B7A265D03AE34039" - + "6AAC0145CFCC93F8BDB219DDFF22A603B8856A5DC59B6FAB7F17C5660CF38670" - + "8794FC72F273ADEB7A4F316519794AED6F8AB61F95DFB360FAF18C6C8CABE471" - + "6E18FE215348C2E582171A57FC41146B16C4AFE429000024A634B61C0E5C90C6" - + "8D8818B0955B125A9B1DF47BBD18775710792E651083105C2900001C00004004" - + "406FA3C5685A16B9B72C7F2EEE9993462C619ABE2900001C00004005AF905A87" - + "0A32222AA284A7070585601208A282F0290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - private static final String SUCCESS_IKE_AUTH_RESP = - "46B8ECA1E0D72A18B45427679F9245D42E20232000000001000000EC240000D0" - + "0D06D37198F3F0962DE8170D66F1A9008267F98CDD956D984BDCED2FC7FAF84A" - + "A6664EF25049B46B93C9ED420488E0C172AA6635BF4011C49792EF2B88FE7190" - + "E8859FEEF51724FD20C46E7B9A9C3DC4708EF7005707A18AB747C903ABCEAC5C" - + "6ECF5A5FC13633DCE3844A920ED10EF202F115DBFBB5D6D2D7AB1F34EB08DE7C" - + "A54DCE0A3A582753345CA2D05A0EFDB9DC61E81B2483B7D13EEE0A815D37252C" - + "23D2F29E9C30658227D2BB0C9E1A481EAA80BC6BE9006BEDC13E925A755A0290" - + "AEC4164D29997F52ED7DCC2E"; - private static final String SUCCESS_CREATE_CHILD_RESP = - "46B8ECA1E0D72A18B45427679F9245D42E20242000000002000000CC210000B0" - + "484565D4AF6546274674A8DE339E9C9584EE2326AB9260F41C4D0B6C5B02D1D" - + "2E8394E3CDE3094895F2ACCABCDCA8E82960E5196E9622BD13745FC8D6A2BED" - + "E561FF5D9975421BC463C959A3CBA3478256B6D278159D99B512DDF56AC1658" - + "63C65A986F395FE8B1476124B91F83FD7865304EB95B22CA4DD9601DA7A2533" - + "ABF4B36EB1B8CD09522F6A600032316C74E562E6756D9D49D945854E2ABDC4C" - + "3AF36305353D60D40B58BE44ABF82"; - private static final String SUCCESS_DELETE_CHILD_RESP = - "46B8ECA1E0D72A18B45427679F9245D42E202520000000030000004C2A000030" - + "0C5CEB882DBCA65CE32F4C53909335F1365C91C555316C5E9D9FB553F7AA916" - + "EF3A1D93460B7FABAF0B4B854"; - private static final String SUCCESS_DELETE_IKE_RESP = - "46B8ECA1E0D72A18B45427679F9245D42E202520000000040000004C00000030" - + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" - + "6743A7CEB2BE34AC00095A5B8"; - - private IkeSession openIkeSessionWithTunnelModeChild(InetAddress remoteAddress) { - return openIkeSession(remoteAddress, buildTunnelModeChildSessionParams()); - } - - private IkeSession openIkeSessionWithTransportModeChild(InetAddress remoteAddress) { - return openIkeSession(remoteAddress, buildTransportModeChildParamsWithDefaultTs()); - } - - private IkeSession openIkeSession(InetAddress remoteAddress, ChildSessionParams childParams) { - IkeSessionParams ikeParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(remoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) - .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) - .setAuthPsk(IKE_PSK) - .build(); - return new IkeSession( - sContext, - ikeParams, - childParams, - mUserCbExecutor, - mIkeSessionCallback, - mFirstChildSessionCallback); - } - - @BeforeClass - public static void setUpTunnelPermissionBeforeClass() throws Exception { - // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and - // a standard permission is insufficient. So we shell out the appop, to give us the - // right appop permissions. - setAppOp(OP_MANAGE_IPSEC_TUNNELS, true); - } - - // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass - // methods. - @AfterClass - public static void tearDownTunnelPermissionAfterClass() throws Exception { - setAppOp(OP_MANAGE_IPSEC_TUNNELS, false); - } - - @Test - public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception { - if (!hasTunnelsFeature()) return; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); - - // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 - int expectedMsgId = 2; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TUNNEL_MODE_INBOUND_TS), - Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), - Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR)); - - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Open additional Child Session - TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); - ikeSession.openChildSession(buildTunnelModeChildSessionParams(), additionalChildCb); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - SUCCESS_CREATE_CHILD_RESP); - - // Verify opening additional Child Session - verifyChildSessionSetupBlocking( - additionalChildCb, - Arrays.asList(TUNNEL_MODE_INBOUND_TS), - Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord additionalTransformRecordA = - additionalChildCb.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord additionalTransformRecordB = - additionalChildCb.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(additionalTransformRecordA, additionalTransformRecordB); - - // Close additional Child Session - ikeSession.closeChildSession(additionalChildCb); - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - SUCCESS_DELETE_CHILD_RESP); - - verifyDeleteIpSecTransformPair( - additionalChildCb, additionalTransformRecordA, additionalTransformRecordB); - additionalChildCb.awaitOnClosed(); - - // Close IKE Session - ikeSession.close(); - performCloseIkeBlocking(expectedMsgId++, SUCCESS_DELETE_IKE_RESP); - verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); - } - - @Test - public void testIkeSessionSetupAndChildSessionSetupWithTunnelModeV6() throws Exception { - if (!hasTunnelsFeature()) return; - - final String ikeInitResp = - "46B8ECA1E0D72A186F7B6C2CEB77EB9021202220000000000000011822000030" - + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" - + "0200000500000008040000022800008800020000DABAA04B38B491E2403F2125" - + "96ECF1C8EF7B1DC19A422FDD46E1756C826BB3A16404361B775D9950577B5CDF" - + "6AAA1642BD1427BDA8BC55354A97C1025E19C1E2EE2DF8A0C9406E545D829F52" - + "75695008E3B742984B8DD1770F3514213B0DF3EE8B199416DF200D248115C057" - + "1C193E4F96802E5EF48DD99CAC251882A8F7CCC329000024BC6F0F1D3653C2C7" - + "679E02CDB6A3B32B2FEE9AF52F0326D4D9AE073D56CE8922290000080000402E" - + "290000100000402F00020003000400050000000800004014"; - final String ikeAuthResp = - "46B8ECA1E0D72A186F7B6C2CEB77EB902E202320000000010000015024000134" - + "4D115AFDCDAD0310760BB664EB7D405A340869AD6EDF0AAEAD0663A9253DADCB" - + "73EBE5CD29D4FA1CDEADE0B94391B5C4CF77BCC1596ACE3CE6A7891E44888FA5" - + "46632C0EF4E6193C023C9DC59142C37D1C49D6EF5CD324EC6FC35C89E1721C78" - + "91FDCDB723D8062709950F4AA9273D26A54C9C7E86862DBC15F7B6641D2B9BAD" - + "E55069008201D12968D97B537B1518FE87B0FFA03C3EE6012C06721B1E2A3F68" - + "92108BC4A4F7063F7F94562D8B60F291A1377A836CF12BCDA7E15C1A8F3C77BB" - + "6DB7F2C833CCE4CDDED7506536621A3356CE2BC1874E7B1A1A9B447D7DF6AB09" - + "638B8AD94A781B28BB91B514B611B24DF8E8A047A10AE27BBF15C754D3D2F792" - + "D3E1CCADDAE934C98AE53A8FC3419C88AFF0355564F82A629C998012DA7BB704" - + "5307270DF326377E3E1994476902035B"; - final String deleteIkeResp = - "46B8ECA1E0D72A186F7B6C2CEB77EB902E202520000000020000005000000034" - + "CF15C299F35688E5140A48B61C95F004121BF8236201415E5CD45BA41AAB16D4" - + "90B44B9E6D5D92B5B97D24196A58C73F"; - - mLocalAddress = IPV6_ADDRESS_LOCAL; - mRemoteAddress = IPV6_ADDRESS_REMOTE; - - // Teardown current test network that uses IPv4 address and set up new network with IPv6 - // address. - tearDownTestNetwork(); - setUpTestNetwork(mLocalAddress); - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking( - ikeInitResp, - 1 /* expectedAuthReqPktCnt */, - false /* expectedAuthUseEncap */, - ikeAuthResp); - - // Local request message ID starts from 2 because there is one IKE_INIT message and a single - // IKE_AUTH message. - int expectedMsgId = 2; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TUNNEL_MODE_INBOUND_TS_V6), - Arrays.asList(TUNNEL_MODE_OUTBOUND_TS_V6), - Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR_V6), - Arrays.asList(EXPECTED_DNS_SERVERS_ONE, EXPECTED_DNS_SERVERS_TWO)); - - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Close IKE Session - ikeSession.close(); - performCloseIkeBlocking(expectedMsgId++, false /* expectedUseEncap */, deleteIkeResp); - verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); - } - - @Test - public void testIkeSessionKillWithTunnelMode() throws Exception { - if (!hasTunnelsFeature()) return; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); - - ikeSession.kill(); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); - } - - @Test - public void testIkeInitFail() throws Exception { - final String ikeInitFailRespHex = - "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E"; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - ikeInitFailRespHex); - - mFirstChildSessionCallback.awaitOnClosed(); - - IkeProtocolException protocolException = - (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException(); - assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, protocolException.getErrorType()); - assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); - } - - @Test - public void testIkeAuthHandlesAuthFailNotification() throws Exception { - final String ikeInitRespHex = - "46B8ECA1E0D72A18CF94CE3159486F002120222000000000000001502200" - + "00300000002C010100040300000C0100000C800E01000300000803000005" - + "0300000802000004000000080400000228000088000200001821AA854691" - + "FA3292DF710F0AC149ACBD0CB421608B8796C1912AF04C5B4B23936FDEC4" - + "7CB640E3EAFB56BBB562825E87AF68B40E4BAB80A49BAD44407450A4195A" - + "1DD54BD99F48D28C9F0FBA315A3401C1C3C4AD55911F514A8DF2D2467C46" - + "A73DDC1452AE81336E0F0D5EC896D2E7A77628AF2F9089F48943399DF216" - + "EFCD2900002418D2B7E4E6AF0FEFF5962CF8D68F7793B1293FEDE13331D4" - + "AB0CE9436C2EE1EC2900001C0000400457BD9AEF5B362A83DD7F3DDAA4A9" - + "9B6B4041DAF32900001C000040055A81893582701E44D4B6729A22FE06DE" - + "82A03A36290000080000402E290000100000402F00020003000400050000" - + "000800004014"; - final String ikeAuthFailRespHex = - "46B8ECA1E0D72A18CF94CE3159486F002E202320000000010000004C2900" - + "00301B9E4C8242D3BE62E7F0A537FE8B92C6EAB7153105DA421DCE43A06D" - + "AB6E4808BAC0CA1DAD6ADD0A126A41BD"; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthFailRespHex); - - mFirstChildSessionCallback.awaitOnClosed(); - IkeProtocolException protocolException = - (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException(); - assertEquals(ERROR_TYPE_AUTHENTICATION_FAILED, protocolException.getErrorType()); - assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); - } - - @Test - public void testIkeAuthHandlesFirstChildCreationFail() throws Exception { - final String ikeInitRespHex = - "46B8ECA1E0D72A18F5ABBF896A1240BE2120222000000000000001502200" - + "00300000002C010100040300000C0100000C800E0100030000080300000C" - + "03000008020000050000000804000002280000880002000074950F016B85" - + "605E57E24651843AB70E41B552EDEE227DFE51E6CBEC00E75FFEFC7D5453" - + "109B15F721FCD811FC9F113BE06050882F2FC5F5FF25857E555CCFB5AB64" - + "8B0D1D7A819A3B05DE1FE89A4A627C60D5AA06CD0F66ACD3748722F9CD4F" - + "F30AE7477CBC12049821F07AD6C9F0ED732321A6A36FA817722E025AC34B" - + "ABE62900002432E3807F595070E95EDA341A787599B24B1151B535B0222B" - + "65C003401B9B38F82900001C000040043BB760DB3037B51768DFFAB4B21D" - + "B1716EA1C1382900001C0000400531098EB04DF1BE3F304606BD59B454A8" - + "CC7E7311290000080000402E290000100000402F00020003000400050000" - + "000800004014"; - final String ikeAuthCreateChildFailHex = - "46B8ECA1E0D72A18F5ABBF896A1240BE2E20232000000001000000B02400" - + "009400B0861242E0C88ECB3848D772B560CAD65B6AC9DFFDC8622A394B8E" - + "64E550BDD69FCD7E768129787ED9062992C1D6DB0F0631C2E05765B403CF" - + "EF1D0A055B32F6698FF7DB5B8FB1B6A83A81634D00E22C86E35B3BFBEC73" - + "EAC6806678926945BC7A57003DC1A3528A1EC423EE56C1075B36C0B57A6B" - + "C6DD990182F6FABFFA167D199C7D629E5B830AAD2AFBD31CEBA6"; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress); - performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthCreateChildFailHex); - - // Even though the child creation failed, the authentication succeeded, so the IKE Session's - // onOpened() callback is still expected - verifyIkeSessionSetupBlocking(); - - // Verify Child Creation failed - IkeProtocolException protocolException = - (IkeProtocolException) mFirstChildSessionCallback.awaitOnClosedException(); - assertEquals(ERROR_TYPE_TS_UNACCEPTABLE, protocolException.getErrorType()); - assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData()); - - ikeSession.kill(); - mIkeSessionCallback.awaitOnClosed(); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java deleted file mode 100644 index f954fcd031..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static com.android.internal.util.HexDump.hexStringToByteArray; - -import android.net.InetAddresses; -import android.net.LinkAddress; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeTrafficSelector; -import android.net.ipsec.ike.cts.IkeTunUtils.PortPair; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Explicitly test transport mode Child SA so that devices without FEATURE_IPSEC_TUNNELS can be test - * covered. Tunnel mode Child SA setup has been tested in IkeSessionPskTest. Rekeying process is - * independent from Child SA mode. - */ -@RunWith(AndroidJUnit4.class) -public class IkeSessionRekeyTest extends IkeSessionTestBase { - // This value is align with the test vectors hex that are generated in an IPv4 environment - private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("172.58.35.40"), - InetAddresses.parseNumericAddress("172.58.35.40")); - - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { - IkeSessionParams ikeParams = - new IkeSessionParams.Builder(sContext) - .setNetwork(mTunNetwork) - .setServerHostname(remoteAddress.getHostAddress()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher()) - .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME)) - .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME)) - .setAuthPsk(IKE_PSK) - .build(); - return new IkeSession( - sContext, - ikeParams, - buildTransportModeChildParamsWithTs( - TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS), - mUserCbExecutor, - mIkeSessionCallback, - mFirstChildSessionCallback); - } - - private byte[] buildInboundPkt(PortPair outPktSrcDestPortPair, String inboundDataHex) - throws Exception { - // Build inbound packet by flipping the outbound packet addresses and ports - return IkeTunUtils.buildIkePacket( - mRemoteAddress, - mLocalAddress, - outPktSrcDestPortPair.dstPort, - outPktSrcDestPortPair.srcPort, - true /* useEncap */, - hexStringToByteArray(inboundDataHex)); - } - - @Test - public void testRekeyIke() throws Exception { - final String ikeInitResp = - "46B8ECA1E0D72A1866B5248CF6C7472D21202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" - + "0200000500000008040000022800008800020000920D3E830E7276908209212D" - + "E5A7F2A48706CFEF1BE8CB6E3B173B8B4E0D8C2DC626271FF1B13A88619E569E" - + "7B03C3ED2C127390749CDC7CDC711D0A8611E4457FFCBC4F0981B3288FBF58EA" - + "3E8B70E27E76AE70117FBBCB753660ADDA37EB5EB3A81BED6A374CCB7E132C2A" - + "94BFCE402DC76B19C158B533F6B1F2ABF01ACCC329000024B302CA2FB85B6CF4" - + "02313381246E3C53828D787F6DFEA6BD62D6405254AEE6242900001C00004004" - + "7A1682B06B58596533D00324886EF1F20EF276032900001C00004005BF633E31" - + "F9984B29A62E370BB2770FC09BAEA665290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - final String ikeAuthResp = - "46B8ECA1E0D72A1866B5248CF6C7472D2E20232000000001000000F0240000D4" - + "10166CA8647F56123DE74C17FA5E256043ABF73216C812EE32EE1BB01EAF4A82" - + "DC107AB3ADBFEE0DEA5EEE10BDD5D43178F4C975C7C775D252273BB037283C7F" - + "236FE34A6BCE4833816897075DB2055B9FFD66DFA45A0A89A8F70AFB59431EED" - + "A20602FB614369D12906D3355CF7298A5D25364ABBCC75A9D88E0E6581449FCD" - + "4E361A39E00EFD1FD0A69651F63DB46C12470226AA21BA5EFF48FAF0B6DDF61C" - + "B0A69392CE559495EEDB4D1C1D80688434D225D57210A424C213F7C993D8A456" - + "38153FBD194C5E247B592D1D048DB4C8"; - final String rekeyIkeCreateReq = - "46B8ECA1E0D72A1866B5248CF6C7472D2E202400000000000000013021000114" - + "13743670039E308A8409BA5FD47B67F956B36FEE88AC3B70BB5D789B8218A135" - + "1B3D83E260E87B3EDB1BF064F09D4DC2611AEDBC99951B4B2DE767BD4AA2ACC3" - + "3653549CFC66B75869DF003CDC9A137A9CC27776AD5732B34203E74BE8CA4858" - + "1D5C0D9C9CA52D680EB299B4B21C7FA25FFEE174D57015E0FF2EAED653AAD95C" - + "071ABE269A8C2C9FBC1188E07550EB992F910D4CA9689E44BA66DE0FABB2BDF9" - + "8DD377186DBB25EF9B68B027BB2A27981779D8303D88D7CE860010A42862D50B" - + "1E0DBFD3D27C36F14809D7F493B2B96A65534CF98B0C32AD5219AD77F681AC04" - + "9D5CB89A0230A91A243FA7F16251B0D9B4B65E7330BEEAC9663EF4578991EAC8" - + "46C19EBB726E7D113F1D0D601102C05E"; - final String rekeyIkeDeleteReq = - "46B8ECA1E0D72A1866B5248CF6C7472D2E20250000000001000000502A000034" - + "02E40C0C7B1ED977729F705BB9B643FAC513A1070A6EB28ECD2AEA8A441ADC05" - + "7841382A7967BBF116AE52496590B2AD"; - final String deleteIkeReq = - "7D3DEDC65407D1FC9361C8CF8C47162A2E20250800000000000000502A000034" - + "201915C9E4E9173AA9EE79F3E02FE2D4954B22085C66D164762C34D347C16E9F" - + "FC5F7F114428C54D8D915860C57B1BC1"; - final long newIkeDeterministicInitSpi = Long.parseLong("7D3DEDC65407D1FC", 16); - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp); - - // Local request message ID starts from 2 because there is one IKE_INIT message and a single - // IKE_AUTH message. - int expectedReqMsgId = 2; - int expectedRespMsgId = 0; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TRANSPORT_MODE_INBOUND_TS), - Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord firstTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord firstTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB); - - // Inject rekey IKE requests - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeCreateReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeDeleteReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - - // IKE has been rekeyed, reset message IDs - expectedReqMsgId = 0; - expectedRespMsgId = 0; - - // Inject delete IKE request - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq)); - mTunUtils.awaitResp( - newIkeDeterministicInitSpi, expectedRespMsgId++, true /* expectedUseEncap */); - - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); - } - - @Test - public void testRekeyTransportModeChildSa() throws Exception { - final String ikeInitResp = - "46B8ECA1E0D72A18CECD871146CF83A121202220000000000000015022000030" - + "0000002C010100040300000C0100000C800E0100030000080300000C03000008" - + "0200000500000008040000022800008800020000C4904458957746BCF1C12972" - + "1D4E19EB8A584F78DE673053396D167CE0F34552DBC69BA63FE7C673B4CF4A99" - + "62481518EE985357876E8C47BAAA0DBE9C40AE47B12E52165874703586E8F786" - + "045F72EEEB238C5D1823352BED44B71B3214609276ADC0B3D42DAC820168C4E2" - + "660730DAAC92492403288805EBB9053F1AB060DA290000242D9364ACB93519FF" - + "8F8B019BAA43A40D699F59714B327B8382216EF427ED52282900001C00004004" - + "06D91438A0D6B734E152F76F5CC55A72A2E38A0A2900001C000040052EFF78B3" - + "55B37F3CE75AFF26C721B050F892C0D6290000080000402E290000100000402F" - + "00020003000400050000000800004014"; - final String ikeAuthResp = - "46B8ECA1E0D72A18CECD871146CF83A12E20232000000001000000F0240000D4" - + "A17BC258BA2714CF536663639DD5F665A60C75E93557CD5141990A8CEEDD2017" - + "93F5B181C8569FBCD6C2A00198EC2B62D42BEFAC016B8B6BF6A7BC9CEDE3413A" - + "6C495A6B8EC941864DC3E08F57D015EA6520C4B05884960B85478FCA53DA5F17" - + "9628BB1097DA77461C71837207A9EB80720B3E6E661816EE4E14AC995B5E8441" - + "A4C3F9097CC148142BA300076C94A23EC4ADE82B1DD2B121F7E9102860A8C3BF" - + "58DDC207285A3176E924C44DE820322524E1AA438EFDFBA781B36084AED80846" - + "3B77FCED9682B6E4E476408EF3F1037E"; - final String rekeyChildCreateReq = - "46B8ECA1E0D72A18CECD871146CF83A12E202400000000000000015029000134" - + "319D74B6B155B86942143CEC1D29D21F073F24B7BEDC9BFE0F0FDD8BDB5458C0" - + "8DB93506E1A43DD0640FE7370C97F9B34FF4EC9B2DB7257A87B75632301FB68A" - + "86B54871249534CA3D01C9BEB127B669F46470E1C8AAF72574C3CEEC15B901CF" - + "5A0D6ADAE59C3CA64AC8C86689C860FAF9500E608DFE63F2DCD30510FD6FFCD5" - + "A50838574132FD1D069BCACD4C7BAF45C9B1A7689FAD132E3F56DBCFAF905A8C" - + "4145D4BA1B74A54762F8F43308D94DE05649C49D885121CE30681D51AC1E3E68" - + "AB82F9A19B99579AFE257F32DBD1037814DA577379E4F42DEDAC84502E49C933" - + "9EA83F6F5DB4401B660CB1681B023B8603D205DFDD1DE86AD8DE22B6B754F30D" - + "05EAE81A709C2CEE81386133DC3DC7B5EF8F166E48E54A0722DD0C64F4D00638" - + "40F272144C47F6ECED72A248180645DB"; - final String rekeyChildDeleteReq = - "46B8ECA1E0D72A18CECD871146CF83A12E20250000000001000000502A000034" - + "02D98DAF0432EBD991CA4F2D89C1E0EFABC6E91A3327A85D8914FB2F1485BE1B" - + "8D3415D548F7CE0DC4224E7E9D0D3355"; - final String deleteIkeReq = - "46B8ECA1E0D72A18CECD871146CF83A12E20250000000002000000502A000034" - + "095041F4026B4634F04B0AB4F9349484F7BE9AEF03E3733EEE293330043B75D2" - + "ABF5F965ED51127629585E1B1BBA787F"; - - // Open IKE Session - IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp); - - // IKE INIT and IKE AUTH takes two exchanges. Local request message ID starts from 2 - int expectedReqMsgId = 2; - int expectedRespMsgId = 0; - - verifyIkeSessionSetupBlocking(); - verifyChildSessionSetupBlocking( - mFirstChildSessionCallback, - Arrays.asList(TRANSPORT_MODE_INBOUND_TS), - Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS), - new ArrayList()); - IpSecTransformCallRecord oldTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord oldTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(oldTransformRecordA, oldTransformRecordB); - - // Inject rekey Child requests - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildCreateReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildDeleteReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - - // Verify IpSecTransforms are renewed - IpSecTransformCallRecord newTransformRecordA = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - IpSecTransformCallRecord newTransformRecordB = - mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); - verifyCreateIpSecTransformPair(newTransformRecordA, newTransformRecordB); - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, oldTransformRecordA, oldTransformRecordB); - - // Inject delete IKE request - mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq)); - mTunUtils.awaitResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */); - - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, newTransformRecordA, newTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java deleted file mode 100644 index 6264ceab99..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ /dev/null @@ -1,598 +0,0 @@ -/* - * 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 - * - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.annotation.NonNull; -import android.app.AppOpsManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.InetAddresses; -import android.net.IpSecManager; -import android.net.IpSecTransform; -import android.net.LinkAddress; -import android.net.Network; -import android.net.TestNetworkInterface; -import android.net.TestNetworkManager; -import android.net.annotations.PolicyDirection; -import android.net.ipsec.ike.ChildSessionCallback; -import android.net.ipsec.ike.ChildSessionConfiguration; -import android.net.ipsec.ike.IkeSessionCallback; -import android.net.ipsec.ike.IkeSessionConfiguration; -import android.net.ipsec.ike.IkeSessionConnectionInfo; -import android.net.ipsec.ike.IkeTrafficSelector; -import android.net.ipsec.ike.TransportModeChildSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams; -import android.net.ipsec.ike.cts.IkeTunUtils.PortPair; -import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; -import android.net.ipsec.ike.exceptions.IkeException; -import android.net.ipsec.ike.exceptions.IkeProtocolException; -import android.os.Binder; -import android.os.ParcelFileDescriptor; -import android.platform.test.annotations.AppModeFull; - -import androidx.test.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.compatibility.common.util.SystemUtil; -import com.android.net.module.util.ArrayTrackRecord; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -/** - * Package private base class for testing IkeSessionParams and IKE exchanges. - * - *

    Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use - * the test network - * - *

    All IKE Sessions running in test mode will generate SPIs deterministically. That is to say - * each IKE Session will always generate the same IKE INIT SPI and test vectors are generated based - * on this deterministic IKE SPI. Each test will use different local and remote addresses to avoid - * the case that the next test try to allocate the same SPI before the previous test has released - * it, since SPI resources are not released in testing thread. Similarly, each test MUST use - * different Network instances to avoid sharing the same IkeSocket and hitting IKE SPI collision. - */ -@RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") -abstract class IkeSessionTestBase extends IkeTestBase { - // Package-wide common expected results that will be shared by all IKE/Child SA creation tests - static final String EXPECTED_REMOTE_APP_VERSION_EMPTY = ""; - static final byte[] EXPECTED_PROTOCOL_ERROR_DATA_NONE = new byte[0]; - - static final InetAddress EXPECTED_DNS_SERVERS_ONE = - InetAddresses.parseNumericAddress("8.8.8.8"); - static final InetAddress EXPECTED_DNS_SERVERS_TWO = - InetAddresses.parseNumericAddress("8.8.4.4"); - - static final InetAddress EXPECTED_INTERNAL_ADDR = - InetAddresses.parseNumericAddress("198.51.100.10"); - static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR = - new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN); - static final InetAddress EXPECTED_INTERNAL_ADDR_V6 = - InetAddresses.parseNumericAddress("2001:db8::2"); - static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR_V6 = - new LinkAddress(EXPECTED_INTERNAL_ADDR_V6, IP6_PREFIX_LEN); - - static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); - static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS; - static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS_V6 = - new IkeTrafficSelector( - MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR_V6, EXPECTED_INTERNAL_ADDR_V6); - static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS_V6 = DEFAULT_V6_TS; - - // This value is align with the test vectors hex that are generated in an IPv4 environment - static final IkeTrafficSelector TRANSPORT_MODE_OUTBOUND_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("10.138.0.2"), - InetAddresses.parseNumericAddress("10.138.0.2")); - - static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); - - // Static state to reduce setup/teardown - static Context sContext = InstrumentationRegistry.getContext(); - static ConnectivityManager sCM = - (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); - static TestNetworkManager sTNM; - - private static final int TIMEOUT_MS = 500; - - // Constants to be used for providing different IP addresses for each tests - private static final byte IP_ADDR_LAST_BYTE_MAX = (byte) 100; - private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_LOCAL = - InetAddresses.parseNumericAddress("192.0.2.1").getAddress(); - private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_REMOTE = - InetAddresses.parseNumericAddress("198.51.100.1").getAddress(); - private static final byte[] NEXT_AVAILABLE_IP4_ADDR_LOCAL = INITIAL_AVAILABLE_IP4_ADDR_LOCAL; - private static final byte[] NEXT_AVAILABLE_IP4_ADDR_REMOTE = INITIAL_AVAILABLE_IP4_ADDR_REMOTE; - - ParcelFileDescriptor mTunFd; - TestNetworkCallback mTunNetworkCallback; - Network mTunNetwork; - IkeTunUtils mTunUtils; - - InetAddress mLocalAddress; - InetAddress mRemoteAddress; - - Executor mUserCbExecutor; - TestIkeSessionCallback mIkeSessionCallback; - TestChildSessionCallback mFirstChildSessionCallback; - - // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass - // methods. - @BeforeClass - public static void setUpPermissionBeforeClass() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(); - sTNM = sContext.getSystemService(TestNetworkManager.class); - } - - // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass - // methods. - @AfterClass - public static void tearDownPermissionAfterClass() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .dropShellPermissionIdentity(); - } - - @Before - public void setUp() throws Exception { - mLocalAddress = getNextAvailableIpv4AddressLocal(); - mRemoteAddress = getNextAvailableIpv4AddressRemote(); - setUpTestNetwork(mLocalAddress); - - mUserCbExecutor = Executors.newSingleThreadExecutor(); - mIkeSessionCallback = new TestIkeSessionCallback(); - mFirstChildSessionCallback = new TestChildSessionCallback(); - } - - @After - public void tearDown() throws Exception { - tearDownTestNetwork(); - } - - void setUpTestNetwork(InetAddress localAddr) throws Exception { - int prefixLen = localAddr instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN; - - TestNetworkInterface testIface = - sTNM.createTunInterface(new LinkAddress[] {new LinkAddress(localAddr, prefixLen)}); - - mTunFd = testIface.getFileDescriptor(); - mTunNetworkCallback = - TestNetworkUtils.setupAndGetTestNetwork( - sCM, sTNM, testIface.getInterfaceName(), new Binder()); - mTunNetwork = mTunNetworkCallback.getNetworkBlocking(); - mTunUtils = new IkeTunUtils(mTunFd); - } - - void tearDownTestNetwork() throws Exception { - sCM.unregisterNetworkCallback(mTunNetworkCallback); - - sTNM.teardownTestNetwork(mTunNetwork); - mTunFd.close(); - } - - static void setAppOp(int appop, boolean allow) { - String opName = AppOpsManager.opToName(appop); - for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { - String cmd = - String.format( - "appops set %s %s %s", - pkg, // Package name - opName, // Appop - (allow ? "allow" : "deny")); // Action - - SystemUtil.runShellCommand(cmd); - } - } - - Inet4Address getNextAvailableIpv4AddressLocal() throws Exception { - return (Inet4Address) - getNextAvailableAddress( - NEXT_AVAILABLE_IP4_ADDR_LOCAL, - INITIAL_AVAILABLE_IP4_ADDR_LOCAL, - false /* isIp6 */); - } - - Inet4Address getNextAvailableIpv4AddressRemote() throws Exception { - return (Inet4Address) - getNextAvailableAddress( - NEXT_AVAILABLE_IP4_ADDR_REMOTE, - INITIAL_AVAILABLE_IP4_ADDR_REMOTE, - false /* isIp6 */); - } - - InetAddress getNextAvailableAddress( - byte[] nextAddressBytes, byte[] initialAddressBytes, boolean isIp6) throws Exception { - int addressLen = isIp6 ? IP6_ADDRESS_LEN : IP4_ADDRESS_LEN; - - synchronized (nextAddressBytes) { - if (nextAddressBytes[addressLen - 1] == IP_ADDR_LAST_BYTE_MAX) { - resetNextAvailableAddress(nextAddressBytes, initialAddressBytes); - } - - InetAddress address = InetAddress.getByAddress(nextAddressBytes); - nextAddressBytes[addressLen - 1]++; - return address; - } - } - - private void resetNextAvailableAddress(byte[] nextAddressBytes, byte[] initialAddressBytes) { - synchronized (nextAddressBytes) { - System.arraycopy( - nextAddressBytes, 0, initialAddressBytes, 0, initialAddressBytes.length); - } - } - - TransportModeChildSessionParams buildTransportModeChildParamsWithTs( - IkeTrafficSelector inboundTs, IkeTrafficSelector outboundTs) { - return new TransportModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .addInboundTrafficSelectors(inboundTs) - .addOutboundTrafficSelectors(outboundTs) - .build(); - } - - TransportModeChildSessionParams buildTransportModeChildParamsWithDefaultTs() { - return new TransportModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .build(); - } - - TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { - return new TunnelModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addInternalAddressRequest(AF_INET) - .addInternalAddressRequest(AF_INET6) - .build(); - } - - PortPair performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes) - throws Exception { - return performSetupIkeAndFirstChildBlocking( - ikeInitRespHex, - 1 /* expectedAuthReqPktCnt */, - true /*expectedAuthUseEncap*/, - ikeAuthRespHexes); - } - - PortPair performSetupIkeAndFirstChildBlocking( - String ikeInitRespHex, boolean expectedAuthUseEncap, String... ikeAuthRespHexes) - throws Exception { - return performSetupIkeAndFirstChildBlocking( - ikeInitRespHex, - 1 /* expectedAuthReqPktCnt */, - expectedAuthUseEncap, - ikeAuthRespHexes); - } - - PortPair performSetupIkeAndFirstChildBlocking( - String ikeInitRespHex, - int expectedAuthReqPktCnt, - boolean expectedAuthUseEncap, - String... ikeAuthRespHexes) - throws Exception { - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 0 /* expectedMsgId */, - false /* expectedUseEncap */, - ikeInitRespHex); - - byte[] ikeAuthReqPkt = - mTunUtils - .awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 1 /* expectedMsgId */, - expectedAuthUseEncap, - expectedAuthReqPktCnt, - ikeAuthRespHexes) - .get(0); - return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt); - } - - void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { - performCloseIkeBlocking(expectedMsgId, true /* expectedUseEncap*/, deleteIkeRespHex); - } - - void performCloseIkeBlocking( - int expectedMsgId, boolean expectedUseEncap, String deleteIkeRespHex) throws Exception { - mTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId, expectedUseEncap, deleteIkeRespHex); - } - - /** Testing callback that allows caller to block current thread until a method get called */ - static class TestIkeSessionCallback implements IkeSessionCallback { - private CompletableFuture mFutureIkeConfig = - new CompletableFuture<>(); - private CompletableFuture mFutureOnClosedCall = new CompletableFuture<>(); - private CompletableFuture mFutureOnClosedException = - new CompletableFuture<>(); - - private int mOnErrorExceptionsCount = 0; - private ArrayTrackRecord mOnErrorExceptionsTrackRecord = - new ArrayTrackRecord<>(); - - @Override - public void onOpened(@NonNull IkeSessionConfiguration sessionConfiguration) { - mFutureIkeConfig.complete(sessionConfiguration); - } - - @Override - public void onClosed() { - mFutureOnClosedCall.complete(true /* unused */); - } - - @Override - public void onClosedExceptionally(@NonNull IkeException exception) { - mFutureOnClosedException.complete(exception); - } - - @Override - public void onError(@NonNull IkeProtocolException exception) { - mOnErrorExceptionsTrackRecord.add(exception); - } - - public IkeSessionConfiguration awaitIkeConfig() throws Exception { - return mFutureIkeConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - public IkeException awaitOnClosedException() throws Exception { - return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - public IkeProtocolException awaitNextOnErrorException() { - return mOnErrorExceptionsTrackRecord.poll( - (long) TIMEOUT_MS, - mOnErrorExceptionsCount++, - (transform) -> { - return true; - }); - } - - public void awaitOnClosed() throws Exception { - mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - } - - /** Testing callback that allows caller to block current thread until a method get called */ - static class TestChildSessionCallback implements ChildSessionCallback { - private CompletableFuture mFutureChildConfig = - new CompletableFuture<>(); - private CompletableFuture mFutureOnClosedCall = new CompletableFuture<>(); - private CompletableFuture mFutureOnClosedException = - new CompletableFuture<>(); - - private int mCreatedIpSecTransformCount = 0; - private int mDeletedIpSecTransformCount = 0; - private ArrayTrackRecord mCreatedIpSecTransformsTrackRecord = - new ArrayTrackRecord<>(); - private ArrayTrackRecord mDeletedIpSecTransformsTrackRecord = - new ArrayTrackRecord<>(); - - @Override - public void onOpened(@NonNull ChildSessionConfiguration sessionConfiguration) { - mFutureChildConfig.complete(sessionConfiguration); - } - - @Override - public void onClosed() { - mFutureOnClosedCall.complete(true /* unused */); - } - - @Override - public void onClosedExceptionally(@NonNull IkeException exception) { - mFutureOnClosedException.complete(exception); - } - - @Override - public void onIpSecTransformCreated(@NonNull IpSecTransform ipSecTransform, int direction) { - mCreatedIpSecTransformsTrackRecord.add( - new IpSecTransformCallRecord(ipSecTransform, direction)); - } - - @Override - public void onIpSecTransformDeleted(@NonNull IpSecTransform ipSecTransform, int direction) { - mDeletedIpSecTransformsTrackRecord.add( - new IpSecTransformCallRecord(ipSecTransform, direction)); - } - - public ChildSessionConfiguration awaitChildConfig() throws Exception { - return mFutureChildConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - public IkeException awaitOnClosedException() throws Exception { - return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - public IpSecTransformCallRecord awaitNextCreatedIpSecTransform() { - return mCreatedIpSecTransformsTrackRecord.poll( - (long) TIMEOUT_MS, - mCreatedIpSecTransformCount++, - (transform) -> { - return true; - }); - } - - public IpSecTransformCallRecord awaitNextDeletedIpSecTransform() { - return mDeletedIpSecTransformsTrackRecord.poll( - (long) TIMEOUT_MS, - mDeletedIpSecTransformCount++, - (transform) -> { - return true; - }); - } - - public void awaitOnClosed() throws Exception { - mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - } - - /** - * This class represents a created or deleted IpSecTransfrom that is provided by - * ChildSessionCallback - */ - static class IpSecTransformCallRecord { - public final IpSecTransform ipSecTransform; - public final int direction; - - IpSecTransformCallRecord(IpSecTransform ipSecTransform, @PolicyDirection int direction) { - this.ipSecTransform = ipSecTransform; - this.direction = direction; - } - - @Override - public int hashCode() { - return Objects.hash(ipSecTransform, direction); - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof IpSecTransformCallRecord)) return false; - - IpSecTransformCallRecord record = (IpSecTransformCallRecord) o; - return ipSecTransform.equals(record.ipSecTransform) && direction == record.direction; - } - } - - void verifyIkeSessionSetupBlocking() throws Exception { - IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); - assertNotNull(ikeConfig); - assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); - assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); - assertTrue(ikeConfig.getPcscfServers().isEmpty()); - assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); - - IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); - assertNotNull(ikeConnectInfo); - assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); - assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); - assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); - } - - void verifyChildSessionSetupBlocking( - TestChildSessionCallback childCallback, - List expectedInboundTs, - List expectedOutboundTs, - List expectedInternalAddresses) - throws Exception { - verifyChildSessionSetupBlocking( - childCallback, - expectedInboundTs, - expectedOutboundTs, - expectedInternalAddresses, - new ArrayList() /* expectedDnsServers */); - } - - void verifyChildSessionSetupBlocking( - TestChildSessionCallback childCallback, - List expectedInboundTs, - List expectedOutboundTs, - List expectedInternalAddresses, - List expectedDnsServers) - throws Exception { - ChildSessionConfiguration childConfig = childCallback.awaitChildConfig(); - assertNotNull(childConfig); - assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors()); - assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors()); - assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses()); - assertEquals(expectedDnsServers, childConfig.getInternalDnsServers()); - assertTrue(childConfig.getInternalSubnets().isEmpty()); - assertTrue(childConfig.getInternalDhcpServers().isEmpty()); - } - - void verifyCloseIkeAndChildBlocking( - IpSecTransformCallRecord expectedTransformRecordA, - IpSecTransformCallRecord expectedTransformRecordB) - throws Exception { - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, expectedTransformRecordA, expectedTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); - } - - static void verifyCreateIpSecTransformPair( - IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) { - IpSecTransform transformA = transformRecordA.ipSecTransform; - IpSecTransform transformB = transformRecordB.ipSecTransform; - - assertNotNull(transformA); - assertNotNull(transformB); - - Set expectedDirections = new HashSet<>(); - expectedDirections.add(IpSecManager.DIRECTION_IN); - expectedDirections.add(IpSecManager.DIRECTION_OUT); - - Set resultDirections = new HashSet<>(); - resultDirections.add(transformRecordA.direction); - resultDirections.add(transformRecordB.direction); - - assertEquals(expectedDirections, resultDirections); - } - - static void verifyDeleteIpSecTransformPair( - TestChildSessionCallback childCb, - IpSecTransformCallRecord expectedTransformRecordA, - IpSecTransformCallRecord expectedTransformRecordB) { - Set expectedTransforms = new HashSet<>(); - expectedTransforms.add(expectedTransformRecordA); - expectedTransforms.add(expectedTransformRecordB); - - Set resultTransforms = new HashSet<>(); - resultTransforms.add(childCb.awaitNextDeletedIpSecTransform()); - resultTransforms.add(childCb.awaitNextDeletedIpSecTransform()); - - assertEquals(expectedTransforms, resultTransforms); - } - - /** Package private method to check if device has IPsec tunnels feature */ - static boolean hasTunnelsFeature() { - return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); - } - - // TODO(b/148689509): Verify hostname based creation -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java deleted file mode 100644 index c70e5372ec..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.net.InetAddresses; -import android.net.ipsec.ike.IkeTrafficSelector; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** Shared parameters and util methods for testing different components of IKE */ -abstract class IkeTestBase { - static final int MIN_PORT = 0; - static final int MAX_PORT = 65535; - private static final int INBOUND_TS_START_PORT = MIN_PORT; - private static final int INBOUND_TS_END_PORT = 65520; - private static final int OUTBOUND_TS_START_PORT = 16; - private static final int OUTBOUND_TS_END_PORT = MAX_PORT; - - static final int IP4_ADDRESS_LEN = 4; - static final int IP6_ADDRESS_LEN = 16; - static final int IP4_PREFIX_LEN = 32; - static final int IP6_PREFIX_LEN = 64; - - static final byte[] IKE_PSK = "ikeAndroidPsk".getBytes(); - - static final String LOCAL_HOSTNAME = "client.test.ike.android.net"; - static final String REMOTE_HOSTNAME = "server.test.ike.android.net"; - static final String LOCAL_ASN1_DN_STRING = "CN=client.test.ike.android.net, O=Android, C=US"; - static final String LOCAL_RFC822_NAME = "client.test.ike@example.com"; - static final byte[] LOCAL_KEY_ID = "Local Key ID".getBytes(); - - static final int SUB_ID = 1; - static final byte[] EAP_IDENTITY = "test@android.net".getBytes(); - static final String NETWORK_NAME = "android.net"; - static final String EAP_MSCHAPV2_USERNAME = "mschapv2user"; - static final String EAP_MSCHAPV2_PASSWORD = "password"; - - static final Inet4Address IPV4_ADDRESS_LOCAL = - (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100")); - static final Inet4Address IPV4_ADDRESS_REMOTE = - (Inet4Address) (InetAddresses.parseNumericAddress("198.51.100.100")); - static final Inet6Address IPV6_ADDRESS_LOCAL = - (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8::100")); - static final Inet6Address IPV6_ADDRESS_REMOTE = - (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8:255::100")); - - static final InetAddress PCSCF_IPV4_ADDRESS_1 = InetAddresses.parseNumericAddress("192.0.2.1"); - static final InetAddress PCSCF_IPV4_ADDRESS_2 = InetAddresses.parseNumericAddress("192.0.2.2"); - static final InetAddress PCSCF_IPV6_ADDRESS_1 = - InetAddresses.parseNumericAddress("2001:DB8::1"); - static final InetAddress PCSCF_IPV6_ADDRESS_2 = - InetAddresses.parseNumericAddress("2001:DB8::2"); - - static final IkeTrafficSelector DEFAULT_V4_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("0.0.0.0"), - InetAddresses.parseNumericAddress("255.255.255.255")); - static final IkeTrafficSelector DEFAULT_V6_TS = - new IkeTrafficSelector( - MIN_PORT, - MAX_PORT, - InetAddresses.parseNumericAddress("::"), - InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - static final IkeTrafficSelector INBOUND_V4_TS = - new IkeTrafficSelector( - INBOUND_TS_START_PORT, - INBOUND_TS_END_PORT, - InetAddresses.parseNumericAddress("192.0.2.10"), - InetAddresses.parseNumericAddress("192.0.2.20")); - static final IkeTrafficSelector OUTBOUND_V4_TS = - new IkeTrafficSelector( - OUTBOUND_TS_START_PORT, - OUTBOUND_TS_END_PORT, - InetAddresses.parseNumericAddress("198.51.100.0"), - InetAddresses.parseNumericAddress("198.51.100.255")); - - static final IkeTrafficSelector INBOUND_V6_TS = - new IkeTrafficSelector( - INBOUND_TS_START_PORT, - INBOUND_TS_END_PORT, - InetAddresses.parseNumericAddress("2001:db8::10"), - InetAddresses.parseNumericAddress("2001:db8::128")); - static final IkeTrafficSelector OUTBOUND_V6_TS = - new IkeTrafficSelector( - OUTBOUND_TS_START_PORT, - OUTBOUND_TS_END_PORT, - InetAddresses.parseNumericAddress("2001:db8:255::64"), - InetAddresses.parseNumericAddress("2001:db8:255::255")); - - // Verify Config requests in TunnelModeChildSessionParams and IkeSessionParams - void verifyConfigRequestTypes( - Map, Integer> expectedReqCntMap, List resultReqList) { - Map, Integer> resultReqCntMap = new HashMap<>(); - - // Verify that every config request type in resultReqList is expected, and build - // resultReqCntMap at the same time - for (T resultReq : resultReqList) { - boolean isResultReqExpected = false; - - for (Class expectedReqInterface : expectedReqCntMap.keySet()) { - if (expectedReqInterface.isInstance(resultReq)) { - isResultReqExpected = true; - - resultReqCntMap.put( - expectedReqInterface, - resultReqCntMap.getOrDefault(expectedReqInterface, 0) + 1); - } - } - - if (!isResultReqExpected) { - fail("Failed due to unexpected config request " + resultReq); - } - } - - assertEquals(expectedReqCntMap, resultReqCntMap); - - // TODO: Think of a neat way to validate both counts and values in this method. Probably can - // build Runnables as validators for count and values. - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java deleted file mode 100644 index 41cbf0baa1..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.cts.PacketUtils.BytePayload; -import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.Ip4Header; -import static android.net.ipsec.ike.cts.PacketUtils.Ip6Header; -import static android.net.ipsec.ike.cts.PacketUtils.IpHeader; -import static android.net.ipsec.ike.cts.PacketUtils.Payload; -import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader; -import static android.system.OsConstants.IPPROTO_UDP; - -import static com.android.internal.util.HexDump.hexStringToByteArray; - -import static org.junit.Assert.fail; - -import android.os.ParcelFileDescriptor; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.Predicate; - -public class IkeTunUtils extends TunUtils { - private static final int PORT_LEN = 2; - - private static final int NON_ESP_MARKER_LEN = 4; - private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN]; - - private static final int IKE_INIT_SPI_OFFSET = 0; - private static final int IKE_FIRST_PAYLOAD_OFFSET = 16; - private static final int IKE_IS_RESP_BYTE_OFFSET = 19; - private static final int IKE_MSG_ID_OFFSET = 20; - private static final int IKE_HEADER_LEN = 28; - private static final int IKE_FRAG_NUM_OFFSET = 32; - private static final int IKE_PAYLOAD_TYPE_SKF = 53; - - private static final int RSP_FLAG_MASK = 0x20; - - public IkeTunUtils(ParcelFileDescriptor tunFd) { - super(tunFd); - } - - /** - * Await the expected IKE request inject an IKE response (or a list of response fragments) - * - * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without - * IP/UDP headers or NON ESP MARKER. - */ - public byte[] awaitReqAndInjectResp( - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedUseEncap, - String... ikeRespDataFragmentsHex) - throws Exception { - return awaitReqAndInjectResp( - expectedInitIkeSpi, - expectedMsgId, - expectedUseEncap, - 1 /* expectedReqPktCnt */, - ikeRespDataFragmentsHex) - .get(0); - } - - /** - * Await the expected IKE request (or the list of IKE request fragments) and inject an IKE - * response (or a list of response fragments) - * - * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without - * IP/UDP headers or NON ESP MARKER. - */ - public List awaitReqAndInjectResp( - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedUseEncap, - int expectedReqPktCnt, - String... ikeRespDataFragmentsHex) - throws Exception { - List reqList = new ArrayList<>(expectedReqPktCnt); - if (expectedReqPktCnt == 1) { - // Expecting one complete IKE packet - byte[] req = - awaitIkePacket( - (pkt) -> { - return isExpectedIkePkt( - pkt, - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap); - }); - reqList.add(req); - } else { - // Expecting "expectedReqPktCnt" number of request fragments - for (int i = 0; i < expectedReqPktCnt; i++) { - // IKE Fragment number always starts from 1 - int expectedFragNum = i + 1; - byte[] req = - awaitIkePacket( - (pkt) -> { - return isExpectedIkeFragPkt( - pkt, - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap, - expectedFragNum); - }); - reqList.add(req); - } - } - - // All request fragments have the same addresses and ports - byte[] request = reqList.get(0); - - // Build response header by flipping address and port - InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); - InetAddress dstAddr = getAddress(request, true /* shouldGetSource */); - int srcPort = getPort(request, false /* shouldGetSource */); - int dstPort = getPort(request, true /* shouldGetSource */); - for (String resp : ikeRespDataFragmentsHex) { - byte[] response = - buildIkePacket( - srcAddr, - dstAddr, - srcPort, - dstPort, - expectedUseEncap, - hexStringToByteArray(resp)); - injectPacket(response); - } - - return reqList; - } - - /** Await the expected IKE response */ - public byte[] awaitResp(long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap) - throws Exception { - return awaitIkePacket( - (pkt) -> { - return isExpectedIkePkt( - pkt, - expectedInitIkeSpi, - expectedMsgId, - true /* expectedResp*/, - expectedUseEncap); - }); - } - - private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { - long endTime = System.currentTimeMillis() + TIMEOUT; - int startIndex = 0; - synchronized (mPackets) { - while (System.currentTimeMillis() < endTime) { - byte[] ikePkt = getFirstMatchingPacket(pktVerifier, startIndex); - if (ikePkt != null) { - return ikePkt; // We've found the packet we're looking for. - } - - startIndex = mPackets.size(); - - // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout - long waitTimeout = endTime - System.currentTimeMillis(); - if (waitTimeout > 0) { - mPackets.wait(waitTimeout); - } - } - - fail("No matching packet found"); - } - - throw new IllegalStateException( - "Hit an impossible case where fail() didn't throw an exception"); - } - - private static boolean isExpectedIkePkt( - byte[] pkt, - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp, - boolean expectedUseEncap) { - int ipProtocolOffset = isIpv6(pkt) ? IP6_PROTO_OFFSET : IP4_PROTO_OFFSET; - int ikeOffset = getIkeOffset(pkt, expectedUseEncap); - - return pkt[ipProtocolOffset] == IPPROTO_UDP - && expectedUseEncap == hasNonEspMarker(pkt) - && isExpectedSpiAndMsgId( - pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); - } - - private static boolean isExpectedIkeFragPkt( - byte[] pkt, - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp, - boolean expectedUseEncap, - int expectedFragNum) { - return isExpectedIkePkt( - pkt, expectedInitIkeSpi, expectedMsgId, expectedResp, expectedUseEncap) - && isExpectedFragNum(pkt, getIkeOffset(pkt, expectedUseEncap), expectedFragNum); - } - - private static int getIkeOffset(byte[] pkt, boolean useEncap) { - if (isIpv6(pkt)) { - // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap. - return IP6_HDRLEN + UDP_HDRLEN; - } else { - // Use default IPv4 header length (assuming no options) - int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; - return useEncap ? ikeOffset + NON_ESP_MARKER_LEN : ikeOffset; - } - } - - private static boolean hasNonEspMarker(byte[] pkt) { - ByteBuffer buffer = ByteBuffer.wrap(pkt); - int ikeOffset = IP4_HDRLEN + UDP_HDRLEN; - if (buffer.remaining() < ikeOffset) return false; - - buffer.get(new byte[ikeOffset]); // Skip IP and UDP header - byte[] nonEspMarker = new byte[NON_ESP_MARKER_LEN]; - if (buffer.remaining() < NON_ESP_MARKER_LEN) return false; - - buffer.get(nonEspMarker); - return Arrays.equals(NON_ESP_MARKER, nonEspMarker); - } - - private static boolean isExpectedSpiAndMsgId( - byte[] pkt, - int ikeOffset, - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp) { - if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false; - - ByteBuffer buffer = ByteBuffer.wrap(pkt); - buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER) - buffer.mark(); // Mark this position so that later we can reset back here - - // Check SPI - buffer.get(new byte[IKE_INIT_SPI_OFFSET]); - long initSpi = buffer.getLong(); - if (expectedInitIkeSpi != initSpi) { - return false; - } - - // Check direction - buffer.reset(); - buffer.get(new byte[IKE_IS_RESP_BYTE_OFFSET]); - byte flagsByte = buffer.get(); - boolean isResp = ((flagsByte & RSP_FLAG_MASK) != 0); - if (expectedResp != isResp) { - return false; - } - - // Check message ID - buffer.reset(); - buffer.get(new byte[IKE_MSG_ID_OFFSET]); - - // Both the expected message ID and the packet's msgId are signed integers, so directly - // compare them. - int msgId = buffer.getInt(); - if (expectedMsgId != msgId) { - return false; - } - - return true; - } - - private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) { - ByteBuffer buffer = ByteBuffer.wrap(pkt); - buffer.get(new byte[ikeOffset]); - buffer.mark(); // Mark this position so that later we can reset back here - - // Check if it is a fragment packet - buffer.get(new byte[IKE_FIRST_PAYLOAD_OFFSET]); - int firstPayload = Byte.toUnsignedInt(buffer.get()); - if (firstPayload != IKE_PAYLOAD_TYPE_SKF) { - return false; - } - - // Check fragment number - buffer.reset(); - buffer.get(new byte[IKE_FRAG_NUM_OFFSET]); - int fragNum = Short.toUnsignedInt(buffer.getShort()); - return expectedFragNum == fragNum; - } - - public static class PortPair { - public final int srcPort; - public final int dstPort; - - public PortPair(int sourcePort, int destinationPort) { - srcPort = sourcePort; - dstPort = destinationPort; - } - } - - public static PortPair getSrcDestPortPair(byte[] outboundIkePkt) throws Exception { - return new PortPair( - getPort(outboundIkePkt, true /* shouldGetSource */), - getPort(outboundIkePkt, false /* shouldGetSource */)); - } - - private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { - int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; - int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; - int ipOffset = shouldGetSource ? srcIpOffset : srcIpOffset + ipLen; - - ByteBuffer buffer = ByteBuffer.wrap(pkt); - buffer.get(new byte[ipOffset]); - byte[] ipAddrBytes = new byte[ipLen]; - buffer.get(ipAddrBytes); - return InetAddress.getByAddress(ipAddrBytes); - } - - private static int getPort(byte[] pkt, boolean shouldGetSource) { - ByteBuffer buffer = ByteBuffer.wrap(pkt); - int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; - int portOffset = shouldGetSource ? srcPortOffset : srcPortOffset + PORT_LEN; - - buffer.get(new byte[portOffset]); - return Short.toUnsignedInt(buffer.getShort()); - } - - public static byte[] buildIkePacket( - InetAddress srcAddr, - InetAddress dstAddr, - int srcPort, - int dstPort, - boolean useEncap, - byte[] ikePacket) - throws Exception { - if (useEncap) { - ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER_LEN + ikePacket.length); - buffer.put(NON_ESP_MARKER); - buffer.put(ikePacket); - ikePacket = buffer.array(); - } - - UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(ikePacket)); - IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt); - return ipPkt.getPacketBytes(); - } - - private static IpHeader getIpHeader( - int protocol, InetAddress src, InetAddress dst, Payload payload) { - if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { - throw new IllegalArgumentException("Invalid src/dst address combination"); - } - - if (src instanceof Inet6Address) { - return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); - } else { - return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); - } - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java deleted file mode 100644 index 35e6719fb7..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java +++ /dev/null @@ -1,467 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.system.OsConstants.IPPROTO_IPV6; -import static android.system.OsConstants.IPPROTO_UDP; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ShortBuffer; -import java.security.GeneralSecurityException; -import java.security.SecureRandom; -import java.util.Arrays; - -import javax.crypto.Cipher; -import javax.crypto.Mac; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -/** - * This code is a exact copy of {@link PacketUtils} in - * cts/tests/tests/net/src/android/net/cts/PacketUtils.java. - * - *

    TODO(b/148689509): Statically include the PacketUtils source file instead of copying it. - */ -public class PacketUtils { - private static final String TAG = PacketUtils.class.getSimpleName(); - - private static final int DATA_BUFFER_LEN = 4096; - - static final int IP4_HDRLEN = 20; - static final int IP6_HDRLEN = 40; - static final int UDP_HDRLEN = 8; - static final int TCP_HDRLEN = 20; - static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12; - - // Not defined in OsConstants - static final int IPPROTO_IPV4 = 4; - static final int IPPROTO_ESP = 50; - - // Encryption parameters - static final int AES_GCM_IV_LEN = 8; - static final int AES_CBC_IV_LEN = 16; - static final int AES_GCM_BLK_SIZE = 4; - static final int AES_CBC_BLK_SIZE = 16; - - // Encryption algorithms - static final String AES = "AES"; - static final String AES_CBC = "AES/CBC/NoPadding"; - static final String HMAC_SHA_256 = "HmacSHA256"; - - public interface Payload { - byte[] getPacketBytes(IpHeader header) throws Exception; - - void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception; - - short length(); - - int getProtocolId(); - } - - public abstract static class IpHeader { - - public final byte proto; - public final InetAddress srcAddr; - public final InetAddress dstAddr; - public final Payload payload; - - public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) { - this.proto = (byte) proto; - this.srcAddr = src; - this.dstAddr = dst; - this.payload = payload; - } - - public abstract byte[] getPacketBytes() throws Exception; - - public abstract int getProtocolId(); - } - - public static class Ip4Header extends IpHeader { - private short checksum; - - public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) { - super(proto, src, dst, payload); - } - - public byte[] getPacketBytes() throws Exception { - ByteBuffer resultBuffer = buildHeader(); - payload.addPacketBytes(this, resultBuffer); - - return getByteArrayFromBuffer(resultBuffer); - } - - public ByteBuffer buildHeader() { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - // Version, IHL - bb.put((byte) (0x45)); - - // DCSP, ECN - bb.put((byte) 0); - - // Total Length - bb.putShort((short) (IP4_HDRLEN + payload.length())); - - // Empty for Identification, Flags and Fragment Offset - bb.putShort((short) 0); - bb.put((byte) 0x40); - bb.put((byte) 0x00); - - // TTL - bb.put((byte) 64); - - // Protocol - bb.put(proto); - - // Header Checksum - final int ipChecksumOffset = bb.position(); - bb.putShort((short) 0); - - // Src/Dst addresses - bb.put(srcAddr.getAddress()); - bb.put(dstAddr.getAddress()); - - bb.putShort(ipChecksumOffset, calculateChecksum(bb)); - - return bb; - } - - private short calculateChecksum(ByteBuffer bb) { - int checksum = 0; - - // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit - // aligned, so no special cases needed for unaligned values. - ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer(); - while (shortBuffer.hasRemaining()) { - short val = shortBuffer.get(); - - // Wrap as needed - checksum = addAndWrapForChecksum(checksum, val); - } - - return onesComplement(checksum); - } - - public int getProtocolId() { - return IPPROTO_IPV4; - } - } - - public static class Ip6Header extends IpHeader { - public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) { - super(nextHeader, src, dst, payload); - } - - public byte[] getPacketBytes() throws Exception { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - // Version | Traffic Class (First 4 bits) - bb.put((byte) 0x60); - - // Traffic class (Last 4 bits), Flow Label - bb.put((byte) 0); - bb.put((byte) 0); - bb.put((byte) 0); - - // Payload Length - bb.putShort((short) payload.length()); - - // Next Header - bb.put(proto); - - // Hop Limit - bb.put((byte) 64); - - // Src/Dst addresses - bb.put(srcAddr.getAddress()); - bb.put(dstAddr.getAddress()); - - // Payload - payload.addPacketBytes(this, bb); - - return getByteArrayFromBuffer(bb); - } - - public int getProtocolId() { - return IPPROTO_IPV6; - } - } - - public static class BytePayload implements Payload { - public final byte[] payload; - - public BytePayload(byte[] payload) { - this.payload = payload; - } - - public int getProtocolId() { - return -1; - } - - public byte[] getPacketBytes(IpHeader header) { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - addPacketBytes(header, bb); - return getByteArrayFromBuffer(bb); - } - - public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) { - resultBuffer.put(payload); - } - - public short length() { - return (short) payload.length; - } - } - - public static class UdpHeader implements Payload { - - public final short srcPort; - public final short dstPort; - public final Payload payload; - - public UdpHeader(int srcPort, int dstPort, Payload payload) { - this.srcPort = (short) srcPort; - this.dstPort = (short) dstPort; - this.payload = payload; - } - - public int getProtocolId() { - return IPPROTO_UDP; - } - - public short length() { - return (short) (payload.length() + 8); - } - - public byte[] getPacketBytes(IpHeader header) throws Exception { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - addPacketBytes(header, bb); - return getByteArrayFromBuffer(bb); - } - - public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { - // Source, Destination port - resultBuffer.putShort(srcPort); - resultBuffer.putShort(dstPort); - - // Payload Length - resultBuffer.putShort(length()); - - // Get payload bytes for checksum + payload - ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); - payload.addPacketBytes(header, payloadBuffer); - byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer); - - // Checksum - resultBuffer.putShort(calculateChecksum(header, payloadBytes)); - - // Payload - resultBuffer.put(payloadBytes); - } - - private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception { - int newChecksum = 0; - ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer(); - ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer(); - - while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) { - short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get(); - - // Wrap as needed - newChecksum = addAndWrapForChecksum(newChecksum, val); - } - - // Add pseudo-header values. Proto is 0-padded, so just use the byte. - newChecksum = addAndWrapForChecksum(newChecksum, header.proto); - newChecksum = addAndWrapForChecksum(newChecksum, length()); - newChecksum = addAndWrapForChecksum(newChecksum, srcPort); - newChecksum = addAndWrapForChecksum(newChecksum, dstPort); - newChecksum = addAndWrapForChecksum(newChecksum, length()); - - ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer(); - while (payloadShortBuffer.hasRemaining()) { - newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get()); - } - if (payload.length() % 2 != 0) { - newChecksum = - addAndWrapForChecksum( - newChecksum, (payloadBytes[payloadBytes.length - 1] << 8)); - } - - return onesComplement(newChecksum); - } - } - - public static class EspHeader implements Payload { - public final int nextHeader; - public final int spi; - public final int seqNum; - public final byte[] key; - public final byte[] payload; - - /** - * Generic constructor for ESP headers. - * - *

    For Tunnel mode, payload will be a full IP header + attached payloads - * - *

    For Transport mode, payload will be only the attached payloads, but with the checksum - * calculated using the pre-encryption IP header - */ - public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) { - this.nextHeader = nextHeader; - this.spi = spi; - this.seqNum = seqNum; - this.key = key; - this.payload = payload; - } - - public int getProtocolId() { - return IPPROTO_ESP; - } - - public short length() { - // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len) - return (short) - calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128); - } - - public byte[] getPacketBytes(IpHeader header) throws Exception { - ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); - - addPacketBytes(header, bb); - return getByteArrayFromBuffer(bb); - } - - public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { - ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); - espPayloadBuffer.putInt(spi); - espPayloadBuffer.putInt(seqNum); - espPayloadBuffer.put(getCiphertext(key)); - - espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16); - resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer)); - } - - private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException { - Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256); - SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256); - sha256HMAC.init(authKey); - - return sha256HMAC.doFinal(authenticatedSection); - } - - /** - * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks - * - *

    The ciphertext does NOT include the SPI/Sequence numbers, or the ICV. - */ - private byte[] getCiphertext(byte[] key) throws GeneralSecurityException { - int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE); - ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen); - paddedPayload.put(payload); - - // Add padding - consecutive integers from 0x01 - int pad = 1; - while (paddedPayload.position() < paddedPayload.limit()) { - paddedPayload.put((byte) pad++); - } - - paddedPayload.position(paddedPayload.limit() - 2); - paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length - paddedPayload.put((byte) nextHeader); - - // Generate Initialization Vector - byte[] iv = new byte[AES_CBC_IV_LEN]; - new SecureRandom().nextBytes(iv); - IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); - SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); - - // Encrypt payload - Cipher cipher = Cipher.getInstance(AES_CBC); - cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); - byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload)); - - // Build ciphertext - ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length); - cipherText.put(iv); - cipherText.put(encrypted); - - return getByteArrayFromBuffer(cipherText); - } - } - - private static int addAndWrapForChecksum(int currentChecksum, int value) { - currentChecksum += value & 0x0000ffff; - - // Wrap anything beyond the first 16 bits, and add to lower order bits - return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff); - } - - private static short onesComplement(int val) { - val = (val >>> 16) + (val & 0xffff); - - if (val == 0) return 0; - return (short) ((~val) & 0xffff); - } - - public static int calculateEspPacketSize( - int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { - final int ESP_HDRLEN = 4 + 4; // SPI + Seq# - final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length - payloadLen += cryptIvLength; // Initialization Vector - - // Align to block size of encryption algorithm - payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize); - return payloadLen + ESP_HDRLEN + ICV_LEN; - } - - private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) { - payloadLen += 2; // ESP trailer - - // Align to block size of encryption algorithm - return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize); - } - - private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) { - return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; - } - - private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) { - return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); - } - - /* - * Debug printing - */ - private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); - - public static String bytesToHex(byte[] bytes) { - StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { - sb.append(hexArray[b >>> 4]); - sb.append(hexArray[b & 0x0F]); - sb.append(' '); - } - return sb.toString(); - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java deleted file mode 100644 index e0d3be0540..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP; -import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; -import static android.net.ipsec.ike.SaProposal.DH_GROUP_NONE; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256; -import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE; -import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; -import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192; -import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256; -import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.IkeSaProposal; -import android.util.Pair; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -@RunWith(AndroidJUnit4.class) -public class SaProposalTest { - private static final List> NORMAL_MODE_CIPHERS = new ArrayList<>(); - private static final List> COMBINED_MODE_CIPHERS = new ArrayList<>(); - private static final List INTEGRITY_ALGOS = new ArrayList<>(); - private static final List DH_GROUPS = new ArrayList<>(); - private static final List DH_GROUPS_WITH_NONE = new ArrayList<>(); - private static final List PRFS = new ArrayList<>(); - - static { - NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)); - NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128)); - NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192)); - NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)); - - COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128)); - COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192)); - COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256)); - - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96); - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_AES_XCBC_96); - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128); - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192); - INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256); - - DH_GROUPS.add(DH_GROUP_1024_BIT_MODP); - DH_GROUPS.add(DH_GROUP_2048_BIT_MODP); - - DH_GROUPS_WITH_NONE.add(DH_GROUP_NONE); - DH_GROUPS_WITH_NONE.addAll(DH_GROUPS); - - PRFS.add(PSEUDORANDOM_FUNCTION_HMAC_SHA1); - PRFS.add(PSEUDORANDOM_FUNCTION_AES128_XCBC); - PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_256); - PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_384); - PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_512); - } - - // Package private - static IkeSaProposal buildIkeSaProposalWithNormalModeCipher() { - return buildIkeSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, PRFS, DH_GROUPS); - } - - // Package private - static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher() { - return buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); - } - - private static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher( - boolean hasIntegrityNone) { - List integerAlgos = new ArrayList<>(); - if (hasIntegrityNone) { - integerAlgos.add(INTEGRITY_ALGORITHM_NONE); - } - return buildIkeSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, PRFS, DH_GROUPS); - } - - private static IkeSaProposal buildIkeSaProposal( - List> ciphers, - List integrityAlgos, - List prfs, - List dhGroups) { - IkeSaProposal.Builder builder = new IkeSaProposal.Builder(); - - for (Pair pair : ciphers) { - builder.addEncryptionAlgorithm(pair.first, pair.second); - } - for (int algo : integrityAlgos) { - builder.addIntegrityAlgorithm(algo); - } - for (int algo : prfs) { - builder.addPseudorandomFunction(algo); - } - for (int algo : dhGroups) { - builder.addDhGroup(algo); - } - - return builder.build(); - } - - // Package private - static ChildSaProposal buildChildSaProposalWithNormalModeCipher() { - return buildChildSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, DH_GROUPS_WITH_NONE); - } - - // Package private - static ChildSaProposal buildChildSaProposalWithCombinedModeCipher() { - return buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); - } - - private static ChildSaProposal buildChildSaProposalWithCombinedModeCipher( - boolean hasIntegrityNone) { - List integerAlgos = new ArrayList<>(); - if (hasIntegrityNone) { - integerAlgos.add(INTEGRITY_ALGORITHM_NONE); - } - - return buildChildSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, DH_GROUPS_WITH_NONE); - } - - private static ChildSaProposal buildChildSaProposal( - List> ciphers, - List integrityAlgos, - List dhGroups) { - ChildSaProposal.Builder builder = new ChildSaProposal.Builder(); - - for (Pair pair : ciphers) { - builder.addEncryptionAlgorithm(pair.first, pair.second); - } - for (int algo : integrityAlgos) { - builder.addIntegrityAlgorithm(algo); - } - for (int algo : dhGroups) { - builder.addDhGroup(algo); - } - - return builder.build(); - } - - // Package private - static ChildSaProposal buildChildSaProposalWithOnlyCiphers() { - return buildChildSaProposal( - COMBINED_MODE_CIPHERS, Collections.EMPTY_LIST, Collections.EMPTY_LIST); - } - - @Test - public void testBuildIkeSaProposalWithNormalModeCipher() { - IkeSaProposal saProposal = buildIkeSaProposalWithNormalModeCipher(); - - assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms()); - assertEquals(PRFS, saProposal.getPseudorandomFunctions()); - assertEquals(DH_GROUPS, saProposal.getDhGroups()); - } - - @Test - public void testBuildIkeSaProposalWithCombinedModeCipher() { - IkeSaProposal saProposal = - buildIkeSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(PRFS, saProposal.getPseudorandomFunctions()); - assertEquals(DH_GROUPS, saProposal.getDhGroups()); - assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); - } - - @Test - public void testBuildIkeSaProposalWithCombinedModeCipherAndIntegrityNone() { - IkeSaProposal saProposal = - buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(PRFS, saProposal.getPseudorandomFunctions()); - assertEquals(DH_GROUPS, saProposal.getDhGroups()); - assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms()); - } - - @Test - public void testBuildChildSaProposalWithNormalModeCipher() { - ChildSaProposal saProposal = buildChildSaProposalWithNormalModeCipher(); - - assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms()); - assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); - } - - @Test - public void testBuildChildProposalWithCombinedModeCipher() { - ChildSaProposal saProposal = - buildChildSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); - assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); - } - - @Test - public void testBuildChildProposalWithCombinedModeCipherAndIntegrityNone() { - ChildSaProposal saProposal = - buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms()); - assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups()); - } - - @Test - public void testBuildChildSaProposalWithOnlyCiphers() { - ChildSaProposal saProposal = buildChildSaProposalWithOnlyCiphers(); - - assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms()); - assertTrue(saProposal.getIntegrityAlgorithms().isEmpty()); - assertTrue(saProposal.getDhGroups().isEmpty()); - } - - // TODO(b/148689509): Test throwing exception when algorithm combination is invalid -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java deleted file mode 100644 index 5b08cdc8f2..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; -import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; -import static android.net.NetworkCapabilities.TRANSPORT_TEST; - -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkRequest; -import android.net.TestNetworkManager; -import android.os.IBinder; -import android.os.RemoteException; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -// TODO(b/148689509): Share this class with net CTS test (e.g. IpSecManagerTunnelTest) -public class TestNetworkUtils { - private static final int TIMEOUT_MS = 500; - - /** Callback to receive requested test network. */ - public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CompletableFuture futureNetwork = new CompletableFuture<>(); - - @Override - public void onAvailable(Network network) { - futureNetwork.complete(network); - } - - public Network getNetworkBlocking() throws Exception { - return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - } - - /** - * Set up test network. - * - *

    Caller MUST have MANAGE_TEST_NETWORKS permission to use this method. - * - * @param connMgr ConnectivityManager to request network. - * @param testNetworkMgr TestNetworkManager to set up test network. - * @param ifname the name of the interface to be used for the Network LinkProperties. - * @param binder a binder object guarding the lifecycle of this test network. - * @return TestNetworkCallback to retrieve the test network. - * @throws RemoteException if test network setup failed. - * @see android.net.TestNetworkManager - */ - public static TestNetworkCallback setupAndGetTestNetwork( - ConnectivityManager connMgr, - TestNetworkManager testNetworkMgr, - String ifname, - IBinder binder) - throws RemoteException { - NetworkRequest nr = - new NetworkRequest.Builder() - .addTransportType(TRANSPORT_TEST) - .removeCapability(NET_CAPABILITY_TRUSTED) - .removeCapability(NET_CAPABILITY_NOT_VPN) - .setNetworkSpecifier(ifname) - .build(); - - TestNetworkCallback cb = new TestNetworkCallback(); - connMgr.requestNetwork(nr, cb); - - // Setup the test network after network request is filed to prevent Network from being - // reaped due to no requests matching it. - testNetworkMgr.setupTestNetwork(ifname, binder); - - return cb; - } -} diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java deleted file mode 100644 index 5539dbca23..0000000000 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 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.ipsec.ike.cts; - -import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; -import static android.net.ipsec.ike.cts.PacketUtils.IPPROTO_ESP; -import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; -import static android.system.OsConstants.IPPROTO_UDP; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; - -import android.os.ParcelFileDescriptor; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.function.Predicate; - -/** - * This code is a exact copy of {@link TunUtils} in - * cts/tests/tests/net/src/android/net/cts/TunUtils.java, except the import path of PacketUtils is - * the path to the copy of PacktUtils. - * - *

    TODO(b/148689509): Statically include the TunUtils source file instead of copying it. - */ -public class TunUtils { - private static final String TAG = TunUtils.class.getSimpleName(); - - private static final int DATA_BUFFER_LEN = 4096; - static final int TIMEOUT = 500; - - static final int IP4_PROTO_OFFSET = 9; - static final int IP6_PROTO_OFFSET = 6; - - static final int IP4_ADDR_OFFSET = 12; - static final int IP4_ADDR_LEN = 4; - static final int IP6_ADDR_OFFSET = 8; - static final int IP6_ADDR_LEN = 16; - - final List mPackets = new ArrayList<>(); - private final ParcelFileDescriptor mTunFd; - private final Thread mReaderThread; - - public TunUtils(ParcelFileDescriptor tunFd) { - mTunFd = tunFd; - - // Start background reader thread - mReaderThread = - new Thread( - () -> { - try { - // Loop will exit and thread will quit when tunFd is closed. - // Receiving either EOF or an exception will exit this reader loop. - // FileInputStream in uninterruptable, so there's no good way to - // ensure that this thread shuts down except upon FD closure. - while (true) { - byte[] intercepted = receiveFromTun(); - if (intercepted == null) { - // Exit once we've hit EOF - return; - } else if (intercepted.length > 0) { - // Only save packet if we've received any bytes. - synchronized (mPackets) { - mPackets.add(intercepted); - mPackets.notifyAll(); - } - } - } - } catch (IOException ignored) { - // Simply exit this reader thread - return; - } - }); - mReaderThread.start(); - } - - private byte[] receiveFromTun() throws IOException { - FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor()); - byte[] inBytes = new byte[DATA_BUFFER_LEN]; - int bytesRead = in.read(inBytes); - - if (bytesRead < 0) { - return null; // return null for EOF - } else if (bytesRead >= DATA_BUFFER_LEN) { - throw new IllegalStateException("Too big packet. Fragmentation unsupported"); - } - return Arrays.copyOf(inBytes, bytesRead); - } - - byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { - synchronized (mPackets) { - for (int i = startIndex; i < mPackets.size(); i++) { - byte[] pkt = mPackets.get(i); - if (verifier.test(pkt)) { - return pkt; - } - } - } - return null; - } - - /** - * Checks if the specified bytes were ever sent in plaintext. - * - *

    Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like - * - * @param plaintext the plaintext bytes to check for - * @param startIndex the index in the list to check for - */ - public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { - Predicate verifier = - (pkt) -> { - return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) - != -1; - }; - return getFirstMatchingPacket(verifier, startIndex) != null; - } - - public byte[] getEspPacket(int spi, boolean encap, int startIndex) { - return getFirstMatchingPacket( - (pkt) -> { - return isEsp(pkt, spi, encap); - }, - startIndex); - } - - public byte[] awaitEspPacketNoPlaintext( - int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { - long endTime = System.currentTimeMillis() + TIMEOUT; - int startIndex = 0; - - synchronized (mPackets) { - while (System.currentTimeMillis() < endTime) { - byte[] espPkt = getEspPacket(spi, useEncap, startIndex); - if (espPkt != null) { - // Validate packet size - assertEquals(expectedPacketSize, espPkt.length); - - // Always check plaintext from start - assertFalse(hasPlaintextPacket(plaintext, 0)); - return espPkt; // We've found the packet we're looking for. - } - - startIndex = mPackets.size(); - - // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout - long waitTimeout = endTime - System.currentTimeMillis(); - if (waitTimeout > 0) { - mPackets.wait(waitTimeout); - } - } - - fail("No such ESP packet found with SPI " + spi); - } - return null; - } - - private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { - // Check SPI byte by byte. - return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) - && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) - && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) - && pkt[espOffset + 3] == (byte) (spi & 0xff); - } - - private static boolean isEsp(byte[] pkt, int spi, boolean encap) { - if (isIpv6(pkt)) { - // IPv6 UDP encap not supported by kernels; assume non-encap. - return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); - } else { - // Use default IPv4 header length (assuming no options) - if (encap) { - return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP - && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi); - } else { - return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi); - } - } - } - - static boolean isIpv6(byte[] pkt) { - // First nibble shows IP version. 0x60 for IPv6 - return (pkt[0] & (byte) 0xF0) == (byte) 0x60; - } - - private static byte[] getReflectedPacket(byte[] pkt) { - byte[] reflected = Arrays.copyOf(pkt, pkt.length); - - if (isIpv6(pkt)) { - // Set reflected packet's dst to that of the original's src - System.arraycopy( - pkt, // src - IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset - reflected, // dst - IP6_ADDR_OFFSET, // dst offset - IP6_ADDR_LEN); // len - // Set reflected packet's src IP to that of the original's dst IP - System.arraycopy( - pkt, // src - IP6_ADDR_OFFSET, // src offset - reflected, // dst - IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset - IP6_ADDR_LEN); // len - } else { - // Set reflected packet's dst to that of the original's src - System.arraycopy( - pkt, // src - IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset - reflected, // dst - IP4_ADDR_OFFSET, // dst offset - IP4_ADDR_LEN); // len - // Set reflected packet's src IP to that of the original's dst IP - System.arraycopy( - pkt, // src - IP4_ADDR_OFFSET, // src offset - reflected, // dst - IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset - IP4_ADDR_LEN); // len - } - return reflected; - } - - /** Takes all captured packets, flips the src/dst, and re-injects them. */ - public void reflectPackets() throws IOException { - synchronized (mPackets) { - for (byte[] pkt : mPackets) { - injectPacket(getReflectedPacket(pkt)); - } - } - } - - public void injectPacket(byte[] pkt) throws IOException { - FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor()); - out.write(pkt); - out.flush(); - } - - /** Resets the intercepted packets. */ - public void reset() throws IOException { - synchronized (mPackets) { - mPackets.clear(); - } - } -} From 72fe9c607263edd8c913f47a6b7c70eeca003b19 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Wed, 14 Oct 2020 12:08:43 +0000 Subject: [PATCH 1340/1415] Do not expect broadcasts in CaptivePortalTest The legacy broadcast may not be sent if wifi does not become the default network within timeout. CaptivePortalTest does not need wifi to be the default network at the start of the test, as it will be disconnected/reconnected immediately after anyway. Bug: 169106352 Test: atest CtsNetTestCasesLatestSdk:CaptivePortalTest Original-Change: https://android-review.googlesource.com/1459764 Merged-In: Ie4ee6b3c3ed7c0d414fd3cc162d4183248120895 Change-Id: Ie4ee6b3c3ed7c0d414fd3cc162d4183248120895 --- tests/cts/net/src/android/net/cts/CaptivePortalTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index f2c5028f96..eb5048fa9b 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -123,7 +123,7 @@ class CaptivePortalTest { fun testCaptivePortalIsNotDefaultNetwork() { assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY)) assumeTrue(pm.hasSystemFeature(FEATURE_WIFI)) - utils.connectToWifi() + utils.ensureWifiConnected() utils.connectToCell() // Have network validation use a local server that serves a HTTPS error / HTTP redirect From 2888ab7bc702efded37771dfbbb28b8b1977d097 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 15 Oct 2020 15:25:28 +0800 Subject: [PATCH 1341/1415] Migrate Tethering util functions to CtsTetheringUtils Bug: 166057846 Bug: 170265597 Test: atest MtsTetheringTest atest CtsTetheringTest Change-Id: I59d529cb50b4b6cdafc6be78ad61a55ee1be0404 --- tests/cts/net/util/Android.bp | 1 + .../net/cts/util/CtsTetheringUtils.java | 397 ++++++++++++++++++ .../tethering/cts/TetheringManagerTest.java | 387 ++--------------- 3 files changed, 424 insertions(+), 361 deletions(-) create mode 100644 tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp index 1f94613ffb..c36d976423 100644 --- a/tests/cts/net/util/Android.bp +++ b/tests/cts/net/util/Android.bp @@ -21,5 +21,6 @@ java_library { static_libs: [ "compatibility-device-util-axt", "junit", + "net-tests-utils", ], } \ No newline at end of file diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java new file mode 100644 index 0000000000..b18c1e72e1 --- /dev/null +++ b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java @@ -0,0 +1,397 @@ +/* + * 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.util; + +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.Network; +import android.net.TetheredClient; +import android.net.TetheringManager; +import android.net.TetheringManager.TetheringEventCallback; +import android.net.TetheringManager.TetheringInterfaceRegexps; +import android.net.TetheringManager.TetheringRequest; +import android.net.wifi.WifiClient; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.SoftApCallback; +import android.os.ConditionVariable; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.ArrayTrackRecord; + +import java.util.Collection; +import java.util.List; + +public final class CtsTetheringUtils { + private TetheringManager mTm; + private WifiManager mWm; + private Context mContext; + + private static final int DEFAULT_TIMEOUT_MS = 60_000; + + public CtsTetheringUtils(Context ctx) { + mContext = ctx; + mTm = mContext.getSystemService(TetheringManager.class); + mWm = mContext.getSystemService(WifiManager.class); + } + + public static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static int TIMEOUT_MS = 30_000; + public static class CallbackValue { + public final int error; + + private CallbackValue(final int e) { + error = e; + } + + public static class OnTetheringStarted extends CallbackValue { + OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); } + } + + public static class OnTetheringFailed extends CallbackValue { + OnTetheringFailed(final int error) { super(error); } + } + + @Override + public String toString() { + return String.format("%s(%d)", getClass().getSimpleName(), error); + } + } + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + + @Override + public void onTetheringStarted() { + mHistory.add(new CallbackValue.OnTetheringStarted()); + } + + @Override + public void onTetheringFailed(final int error) { + mHistory.add(new CallbackValue.OnTetheringFailed(error)); + } + + public void verifyTetheringStarted() { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv); + assertTrue("Fail start tethering:" + cv, + cv instanceof CallbackValue.OnTetheringStarted); + } + + public void expectTetheringFailed(final int expected) throws InterruptedException { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv); + assertTrue("Expect fail with error code " + expected + ", but received: " + cv, + (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected)); + } + } + + public static boolean isIfaceMatch(final List ifaceRegexs, final List ifaces) { + return isIfaceMatch(ifaceRegexs.toArray(new String[0]), ifaces); + } + + public static boolean isIfaceMatch(final String[] ifaceRegexs, final List ifaces) { + if (ifaceRegexs == null) fail("ifaceRegexs should not be null"); + + if (ifaces == null) return false; + + for (String s : ifaces) { + for (String regex : ifaceRegexs) { + if (s.matches(regex)) { + return true; + } + } + } + return false; + } + + // Must poll the callback before looking at the member. + public static class TestTetheringEventCallback implements TetheringEventCallback { + private static final int TIMEOUT_MS = 30_000; + + public enum CallbackType { + ON_SUPPORTED, + ON_UPSTREAM, + ON_TETHERABLE_REGEX, + ON_TETHERABLE_IFACES, + ON_TETHERED_IFACES, + ON_ERROR, + ON_CLIENTS, + ON_OFFLOAD_STATUS, + }; + + public static class CallbackValue { + public final CallbackType callbackType; + public final Object callbackParam; + public final int callbackParam2; + + private CallbackValue(final CallbackType type, final Object param, final int param2) { + this.callbackType = type; + this.callbackParam = param; + this.callbackParam2 = param2; + } + } + + private final ArrayTrackRecord mHistory = + new ArrayTrackRecord(); + + private final ArrayTrackRecord.ReadHead mCurrent = + mHistory.newReadHead(); + + private TetheringInterfaceRegexps mTetherableRegex; + private List mTetherableIfaces; + private List mTetheredIfaces; + + @Override + public void onTetheringSupported(boolean supported) { + mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, (supported ? 1 : 0))); + } + + @Override + public void onUpstreamChanged(Network network) { + mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); + } + + @Override + public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { + mTetherableRegex = reg; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); + } + + @Override + public void onTetherableInterfacesChanged(List interfaces) { + mTetherableIfaces = interfaces; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); + } + + @Override + public void onTetheredInterfacesChanged(List interfaces) { + mTetheredIfaces = interfaces; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); + } + + @Override + public void onError(String ifName, int error) { + mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); + } + + @Override + public void onClientsChanged(Collection clients) { + mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); + } + + @Override + public void onOffloadStatusChanged(int status) { + mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); + } + + public void expectTetherableInterfacesChanged(@NonNull List regexs) { + assertNotNull("No expected tetherable ifaces callback", mCurrent.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; + final List interfaces = (List) cv.callbackParam; + return isIfaceMatch(regexs, interfaces); + })); + } + + public void expectTetheredInterfacesChanged(@NonNull List regexs) { + assertNotNull("No expected tethered ifaces callback", mCurrent.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; + + final List interfaces = (List) cv.callbackParam; + + // Null regexs means no active tethering. + if (regexs == null) return interfaces.isEmpty(); + + return isIfaceMatch(regexs, interfaces); + })); + } + + public void expectCallbackStarted() { + int receivedBitMap = 0; + // The each bit represent a type from CallbackType.ON_*. + // Expect all of callbacks except for ON_ERROR. + final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal()); + // Receive ON_ERROR on started callback is not matter. It just means tethering is + // failed last time, should able to continue the test this time. + while ((receivedBitMap & expectedBitMap) != expectedBitMap) { + final CallbackValue cv = mCurrent.poll(TIMEOUT_MS, c -> true); + if (cv == null) { + fail("No expected callbacks, " + "expected bitmap: " + + expectedBitMap + ", actual: " + receivedBitMap); + } + + receivedBitMap |= (1 << cv.callbackType.ordinal()); + } + } + + public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { + assertNotNull("No offload status changed", mCurrent.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; + + final int status = (int) cv.callbackParam; + for (int offloadStatus : offloadStatuses) { + if (offloadStatus == status) return true; + } + + return false; + })); + } + + public void expectErrorOrTethered(final String iface) { + assertNotNull("No expected callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType == CallbackType.ON_ERROR + && iface.equals((String) cv.callbackParam)) { + return true; + } + if (cv.callbackType == CallbackType.ON_TETHERED_IFACES + && ((List) cv.callbackParam).contains(iface)) { + return true; + } + + return false; + })); + } + + public Network getCurrentValidUpstream() { + final CallbackValue result = mCurrent.poll(TIMEOUT_MS, (cv) -> { + return (cv.callbackType == CallbackType.ON_UPSTREAM) + && cv.callbackParam != null; + }); + + assertNotNull("No valid upstream", result); + return (Network) result.callbackParam; + } + + public void assumeTetheringSupported() { + final ArrayTrackRecord.ReadHead history = + mHistory.newReadHead(); + assertNotNull("No onSupported callback", history.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_SUPPORTED) return false; + + assumeTrue(cv.callbackParam2 == 1 /* supported */); + return true; + })); + } + + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { + return mTetherableRegex; + } + + public List getTetherableInterfaces() { + return mTetherableIfaces; + } + + public List getTetheredInterfaces() { + return mTetheredIfaces; + } + } + + public TestTetheringEventCallback registerTetheringEventCallback() { + final TestTetheringEventCallback tetherEventCallback = + new TestTetheringEventCallback(); + + mTm.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); + tetherEventCallback.expectCallbackStarted(); + + return tetherEventCallback; + } + + public void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) { + mTm.unregisterTetheringEventCallback(callback); + } + + private static List getWifiTetherableInterfaceRegexps( + final TestTetheringEventCallback callback) { + return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); + } + + public static boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) { + return !getWifiTetherableInterfaceRegexps(callback).isEmpty(); + } + + public void startWifiTethering(final TestTetheringEventCallback callback) + throws InterruptedException { + final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); + assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); + + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) + .setShouldShowEntitlementUi(false).build(); + mTm.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); + + callback.expectTetheredInterfacesChanged(wifiRegexs); + + callback.expectOneOfOffloadStatusChanged( + TETHER_HARDWARE_OFFLOAD_STARTED, + TETHER_HARDWARE_OFFLOAD_FAILED); + } + + private static class StopSoftApCallback implements SoftApCallback { + private final ConditionVariable mWaiting = new ConditionVariable(); + @Override + public void onStateChanged(int state, int failureReason) { + if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open(); + } + + @Override + public void onConnectedClientsChanged(List clients) { } + + public void waitForSoftApStopped() { + if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { + fail("stopSoftAp Timeout"); + } + } + } + + // Wait for softAp to be disabled. This is necessary on devices where stopping softAp + // deletes the interface. On these devices, tethering immediately stops when the softAp + // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be + // fully disabled, because otherwise the next test might fail because it attempts to + // start softAp before it's fully stopped. + public void expectSoftApDisabled() { + final StopSoftApCallback callback = new StopSoftApCallback(); + try { + mWm.registerSoftApCallback(c -> c.run(), callback); + // registerSoftApCallback will immediately call the callback with the current state, so + // this callback will fire even if softAp is already disabled. + callback.waitForSoftApStopped(); + } finally { + mWm.unregisterSoftApCallback(callback); + } + } + + public void stopWifiTethering(final TestTetheringEventCallback callback) { + mTm.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); + callback.expectTetheredInterfacesChanged(null); + callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + } +} diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 92dca3984c..397b4b88ca 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -26,9 +26,8 @@ import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; +import static android.net.cts.util.CtsTetheringUtils.isIfaceMatch; +import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -49,31 +48,26 @@ import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.TetheredClient; import android.net.TetheringManager; import android.net.TetheringManager.OnTetheringEntitlementResultListener; -import android.net.TetheringManager.TetheringEventCallback; import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; import android.net.cts.util.CtsNetUtils; import android.net.cts.util.CtsNetUtils.TestNetworkCallback; -import android.net.wifi.WifiClient; +import android.net.cts.util.CtsTetheringUtils; +import android.net.cts.util.CtsTetheringUtils.StartTetheringCallback; +import android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.SoftApCallback; import android.os.Bundle; -import android.os.ConditionVariable; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.ArrayTrackRecord; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -81,7 +75,6 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.LinkedBlockingQueue; @@ -100,6 +93,7 @@ public class TetheringManagerTest { private TetherChangeReceiver mTetherChangeReceiver; private CtsNetUtils mCtsNetUtils; + private CtsTetheringUtils mCtsTetheringUtils; private static final int DEFAULT_TIMEOUT_MS = 60_000; @@ -124,6 +118,7 @@ public class TetheringManagerTest { mWm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPm = mContext.getPackageManager(); mCtsNetUtils = new CtsNetUtils(mContext); + mCtsTetheringUtils = new CtsTetheringUtils(mContext); mTetherChangeReceiver = new TetherChangeReceiver(); final IntentFilter filter = new IntentFilter( TetheringManager.ACTION_TETHER_STATE_CHANGED); @@ -138,40 +133,6 @@ public class TetheringManagerTest { dropShellPermissionIdentity(); } - private static class StopSoftApCallback implements SoftApCallback { - private final ConditionVariable mWaiting = new ConditionVariable(); - @Override - public void onStateChanged(int state, int failureReason) { - if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open(); - } - - @Override - public void onConnectedClientsChanged(List clients) { } - - public void waitForSoftApStopped() { - if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { - fail("stopSoftAp Timeout"); - } - } - } - - // Wait for softAp to be disabled. This is necessary on devices where stopping softAp - // deletes the interface. On these devices, tethering immediately stops when the softAp - // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be - // fully disabled, because otherwise the next test might fail because it attempts to - // start softAp before it's fully stopped. - private void expectSoftApDisabled() { - final StopSoftApCallback callback = new StopSoftApCallback(); - try { - mWm.registerSoftApCallback(c -> c.run(), callback); - // registerSoftApCallback will immediately call the callback with the current state, so - // this callback will fire even if softAp is already disabled. - callback.waitForSoftApStopped(); - } finally { - mWm.unregisterSoftApCallback(callback); - } - } - private class TetherChangeReceiver extends BroadcastReceiver { private class TetherState { final ArrayList mAvailable; @@ -241,77 +202,6 @@ public class TetheringManagerTest { } } - private static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { - private static int TIMEOUT_MS = 30_000; - public static class CallbackValue { - public final int error; - - private CallbackValue(final int e) { - error = e; - } - - public static class OnTetheringStarted extends CallbackValue { - OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); } - } - - public static class OnTetheringFailed extends CallbackValue { - OnTetheringFailed(final int error) { super(error); } - } - - @Override - public String toString() { - return String.format("%s(%d)", getClass().getSimpleName(), error); - } - } - - private final ArrayTrackRecord.ReadHead mHistory = - new ArrayTrackRecord().newReadHead(); - - @Override - public void onTetheringStarted() { - mHistory.add(new CallbackValue.OnTetheringStarted()); - } - - @Override - public void onTetheringFailed(final int error) { - mHistory.add(new CallbackValue.OnTetheringFailed(error)); - } - - public void verifyTetheringStarted() { - final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); - assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv); - assertTrue("Fail start tethering:" + cv, - cv instanceof CallbackValue.OnTetheringStarted); - } - - public void expectTetheringFailed(final int expected) throws InterruptedException { - final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); - assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv); - assertTrue("Expect fail with error code " + expected + ", but received: " + cv, - (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected)); - } - } - - private static boolean isIfaceMatch(final List ifaceRegexs, - final List ifaces) { - return isIfaceMatch(ifaceRegexs.toArray(new String[0]), ifaces); - } - - private static boolean isIfaceMatch(final String[] ifaceRegexs, final List ifaces) { - if (ifaceRegexs == null) fail("ifaceRegexs should not be null"); - - if (ifaces == null) return false; - - for (String s : ifaces) { - for (String regex : ifaceRegexs) { - if (s.matches(regex)) { - return true; - } - } - } - return false; - } - @Test public void testStartTetheringWithStateChangeBroadcast() throws Exception { if (!mTM.isTetheringSupported()) return; @@ -331,7 +221,7 @@ public class TetheringManagerTest { mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); mTM.stopTethering(TETHERING_WIFI); - expectSoftApDisabled(); + mCtsTetheringUtils.expectSoftApDisabled(); mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); } @@ -358,252 +248,24 @@ public class TetheringManagerTest { assertFalse(tr2.getShouldShowEntitlementUi()); } - // Must poll the callback before looking at the member. - private static class TestTetheringEventCallback implements TetheringEventCallback { - private static final int TIMEOUT_MS = 30_000; - - public enum CallbackType { - ON_SUPPORTED, - ON_UPSTREAM, - ON_TETHERABLE_REGEX, - ON_TETHERABLE_IFACES, - ON_TETHERED_IFACES, - ON_ERROR, - ON_CLIENTS, - ON_OFFLOAD_STATUS, - }; - - public static class CallbackValue { - public final CallbackType callbackType; - public final Object callbackParam; - public final int callbackParam2; - - private CallbackValue(final CallbackType type, final Object param, final int param2) { - this.callbackType = type; - this.callbackParam = param; - this.callbackParam2 = param2; - } - } - - private final ArrayTrackRecord mHistory = - new ArrayTrackRecord(); - - private final ArrayTrackRecord.ReadHead mCurrent = - mHistory.newReadHead(); - - private TetheringInterfaceRegexps mTetherableRegex; - private List mTetherableIfaces; - private List mTetheredIfaces; - - @Override - public void onTetheringSupported(boolean supported) { - mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, (supported ? 1 : 0))); - } - - @Override - public void onUpstreamChanged(Network network) { - mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); - } - - @Override - public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { - mTetherableRegex = reg; - mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); - } - - @Override - public void onTetherableInterfacesChanged(List interfaces) { - mTetherableIfaces = interfaces; - mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); - } - - @Override - public void onTetheredInterfacesChanged(List interfaces) { - mTetheredIfaces = interfaces; - mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); - } - - @Override - public void onError(String ifName, int error) { - mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); - } - - @Override - public void onClientsChanged(Collection clients) { - mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); - } - - @Override - public void onOffloadStatusChanged(int status) { - mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); - } - - public void expectTetherableInterfacesChanged(@NonNull List regexs) { - assertNotNull("No expected tetherable ifaces callback", mCurrent.poll(TIMEOUT_MS, - (cv) -> { - if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; - final List interfaces = (List) cv.callbackParam; - return isIfaceMatch(regexs, interfaces); - })); - } - - public void expectTetheredInterfacesChanged(@NonNull List regexs) { - assertNotNull("No expected tethered ifaces callback", mCurrent.poll(TIMEOUT_MS, - (cv) -> { - if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; - - final List interfaces = (List) cv.callbackParam; - - // Null regexs means no active tethering. - if (regexs == null) return interfaces.isEmpty(); - - return isIfaceMatch(regexs, interfaces); - })); - } - - public void expectCallbackStarted() { - int receivedBitMap = 0; - // The each bit represent a type from CallbackType.ON_*. - // Expect all of callbacks except for ON_ERROR. - final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal()); - // Receive ON_ERROR on started callback is not matter. It just means tethering is - // failed last time, should able to continue the test this time. - while ((receivedBitMap & expectedBitMap) != expectedBitMap) { - final CallbackValue cv = mCurrent.poll(TIMEOUT_MS, c -> true); - if (cv == null) { - fail("No expected callbacks, " + "expected bitmap: " - + expectedBitMap + ", actual: " + receivedBitMap); - } - - receivedBitMap |= (1 << cv.callbackType.ordinal()); - } - } - - public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { - assertNotNull("No offload status changed", mCurrent.poll(TIMEOUT_MS, (cv) -> { - if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; - - final int status = (int) cv.callbackParam; - for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return true; - - return false; - })); - } - - public void expectErrorOrTethered(final String iface) { - assertNotNull("No expected callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { - if (cv.callbackType == CallbackType.ON_ERROR - && iface.equals((String) cv.callbackParam)) { - return true; - } - if (cv.callbackType == CallbackType.ON_TETHERED_IFACES - && ((List) cv.callbackParam).contains(iface)) { - return true; - } - - return false; - })); - } - - public Network getCurrentValidUpstream() { - final CallbackValue result = mCurrent.poll(TIMEOUT_MS, (cv) -> { - return (cv.callbackType == CallbackType.ON_UPSTREAM) - && cv.callbackParam != null; - }); - - assertNotNull("No valid upstream", result); - return (Network) result.callbackParam; - } - - public void assumeTetheringSupported() { - final ArrayTrackRecord.ReadHead history = - mHistory.newReadHead(); - assertNotNull("No onSupported callback", history.poll(TIMEOUT_MS, (cv) -> { - if (cv.callbackType != CallbackType.ON_SUPPORTED) return false; - - assumeTrue(cv.callbackParam2 == 1 /* supported */); - return true; - })); - } - - public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { - return mTetherableRegex; - } - - public List getTetherableInterfaces() { - return mTetherableIfaces; - } - - public List getTetheredInterfaces() { - return mTetheredIfaces; - } - } - - private TestTetheringEventCallback registerTetheringEventCallback() { - final TestTetheringEventCallback tetherEventCallback = - new TestTetheringEventCallback(); - - mTM.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); - tetherEventCallback.expectCallbackStarted(); - - return tetherEventCallback; - } - - private void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) { - mTM.unregisterTetheringEventCallback(callback); - } - - private List getWifiTetherableInterfaceRegexps( - final TestTetheringEventCallback callback) { - return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); - } - - private boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) { - return !getWifiTetherableInterfaceRegexps(callback).isEmpty(); - } - - private void startWifiTethering(final TestTetheringEventCallback callback) - throws InterruptedException { - final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); - assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); - - final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) - .setShouldShowEntitlementUi(false).build(); - mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); - startTetheringCallback.verifyTetheringStarted(); - - callback.expectTetheredInterfacesChanged(wifiRegexs); - - callback.expectOneOfOffloadStatusChanged( - TETHER_HARDWARE_OFFLOAD_STARTED, - TETHER_HARDWARE_OFFLOAD_FAILED); - } - - private void stopWifiTethering(final TestTetheringEventCallback callback) { - mTM.stopTethering(TETHERING_WIFI); - expectSoftApDisabled(); - callback.expectTetheredInterfacesChanged(null); - callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - } - @Test public void testRegisterTetheringEventCallback() throws Exception { - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); tetherEventCallback.assumeTetheringSupported(); if (!isWifiTetheringSupported(tetherEventCallback)) { - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); return; } - startWifiTethering(tetherEventCallback); + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); final List tetheredIfaces = tetherEventCallback.getTetheredInterfaces(); assertEquals(1, tetheredIfaces.size()); final String wifiTetheringIface = tetheredIfaces.get(0); - stopWifiTethering(tetherEventCallback); + mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); try { final int ret = mTM.tether(wifiTetheringIface); @@ -617,13 +279,14 @@ public class TetheringManagerTest { tetherEventCallback.expectErrorOrTethered(wifiTetheringIface); } finally { mTM.untether(wifiTetheringIface); - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); } } @Test public void testGetTetherableInterfaceRegexps() { - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); tetherEventCallback.assumeTetheringSupported(); final TetheringInterfaceRegexps tetherableRegexs = @@ -641,12 +304,13 @@ public class TetheringManagerTest { wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); } @Test public void testStopAllTethering() throws Exception { - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); tetherEventCallback.assumeTetheringSupported(); try { @@ -655,12 +319,12 @@ public class TetheringManagerTest { // TODO: start ethernet tethering here when TetheringManagerTest is moved to // TetheringIntegrationTest. - startWifiTethering(tetherEventCallback); + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); mTM.stopAllTethering(); tetherEventCallback.expectTetheredInterfacesChanged(null); } finally { - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); } } @@ -749,7 +413,8 @@ public class TetheringManagerTest { @Test public void testTetheringUpstream() throws Exception { assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY)); - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); tetherEventCallback.assumeTetheringSupported(); final boolean previousWifiEnabledState = mWm.isWifiEnabled(); @@ -778,7 +443,7 @@ public class TetheringManagerTest { assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR)); - startWifiTethering(tetherEventCallback); + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); @@ -789,9 +454,9 @@ public class TetheringManagerTest { assertTrue(netCap.hasTransport(TRANSPORT_CELLULAR)); assertTrue(netCap.hasCapability(expectedCap)); - stopWifiTethering(tetherEventCallback); + mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); } finally { - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); if (previousWifiEnabledState) { mCtsNetUtils.connectToWifi(); } From 845fa07bdcd2927649fc9b49f896116171cf0fee Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 15 Oct 2020 11:31:30 +0900 Subject: [PATCH 1342/1415] Make sure agents start in the CONNECTING state Bug: 170904131 Test: this Change-Id: I302b75c8e6606379c1887fa559b29bb4d29e0bdf --- .../src/android/net/cts/NetworkAgentTest.kt | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index d2ca3f88cd..7508228734 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -34,6 +34,7 @@ import android.net.NetworkAgent.INVALID_NETWORK import android.net.NetworkAgent.VALID_NETWORK import android.net.NetworkAgentConfig import android.net.NetworkCapabilities +import android.net.NetworkInfo import android.net.NetworkProvider import android.net.NetworkRequest import android.net.SocketKeepalive @@ -71,6 +72,13 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.argThat +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify import java.net.InetAddress import java.time.Duration import java.util.UUID @@ -98,7 +106,7 @@ private const val BETTER_NETWORK_SCORE = 75 private const val FAKE_NET_ID = 1098 private val instrumentation: Instrumentation get() = InstrumentationRegistry.getInstrumentation() -private val context: Context +private val realContext: Context get() = InstrumentationRegistry.getContext() private fun Message(what: Int, arg1: Int, arg2: Int, obj: Any?) = Message.obtain().also { it.what = what @@ -115,7 +123,7 @@ class NetworkAgentTest { private val LOCAL_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.1") private val REMOTE_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.2") - private val mCM = context.getSystemService(ConnectivityManager::class.java) + private val mCM = realContext.getSystemService(ConnectivityManager::class.java) private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") private val mFakeConnectivityService by lazy { FakeConnectivityService(mHandlerThread.looper) } @@ -166,7 +174,7 @@ class NetworkAgentTest { } } - fun connect(agentMsngr: Messenger) = asyncChannel.connect(context, handler, agentMsngr) + fun connect(agentMsngr: Messenger) = asyncChannel.connect(realContext, handler, agentMsngr) fun disconnect() = asyncChannel.disconnect() @@ -180,6 +188,7 @@ class NetworkAgentTest { } private open class TestableNetworkAgent( + context: Context, looper: Looper, val nc: NetworkCapabilities, val lp: LinkProperties, @@ -300,7 +309,10 @@ class NetworkAgentTest { callbacksToCleanUp.add(callback) } - private fun createNetworkAgent(name: String? = null): TestableNetworkAgent { + private fun createNetworkAgent( + context: Context = realContext, + name: String? = null + ): TestableNetworkAgent { val nc = NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) @@ -316,12 +328,12 @@ class NetworkAgentTest { addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) } val config = NetworkAgentConfig.Builder().build() - return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config).also { + return TestableNetworkAgent(context, mHandlerThread.looper, nc, lp, config).also { agentsToCleanUp.add(it) } } - private fun createConnectedNetworkAgent(name: String? = null): + private fun createConnectedNetworkAgent(context: Context = realContext, name: String? = null): Pair { val request: NetworkRequest = NetworkRequest.Builder() .clearCapabilities() @@ -329,7 +341,7 @@ class NetworkAgentTest { .build() val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) requestNetwork(request, callback) - val agent = createNetworkAgent(name) + val agent = createNetworkAgent(context, name) agent.register() agent.markConnected() return agent to callback @@ -509,13 +521,13 @@ class NetworkAgentTest { requestNetwork(request, callback) // Connect the first Network - createConnectedNetworkAgent(name1).let { (agent1, _) -> + createConnectedNetworkAgent(name = name1).let { (agent1, _) -> callback.expectAvailableThenValidatedCallbacks(agent1.network) // Upgrade agent1 to a better score so that there is no ambiguity when // agent2 connects that agent1 is still better agent1.sendNetworkScore(BETTER_NETWORK_SCORE - 1) // Connect the second agent - createConnectedNetworkAgent(name2).let { (agent2, _) -> + createConnectedNetworkAgent(name = name2).let { (agent2, _) -> agent2.markConnected() // The callback should not see anything yet callback.assertNoCallback(NO_CALLBACK_TIMEOUT) @@ -528,6 +540,21 @@ class NetworkAgentTest { // tearDown() will unregister the requests and agents } + @Test + fun testAgentStartsInConnecting() { + val mockContext = mock(Context::class.java) + val mockCm = mock(ConnectivityManager::class.java) + doReturn(mockCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE) + createConnectedNetworkAgent(mockContext) + verify(mockCm).registerNetworkAgent(any(Messenger::class.java), + argThat { it.detailedState == NetworkInfo.DetailedState.CONNECTING }, + any(LinkProperties::class.java), + any(NetworkCapabilities::class.java), + anyInt() /* score */, + any(NetworkAgentConfig::class.java), + eq(NetworkProvider.ID_NONE)) + } + @Test fun testSetAcceptUnvalidated() { createNetworkAgentWithFakeCS().let { agent -> From bb36657e1f3ad9faa485a0b335bcff46bd0e7215 Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Sat, 17 Oct 2020 01:52:50 +0000 Subject: [PATCH 1343/1415] Migrate Tethering util functions to CtsTetheringUtils Bug: 166057846 Bug: 170265597 Test: atest MtsTetheringTest atest CtsTetheringTest Exempt-From-Owner-Approval: - this is clean CP from aosp/1460711 which is already approve by owner. - owner(Lorenzo) is on the vacation and we need this CL for FRC respin(b/171013290) Original change: https://android-review.googlesource.com/c/platform/cts/+/1460711 Change-Id: I0f2b116b39eab6fc9f9b201709a7e4146a5c0c5f Merged-In: I59d529cb50b4b6cdafc6be78ad61a55ee1be0404 (cherry picked from commit b220c5b694ddac3c64f9ba88290a35363413919b) --- tests/cts/net/util/Android.bp | 1 + .../net/cts/util/CtsTetheringUtils.java | 397 ++++++++++++++++++ .../tethering/cts/TetheringManagerTest.java | 387 ++--------------- 3 files changed, 424 insertions(+), 361 deletions(-) create mode 100644 tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp index 1f94613ffb..c36d976423 100644 --- a/tests/cts/net/util/Android.bp +++ b/tests/cts/net/util/Android.bp @@ -21,5 +21,6 @@ java_library { static_libs: [ "compatibility-device-util-axt", "junit", + "net-tests-utils", ], } \ No newline at end of file diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java new file mode 100644 index 0000000000..b18c1e72e1 --- /dev/null +++ b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java @@ -0,0 +1,397 @@ +/* + * 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.util; + +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.Network; +import android.net.TetheredClient; +import android.net.TetheringManager; +import android.net.TetheringManager.TetheringEventCallback; +import android.net.TetheringManager.TetheringInterfaceRegexps; +import android.net.TetheringManager.TetheringRequest; +import android.net.wifi.WifiClient; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.SoftApCallback; +import android.os.ConditionVariable; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.ArrayTrackRecord; + +import java.util.Collection; +import java.util.List; + +public final class CtsTetheringUtils { + private TetheringManager mTm; + private WifiManager mWm; + private Context mContext; + + private static final int DEFAULT_TIMEOUT_MS = 60_000; + + public CtsTetheringUtils(Context ctx) { + mContext = ctx; + mTm = mContext.getSystemService(TetheringManager.class); + mWm = mContext.getSystemService(WifiManager.class); + } + + public static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static int TIMEOUT_MS = 30_000; + public static class CallbackValue { + public final int error; + + private CallbackValue(final int e) { + error = e; + } + + public static class OnTetheringStarted extends CallbackValue { + OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); } + } + + public static class OnTetheringFailed extends CallbackValue { + OnTetheringFailed(final int error) { super(error); } + } + + @Override + public String toString() { + return String.format("%s(%d)", getClass().getSimpleName(), error); + } + } + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + + @Override + public void onTetheringStarted() { + mHistory.add(new CallbackValue.OnTetheringStarted()); + } + + @Override + public void onTetheringFailed(final int error) { + mHistory.add(new CallbackValue.OnTetheringFailed(error)); + } + + public void verifyTetheringStarted() { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv); + assertTrue("Fail start tethering:" + cv, + cv instanceof CallbackValue.OnTetheringStarted); + } + + public void expectTetheringFailed(final int expected) throws InterruptedException { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv); + assertTrue("Expect fail with error code " + expected + ", but received: " + cv, + (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected)); + } + } + + public static boolean isIfaceMatch(final List ifaceRegexs, final List ifaces) { + return isIfaceMatch(ifaceRegexs.toArray(new String[0]), ifaces); + } + + public static boolean isIfaceMatch(final String[] ifaceRegexs, final List ifaces) { + if (ifaceRegexs == null) fail("ifaceRegexs should not be null"); + + if (ifaces == null) return false; + + for (String s : ifaces) { + for (String regex : ifaceRegexs) { + if (s.matches(regex)) { + return true; + } + } + } + return false; + } + + // Must poll the callback before looking at the member. + public static class TestTetheringEventCallback implements TetheringEventCallback { + private static final int TIMEOUT_MS = 30_000; + + public enum CallbackType { + ON_SUPPORTED, + ON_UPSTREAM, + ON_TETHERABLE_REGEX, + ON_TETHERABLE_IFACES, + ON_TETHERED_IFACES, + ON_ERROR, + ON_CLIENTS, + ON_OFFLOAD_STATUS, + }; + + public static class CallbackValue { + public final CallbackType callbackType; + public final Object callbackParam; + public final int callbackParam2; + + private CallbackValue(final CallbackType type, final Object param, final int param2) { + this.callbackType = type; + this.callbackParam = param; + this.callbackParam2 = param2; + } + } + + private final ArrayTrackRecord mHistory = + new ArrayTrackRecord(); + + private final ArrayTrackRecord.ReadHead mCurrent = + mHistory.newReadHead(); + + private TetheringInterfaceRegexps mTetherableRegex; + private List mTetherableIfaces; + private List mTetheredIfaces; + + @Override + public void onTetheringSupported(boolean supported) { + mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, (supported ? 1 : 0))); + } + + @Override + public void onUpstreamChanged(Network network) { + mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); + } + + @Override + public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { + mTetherableRegex = reg; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); + } + + @Override + public void onTetherableInterfacesChanged(List interfaces) { + mTetherableIfaces = interfaces; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); + } + + @Override + public void onTetheredInterfacesChanged(List interfaces) { + mTetheredIfaces = interfaces; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); + } + + @Override + public void onError(String ifName, int error) { + mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); + } + + @Override + public void onClientsChanged(Collection clients) { + mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); + } + + @Override + public void onOffloadStatusChanged(int status) { + mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); + } + + public void expectTetherableInterfacesChanged(@NonNull List regexs) { + assertNotNull("No expected tetherable ifaces callback", mCurrent.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; + final List interfaces = (List) cv.callbackParam; + return isIfaceMatch(regexs, interfaces); + })); + } + + public void expectTetheredInterfacesChanged(@NonNull List regexs) { + assertNotNull("No expected tethered ifaces callback", mCurrent.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; + + final List interfaces = (List) cv.callbackParam; + + // Null regexs means no active tethering. + if (regexs == null) return interfaces.isEmpty(); + + return isIfaceMatch(regexs, interfaces); + })); + } + + public void expectCallbackStarted() { + int receivedBitMap = 0; + // The each bit represent a type from CallbackType.ON_*. + // Expect all of callbacks except for ON_ERROR. + final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal()); + // Receive ON_ERROR on started callback is not matter. It just means tethering is + // failed last time, should able to continue the test this time. + while ((receivedBitMap & expectedBitMap) != expectedBitMap) { + final CallbackValue cv = mCurrent.poll(TIMEOUT_MS, c -> true); + if (cv == null) { + fail("No expected callbacks, " + "expected bitmap: " + + expectedBitMap + ", actual: " + receivedBitMap); + } + + receivedBitMap |= (1 << cv.callbackType.ordinal()); + } + } + + public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { + assertNotNull("No offload status changed", mCurrent.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; + + final int status = (int) cv.callbackParam; + for (int offloadStatus : offloadStatuses) { + if (offloadStatus == status) return true; + } + + return false; + })); + } + + public void expectErrorOrTethered(final String iface) { + assertNotNull("No expected callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType == CallbackType.ON_ERROR + && iface.equals((String) cv.callbackParam)) { + return true; + } + if (cv.callbackType == CallbackType.ON_TETHERED_IFACES + && ((List) cv.callbackParam).contains(iface)) { + return true; + } + + return false; + })); + } + + public Network getCurrentValidUpstream() { + final CallbackValue result = mCurrent.poll(TIMEOUT_MS, (cv) -> { + return (cv.callbackType == CallbackType.ON_UPSTREAM) + && cv.callbackParam != null; + }); + + assertNotNull("No valid upstream", result); + return (Network) result.callbackParam; + } + + public void assumeTetheringSupported() { + final ArrayTrackRecord.ReadHead history = + mHistory.newReadHead(); + assertNotNull("No onSupported callback", history.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_SUPPORTED) return false; + + assumeTrue(cv.callbackParam2 == 1 /* supported */); + return true; + })); + } + + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { + return mTetherableRegex; + } + + public List getTetherableInterfaces() { + return mTetherableIfaces; + } + + public List getTetheredInterfaces() { + return mTetheredIfaces; + } + } + + public TestTetheringEventCallback registerTetheringEventCallback() { + final TestTetheringEventCallback tetherEventCallback = + new TestTetheringEventCallback(); + + mTm.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); + tetherEventCallback.expectCallbackStarted(); + + return tetherEventCallback; + } + + public void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) { + mTm.unregisterTetheringEventCallback(callback); + } + + private static List getWifiTetherableInterfaceRegexps( + final TestTetheringEventCallback callback) { + return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); + } + + public static boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) { + return !getWifiTetherableInterfaceRegexps(callback).isEmpty(); + } + + public void startWifiTethering(final TestTetheringEventCallback callback) + throws InterruptedException { + final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); + assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); + + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) + .setShouldShowEntitlementUi(false).build(); + mTm.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); + + callback.expectTetheredInterfacesChanged(wifiRegexs); + + callback.expectOneOfOffloadStatusChanged( + TETHER_HARDWARE_OFFLOAD_STARTED, + TETHER_HARDWARE_OFFLOAD_FAILED); + } + + private static class StopSoftApCallback implements SoftApCallback { + private final ConditionVariable mWaiting = new ConditionVariable(); + @Override + public void onStateChanged(int state, int failureReason) { + if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open(); + } + + @Override + public void onConnectedClientsChanged(List clients) { } + + public void waitForSoftApStopped() { + if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { + fail("stopSoftAp Timeout"); + } + } + } + + // Wait for softAp to be disabled. This is necessary on devices where stopping softAp + // deletes the interface. On these devices, tethering immediately stops when the softAp + // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be + // fully disabled, because otherwise the next test might fail because it attempts to + // start softAp before it's fully stopped. + public void expectSoftApDisabled() { + final StopSoftApCallback callback = new StopSoftApCallback(); + try { + mWm.registerSoftApCallback(c -> c.run(), callback); + // registerSoftApCallback will immediately call the callback with the current state, so + // this callback will fire even if softAp is already disabled. + callback.waitForSoftApStopped(); + } finally { + mWm.unregisterSoftApCallback(callback); + } + } + + public void stopWifiTethering(final TestTetheringEventCallback callback) { + mTm.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); + callback.expectTetheredInterfacesChanged(null); + callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + } +} diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 65a8c7c76b..87787b96f7 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -26,9 +26,8 @@ import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; +import static android.net.cts.util.CtsTetheringUtils.isIfaceMatch; +import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -49,31 +48,26 @@ import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.TetheredClient; import android.net.TetheringManager; import android.net.TetheringManager.OnTetheringEntitlementResultListener; -import android.net.TetheringManager.TetheringEventCallback; import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; import android.net.cts.util.CtsNetUtils; import android.net.cts.util.CtsNetUtils.TestNetworkCallback; -import android.net.wifi.WifiClient; +import android.net.cts.util.CtsTetheringUtils; +import android.net.cts.util.CtsTetheringUtils.StartTetheringCallback; +import android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.SoftApCallback; import android.os.Bundle; -import android.os.ConditionVariable; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.ArrayTrackRecord; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -81,7 +75,6 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.LinkedBlockingQueue; @@ -100,6 +93,7 @@ public class TetheringManagerTest { private TetherChangeReceiver mTetherChangeReceiver; private CtsNetUtils mCtsNetUtils; + private CtsTetheringUtils mCtsTetheringUtils; private static final int DEFAULT_TIMEOUT_MS = 60_000; @@ -124,6 +118,7 @@ public class TetheringManagerTest { mWm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPm = mContext.getPackageManager(); mCtsNetUtils = new CtsNetUtils(mContext); + mCtsTetheringUtils = new CtsTetheringUtils(mContext); mTetherChangeReceiver = new TetherChangeReceiver(); final IntentFilter filter = new IntentFilter( TetheringManager.ACTION_TETHER_STATE_CHANGED); @@ -138,40 +133,6 @@ public class TetheringManagerTest { dropShellPermissionIdentity(); } - private static class StopSoftApCallback implements SoftApCallback { - private final ConditionVariable mWaiting = new ConditionVariable(); - @Override - public void onStateChanged(int state, int failureReason) { - if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open(); - } - - @Override - public void onConnectedClientsChanged(List clients) { } - - public void waitForSoftApStopped() { - if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { - fail("stopSoftAp Timeout"); - } - } - } - - // Wait for softAp to be disabled. This is necessary on devices where stopping softAp - // deletes the interface. On these devices, tethering immediately stops when the softAp - // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be - // fully disabled, because otherwise the next test might fail because it attempts to - // start softAp before it's fully stopped. - private void expectSoftApDisabled() { - final StopSoftApCallback callback = new StopSoftApCallback(); - try { - mWm.registerSoftApCallback(c -> c.run(), callback); - // registerSoftApCallback will immediately call the callback with the current state, so - // this callback will fire even if softAp is already disabled. - callback.waitForSoftApStopped(); - } finally { - mWm.unregisterSoftApCallback(callback); - } - } - private class TetherChangeReceiver extends BroadcastReceiver { private class TetherState { final ArrayList mAvailable; @@ -241,77 +202,6 @@ public class TetheringManagerTest { } } - private static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { - private static int TIMEOUT_MS = 30_000; - public static class CallbackValue { - public final int error; - - private CallbackValue(final int e) { - error = e; - } - - public static class OnTetheringStarted extends CallbackValue { - OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); } - } - - public static class OnTetheringFailed extends CallbackValue { - OnTetheringFailed(final int error) { super(error); } - } - - @Override - public String toString() { - return String.format("%s(%d)", getClass().getSimpleName(), error); - } - } - - private final ArrayTrackRecord.ReadHead mHistory = - new ArrayTrackRecord().newReadHead(); - - @Override - public void onTetheringStarted() { - mHistory.add(new CallbackValue.OnTetheringStarted()); - } - - @Override - public void onTetheringFailed(final int error) { - mHistory.add(new CallbackValue.OnTetheringFailed(error)); - } - - public void verifyTetheringStarted() { - final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); - assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv); - assertTrue("Fail start tethering:" + cv, - cv instanceof CallbackValue.OnTetheringStarted); - } - - public void expectTetheringFailed(final int expected) throws InterruptedException { - final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); - assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv); - assertTrue("Expect fail with error code " + expected + ", but received: " + cv, - (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected)); - } - } - - private static boolean isIfaceMatch(final List ifaceRegexs, - final List ifaces) { - return isIfaceMatch(ifaceRegexs.toArray(new String[0]), ifaces); - } - - private static boolean isIfaceMatch(final String[] ifaceRegexs, final List ifaces) { - if (ifaceRegexs == null) fail("ifaceRegexs should not be null"); - - if (ifaces == null) return false; - - for (String s : ifaces) { - for (String regex : ifaceRegexs) { - if (s.matches(regex)) { - return true; - } - } - } - return false; - } - @Test public void testStartTetheringWithStateChangeBroadcast() throws Exception { if (!mTM.isTetheringSupported()) return; @@ -331,7 +221,7 @@ public class TetheringManagerTest { mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); mTM.stopTethering(TETHERING_WIFI); - expectSoftApDisabled(); + mCtsTetheringUtils.expectSoftApDisabled(); mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); } @@ -358,252 +248,24 @@ public class TetheringManagerTest { assertFalse(tr2.getShouldShowEntitlementUi()); } - // Must poll the callback before looking at the member. - private static class TestTetheringEventCallback implements TetheringEventCallback { - private static final int TIMEOUT_MS = 30_000; - - public enum CallbackType { - ON_SUPPORTED, - ON_UPSTREAM, - ON_TETHERABLE_REGEX, - ON_TETHERABLE_IFACES, - ON_TETHERED_IFACES, - ON_ERROR, - ON_CLIENTS, - ON_OFFLOAD_STATUS, - }; - - public static class CallbackValue { - public final CallbackType callbackType; - public final Object callbackParam; - public final int callbackParam2; - - private CallbackValue(final CallbackType type, final Object param, final int param2) { - this.callbackType = type; - this.callbackParam = param; - this.callbackParam2 = param2; - } - } - - private final ArrayTrackRecord mHistory = - new ArrayTrackRecord(); - - private final ArrayTrackRecord.ReadHead mCurrent = - mHistory.newReadHead(); - - private TetheringInterfaceRegexps mTetherableRegex; - private List mTetherableIfaces; - private List mTetheredIfaces; - - @Override - public void onTetheringSupported(boolean supported) { - mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, (supported ? 1 : 0))); - } - - @Override - public void onUpstreamChanged(Network network) { - mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); - } - - @Override - public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { - mTetherableRegex = reg; - mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); - } - - @Override - public void onTetherableInterfacesChanged(List interfaces) { - mTetherableIfaces = interfaces; - mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); - } - - @Override - public void onTetheredInterfacesChanged(List interfaces) { - mTetheredIfaces = interfaces; - mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); - } - - @Override - public void onError(String ifName, int error) { - mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); - } - - @Override - public void onClientsChanged(Collection clients) { - mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); - } - - @Override - public void onOffloadStatusChanged(int status) { - mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); - } - - public void expectTetherableInterfacesChanged(@NonNull List regexs) { - assertNotNull("No expected tetherable ifaces callback", mCurrent.poll(TIMEOUT_MS, - (cv) -> { - if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; - final List interfaces = (List) cv.callbackParam; - return isIfaceMatch(regexs, interfaces); - })); - } - - public void expectTetheredInterfacesChanged(@NonNull List regexs) { - assertNotNull("No expected tethered ifaces callback", mCurrent.poll(TIMEOUT_MS, - (cv) -> { - if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; - - final List interfaces = (List) cv.callbackParam; - - // Null regexs means no active tethering. - if (regexs == null) return interfaces.isEmpty(); - - return isIfaceMatch(regexs, interfaces); - })); - } - - public void expectCallbackStarted() { - int receivedBitMap = 0; - // The each bit represent a type from CallbackType.ON_*. - // Expect all of callbacks except for ON_ERROR. - final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal()); - // Receive ON_ERROR on started callback is not matter. It just means tethering is - // failed last time, should able to continue the test this time. - while ((receivedBitMap & expectedBitMap) != expectedBitMap) { - final CallbackValue cv = mCurrent.poll(TIMEOUT_MS, c -> true); - if (cv == null) { - fail("No expected callbacks, " + "expected bitmap: " - + expectedBitMap + ", actual: " + receivedBitMap); - } - - receivedBitMap |= (1 << cv.callbackType.ordinal()); - } - } - - public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { - assertNotNull("No offload status changed", mCurrent.poll(TIMEOUT_MS, (cv) -> { - if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; - - final int status = (int) cv.callbackParam; - for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return true; - - return false; - })); - } - - public void expectErrorOrTethered(final String iface) { - assertNotNull("No expected callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { - if (cv.callbackType == CallbackType.ON_ERROR - && iface.equals((String) cv.callbackParam)) { - return true; - } - if (cv.callbackType == CallbackType.ON_TETHERED_IFACES - && ((List) cv.callbackParam).contains(iface)) { - return true; - } - - return false; - })); - } - - public Network getCurrentValidUpstream() { - final CallbackValue result = mCurrent.poll(TIMEOUT_MS, (cv) -> { - return (cv.callbackType == CallbackType.ON_UPSTREAM) - && cv.callbackParam != null; - }); - - assertNotNull("No valid upstream", result); - return (Network) result.callbackParam; - } - - public void assumeTetheringSupported() { - final ArrayTrackRecord.ReadHead history = - mHistory.newReadHead(); - assertNotNull("No onSupported callback", history.poll(TIMEOUT_MS, (cv) -> { - if (cv.callbackType != CallbackType.ON_SUPPORTED) return false; - - assumeTrue(cv.callbackParam2 == 1 /* supported */); - return true; - })); - } - - public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { - return mTetherableRegex; - } - - public List getTetherableInterfaces() { - return mTetherableIfaces; - } - - public List getTetheredInterfaces() { - return mTetheredIfaces; - } - } - - private TestTetheringEventCallback registerTetheringEventCallback() { - final TestTetheringEventCallback tetherEventCallback = - new TestTetheringEventCallback(); - - mTM.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); - tetherEventCallback.expectCallbackStarted(); - - return tetherEventCallback; - } - - private void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) { - mTM.unregisterTetheringEventCallback(callback); - } - - private List getWifiTetherableInterfaceRegexps( - final TestTetheringEventCallback callback) { - return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); - } - - private boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) { - return !getWifiTetherableInterfaceRegexps(callback).isEmpty(); - } - - private void startWifiTethering(final TestTetheringEventCallback callback) - throws InterruptedException { - final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); - assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); - - final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) - .setShouldShowEntitlementUi(false).build(); - mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); - startTetheringCallback.verifyTetheringStarted(); - - callback.expectTetheredInterfacesChanged(wifiRegexs); - - callback.expectOneOfOffloadStatusChanged( - TETHER_HARDWARE_OFFLOAD_STARTED, - TETHER_HARDWARE_OFFLOAD_FAILED); - } - - private void stopWifiTethering(final TestTetheringEventCallback callback) { - mTM.stopTethering(TETHERING_WIFI); - expectSoftApDisabled(); - callback.expectTetheredInterfacesChanged(null); - callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - } - @Test public void testRegisterTetheringEventCallback() throws Exception { - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); tetherEventCallback.assumeTetheringSupported(); if (!isWifiTetheringSupported(tetherEventCallback)) { - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); return; } - startWifiTethering(tetherEventCallback); + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); final List tetheredIfaces = tetherEventCallback.getTetheredInterfaces(); assertEquals(1, tetheredIfaces.size()); final String wifiTetheringIface = tetheredIfaces.get(0); - stopWifiTethering(tetherEventCallback); + mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); try { final int ret = mTM.tether(wifiTetheringIface); @@ -617,13 +279,14 @@ public class TetheringManagerTest { tetherEventCallback.expectErrorOrTethered(wifiTetheringIface); } finally { mTM.untether(wifiTetheringIface); - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); } } @Test public void testGetTetherableInterfaceRegexps() { - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); tetherEventCallback.assumeTetheringSupported(); final TetheringInterfaceRegexps tetherableRegexs = @@ -641,12 +304,13 @@ public class TetheringManagerTest { wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); } @Test public void testStopAllTethering() throws Exception { - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); tetherEventCallback.assumeTetheringSupported(); try { @@ -655,12 +319,12 @@ public class TetheringManagerTest { // TODO: start ethernet tethering here when TetheringManagerTest is moved to // TetheringIntegrationTest. - startWifiTethering(tetherEventCallback); + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); mTM.stopAllTethering(); tetherEventCallback.expectTetheredInterfacesChanged(null); } finally { - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); } } @@ -749,7 +413,8 @@ public class TetheringManagerTest { @Test public void testTetheringUpstream() throws Exception { assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY)); - final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); tetherEventCallback.assumeTetheringSupported(); final boolean previousWifiEnabledState = mWm.isWifiEnabled(); @@ -778,7 +443,7 @@ public class TetheringManagerTest { assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR)); - startWifiTethering(tetherEventCallback); + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); @@ -789,9 +454,9 @@ public class TetheringManagerTest { assertTrue(netCap.hasTransport(TRANSPORT_CELLULAR)); assertTrue(netCap.hasCapability(expectedCap)); - stopWifiTethering(tetherEventCallback); + mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); } finally { - unregisterTetheringEventCallback(tetherEventCallback); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); if (previousWifiEnabledState) { mCtsNetUtils.connectToWifi(); } From 4607c5535b025d820fae3b2e34d56a8bae4df23d Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 15 Oct 2020 09:42:31 +0800 Subject: [PATCH 1344/1415] Add the flag and default enable selectAllPrefixRange Also add MtsTetheringTest which only run if tethering mainline module is installed. Bug: 166057846 Bug: 170265597 Test: atest TetheringTests Change-Id: I434dda81eb5fab700d873a8ff3429b4222f0c7e6 --- .../tethering/PrivateAddressCoordinator.java | 11 +- .../tethering/TetheringConfiguration.java | 22 ++- Tethering/tests/mts/Android.bp | 56 ++++++ Tethering/tests/mts/AndroidManifest.xml | 34 ++++ Tethering/tests/mts/AndroidTest.xml | 36 ++++ .../tethering/mts/TetheringModuleTest.java | 183 ++++++++++++++++++ .../PrivateAddressCoordinatorTest.java | 4 +- .../tethering/TetheringConfigurationTest.java | 27 +++ .../networkstack/tethering/TetheringTest.java | 6 +- 9 files changed, 365 insertions(+), 14 deletions(-) create mode 100644 Tethering/tests/mts/Android.bp create mode 100644 Tethering/tests/mts/AndroidManifest.xml create mode 100644 Tethering/tests/mts/AndroidTest.xml create mode 100644 Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index 9fc1d7e5bc..4f616cdff0 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -80,11 +80,6 @@ public class PrivateAddressCoordinator { private final SparseArray mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { - this(context, config, new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16")))); - } - - public PrivateAddressCoordinator(Context context, TetheringConfiguration config, - List prefixPools) { mDownstreams = new ArraySet<>(); mUpstreamPrefixMap = new ArrayMap<>(); mConnectivityMgr = (ConnectivityManager) context.getSystemService( @@ -95,7 +90,11 @@ public class PrivateAddressCoordinator { mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); - mTetheringPrefixes = prefixPools; + mTetheringPrefixes = new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16"))); + if (config.isSelectAllPrefixRangeEnabled()) { + mTetheringPrefixes.add(new IpPrefix("172.16.0.0/12")); + mTetheringPrefixes.add(new IpPrefix("10.0.0.0/8")); + } } /** diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 5783805861..799637c9b1 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -40,7 +40,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.StringJoiner; - /** * A utility class to encapsulate the various tethering configuration elements. * @@ -87,6 +86,13 @@ public class TetheringConfiguration { public static final String USE_LEGACY_WIFI_P2P_DEDICATED_IP = "use_legacy_wifi_p2p_dedicated_ip"; + /** + * Flag use to enable select all prefix ranges feature. + * TODO: Remove this flag if there are no problems after M-2020-12 rolls out. + */ + public static final String TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES = + "tether_enable_select_all_prefix_ranges"; + /** * Default value that used to periodic polls tether offload stats from tethering offload HAL * to make the data warnings work. @@ -118,6 +124,8 @@ public class TetheringConfiguration { private final boolean mEnableBpfOffload; private final boolean mEnableWifiP2pDedicatedIp; + private final boolean mEnableSelectAllPrefixRange; + public TetheringConfiguration(Context ctx, SharedLog log, int id) { final SharedLog configLog = log.forSubComponent("config"); @@ -164,6 +172,11 @@ public class TetheringConfiguration { R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip, false /* defaultValue */); + // Flags should normally not be booleans, but this is a kill-switch flag that is only used + // to turn off the feature, so binary rollback problems do not apply. + mEnableSelectAllPrefixRange = getDeviceConfigBoolean( + TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES, true /* defaultValue */); + configLog.log(toString()); } @@ -249,6 +262,9 @@ public class TetheringConfiguration { pw.print("enableWifiP2pDedicatedIp: "); pw.println(mEnableWifiP2pDedicatedIp); + + pw.print("mEnableSelectAllPrefixRange: "); + pw.println(mEnableSelectAllPrefixRange); } /** Returns the string representation of this object.*/ @@ -310,6 +326,10 @@ public class TetheringConfiguration { return mEnableBpfOffload; } + public boolean isSelectAllPrefixRangeEnabled() { + return mEnableSelectAllPrefixRange; + } + private static Collection getUpstreamIfaceTypes(Resources res, boolean dunRequired) { final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types); final ArrayList upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); diff --git a/Tethering/tests/mts/Android.bp b/Tethering/tests/mts/Android.bp new file mode 100644 index 0000000000..f925b0a53f --- /dev/null +++ b/Tethering/tests/mts/Android.bp @@ -0,0 +1,56 @@ +// 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. + +android_test { + // This tests for functionality that is not required for devices that + // don't use Tethering mainline module. + name: "MtsTetheringTest", + + libs: [ + "android.test.base", + ], + + srcs: [ + "src/**/*.java", + ], + + static_libs: [ + "androidx.test.rules", + // mockito-target-extended-minus-junit4 used in this lib have dependency with + // jni_libs libdexmakerjvmtiagent and libstaticjvmtiagent. + "cts-net-utils", + // This is needed for androidx.test.runner.AndroidJUnitRunner. + "ctstestrunner-axt", + "junit", + "junit-params", + ], + + jni_libs: [ + // For mockito extended which is pulled in from -net-utils -> net-tests-utils + // (mockito-target-extended-minus-junit4). + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], + + platform_apis: true, + + // Tag this module as a mts test artifact + test_suites: [ + "general-tests", + "mts", + ], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", +} diff --git a/Tethering/tests/mts/AndroidManifest.xml b/Tethering/tests/mts/AndroidManifest.xml new file mode 100644 index 0000000000..6d2abcad42 --- /dev/null +++ b/Tethering/tests/mts/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + diff --git a/Tethering/tests/mts/AndroidTest.xml b/Tethering/tests/mts/AndroidTest.xml new file mode 100644 index 0000000000..80788dfa6f --- /dev/null +++ b/Tethering/tests/mts/AndroidTest.xml @@ -0,0 +1,36 @@ + + + + diff --git a/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java b/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java new file mode 100644 index 0000000000..7ffe37ad64 --- /dev/null +++ b/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java @@ -0,0 +1,183 @@ +/* + * 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.tethering.mts; + +import static android.Manifest.permission.MANAGE_TEST_NETWORKS; +import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.Manifest.permission.READ_DEVICE_CONFIG; +import static android.Manifest.permission.TETHER_PRIVILEGED; +import static android.Manifest.permission.WRITE_SETTINGS; +import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; + +import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.app.UiAutomation; +import android.content.Context; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.TetheringManager; +import android.net.cts.util.CtsTetheringUtils; +import android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; +import android.provider.DeviceConfig; + +import androidx.annotation.NonNull; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.TestNetworkTracker; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class TetheringModuleTest { + private Context mContext; + private TetheringManager mTm; + private CtsTetheringUtils mCtsTetheringUtils; + + private UiAutomation mUiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + + @Before + public void setUp() throws Exception { + mUiAutomation.adoptShellPermissionIdentity(MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, + WRITE_SETTINGS, READ_DEVICE_CONFIG, TETHER_PRIVILEGED); + mContext = InstrumentationRegistry.getContext(); + mTm = mContext.getSystemService(TetheringManager.class); + mCtsTetheringUtils = new CtsTetheringUtils(mContext); + } + + @After + public void tearDown() throws Exception { + mUiAutomation.dropShellPermissionIdentity(); + } + + private static final String TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES = + "tether_enable_select_all_prefix_ranges"; + @Test + public void testSwitchBasePrefixRangeWhenConflict() throws Exception { + assumeTrue(isFeatureEnabled(TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES, true)); + + addressConflictTest(true); + } + + @Test + public void testSwitchPrefixRangeWhenConflict() throws Exception { + addressConflictTest(false); + } + + private void addressConflictTest(final boolean wholeRangeConflict) throws Exception { + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); + + TestNetworkTracker tnt = null; + try { + tetherEventCallback.assumeTetheringSupported(); + assumeTrue(isWifiTetheringSupported(tetherEventCallback)); + + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); + + final List tetheredIfaces = tetherEventCallback.getTetheredInterfaces(); + assertEquals(1, tetheredIfaces.size()); + final String wifiTetheringIface = tetheredIfaces.get(0); + + NetworkInterface nif = NetworkInterface.getByName(wifiTetheringIface); + // Tethering downstream only have one ipv4 address. + final LinkAddress hotspotAddr = getFirstIpv4Address(nif); + assertNotNull(hotspotAddr); + + final IpPrefix testPrefix = getConflictingPrefix(hotspotAddr, wholeRangeConflict); + assertNotNull(testPrefix); + + tnt = setUpTestNetwork( + new LinkAddress(testPrefix.getAddress(), testPrefix.getPrefixLength())); + + tetherEventCallback.expectTetheredInterfacesChanged(null); + final List wifiRegexs = + tetherEventCallback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); + + tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); + nif = NetworkInterface.getByName(wifiTetheringIface); + final LinkAddress newHotspotAddr = getFirstIpv4Address(nif); + assertNotNull(newHotspotAddr); + + assertFalse(testPrefix.containsPrefix( + new IpPrefix(newHotspotAddr.getAddress(), newHotspotAddr.getPrefixLength()))); + + mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); + } finally { + if (tnt != null) { + tnt.teardown(); + } + mTm.stopAllTethering(); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); + } + } + + private LinkAddress getFirstIpv4Address(final NetworkInterface nif) { + for (InterfaceAddress ia : nif.getInterfaceAddresses()) { + final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength()); + if (addr.isIpv4()) return addr; + } + return null; + } + + @NonNull + private IpPrefix getConflictingPrefix(final LinkAddress address, + final boolean wholeRangeConflict) { + if (!wholeRangeConflict) { + return new IpPrefix(address.getAddress(), address.getPrefixLength()); + } + + final ArrayList prefixPool = new ArrayList<>(Arrays.asList( + new IpPrefix("192.168.0.0/16"), + new IpPrefix("172.16.0.0/12"), + new IpPrefix("10.0.0.0/8"))); + + for (IpPrefix prefix : prefixPool) { + if (prefix.contains(address.getAddress())) return prefix; + } + + fail("Could not find sutiable conflict prefix"); + + // Never go here. + return null; + } + + private TestNetworkTracker setUpTestNetwork(final LinkAddress address) throws Exception { + return initTestNetwork(mContext, address, 10_000L /* test timeout ms*/); + + } + + public static boolean isFeatureEnabled(final String name, final boolean defaultValue) { + return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, defaultValue); + } +} diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 8cb80bad80..41d46e522c 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -99,9 +99,9 @@ public final class PrivateAddressCoordinatorTest { when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr); when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks); when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false); + when(mConfig.isSelectAllPrefixRangeEnabled()).thenReturn(true); setUpIpServers(); - mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig, - mTetheringPrefixes)); + mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig)); } private LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index dc0940cc02..237e2c27bf 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -131,6 +131,7 @@ public class TetheringConfigurationTest { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip)) .thenReturn(false); initializeBpfOffloadConfiguration(true, null /* unset */); + initEnableSelectAllPrefixRangeFlag(null /* unset */); mHasTelephonyManager = true; mMockContext = new MockContext(mContext); @@ -428,4 +429,30 @@ public class TetheringConfigurationTest { mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp()); } + + private void initEnableSelectAllPrefixRangeFlag(final String value) { + doReturn(value).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES))); + } + + @Test + public void testSelectAllPrefixRangeFlag() throws Exception { + // Test default value. + final TetheringConfiguration defaultCfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(defaultCfg.isSelectAllPrefixRangeEnabled()); + + // Test disable flag. + initEnableSelectAllPrefixRangeFlag("false"); + final TetheringConfiguration testDisable = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(testDisable.isSelectAllPrefixRangeEnabled()); + + // Test enable flag. + initEnableSelectAllPrefixRangeFlag("true"); + final TetheringConfiguration testEnable = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(testEnable.isSelectAllPrefixRangeEnabled()); + } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 20e94b256a..114cb7ca6e 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -456,11 +456,7 @@ public class TetheringTest { @Override public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx, TetheringConfiguration cfg) { - final ArrayList prefixPool = new ArrayList<>(Arrays.asList( - new IpPrefix("192.168.0.0/16"), - new IpPrefix("172.16.0.0/12"), - new IpPrefix("10.0.0.0/8"))); - mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(ctx, cfg, prefixPool)); + mPrivateAddressCoordinator = super.getPrivateAddressCoordinator(ctx, cfg); return mPrivateAddressCoordinator; } } From 0c7093391636324441d18f842b18b48c7abd9afe Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 22 Oct 2020 10:44:15 +0900 Subject: [PATCH 1345/1415] Wait for connect before dropping permissions WifiManager#connect is implemented with a oneway binder call, so it may return before the permission check. The previous code could drop shell permissions before the check is performed. Use WifiManager.ActionListener to wait for the operation to end before dropping permissions. Also refactor current usages of various "run as shell" utilities to use TestPermissionUtil.runAsShell, which is the "standard" utility used in connectivity tests (both in CTS and in other tests). Bug: 170371191 Test: atest CtsNetTestCasesLatestSdk:CaptivePortalTest Change-Id: I0f47c455f2c1596a887abab7d35146d8557d736a --- .../android/net/cts/util/CtsNetUtils.java | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) 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 f1bc130f2c..be0daae8dc 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 @@ -23,10 +23,11 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.wifi.WifiManager.SCAN_RESULTS_AVAILABLE_ACTION; -import static com.android.compatibility.common.util.ShellIdentityUtils.invokeWithShellPermissions; +import static com.android.testutils.TestPermissionUtil.runAsShell; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -71,7 +72,6 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -219,13 +219,18 @@ public final class CtsNetUtils { if (config == null) { // TODO: this may not clear the BSSID blacklist, as opposed to // mWifiManager.connect(config) - SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(), - NETWORK_SETTINGS); + assertTrue("Error reconnecting wifi", runAsShell(NETWORK_SETTINGS, + mWifiManager::reconnect)); } else { // When running CTS, devices are expected to have wifi networks pre-configured. // This condition is only hit on virtual devices. - SystemUtil.runWithShellPermissionIdentity( - () -> mWifiManager.connect(config, null /* listener */), NETWORK_SETTINGS); + final Integer error = runAsShell(NETWORK_SETTINGS, () -> { + final ConnectWifiListener listener = new ConnectWifiListener(); + mWifiManager.connect(config, listener); + return listener.connectFuture.get( + CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS); + }); + assertNull("Error connecting to wifi: " + error, error); } // Ensure we get an onAvailable callback and possibly a CONNECTIVITY_ACTION. wifiNetwork = callback.waitForAvailable(); @@ -242,8 +247,24 @@ public final class CtsNetUtils { return wifiNetwork; } + private static class ConnectWifiListener implements WifiManager.ActionListener { + /** + * Future completed when the connect process ends. Provides the error code or null if none. + */ + final CompletableFuture connectFuture = new CompletableFuture<>(); + @Override + public void onSuccess() { + connectFuture.complete(null); + } + + @Override + public void onFailure(int reason) { + connectFuture.complete(reason); + } + } + private WifiConfiguration maybeAddVirtualWifiConfiguration() { - final List configs = invokeWithShellPermissions( + final List configs = runAsShell(NETWORK_SETTINGS, mWifiManager::getConfiguredNetworks); // If no network is configured, add a config for virtual access points if applicable if (configs.size() == 0) { @@ -259,7 +280,7 @@ public final class CtsNetUtils { private List getWifiScanResults() { final CompletableFuture> scanResultsFuture = new CompletableFuture<>(); - SystemUtil.runWithShellPermissionIdentity(() -> { + runAsShell(NETWORK_SETTINGS, () -> { final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -296,7 +317,7 @@ public final class CtsNetUtils { virtualConfig.SSID = "\"" + virtualScanResult.SSID + "\""; virtualConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - SystemUtil.runWithShellPermissionIdentity(() -> { + runAsShell(NETWORK_SETTINGS, () -> { final int networkId = mWifiManager.addNetwork(virtualConfig); assertTrue(networkId >= 0); assertTrue(mWifiManager.enableNetwork(networkId, false /* attemptConnect */)); @@ -310,7 +331,7 @@ public final class CtsNetUtils { * to them. */ private void clearWifiBlacklist() { - SystemUtil.runWithShellPermissionIdentity(() -> { + runAsShell(NETWORK_SETTINGS, () -> { for (WifiConfiguration cfg : mWifiManager.getConfiguredNetworks()) { assertTrue(mWifiManager.enableNetwork(cfg.networkId, false /* attemptConnect */)); } From 0582605da71cfffa76f102712db596379482ea04 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 22 Oct 2020 10:50:48 +0800 Subject: [PATCH 1346/1415] Bump Tethering apex version code The version code in the manifest is only used for development builds, as release builds dynamically replace it. Bug: 170183552 Test: m Change-Id: I51916756f41672d372e3a4adce3a8edf5d472c0d --- Tethering/apex/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tethering/apex/manifest.json b/Tethering/apex/manifest.json index 538ffb3ad6..11e205d1b7 100644 --- a/Tethering/apex/manifest.json +++ b/Tethering/apex/manifest.json @@ -1,4 +1,4 @@ { "name": "com.android.tethering", - "version": 300000000 + "version": 309999900 } From 4728ed460fa068335f092b406281df92cb9de5f8 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 22 Oct 2020 09:52:58 +0000 Subject: [PATCH 1347/1415] Wait for connect before dropping permissions WifiManager#connect is implemented with a oneway binder call, so it may return before the permission check. The previous code could drop shell permissions before the check is performed. Use WifiManager.ActionListener to wait for the operation to end before dropping permissions. Also refactor current usages of various "run as shell" utilities to use TestPermissionUtil.runAsShell, which is the "standard" utility used in connectivity tests (both in CTS and in other tests). Bug: 170371191 Test: atest CtsNetTestCasesLatestSdk:CaptivePortalTest Original-Change: https://android-review.googlesource.com/1470543 Merged-In: I0f47c455f2c1596a887abab7d35146d8557d736a Change-Id: I0f47c455f2c1596a887abab7d35146d8557d736a --- .../android/net/cts/util/CtsNetUtils.java | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) 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 f1bc130f2c..be0daae8dc 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 @@ -23,10 +23,11 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.wifi.WifiManager.SCAN_RESULTS_AVAILABLE_ACTION; -import static com.android.compatibility.common.util.ShellIdentityUtils.invokeWithShellPermissions; +import static com.android.testutils.TestPermissionUtil.runAsShell; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -71,7 +72,6 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -219,13 +219,18 @@ public final class CtsNetUtils { if (config == null) { // TODO: this may not clear the BSSID blacklist, as opposed to // mWifiManager.connect(config) - SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(), - NETWORK_SETTINGS); + assertTrue("Error reconnecting wifi", runAsShell(NETWORK_SETTINGS, + mWifiManager::reconnect)); } else { // When running CTS, devices are expected to have wifi networks pre-configured. // This condition is only hit on virtual devices. - SystemUtil.runWithShellPermissionIdentity( - () -> mWifiManager.connect(config, null /* listener */), NETWORK_SETTINGS); + final Integer error = runAsShell(NETWORK_SETTINGS, () -> { + final ConnectWifiListener listener = new ConnectWifiListener(); + mWifiManager.connect(config, listener); + return listener.connectFuture.get( + CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS); + }); + assertNull("Error connecting to wifi: " + error, error); } // Ensure we get an onAvailable callback and possibly a CONNECTIVITY_ACTION. wifiNetwork = callback.waitForAvailable(); @@ -242,8 +247,24 @@ public final class CtsNetUtils { return wifiNetwork; } + private static class ConnectWifiListener implements WifiManager.ActionListener { + /** + * Future completed when the connect process ends. Provides the error code or null if none. + */ + final CompletableFuture connectFuture = new CompletableFuture<>(); + @Override + public void onSuccess() { + connectFuture.complete(null); + } + + @Override + public void onFailure(int reason) { + connectFuture.complete(reason); + } + } + private WifiConfiguration maybeAddVirtualWifiConfiguration() { - final List configs = invokeWithShellPermissions( + final List configs = runAsShell(NETWORK_SETTINGS, mWifiManager::getConfiguredNetworks); // If no network is configured, add a config for virtual access points if applicable if (configs.size() == 0) { @@ -259,7 +280,7 @@ public final class CtsNetUtils { private List getWifiScanResults() { final CompletableFuture> scanResultsFuture = new CompletableFuture<>(); - SystemUtil.runWithShellPermissionIdentity(() -> { + runAsShell(NETWORK_SETTINGS, () -> { final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -296,7 +317,7 @@ public final class CtsNetUtils { virtualConfig.SSID = "\"" + virtualScanResult.SSID + "\""; virtualConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - SystemUtil.runWithShellPermissionIdentity(() -> { + runAsShell(NETWORK_SETTINGS, () -> { final int networkId = mWifiManager.addNetwork(virtualConfig); assertTrue(networkId >= 0); assertTrue(mWifiManager.enableNetwork(networkId, false /* attemptConnect */)); @@ -310,7 +331,7 @@ public final class CtsNetUtils { * to them. */ private void clearWifiBlacklist() { - SystemUtil.runWithShellPermissionIdentity(() -> { + runAsShell(NETWORK_SETTINGS, () -> { for (WifiConfiguration cfg : mWifiManager.getConfiguredNetworks()) { assertTrue(mWifiManager.enableNetwork(cfg.networkId, false /* attemptConnect */)); } From 48c4cf621dbb6fd2020c69d649f0a7a7be8c6cc1 Mon Sep 17 00:00:00 2001 From: easoncylee Date: Fri, 23 Oct 2020 13:10:01 +0800 Subject: [PATCH 1348/1415] Add com.google.android.resolv.apex and com.google.android.tethering.apex for CtsNetTestCasesLatestSdk. Reference: https://android-review.googlesource.com/c/platform/cts/+/1331100/3/tests/tests/net/AndroidTestTemplate.xml#23 Bug: 160877913 Test: forrest. Change-Id: If39c594a0fdc39a8a7272464fc59e2a1483f6d54 --- tests/cts/net/AndroidTestTemplate.xml | 2 +- tests/cts/net/TEST_MAPPING | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml index 4e937512ad..78a01e29c1 100644 --- a/tests/cts/net/AndroidTestTemplate.xml +++ b/tests/cts/net/AndroidTestTemplate.xml @@ -20,7 +20,7 @@

    Must be called from the Test Thread. + * + * @throws Exception if an Exception occurred during any #onReceive invocation + */ boolean waitForCarrierConfigChanged() throws Exception { - return mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS); + final boolean result = mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, + TimeUnit.MILLISECONDS); + + if (mOnReceiveException != null) { + throw mOnReceiveException; + } + + return result; } } } From 6a41dd4d8e64c605cae7c1f697fffbe363a839b0 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Wed, 4 Nov 2020 04:21:14 +0000 Subject: [PATCH 1377/1415] Merge history of CTS BUG: 167962976 Test: TH Merged-In: I30d52c4df571c894b7797300e8f56ddd4b2cc2dd Change-Id: Id343f5a31604abfe70140343bffab20503cd2705 --- tests/cts/hostside/Android.bp | 29 + tests/cts/hostside/AndroidTest.xml | 41 + tests/cts/hostside/OWNERS | 4 + tests/cts/hostside/aidl/Android.bp | 24 + .../android/cts/net/hostside/IMyService.aidl | 29 + .../cts/net/hostside/INetworkCallback.aidl | 27 + .../net/hostside/INetworkStateObserver.aidl | 22 + .../net/hostside/IRemoteSocketFactory.aidl | 25 + tests/cts/hostside/app/Android.bp | 40 + tests/cts/hostside/app/AndroidManifest.xml | 56 + .../net/hostside/AbstractAppIdleTestCase.java | 201 +++ .../AbstractBatterySaverModeTestCase.java | 111 ++ .../hostside/AbstractDozeModeTestCase.java | 141 ++ ...ractRestrictBackgroundNetworkTestCase.java | 880 ++++++++++ .../cts/net/hostside/AppIdleMeteredTest.java | 23 + .../net/hostside/AppIdleNonMeteredTest.java | 23 + .../hostside/BatterySaverModeMeteredTest.java | 23 + .../BatterySaverModeNonMeteredTest.java | 24 + .../cts/net/hostside/DataSaverModeTest.java | 207 +++ .../cts/net/hostside/DozeModeMeteredTest.java | 23 + .../net/hostside/DozeModeNonMeteredTest.java | 23 + .../cts/net/hostside/DumpOnFailureRule.java | 92 + .../MeterednessConfigurationRule.java | 60 + .../cts/net/hostside/MixedModesTest.java | 370 ++++ .../android/cts/net/hostside/MyActivity.java | 49 + .../MyNotificationListenerService.java | 123 ++ .../cts/net/hostside/MyServiceClient.java | 107 ++ .../cts/net/hostside/MyVpnService.java | 184 ++ .../cts/net/hostside/NetworkCallbackTest.java | 300 ++++ .../net/hostside/NetworkPolicyTestRunner.java | 44 + .../net/hostside/NetworkPolicyTestUtils.java | 284 +++ .../cts/net/hostside/PacketReflector.java | 254 +++ .../android/cts/net/hostside/Property.java | 70 + .../hostside/RemoteSocketFactoryClient.java | 100 ++ .../cts/net/hostside/RequiredProperties.java | 31 + .../net/hostside/RequiredPropertiesRule.java | 94 + .../com/android/cts/net/hostside/VpnTest.java | 1165 +++++++++++++ tests/cts/hostside/app2/Android.bp | 29 + tests/cts/hostside/app2/AndroidManifest.xml | 55 + .../app2/res/drawable/ic_notification.png | Bin 0 -> 3777 bytes .../android/cts/net/hostside/app2/Common.java | 94 + .../cts/net/hostside/app2/MyActivity.java | 75 + .../hostside/app2/MyBroadcastReceiver.java | 267 +++ .../hostside/app2/MyForegroundService.java | 72 + .../cts/net/hostside/app2/MyService.java | 193 +++ .../app2/RemoteSocketFactoryService.java | 63 + tests/cts/hostside/certs/Android.bp | 4 + tests/cts/hostside/certs/README | 2 + tests/cts/hostside/certs/cts-net-app.pk8 | Bin 0 -> 1219 bytes tests/cts/hostside/certs/cts-net-app.x509.pem | 19 + .../cts/net/HostsideNetworkCallbackTests.java | 42 + .../cts/net/HostsideNetworkTestCase.java | 186 ++ ...ostsideRestrictBackgroundNetworkTests.java | 377 ++++ .../com/android/cts/net/HostsideVpnTests.java | 103 ++ .../cts/net/NetworkPolicyTestsPreparer.java | 92 + .../src/com/android/cts/net/ProcNetTest.java | 169 ++ tests/cts/net/Android.bp | 84 + tests/cts/net/AndroidManifest.xml | 57 + tests/cts/net/AndroidTestTemplate.xml | 35 + tests/cts/net/OWNERS | 3 + tests/cts/net/TEST_MAPPING | 23 + tests/cts/net/api23Test/Android.bp | 51 + tests/cts/net/api23Test/AndroidManifest.xml | 45 + tests/cts/net/api23Test/AndroidTest.xml | 31 + .../ConnectivityManagerApi23Test.java | 132 ++ .../cts/api23test/ConnectivityReceiver.java | 69 + tests/cts/net/appForApi23/Android.bp | 32 + tests/cts/net/appForApi23/AndroidManifest.xml | 47 + .../ConnectivityListeningActivity.java | 22 + .../cts/appForApi23/ConnectivityReceiver.java | 41 + ...etwork_watchlist_config_empty_for_test.xml | 29 + .../network_watchlist_config_for_test.xml | 34 + tests/cts/net/jarjar-rules-shared.txt | 2 + tests/cts/net/jni/Android.bp | 51 + tests/cts/net/jni/NativeDnsJni.c | 181 ++ tests/cts/net/jni/NativeMultinetworkJni.cpp | 515 ++++++ tests/cts/net/native/dns/Android.bp | 41 + tests/cts/net/native/dns/AndroidTest.xml | 32 + .../cts/net/native/dns/NativeDnsAsyncTest.cpp | 257 +++ tests/cts/net/native/qtaguid/Android.bp | 53 + tests/cts/net/native/qtaguid/AndroidTest.xml | 32 + .../native/qtaguid/src/NativeQtaguidTest.cpp | 130 ++ .../src/android/net/cts/AirplaneModeTest.java | 86 + .../src/android/net/cts/CaptivePortalTest.kt | 194 +++ .../ConnectivityDiagnosticsManagerTest.java | 576 +++++++ .../net/cts/ConnectivityManagerTest.java | 1530 +++++++++++++++++ .../src/android/net/cts/CredentialsTest.java | 44 + .../src/android/net/cts/DnsResolverTest.java | 756 ++++++++ .../cts/net/src/android/net/cts/DnsTest.java | 309 ++++ .../net/src/android/net/cts/IkeTunUtils.java | 188 ++ .../net/src/android/net/cts/Ikev2VpnTest.java | 535 ++++++ .../android/net/cts/InetAddressesTest.java | 134 ++ .../android/net/cts/IpConfigurationTest.java | 123 ++ .../src/android/net/cts/IpSecBaseTest.java | 556 ++++++ .../src/android/net/cts/IpSecManagerTest.java | 1189 +++++++++++++ .../net/cts/IpSecManagerTunnelTest.java | 899 ++++++++++ .../net/cts/LocalServerSocketTest.java | 61 + .../net/cts/LocalSocketAddressTest.java | 47 + .../cts/LocalSocketAddress_NamespaceTest.java | 36 + .../src/android/net/cts/LocalSocketTest.java | 470 +++++ .../src/android/net/cts/MacAddressTest.java | 223 +++ .../net/src/android/net/cts/MailToTest.java | 125 ++ .../android/net/cts/MultinetworkApiTest.java | 242 +++ .../src/android/net/cts/NetworkAgentTest.kt | 668 +++++++ .../src/android/net/cts/NetworkInfoTest.kt | 122 ++ .../cts/NetworkInfo_DetailedStateTest.java | 56 + .../net/cts/NetworkInfo_StateTest.java | 43 + .../android/net/cts/NetworkRequestTest.java | 276 +++ .../net/cts/NetworkStackDependenciesTest.kt | 53 + .../net/cts/NetworkStatsBinderTest.java | 146 ++ .../android/net/cts/NetworkValidationTest.kt | 245 +++ .../net/cts/NetworkValidationTestUtil.kt | 68 + .../android/net/cts/NetworkWatchlistTest.java | 163 ++ .../net/src/android/net/cts/PacketUtils.java | 474 +++++ .../src/android/net/cts/ProxyInfoTest.java | 135 ++ .../net/src/android/net/cts/ProxyTest.java | 39 + .../src/android/net/cts/RssiCurveTest.java | 102 ++ .../cts/SSLCertificateSocketFactoryTest.java | 348 ++++ .../src/android/net/cts/TheaterModeTest.java | 84 + .../src/android/net/cts/TrafficStatsTest.java | 279 +++ .../cts/net/src/android/net/cts/TunUtils.java | 254 +++ .../cts/net/src/android/net/cts/UriTest.java | 590 +++++++ .../src/android/net/cts/Uri_BuilderTest.java | 64 + .../net/cts/UrlQuerySanitizerTest.java | 290 ++++ ...er_IllegalCharacterValueSanitizerTest.java | 29 + ...QuerySanitizer_ParameterValuePairTest.java | 33 + .../src/android/net/cts/VpnServiceTest.java | 124 ++ .../src/android/net/ipv6/cts/PingTest.java | 172 ++ .../android/net/rtp/cts/AudioCodecTest.java | 73 + .../android/net/rtp/cts/AudioGroupTest.java | 177 ++ .../android/net/rtp/cts/AudioStreamTest.java | 96 ++ tests/cts/net/util/Android.bp | 26 + .../android/net/cts/util/CtsNetUtils.java | 693 ++++++++ .../net/cts/util/CtsTetheringUtils.java | 447 +++++ tests/cts/tethering/Android.bp | 56 + tests/cts/tethering/AndroidManifest.xml | 34 + tests/cts/tethering/AndroidTest.xml | 35 + tests/cts/tethering/OWNERS | 4 + .../tethering/cts/TetheringManagerTest.java | 463 +++++ 139 files changed, 24458 insertions(+) create mode 100644 tests/cts/hostside/Android.bp create mode 100644 tests/cts/hostside/AndroidTest.xml create mode 100644 tests/cts/hostside/OWNERS create mode 100644 tests/cts/hostside/aidl/Android.bp create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl create mode 100644 tests/cts/hostside/app/Android.bp create mode 100644 tests/cts/hostside/app/AndroidManifest.xml create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java create mode 100755 tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java create mode 100644 tests/cts/hostside/app2/Android.bp create mode 100644 tests/cts/hostside/app2/AndroidManifest.xml create mode 100644 tests/cts/hostside/app2/res/drawable/ic_notification.png create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java create mode 100644 tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java create mode 100644 tests/cts/hostside/certs/Android.bp create mode 100644 tests/cts/hostside/certs/README create mode 100644 tests/cts/hostside/certs/cts-net-app.pk8 create mode 100644 tests/cts/hostside/certs/cts-net-app.x509.pem create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java create mode 100644 tests/cts/net/Android.bp create mode 100644 tests/cts/net/AndroidManifest.xml create mode 100644 tests/cts/net/AndroidTestTemplate.xml create mode 100644 tests/cts/net/OWNERS create mode 100644 tests/cts/net/TEST_MAPPING create mode 100644 tests/cts/net/api23Test/Android.bp create mode 100644 tests/cts/net/api23Test/AndroidManifest.xml create mode 100644 tests/cts/net/api23Test/AndroidTest.xml create mode 100644 tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java create mode 100644 tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java create mode 100644 tests/cts/net/appForApi23/Android.bp create mode 100644 tests/cts/net/appForApi23/AndroidManifest.xml create mode 100644 tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityListeningActivity.java create mode 100644 tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java create mode 100644 tests/cts/net/assets/network_watchlist_config_empty_for_test.xml create mode 100644 tests/cts/net/assets/network_watchlist_config_for_test.xml create mode 100644 tests/cts/net/jarjar-rules-shared.txt create mode 100644 tests/cts/net/jni/Android.bp create mode 100644 tests/cts/net/jni/NativeDnsJni.c create mode 100644 tests/cts/net/jni/NativeMultinetworkJni.cpp create mode 100644 tests/cts/net/native/dns/Android.bp create mode 100644 tests/cts/net/native/dns/AndroidTest.xml create mode 100644 tests/cts/net/native/dns/NativeDnsAsyncTest.cpp create mode 100644 tests/cts/net/native/qtaguid/Android.bp create mode 100644 tests/cts/net/native/qtaguid/AndroidTest.xml create mode 100644 tests/cts/net/native/qtaguid/src/NativeQtaguidTest.cpp create mode 100644 tests/cts/net/src/android/net/cts/AirplaneModeTest.java create mode 100644 tests/cts/net/src/android/net/cts/CaptivePortalTest.kt create mode 100644 tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java create mode 100644 tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java create mode 100644 tests/cts/net/src/android/net/cts/CredentialsTest.java create mode 100644 tests/cts/net/src/android/net/cts/DnsResolverTest.java create mode 100644 tests/cts/net/src/android/net/cts/DnsTest.java create mode 100644 tests/cts/net/src/android/net/cts/IkeTunUtils.java create mode 100644 tests/cts/net/src/android/net/cts/Ikev2VpnTest.java create mode 100644 tests/cts/net/src/android/net/cts/InetAddressesTest.java create mode 100644 tests/cts/net/src/android/net/cts/IpConfigurationTest.java create mode 100644 tests/cts/net/src/android/net/cts/IpSecBaseTest.java create mode 100644 tests/cts/net/src/android/net/cts/IpSecManagerTest.java create mode 100644 tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalServerSocketTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java create mode 100644 tests/cts/net/src/android/net/cts/LocalSocketTest.java create mode 100644 tests/cts/net/src/android/net/cts/MacAddressTest.java create mode 100644 tests/cts/net/src/android/net/cts/MailToTest.java create mode 100644 tests/cts/net/src/android/net/cts/MultinetworkApiTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkAgentTest.kt create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfoTest.kt create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkRequestTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkStackDependenciesTest.kt create mode 100644 tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java create mode 100644 tests/cts/net/src/android/net/cts/NetworkValidationTest.kt create mode 100644 tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt create mode 100644 tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java create mode 100644 tests/cts/net/src/android/net/cts/PacketUtils.java create mode 100644 tests/cts/net/src/android/net/cts/ProxyInfoTest.java create mode 100644 tests/cts/net/src/android/net/cts/ProxyTest.java create mode 100644 tests/cts/net/src/android/net/cts/RssiCurveTest.java create mode 100644 tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java create mode 100644 tests/cts/net/src/android/net/cts/TheaterModeTest.java create mode 100755 tests/cts/net/src/android/net/cts/TrafficStatsTest.java create mode 100644 tests/cts/net/src/android/net/cts/TunUtils.java create mode 100644 tests/cts/net/src/android/net/cts/UriTest.java create mode 100644 tests/cts/net/src/android/net/cts/Uri_BuilderTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java create mode 100644 tests/cts/net/src/android/net/cts/UrlQuerySanitizer_ParameterValuePairTest.java create mode 100644 tests/cts/net/src/android/net/cts/VpnServiceTest.java create mode 100644 tests/cts/net/src/android/net/ipv6/cts/PingTest.java create mode 100644 tests/cts/net/src/android/net/rtp/cts/AudioCodecTest.java create mode 100644 tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java create mode 100644 tests/cts/net/src/android/net/rtp/cts/AudioStreamTest.java create mode 100644 tests/cts/net/util/Android.bp create mode 100644 tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java create mode 100644 tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java create mode 100644 tests/cts/tethering/Android.bp create mode 100644 tests/cts/tethering/AndroidManifest.xml create mode 100644 tests/cts/tethering/AndroidTest.xml create mode 100644 tests/cts/tethering/OWNERS create mode 100644 tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp new file mode 100644 index 0000000000..47b114b64d --- /dev/null +++ b/tests/cts/hostside/Android.bp @@ -0,0 +1,29 @@ +// Copyright (C) 2014 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. + +java_test_host { + name: "CtsHostsideNetworkTests", + defaults: ["cts_defaults"], + // Only compile source java files in this apk. + srcs: ["src/**/*.java"], + libs: [ + "cts-tradefed", + "tradefed", + ], + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "general-tests", + ], +} diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml new file mode 100644 index 0000000000..b7fefaf3b5 --- /dev/null +++ b/tests/cts/hostside/AndroidTest.xml @@ -0,0 +1,41 @@ + + + + diff --git a/tests/cts/hostside/OWNERS b/tests/cts/hostside/OWNERS new file mode 100644 index 0000000000..52c8053323 --- /dev/null +++ b/tests/cts/hostside/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 61373 +sudheersai@google.com +lorenzo@google.com +jchalard@google.com diff --git a/tests/cts/hostside/aidl/Android.bp b/tests/cts/hostside/aidl/Android.bp new file mode 100644 index 0000000000..320a1fa443 --- /dev/null +++ b/tests/cts/hostside/aidl/Android.bp @@ -0,0 +1,24 @@ +// Copyright (C) 2016 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. + +java_test_helper_library { + name: "CtsHostsideNetworkTestsAidl", + sdk_version: "current", + srcs: [ + "com/android/cts/net/hostside/IMyService.aidl", + "com/android/cts/net/hostside/INetworkCallback.aidl", + "com/android/cts/net/hostside/INetworkStateObserver.aidl", + "com/android/cts/net/hostside/IRemoteSocketFactory.aidl", + ], +} diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl new file mode 100644 index 0000000000..5aafdf06cb --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import com.android.cts.net.hostside.INetworkCallback; + +interface IMyService { + void registerBroadcastReceiver(); + int getCounters(String receiverName, String action); + String checkNetworkStatus(); + String getRestrictBackgroundStatus(); + void sendNotification(int notificationId, String notificationType); + void registerNetworkCallback(in INetworkCallback cb); + void unregisterNetworkCallback(); +} diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl new file mode 100644 index 0000000000..2048bab498 --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import android.net.Network; +import android.net.NetworkCapabilities; + +interface INetworkCallback { + void onBlockedStatusChanged(in Network network, boolean blocked); + void onAvailable(in Network network); + void onLost(in Network network); + void onCapabilitiesChanged(in Network network, in NetworkCapabilities cap); +} diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl new file mode 100644 index 0000000000..165f5306c3 --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +interface INetworkStateObserver { + boolean isForeground(); + void onNetworkStateChecked(String resultData); +} \ No newline at end of file diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl new file mode 100644 index 0000000000..68176ad80d --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import android.os.ParcelFileDescriptor; + +interface IRemoteSocketFactory { + ParcelFileDescriptor openSocketFd(String host, int port, int timeoutMs); + String getPackageName(); + int getUid(); +} diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp new file mode 100644 index 0000000000..99037567b5 --- /dev/null +++ b/tests/cts/hostside/app/Android.bp @@ -0,0 +1,40 @@ +// +// Copyright (C) 2014 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. +// + +android_test_helper_app { + name: "CtsHostsideNetworkTestsApp", + defaults: ["cts_support_defaults"], + //sdk_version: "current", + platform_apis: true, + static_libs: [ + "androidx.test.rules", + "androidx.test.ext.junit", + "compatibility-device-util-axt", + "ctstestrunner-axt", + "ub-uiautomator", + "CtsHostsideNetworkTestsAidl", + ], + libs: [ + "android.test.runner", + "android.test.base", + ], + srcs: ["src/**/*.java"], + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "general-tests", + ], +} diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml new file mode 100644 index 0000000000..3940de4240 --- /dev/null +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java new file mode 100644 index 0000000000..f9e30b6b20 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; + +import static org.junit.Assert.assertEquals; + +import android.os.SystemClock; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Base class for metered and non-metered tests on idle apps. + */ +@RequiredProperties({APP_STANDBY_MODE}) +abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetworkTestCase { + + @Before + public final void setUp() throws Exception { + super.setUp(); + + // Set initial state. + removePowerSaveModeWhitelist(TEST_APP2_PKG); + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + setAppIdle(false); + turnBatteryOn(); + + registerBroadcastReceiver(); + } + + @After + public final void tearDown() throws Exception { + super.tearDown(); + + executeSilentShellCommand("cmd battery reset"); + setAppIdle(false); + } + + @Test + public void testBackgroundNetworkAccess_enabled() throws Exception { + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + // Make sure foreground app doesn't lose access upon enabling it. + setAppIdle(true); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); + finishActivity(); + assertAppIdle(false); // verify - not idle anymore, since activity was launched... + assertBackgroundNetworkAccess(true); + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + // Same for foreground service. + setAppIdle(true); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); + stopForegroundService(); + assertAppIdle(true); + assertBackgroundNetworkAccess(false); + + // Set Idle after foreground service start. + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); + setAppIdle(true); + addPowerSaveModeWhitelist(TEST_PKG); + removePowerSaveModeWhitelist(TEST_PKG); + assertForegroundServiceNetworkAccess(); + stopForegroundService(); + assertAppIdle(true); + assertBackgroundNetworkAccess(false); + + } + + @Test + public void testBackgroundNetworkAccess_whitelisted() throws Exception { + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertAppIdle(false); // verify - not idle anymore, since whitelisted + assertBackgroundNetworkAccess(true); + + setAppIdleNoAssert(true); + assertAppIdle(false); // app is still whitelisted + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertAppIdle(true); // verify - idle again, once whitelisted was removed + assertBackgroundNetworkAccess(false); + + setAppIdle(true); + addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertAppIdle(false); // verify - not idle anymore, since whitelisted + assertBackgroundNetworkAccess(true); + + setAppIdleNoAssert(true); + assertAppIdle(false); // app is still whitelisted + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertAppIdle(true); // verify - idle again, once whitelisted was removed + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + + // verify - no whitelist, no access! + setAppIdle(true); + assertBackgroundNetworkAccess(false); + } + + @Test + public void testBackgroundNetworkAccess_tempWhitelisted() throws Exception { + setAppIdle(true); + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } + + @Test + public void testBackgroundNetworkAccess_disabled() throws Exception { + assertBackgroundNetworkAccess(true); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + } + + @RequiredProperties({BATTERY_SAVER_MODE}) + @Test + public void testAppIdleNetworkAccess_whenCharging() throws Exception { + // Check that app is paroled when charging + setAppIdle(true); + assertBackgroundNetworkAccess(false); + turnBatteryOff(); + assertBackgroundNetworkAccess(true); + turnBatteryOn(); + assertBackgroundNetworkAccess(false); + + // Check that app is restricted when not idle but power-save is on + setAppIdle(false); + assertBackgroundNetworkAccess(true); + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + // Use setBatterySaverMode API to leave power-save mode instead of plugging in charger + setBatterySaverMode(false); + turnBatteryOff(); + assertBackgroundNetworkAccess(true); + + // And when no longer charging, it still has network access, since it's not idle + turnBatteryOn(); + assertBackgroundNetworkAccess(true); + } + + @Test + public void testAppIdleNetworkAccess_idleWhitelisted() throws Exception { + setAppIdle(true); + assertAppIdle(true); + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(true); + + removeAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + // Make sure whitelisting a random app doesn't affect the tested app. + addAppIdleWhitelist(mUid + 1); + assertBackgroundNetworkAccess(false); + removeAppIdleWhitelist(mUid + 1); + } + + @Test + public void testAppIdle_toast() throws Exception { + setAppIdle(true); + assertAppIdle(true); + assertEquals("Shown", showToast()); + assertAppIdle(true); + // Wait for a couple of seconds for the toast to actually be shown + SystemClock.sleep(2000); + assertAppIdle(true); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java new file mode 100644 index 0000000000..04d054d54a --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Base class for metered and non-metered Battery Saver Mode tests. + */ +@RequiredProperties({BATTERY_SAVER_MODE}) +abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { + + @Before + public final void setUp() throws Exception { + super.setUp(); + + // Set initial state. + removePowerSaveModeWhitelist(TEST_APP2_PKG); + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + setBatterySaverMode(false); + + registerBroadcastReceiver(); + } + + @After + public final void tearDown() throws Exception { + super.tearDown(); + + setBatterySaverMode(false); + } + + @Test + public void testBackgroundNetworkAccess_enabled() throws Exception { + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + // Make sure foreground app doesn't lose access upon Battery Saver. + setBatterySaverMode(false); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); + setBatterySaverMode(true); + assertForegroundNetworkAccess(); + + // Although it should not have access while the screen is off. + turnScreenOff(); + assertBackgroundNetworkAccess(false); + turnScreenOn(); + assertForegroundNetworkAccess(); + + // Goes back to background state. + finishActivity(); + assertBackgroundNetworkAccess(false); + + // Make sure foreground service doesn't lose access upon enabling Battery Saver. + setBatterySaverMode(false); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); + setBatterySaverMode(true); + assertForegroundNetworkAccess(); + stopForegroundService(); + assertBackgroundNetworkAccess(false); + } + + @Test + public void testBackgroundNetworkAccess_whitelisted() throws Exception { + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + } + + @Test + public void testBackgroundNetworkAccess_disabled() throws Exception { + assertBackgroundNetworkAccess(true); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java new file mode 100644 index 0000000000..6f32c563c1 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE; + +import android.os.SystemClock; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Base class for metered and non-metered Doze Mode tests. + */ +@RequiredProperties({DOZE_MODE}) +abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { + + @Before + public final void setUp() throws Exception { + super.setUp(); + + // Set initial state. + removePowerSaveModeWhitelist(TEST_APP2_PKG); + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + setDozeMode(false); + + registerBroadcastReceiver(); + } + + @After + public final void tearDown() throws Exception { + super.tearDown(); + + setDozeMode(false); + } + + @Test + public void testBackgroundNetworkAccess_enabled() throws Exception { + setDozeMode(true); + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + // Make sure foreground service doesn't lose network access upon enabling doze. + setDozeMode(false); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); + setDozeMode(true); + assertForegroundNetworkAccess(); + stopForegroundService(); + assertBackgroundState(); + assertBackgroundNetworkAccess(false); + } + + @Test + public void testBackgroundNetworkAccess_whitelisted() throws Exception { + setDozeMode(true); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + } + + @Test + public void testBackgroundNetworkAccess_disabled() throws Exception { + assertBackgroundNetworkAccess(true); + + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + } + + @RequiredProperties({NOT_LOW_RAM_DEVICE}) + @Test + public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() + throws Exception { + setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); + try { + registerNotificationListenerService(); + setDozeMode(true); + assertBackgroundNetworkAccess(false); + + testNotification(4, NOTIFICATION_TYPE_CONTENT); + testNotification(8, NOTIFICATION_TYPE_DELETE); + testNotification(15, NOTIFICATION_TYPE_FULL_SCREEN); + testNotification(16, NOTIFICATION_TYPE_BUNDLE); + testNotification(23, NOTIFICATION_TYPE_ACTION); + testNotification(42, NOTIFICATION_TYPE_ACTION_BUNDLE); + testNotification(108, NOTIFICATION_TYPE_ACTION_REMOTE_INPUT); + } finally { + resetDeviceIdleSettings(); + } + } + + private void testNotification(int id, String type) throws Exception { + sendNotification(id, type); + assertBackgroundNetworkAccess(true); + if (type.equals(NOTIFICATION_TYPE_ACTION)) { + // Make sure access is disabled after it expires. Since this check considerably slows + // downs the CTS tests, do it just once. + SystemClock.sleep(NETWORK_TIMEOUT_MS); + assertBackgroundNetworkAccess(false); + } + } + + // Must override so it only tests foreground service - once an app goes to foreground, device + // leaves Doze Mode. + @Override + protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception { + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); + stopForegroundService(); + assertBackgroundState(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java new file mode 100644 index 0000000000..71f6f2f5f0 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -0,0 +1,880 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; +import static android.os.BatteryManager.BATTERY_PLUGGED_AC; +import static android.os.BatteryManager.BATTERY_PLUGGED_USB; +import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.ActivityManager; +import android.app.Instrumentation; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; +import android.net.wifi.WifiManager; +import android.os.BatteryManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.SystemClock; +import android.provider.Settings; +import android.service.notification.NotificationListenerService; +import android.util.Log; + +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * Superclass for tests related to background network restrictions. + */ +@RunWith(NetworkPolicyTestRunner.class) +public abstract class AbstractRestrictBackgroundNetworkTestCase { + public static final String TAG = "RestrictBackgroundNetworkTests"; + + protected static final String TEST_PKG = "com.android.cts.net.hostside"; + protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; + + private static final String TEST_APP2_ACTIVITY_CLASS = TEST_APP2_PKG + ".MyActivity"; + private static final String TEST_APP2_SERVICE_CLASS = TEST_APP2_PKG + ".MyForegroundService"; + + private static final int SLEEP_TIME_SEC = 1; + + // Constants below must match values defined on app2's Common.java + private static final String MANIFEST_RECEIVER = "ManifestReceiver"; + private static final String DYNAMIC_RECEIVER = "DynamicReceiver"; + + private static final String ACTION_RECEIVER_READY = + "com.android.cts.net.hostside.app2.action.RECEIVER_READY"; + static final String ACTION_SHOW_TOAST = + "com.android.cts.net.hostside.app2.action.SHOW_TOAST"; + + protected static final String NOTIFICATION_TYPE_CONTENT = "CONTENT"; + protected static final String NOTIFICATION_TYPE_DELETE = "DELETE"; + protected static final String NOTIFICATION_TYPE_FULL_SCREEN = "FULL_SCREEN"; + protected static final String NOTIFICATION_TYPE_BUNDLE = "BUNDLE"; + protected static final String NOTIFICATION_TYPE_ACTION = "ACTION"; + protected static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE"; + protected static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT"; + + // TODO: Update BatteryManager.BATTERY_PLUGGED_ANY as @TestApi + public static final int BATTERY_PLUGGED_ANY = + BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS; + + private static final String NETWORK_STATUS_SEPARATOR = "\\|"; + private static final int SECOND_IN_MS = 1000; + static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; + private static int PROCESS_STATE_FOREGROUND_SERVICE; + + private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; + + protected static final int TYPE_COMPONENT_ACTIVTIY = 0; + protected static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1; + + private static final int BATTERY_STATE_TIMEOUT_MS = 5000; + private static final int BATTERY_STATE_CHECK_INTERVAL_MS = 500; + + private static final int FOREGROUND_PROC_NETWORK_TIMEOUT_MS = 6000; + + // Must be higher than NETWORK_TIMEOUT_MS + private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4; + + private static final IntentFilter BATTERY_CHANGED_FILTER = + new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + + private static final String APP_NOT_FOREGROUND_ERROR = "app_not_fg"; + + protected static final long TEMP_POWERSAVE_WHITELIST_DURATION_MS = 5_000; // 5 sec + + protected Context mContext; + protected Instrumentation mInstrumentation; + protected ConnectivityManager mCm; + protected int mUid; + private int mMyUid; + private MyServiceClient mServiceClient; + private String mDeviceIdleConstantsSetting; + + @Rule + public final RuleChain mRuleChain = RuleChain.outerRule(new RequiredPropertiesRule()) + .around(new MeterednessConfigurationRule()); + + protected void setUp() throws Exception { + + PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class + .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null); + mInstrumentation = getInstrumentation(); + mContext = getContext(); + mCm = getConnectivityManager(); + mUid = getUid(TEST_APP2_PKG); + mMyUid = getUid(mContext.getPackageName()); + mServiceClient = new MyServiceClient(mContext); + mServiceClient.bind(); + mDeviceIdleConstantsSetting = "device_idle_constants"; + executeShellCommand("cmd netpolicy start-watching " + mUid); + setAppIdle(false); + + Log.i(TAG, "Apps status:\n" + + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); + } + + protected void tearDown() throws Exception { + executeShellCommand("cmd netpolicy stop-watching"); + mServiceClient.unbind(); + } + + protected int getUid(String packageName) throws Exception { + return mContext.getPackageManager().getPackageUid(packageName, 0); + } + + protected void assertRestrictBackgroundChangedReceived(int expectedCount) throws Exception { + assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, expectedCount); + assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0); + } + + protected void assertRestrictBackgroundChangedReceived(String receiverName, int expectedCount) + throws Exception { + int attempts = 0; + int count = 0; + final int maxAttempts = 5; + do { + attempts++; + count = getNumberBroadcastsReceived(receiverName, ACTION_RESTRICT_BACKGROUND_CHANGED); + assertFalse("Expected count " + expectedCount + " but actual is " + count, + count > expectedCount); + if (count == expectedCount) { + break; + } + Log.d(TAG, "Expecting count " + expectedCount + " but actual is " + count + " after " + + attempts + " attempts; sleeping " + + SLEEP_TIME_SEC + " seconds before trying again"); + SystemClock.sleep(SLEEP_TIME_SEC * SECOND_IN_MS); + } while (attempts <= maxAttempts); + assertEquals("Number of expected broadcasts for " + receiverName + " not reached after " + + maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count); + } + + protected String sendOrderedBroadcast(Intent intent) throws Exception { + return sendOrderedBroadcast(intent, ORDERED_BROADCAST_TIMEOUT_MS); + } + + protected String sendOrderedBroadcast(Intent intent, int timeoutMs) throws Exception { + final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); + Log.d(TAG, "Sending ordered broadcast: " + intent); + mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + final String resultData = getResultData(); + if (resultData == null) { + Log.e(TAG, "Received null data from ordered intent"); + return; + } + result.offer(resultData); + } + }, null, 0, null, null); + + final String resultData = result.poll(timeoutMs, TimeUnit.MILLISECONDS); + Log.d(TAG, "Ordered broadcast response after " + timeoutMs + "ms: " + resultData ); + return resultData; + } + + protected int getNumberBroadcastsReceived(String receiverName, String action) throws Exception { + return mServiceClient.getCounters(receiverName, action); + } + + protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { + final String status = mServiceClient.getRestrictBackgroundStatus(); + assertNotNull("didn't get API status from app2", status); + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(Integer.parseInt(status))); + } + + protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { + assertBackgroundState(); + assertNetworkAccess(expectAllowed /* expectAvailable */, false /* needScreenOn */); + } + + protected void assertForegroundNetworkAccess() throws Exception { + assertForegroundState(); + // We verified that app is in foreground state but if the screen turns-off while + // verifying for network access, the app will go into background state (in case app's + // foreground status was due to top activity). So, turn the screen on when verifying + // network connectivity. + assertNetworkAccess(true /* expectAvailable */, true /* needScreenOn */); + } + + protected void assertForegroundServiceNetworkAccess() throws Exception { + assertForegroundServiceState(); + assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */); + } + + /** + * Asserts that an app always have access while on foreground or running a foreground service. + * + *

    This method will launch an activity and a foreground service to make the assertion, but + * will finish the activity / stop the service afterwards. + */ + protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception{ + // Checks foreground first. + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); + finishActivity(); + + // Then foreground service + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); + stopForegroundService(); + } + + protected final void assertBackgroundState() throws Exception { + final int maxTries = 30; + ProcessState state = null; + for (int i = 1; i <= maxTries; i++) { + state = getProcessStateByUid(mUid); + Log.v(TAG, "assertBackgroundState(): status for app2 (" + mUid + ") on attempt #" + i + + ": " + state); + if (isBackground(state.state)) { + return; + } + Log.d(TAG, "App not on background state (" + state + ") on attempt #" + i + + "; sleeping 1s before trying again"); + SystemClock.sleep(SECOND_IN_MS); + } + fail("App2 is not on background state after " + maxTries + " attempts: " + state ); + } + + protected final void assertForegroundState() throws Exception { + final int maxTries = 30; + ProcessState state = null; + for (int i = 1; i <= maxTries; i++) { + state = getProcessStateByUid(mUid); + Log.v(TAG, "assertForegroundState(): status for app2 (" + mUid + ") on attempt #" + i + + ": " + state); + if (!isBackground(state.state)) { + return; + } + Log.d(TAG, "App not on foreground state on attempt #" + i + + "; sleeping 1s before trying again"); + turnScreenOn(); + SystemClock.sleep(SECOND_IN_MS); + } + fail("App2 is not on foreground state after " + maxTries + " attempts: " + state ); + } + + protected final void assertForegroundServiceState() throws Exception { + final int maxTries = 30; + ProcessState state = null; + for (int i = 1; i <= maxTries; i++) { + state = getProcessStateByUid(mUid); + Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + ") on attempt #" + + i + ": " + state); + if (state.state == PROCESS_STATE_FOREGROUND_SERVICE) { + return; + } + Log.d(TAG, "App not on foreground service state on attempt #" + i + + "; sleeping 1s before trying again"); + SystemClock.sleep(SECOND_IN_MS); + } + fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state ); + } + + /** + * Returns whether an app state should be considered "background" for restriction purposes. + */ + protected boolean isBackground(int state) { + return state > PROCESS_STATE_FOREGROUND_SERVICE; + } + + /** + * Asserts whether the active network is available or not. + */ + private void assertNetworkAccess(boolean expectAvailable, boolean needScreenOn) + throws Exception { + final int maxTries = 5; + String error = null; + int timeoutMs = 500; + + for (int i = 1; i <= maxTries; i++) { + error = checkNetworkAccess(expectAvailable); + + if (error.isEmpty()) return; + + // TODO: ideally, it should retry only when it cannot connect to an external site, + // or no retry at all! But, currently, the initial change fails almost always on + // battery saver tests because the netd changes are made asynchronously. + // Once b/27803922 is fixed, this retry mechanism should be revisited. + + Log.w(TAG, "Network status didn't match for expectAvailable=" + expectAvailable + + " on attempt #" + i + ": " + error + "\n" + + "Sleeping " + timeoutMs + "ms before trying again"); + if (needScreenOn) { + turnScreenOn(); + } + // No sleep after the last turn + if (i < maxTries) { + SystemClock.sleep(timeoutMs); + } + // Exponential back-off. + timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS); + } + fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries + + " attempts.\nLast error: " + error); + } + + /** + * Checks whether the network is available as expected. + * + * @return error message with the mismatch (or empty if assertion passed). + */ + private String checkNetworkAccess(boolean expectAvailable) throws Exception { + final String resultData = mServiceClient.checkNetworkStatus(); + return checkForAvailabilityInResultData(resultData, expectAvailable); + } + + private String checkForAvailabilityInResultData(String resultData, boolean expectAvailable) { + if (resultData == null) { + assertNotNull("Network status from app2 is null", resultData); + } + // Network status format is described on MyBroadcastReceiver.checkNetworkStatus() + final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR); + assertEquals("Wrong network status: " + resultData, 5, parts.length); + final State state = parts[0].equals("null") ? null : State.valueOf(parts[0]); + final DetailedState detailedState = parts[1].equals("null") + ? null : DetailedState.valueOf(parts[1]); + final boolean connected = Boolean.valueOf(parts[2]); + final String connectionCheckDetails = parts[3]; + final String networkInfo = parts[4]; + + final StringBuilder errors = new StringBuilder(); + final State expectedState; + final DetailedState expectedDetailedState; + if (expectAvailable) { + expectedState = State.CONNECTED; + expectedDetailedState = DetailedState.CONNECTED; + } else { + expectedState = State.DISCONNECTED; + expectedDetailedState = DetailedState.BLOCKED; + } + + if (expectAvailable != connected) { + errors.append(String.format("External site connection failed: expected %s, got %s\n", + expectAvailable, connected)); + } + if (expectedState != state || expectedDetailedState != detailedState) { + errors.append(String.format("Connection state mismatch: expected %s/%s, got %s/%s\n", + expectedState, expectedDetailedState, state, detailedState)); + } + + if (errors.length() > 0) { + errors.append("\tnetworkInfo: " + networkInfo + "\n"); + errors.append("\tconnectionCheckDetails: " + connectionCheckDetails + "\n"); + } + return errors.toString(); + } + + /** + * Runs a Shell command which is not expected to generate output. + */ + protected void executeSilentShellCommand(String command) { + final String result = executeShellCommand(command); + assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty()); + } + + /** + * Asserts the result of a command, wait and re-running it a couple times if necessary. + */ + protected void assertDelayedShellCommand(String command, final String expectedResult) + throws Exception { + assertDelayedShellCommand(command, 5, 1, expectedResult); + } + + protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, + final String expectedResult) throws Exception { + assertDelayedShellCommand(command, maxTries, napTimeSeconds, new ExpectResultChecker() { + + @Override + public boolean isExpected(String result) { + return expectedResult.equals(result); + } + + @Override + public String getExpected() { + return expectedResult; + } + }); + } + + protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds, + ExpectResultChecker checker) throws Exception { + String result = ""; + for (int i = 1; i <= maxTries; i++) { + result = executeShellCommand(command).trim(); + if (checker.isExpected(result)) return; + Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" + + checker.getExpected() + "' on attempt #" + i + + "; sleeping " + napTimeSeconds + "s before trying again"); + SystemClock.sleep(napTimeSeconds * SECOND_IN_MS); + } + fail("Command '" + command + "' did not return '" + checker.getExpected() + "' after " + + maxTries + + " attempts. Last result: '" + result + "'"); + } + + protected void addRestrictBackgroundWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, true); + // UID policies live by the Highlander rule: "There can be only one". + // Hence, if app is whitelisted, it should not be blacklisted. + assertRestrictBackgroundBlacklist(uid, false); + } + + protected void removeRestrictBackgroundWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy remove restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, false); + } + + protected void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { + assertRestrictBackground("restrict-background-whitelist", uid, expected); + } + + protected void addRestrictBackgroundBlacklist(int uid) throws Exception { + executeShellCommand("cmd netpolicy add restrict-background-blacklist " + uid); + assertRestrictBackgroundBlacklist(uid, true); + // UID policies live by the Highlander rule: "There can be only one". + // Hence, if app is blacklisted, it should not be whitelisted. + assertRestrictBackgroundWhitelist(uid, false); + } + + protected void removeRestrictBackgroundBlacklist(int uid) throws Exception { + executeShellCommand("cmd netpolicy remove restrict-background-blacklist " + uid); + assertRestrictBackgroundBlacklist(uid, false); + } + + protected void assertRestrictBackgroundBlacklist(int uid, boolean expected) throws Exception { + assertRestrictBackground("restrict-background-blacklist", uid, expected); + } + + protected void addAppIdleWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy add app-idle-whitelist " + uid); + assertAppIdleWhitelist(uid, true); + } + + protected void removeAppIdleWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy remove app-idle-whitelist " + uid); + assertAppIdleWhitelist(uid, false); + } + + protected void assertAppIdleWhitelist(int uid, boolean expected) throws Exception { + assertRestrictBackground("app-idle-whitelist", uid, expected); + } + + private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception { + final int maxTries = 5; + boolean actual = false; + final String expectedUid = Integer.toString(uid); + String uids = ""; + for (int i = 1; i <= maxTries; i++) { + final String output = + executeShellCommand("cmd netpolicy list " + list); + uids = output.split(":")[1]; + for (String candidate : uids.split(" ")) { + actual = candidate.trim().equals(expectedUid); + if (expected == actual) { + return; + } + } + Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected " + + expected + ", got " + actual + "); sleeping 1s before polling again"); + SystemClock.sleep(SECOND_IN_MS); + } + fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual + + ". Full list: " + uids); + } + + protected void addTempPowerSaveModeWhitelist(String packageName, long duration) + throws Exception { + Log.i(TAG, "Adding pkg " + packageName + " to temp-power-save-mode whitelist"); + executeShellCommand("dumpsys deviceidle tempwhitelist -d " + duration + " " + packageName); + } + + protected void assertPowerSaveModeWhitelist(String packageName, boolean expected) + throws Exception { + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + assertDelayedShellCommand("dumpsys deviceidle whitelist =" + packageName, + Boolean.toString(expected)); + } + + protected void addPowerSaveModeWhitelist(String packageName) throws Exception { + Log.i(TAG, "Adding package " + packageName + " to power-save-mode whitelist"); + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + executeShellCommand("dumpsys deviceidle whitelist +" + packageName); + assertPowerSaveModeWhitelist(packageName, true); + } + + protected void removePowerSaveModeWhitelist(String packageName) throws Exception { + Log.i(TAG, "Removing package " + packageName + " from power-save-mode whitelist"); + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + executeShellCommand("dumpsys deviceidle whitelist -" + packageName); + assertPowerSaveModeWhitelist(packageName, false); + } + + protected void assertPowerSaveModeExceptIdleWhitelist(String packageName, boolean expected) + throws Exception { + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + assertDelayedShellCommand("dumpsys deviceidle except-idle-whitelist =" + packageName, + Boolean.toString(expected)); + } + + protected void addPowerSaveModeExceptIdleWhitelist(String packageName) throws Exception { + Log.i(TAG, "Adding package " + packageName + " to power-save-mode-except-idle whitelist"); + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + executeShellCommand("dumpsys deviceidle except-idle-whitelist +" + packageName); + assertPowerSaveModeExceptIdleWhitelist(packageName, true); + } + + protected void removePowerSaveModeExceptIdleWhitelist(String packageName) throws Exception { + Log.i(TAG, "Removing package " + packageName + + " from power-save-mode-except-idle whitelist"); + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + executeShellCommand("dumpsys deviceidle except-idle-whitelist reset"); + assertPowerSaveModeExceptIdleWhitelist(packageName, false); + } + + protected void turnBatteryOn() throws Exception { + executeSilentShellCommand("cmd battery unplug"); + executeSilentShellCommand("cmd battery set status " + + BatteryManager.BATTERY_STATUS_DISCHARGING); + assertBatteryState(false); + } + + protected void turnBatteryOff() throws Exception { + executeSilentShellCommand("cmd battery set ac " + BATTERY_PLUGGED_ANY); + executeSilentShellCommand("cmd battery set level 100"); + executeSilentShellCommand("cmd battery set status " + + BatteryManager.BATTERY_STATUS_CHARGING); + assertBatteryState(true); + } + + private void assertBatteryState(boolean pluggedIn) throws Exception { + final long endTime = SystemClock.elapsedRealtime() + BATTERY_STATE_TIMEOUT_MS; + while (isDevicePluggedIn() != pluggedIn && SystemClock.elapsedRealtime() <= endTime) { + Thread.sleep(BATTERY_STATE_CHECK_INTERVAL_MS); + } + if (isDevicePluggedIn() != pluggedIn) { + fail("Timed out waiting for the plugged-in state to change," + + " expected pluggedIn: " + pluggedIn); + } + } + + private boolean isDevicePluggedIn() { + final Intent batteryIntent = mContext.registerReceiver(null, BATTERY_CHANGED_FILTER); + return batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) > 0; + } + + protected void turnScreenOff() throws Exception { + executeSilentShellCommand("input keyevent KEYCODE_SLEEP"); + } + + protected void turnScreenOn() throws Exception { + executeSilentShellCommand("input keyevent KEYCODE_WAKEUP"); + executeSilentShellCommand("wm dismiss-keyguard"); + } + + protected void setBatterySaverMode(boolean enabled) throws Exception { + Log.i(TAG, "Setting Battery Saver Mode to " + enabled); + if (enabled) { + turnBatteryOn(); + executeSilentShellCommand("cmd power set-mode 1"); + } else { + executeSilentShellCommand("cmd power set-mode 0"); + turnBatteryOff(); + } + } + + protected void setDozeMode(boolean enabled) throws Exception { + // Check doze mode is supported. + assertTrue("Device does not support Doze Mode", isDozeModeSupported()); + + Log.i(TAG, "Setting Doze Mode to " + enabled); + if (enabled) { + turnBatteryOn(); + turnScreenOff(); + executeShellCommand("dumpsys deviceidle force-idle deep"); + } else { + turnScreenOn(); + turnBatteryOff(); + executeShellCommand("dumpsys deviceidle unforce"); + } + assertDozeMode(enabled); + } + + protected void assertDozeMode(boolean enabled) throws Exception { + assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE"); + } + + protected void setAppIdle(boolean enabled) throws Exception { + Log.i(TAG, "Setting app idle to " + enabled); + executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); + assertAppIdle(enabled); + } + + protected void setAppIdleNoAssert(boolean enabled) throws Exception { + Log.i(TAG, "Setting app idle to " + enabled); + executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled ); + } + + protected void assertAppIdle(boolean enabled) throws Exception { + try { + assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled); + } catch (Throwable e) { + throw e; + } + } + + /** + * Starts a service that will register a broadcast receiver to receive + * {@code RESTRICT_BACKGROUND_CHANGE} intents. + *

    + * The service must run in a separate app because otherwise it would be killed every time + * {@link #runDeviceTests(String, String)} is executed. + */ + protected void registerBroadcastReceiver() throws Exception { + mServiceClient.registerBroadcastReceiver(); + + final Intent intent = new Intent(ACTION_RECEIVER_READY) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + // Wait until receiver is ready. + final int maxTries = 10; + for (int i = 1; i <= maxTries; i++) { + final String message = sendOrderedBroadcast(intent, SECOND_IN_MS * 4); + Log.d(TAG, "app2 receiver acked: " + message); + if (message != null) { + return; + } + Log.v(TAG, "app2 receiver is not ready yet; sleeping 1s before polling again"); + SystemClock.sleep(SECOND_IN_MS); + } + fail("app2 receiver is not ready"); + } + + protected void registerNetworkCallback(INetworkCallback cb) throws Exception { + mServiceClient.registerNetworkCallback(cb); + } + + protected void unregisterNetworkCallback() throws Exception { + mServiceClient.unregisterNetworkCallback(); + } + + /** + * Registers a {@link NotificationListenerService} implementation that will execute the + * notification actions right after the notification is sent. + */ + protected void registerNotificationListenerService() throws Exception { + executeShellCommand("cmd notification allow_listener " + + MyNotificationListenerService.getId()); + final NotificationManager nm = mContext.getSystemService(NotificationManager.class); + final ComponentName listenerComponent = MyNotificationListenerService.getComponentName(); + assertTrue(listenerComponent + " has not been granted access", + nm.isNotificationListenerAccessGranted(listenerComponent)); + } + + protected void setPendingIntentWhitelistDuration(int durationMs) throws Exception { + executeSilentShellCommand(String.format( + "settings put global %s %s=%d", mDeviceIdleConstantsSetting, + "notification_whitelist_duration", durationMs)); + } + + protected void resetDeviceIdleSettings() throws Exception { + executeShellCommand(String.format("settings delete global %s", + mDeviceIdleConstantsSetting)); + } + + protected void launchComponentAndAssertNetworkAccess(int type) throws Exception { + if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) { + startForegroundService(); + assertForegroundServiceNetworkAccess(); + return; + } else if (type == TYPE_COMPONENT_ACTIVTIY) { + turnScreenOn(); + // Wait for screen-on state to propagate through the system. + SystemClock.sleep(2000); + final CountDownLatch latch = new CountDownLatch(1); + final Intent launchIntent = getIntentForComponent(type); + final Bundle extras = new Bundle(); + final String[] errors = new String[]{null}; + extras.putBinder(KEY_NETWORK_STATE_OBSERVER, getNewNetworkStateObserver(latch, errors)); + launchIntent.putExtras(extras); + mContext.startActivity(launchIntent); + if (latch.await(FOREGROUND_PROC_NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + if (!errors[0].isEmpty()) { + if (errors[0] == APP_NOT_FOREGROUND_ERROR) { + // App didn't come to foreground when the activity is started, so try again. + assertForegroundNetworkAccess(); + } else { + fail("Network is not available for app2 (" + mUid + "): " + errors[0]); + } + } + } else { + fail("Timed out waiting for network availability status from app2 (" + mUid + ")"); + } + } else { + throw new IllegalArgumentException("Unknown type: " + type); + } + } + + private void startForegroundService() throws Exception { + final Intent launchIntent = getIntentForComponent(TYPE_COMPONENT_FOREGROUND_SERVICE); + mContext.startForegroundService(launchIntent); + assertForegroundServiceState(); + } + + private Intent getIntentForComponent(int type) { + final Intent intent = new Intent(); + if (type == TYPE_COMPONENT_ACTIVTIY) { + intent.setComponent(new ComponentName(TEST_APP2_PKG, TEST_APP2_ACTIVITY_CLASS)) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } else if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) { + intent.setComponent(new ComponentName(TEST_APP2_PKG, TEST_APP2_SERVICE_CLASS)) + .setFlags(1); + } else { + fail("Unknown type: " + type); + } + return intent; + } + + protected void stopForegroundService() throws Exception { + executeShellCommand(String.format("am startservice -f 2 %s/%s", + TEST_APP2_PKG, TEST_APP2_SERVICE_CLASS)); + // NOTE: cannot assert state because it depends on whether activity was on top before. + } + + private Binder getNewNetworkStateObserver(final CountDownLatch latch, + final String[] errors) { + return new INetworkStateObserver.Stub() { + @Override + public boolean isForeground() { + try { + final ProcessState state = getProcessStateByUid(mUid); + return !isBackground(state.state); + } catch (Exception e) { + Log.d(TAG, "Error while reading the proc state for " + mUid + ": " + e); + return false; + } + } + + @Override + public void onNetworkStateChecked(String resultData) { + errors[0] = resultData == null + ? APP_NOT_FOREGROUND_ERROR + : checkForAvailabilityInResultData(resultData, true); + latch.countDown(); + } + }; + } + + /** + * Finishes an activity on app2 so its process is demoted fromforeground status. + */ + protected void finishActivity() throws Exception { + executeShellCommand("am broadcast -a " + + " com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY " + + "--receiver-foreground --receiver-registered-only"); + } + + protected void sendNotification(int notificationId, String notificationType) throws Exception { + Log.d(TAG, "Sending notification broadcast (id=" + notificationId + + ", type=" + notificationType); + mServiceClient.sendNotification(notificationId, notificationType); + } + + protected String showToast() { + final Intent intent = new Intent(ACTION_SHOW_TOAST); + intent.setPackage(TEST_APP2_PKG); + Log.d(TAG, "Sending request to show toast"); + try { + return sendOrderedBroadcast(intent, 3 * SECOND_IN_MS); + } catch (Exception e) { + return ""; + } + } + + private ProcessState getProcessStateByUid(int uid) throws Exception { + return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid)); + } + + private static class ProcessState { + private final String fullState; + final int state; + + ProcessState(String fullState) { + this.fullState = fullState; + try { + this.state = Integer.parseInt(fullState.split(" ")[0]); + } catch (Exception e) { + throw new IllegalArgumentException("Could not parse " + fullState); + } + } + + @Override + public String toString() { + return fullState; + } + } + + /** + * Helper class used to assert the result of a Shell command. + */ + protected static interface ExpectResultChecker { + /** + * Checkes whether the result of the command matched the expectation. + */ + boolean isExpected(String result); + /** + * Gets the expected result so it's displayed on log and failure messages. + */ + String getExpected(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java new file mode 100644 index 0000000000..f1858d65a5 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) +public class AppIdleMeteredTest extends AbstractAppIdleTestCase { +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java new file mode 100644 index 0000000000..e737a6dabe --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) +public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase { +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java new file mode 100644 index 0000000000..c78ca2ec77 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) +public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase { +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java new file mode 100644 index 0000000000..fb52a540d8 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + + +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) +public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase { +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java new file mode 100644 index 0000000000..604a0b62c6 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE; + +import static org.junit.Assert.fail; + +import com.android.compatibility.common.util.CddTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import androidx.test.filters.LargeTest; + +@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK}) +@LargeTest +public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase { + + private static final String[] REQUIRED_WHITELISTED_PACKAGES = { + "com.android.providers.downloads" + }; + + @Before + public void setUp() throws Exception { + super.setUp(); + + // Set initial state. + setRestrictBackground(false); + removeRestrictBackgroundWhitelist(mUid); + removeRestrictBackgroundBlacklist(mUid); + + registerBroadcastReceiver(); + assertRestrictBackgroundChangedReceived(0); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + + setRestrictBackground(false); + } + + @Test + public void testGetRestrictBackgroundStatus_disabled() throws Exception { + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); + + // Verify status is always disabled, never whitelisted + addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundChangedReceived(0); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); + + assertsForegroundAlwaysHasNetworkAccess(); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); + } + + @Test + public void testGetRestrictBackgroundStatus_whitelisted() throws Exception { + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(1); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + + addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundChangedReceived(2); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + + removeRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundChangedReceived(3); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + + assertsForegroundAlwaysHasNetworkAccess(); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + } + + @Test + public void testGetRestrictBackgroundStatus_enabled() throws Exception { + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(1); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + + assertsForegroundAlwaysHasNetworkAccess(); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + + // Make sure foreground app doesn't lose access upon enabling Data Saver. + setRestrictBackground(false); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); + setRestrictBackground(true); + assertForegroundNetworkAccess(); + + // Although it should not have access while the screen is off. + turnScreenOff(); + assertBackgroundNetworkAccess(false); + turnScreenOn(); + assertForegroundNetworkAccess(); + + // Goes back to background state. + finishActivity(); + assertBackgroundNetworkAccess(false); + + // Make sure foreground service doesn't lose access upon enabling Data Saver. + setRestrictBackground(false); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE); + setRestrictBackground(true); + assertForegroundNetworkAccess(); + stopForegroundService(); + assertBackgroundNetworkAccess(false); + } + + @Test + public void testGetRestrictBackgroundStatus_blacklisted() throws Exception { + addRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(1); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + + assertsForegroundAlwaysHasNetworkAccess(); + assertRestrictBackgroundChangedReceived(1); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + + // UID policies live by the Highlander rule: "There can be only one". + // Hence, if app is whitelisted, it should not be blacklisted anymore. + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(2); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + addRestrictBackgroundWhitelist(mUid); + assertRestrictBackgroundChangedReceived(3); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED); + + // Check status after removing blacklist. + // ...re-enables first + addRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(4); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertsForegroundAlwaysHasNetworkAccess(); + // ... remove blacklist - access's still rejected because Data Saver is on + removeRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(4); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED); + assertsForegroundAlwaysHasNetworkAccess(); + // ... finally, disable Data Saver + setRestrictBackground(false); + assertRestrictBackgroundChangedReceived(5); + assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED); + assertsForegroundAlwaysHasNetworkAccess(); + } + + @Test + public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception { + final StringBuilder error = new StringBuilder(); + for (String packageName : REQUIRED_WHITELISTED_PACKAGES) { + int uid = -1; + try { + uid = getUid(packageName); + assertRestrictBackgroundWhitelist(uid, true); + } catch (Throwable t) { + error.append("\nFailed for '").append(packageName).append("'"); + if (uid > 0) { + error.append(" (uid ").append(uid).append(")"); + } + error.append(": ").append(t).append("\n"); + } + } + if (error.length() > 0) { + fail(error.toString()); + } + } + + @RequiredProperties({NO_DATA_SAVER_MODE}) + @CddTest(requirement="7.4.7/C-2-2") + @Test + public void testBroadcastNotSentOnUnsupportedDevices() throws Exception { + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(0); + + setRestrictBackground(false); + assertRestrictBackgroundChangedReceived(0); + + setRestrictBackground(true); + assertRestrictBackgroundChangedReceived(0); + } + + private void assertDataSaverStatusOnBackground(int expectedStatus) throws Exception { + assertRestrictBackgroundStatus(expectedStatus); + assertBackgroundNetworkAccess(expectedStatus != RESTRICT_BACKGROUND_STATUS_ENABLED); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java new file mode 100644 index 0000000000..4306c991c2 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.Property.METERED_NETWORK; + +@RequiredProperties({METERED_NETWORK}) +public class DozeModeMeteredTest extends AbstractDozeModeTestCase { +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java new file mode 100644 index 0000000000..1e89f158a3 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +@RequiredProperties({NON_METERED_NETWORK}) +public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase { +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java new file mode 100644 index 0000000000..5ecb399da0 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_APP2_PKG; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG; + +import android.os.Environment; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import com.android.compatibility.common.util.OnFailureRule; + +import org.junit.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class DumpOnFailureRule extends OnFailureRule { + private File mDumpDir = new File(Environment.getExternalStorageDirectory(), + "CtsHostsideNetworkTests"); + + @Override + public void onTestFailure(Statement base, Description description, Throwable throwable) { + final String testName = description.getClassName() + "_" + description.getMethodName(); + + if (throwable instanceof AssumptionViolatedException) { + Log.d(TAG, "Skipping test " + testName + ": " + throwable); + return; + } + + prepareDumpRootDir(); + final File dumpFile = new File(mDumpDir, "dump-" + testName); + Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath()); + try (FileOutputStream out = new FileOutputStream(dumpFile)) { + for (String cmd : new String[] { + "dumpsys netpolicy", + "dumpsys network_management", + "dumpsys usagestats " + TEST_PKG + " " + TEST_APP2_PKG, + "dumpsys usagestats appstandby", + }) { + dumpCommandOutput(out, cmd); + } + } catch (FileNotFoundException e) { + Log.e(TAG, "Error opening file: " + dumpFile, e); + } catch (IOException e) { + Log.e(TAG, "Error closing file: " + dumpFile, e); + } + } + + void dumpCommandOutput(FileOutputStream out, String cmd) { + final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation() + .getUiAutomation().executeShellCommand(cmd); + try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8)); + FileUtils.copy(in, out); + out.write("\n\n=================================================================\n\n" + .getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + Log.e(TAG, "Error dumping '" + cmd + "'", e); + } + } + + void prepareDumpRootDir() { + if (!mDumpDir.exists() && !mDumpDir.mkdir()) { + Log.e(TAG, "Error creating " + mDumpDir); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java new file mode 100644 index 0000000000..8fadf9e295 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.resetMeteredNetwork; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupMeteredNetwork; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +import android.util.ArraySet; +import android.util.Pair; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class MeterednessConfigurationRule extends BeforeAfterRule { + private Pair mSsidAndInitialMeteredness; + + @Override + public void onBefore(Statement base, Description description) throws Throwable { + final ArraySet requiredProperties + = RequiredPropertiesRule.getRequiredProperties(); + if (requiredProperties.contains(METERED_NETWORK)) { + configureNetworkMeteredness(true); + } else if (requiredProperties.contains(NON_METERED_NETWORK)) { + configureNetworkMeteredness(false); + } + } + + @Override + public void onAfter(Statement base, Description description) throws Throwable { + resetNetworkMeteredness(); + } + + public void configureNetworkMeteredness(boolean metered) throws Exception { + mSsidAndInitialMeteredness = setupMeteredNetwork(metered); + } + + public void resetNetworkMeteredness() throws Exception { + if (mSsidAndInitialMeteredness != null) { + resetMeteredNetwork(mSsidAndInitialMeteredness.first, + mSsidAndInitialMeteredness.second); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java new file mode 100644 index 0000000000..c9edda6e0b --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DOZE_MODE; +import static com.android.cts.net.hostside.Property.METERED_NETWORK; +import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK; + +import android.os.SystemClock; +import android.util.Log; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode + * and Data Saver Mode) are applied simultaneously. + *

    + * NOTE: it might sound like the test methods on this class are testing too much, + * which would make it harder to diagnose individual failures, but the assumption is that such + * failure most likely will happen when the restriction is tested individually as well. + */ +public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { + private static final String TAG = "MixedModesTest"; + + @Before + public void setUp() throws Exception { + super.setUp(); + + // Set initial state. + removeRestrictBackgroundWhitelist(mUid); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + + registerBroadcastReceiver(); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + + try { + setRestrictBackground(false); + } finally { + setBatterySaverMode(false); + } + } + + /** + * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. + */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, METERED_NETWORK}) + @Test + public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(true); + try { + setRestrictBackground(true); + setBatterySaverMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } + } + + /** + * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered + * networks. + */ + @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, NON_METERED_NETWORK}) + @Test + public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + final MeterednessConfigurationRule meterednessConfiguration + = new MeterednessConfigurationRule(); + meterednessConfiguration.configureNetworkMeteredness(false); + try { + setRestrictBackground(true); + setBatterySaverMode(true); + + Log.v(TAG, "Not whitelisted for any."); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + + Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver."); + addRestrictBackgroundWhitelist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver."); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + + Log.v(TAG, "Whitelisted for both."); + addRestrictBackgroundWhitelist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundWhitelist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(false); + removeRestrictBackgroundBlacklist(mUid); + + Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver."); + addRestrictBackgroundBlacklist(mUid); + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + assertsForegroundAlwaysHasNetworkAccess(); + assertBackgroundNetworkAccess(true); + removeRestrictBackgroundBlacklist(mUid); + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } finally { + meterednessConfiguration.resetNetworkMeteredness(); + } + } + + /** + * Tests that powersave whitelists works as expected when doze and battery saver modes + * are enabled. + */ + @RequiredProperties({DOZE_MODE, BATTERY_SAVER_MODE}) + @Test + public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { + setBatterySaverMode(true); + setDozeMode(true); + + try { + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + } finally { + setBatterySaverMode(false); + setDozeMode(false); + } + } + + /** + * Tests that powersave whitelists works as expected when doze and appIdle modes + * are enabled. + */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test + public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception { + setDozeMode(true); + setAppIdle(true); + + try { + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(true); + + removePowerSaveModeWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + + removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setDozeMode(false); + } + } + + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test + public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception { + setDozeMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setDozeMode(false); + } + } + + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test + public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { + setBatterySaverMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setBatterySaverMode(false); + } + } + + /** + * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled. + */ + @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE}) + @Test + public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { + setDozeMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + // UID still shouldn't have access because of Doze. + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + removeAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setDozeMode(false); + } + } + + @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE}) + @Test + public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { + setDozeMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setDozeMode(false); + removeAppIdleWhitelist(mUid); + } + } + + @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE}) + @Test + public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + setBatterySaverMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setBatterySaverMode(false); + removeAppIdleWhitelist(mUid); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java new file mode 100644 index 0000000000..0d0bc58504 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.WindowManager; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class MyActivity extends Activity { + private final LinkedBlockingQueue mResult = new LinkedBlockingQueue<>(1); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (mResult.offer(resultCode) == false) { + throw new RuntimeException("Queue is full! This should never happen"); + } + } + + public Integer getResult(int timeoutMs) throws InterruptedException { + return mResult.poll(timeoutMs, TimeUnit.MILLISECONDS); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java new file mode 100644 index 0000000000..013253670a --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import android.app.Notification; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; +import android.app.RemoteInput; +import android.content.ComponentName; +import android.os.Bundle; +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; +import android.util.Log; + +/** + * NotificationListenerService implementation that executes the notification actions once they're + * created. + */ +public class MyNotificationListenerService extends NotificationListenerService { + private static final String TAG = "MyNotificationListenerService"; + + @Override + public void onListenerConnected() { + Log.d(TAG, "onListenerConnected()"); + } + + @Override + public void onNotificationPosted(StatusBarNotification sbn) { + Log.d(TAG, "onNotificationPosted(): " + sbn); + if (!sbn.getPackageName().startsWith(getPackageName())) { + Log.v(TAG, "ignoring notification from a different package"); + return; + } + final PendingIntentSender sender = new PendingIntentSender(); + final Notification notification = sbn.getNotification(); + if (notification.contentIntent != null) { + sender.send("content", notification.contentIntent); + } + if (notification.deleteIntent != null) { + sender.send("delete", notification.deleteIntent); + } + if (notification.fullScreenIntent != null) { + sender.send("full screen", notification.fullScreenIntent); + } + if (notification.actions != null) { + for (Notification.Action action : notification.actions) { + sender.send("action", action.actionIntent); + sender.send("action extras", action.getExtras()); + final RemoteInput[] remoteInputs = action.getRemoteInputs(); + if (remoteInputs != null && remoteInputs.length > 0) { + for (RemoteInput remoteInput : remoteInputs) { + sender.send("remote input extras", remoteInput.getExtras()); + } + } + } + } + sender.send("notification extras", notification.extras); + } + + static String getId() { + return String.format("%s/%s", MyNotificationListenerService.class.getPackage().getName(), + MyNotificationListenerService.class.getName()); + } + + static ComponentName getComponentName() { + return new ComponentName(MyNotificationListenerService.class.getPackage().getName(), + MyNotificationListenerService.class.getName()); + } + + private static final class PendingIntentSender { + private PendingIntent mSentIntent = null; + private String mReason = null; + + private void send(String reason, PendingIntent pendingIntent) { + if (pendingIntent == null) { + // Could happen on action that only has extras + Log.v(TAG, "Not sending null pending intent for " + reason); + return; + } + if (mSentIntent != null || mReason != null) { + // Sanity check: make sure test case set up just one pending intent in the + // notification, otherwise it could pass because another pending intent caused the + // whitelisting. + throw new IllegalStateException("Already sent a PendingIntent (" + mSentIntent + + ") for reason '" + mReason + "' when requested another for '" + reason + + "' (" + pendingIntent + ")"); + } + Log.i(TAG, "Sending pending intent for " + reason + ":" + pendingIntent); + try { + pendingIntent.send(); + mSentIntent = pendingIntent; + mReason = reason; + } catch (CanceledException e) { + Log.w(TAG, "Pending intent " + pendingIntent + " canceled"); + } + } + + private void send(String reason, Bundle extras) { + if (extras != null) { + for (String key : extras.keySet()) { + Object value = extras.get(key); + if (value instanceof PendingIntent) { + send(reason + " with key '" + key + "'", (PendingIntent) value); + } + } + } + } + + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java new file mode 100644 index 0000000000..6546e26ba7 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.ConditionVariable; +import android.os.IBinder; +import android.os.RemoteException; + +import com.android.cts.net.hostside.IMyService; + +public class MyServiceClient { + private static final int TIMEOUT_MS = 5000; + private static final String PACKAGE = MyServiceClient.class.getPackage().getName(); + private static final String APP2_PACKAGE = PACKAGE + ".app2"; + private static final String SERVICE_NAME = APP2_PACKAGE + ".MyService"; + + private Context mContext; + private ServiceConnection mServiceConnection; + private IMyService mService; + + public MyServiceClient(Context context) { + mContext = context; + } + + public void bind() { + if (mService != null) { + throw new IllegalStateException("Already bound"); + } + + final ConditionVariable cv = new ConditionVariable(); + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IMyService.Stub.asInterface(service); + cv.open(); + } + @Override + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + }; + + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(APP2_PACKAGE, SERVICE_NAME)); + // Needs to use BIND_NOT_FOREGROUND so app2 does not run in + // the same process state as app + mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE + | Context.BIND_NOT_FOREGROUND); + cv.block(TIMEOUT_MS); + if (mService == null) { + throw new IllegalStateException( + "Could not bind to MyService service after " + TIMEOUT_MS + "ms"); + } + } + + public void unbind() { + if (mService != null) { + mContext.unbindService(mServiceConnection); + } + } + + public void registerBroadcastReceiver() throws RemoteException { + mService.registerBroadcastReceiver(); + } + + public int getCounters(String receiverName, String action) throws RemoteException { + return mService.getCounters(receiverName, action); + } + + public String checkNetworkStatus() throws RemoteException { + return mService.checkNetworkStatus(); + } + + public String getRestrictBackgroundStatus() throws RemoteException { + return mService.getRestrictBackgroundStatus(); + } + + public void sendNotification(int notificationId, String notificationType) throws RemoteException { + mService.sendNotification(notificationId, notificationType); + } + + public void registerNetworkCallback(INetworkCallback cb) throws RemoteException { + mService.registerNetworkCallback(cb); + } + + public void unregisterNetworkCallback() throws RemoteException { + mService.unregisterNetworkCallback(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java new file mode 100644 index 0000000000..7d3d4fce74 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import android.content.Intent; +import android.net.Network; +import android.net.ProxyInfo; +import android.net.VpnService; +import android.os.ParcelFileDescriptor; +import android.content.pm.PackageManager.NameNotFoundException; +import android.text.TextUtils; +import android.util.Log; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; + +public class MyVpnService extends VpnService { + + private static String TAG = "MyVpnService"; + private static int MTU = 1799; + + public static final String ACTION_ESTABLISHED = "com.android.cts.net.hostside.ESTABNLISHED"; + public static final String EXTRA_ALWAYS_ON = "is-always-on"; + public static final String EXTRA_LOCKDOWN_ENABLED = "is-lockdown-enabled"; + + private ParcelFileDescriptor mFd = null; + private PacketReflector mPacketReflector = null; + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + String packageName = getPackageName(); + String cmd = intent.getStringExtra(packageName + ".cmd"); + if ("disconnect".equals(cmd)) { + stop(); + } else if ("connect".equals(cmd)) { + start(packageName, intent); + } + + return START_NOT_STICKY; + } + + private void start(String packageName, Intent intent) { + Builder builder = new Builder(); + + String addresses = intent.getStringExtra(packageName + ".addresses"); + if (addresses != null) { + String[] addressArray = addresses.split(","); + for (int i = 0; i < addressArray.length; i++) { + String[] prefixAndMask = addressArray[i].split("/"); + try { + InetAddress address = InetAddress.getByName(prefixAndMask[0]); + int prefixLength = Integer.parseInt(prefixAndMask[1]); + builder.addAddress(address, prefixLength); + } catch (UnknownHostException|NumberFormatException| + ArrayIndexOutOfBoundsException e) { + continue; + } + } + } + + String routes = intent.getStringExtra(packageName + ".routes"); + if (routes != null) { + String[] routeArray = routes.split(","); + for (int i = 0; i < routeArray.length; i++) { + String[] prefixAndMask = routeArray[i].split("/"); + try { + InetAddress address = InetAddress.getByName(prefixAndMask[0]); + int prefixLength = Integer.parseInt(prefixAndMask[1]); + builder.addRoute(address, prefixLength); + } catch (UnknownHostException|NumberFormatException| + ArrayIndexOutOfBoundsException e) { + continue; + } + } + } + + String allowed = intent.getStringExtra(packageName + ".allowedapplications"); + if (allowed != null) { + String[] packageArray = allowed.split(","); + for (int i = 0; i < packageArray.length; i++) { + String allowedPackage = packageArray[i]; + if (!TextUtils.isEmpty(allowedPackage)) { + try { + builder.addAllowedApplication(allowedPackage); + } catch(NameNotFoundException e) { + continue; + } + } + } + } + + String disallowed = intent.getStringExtra(packageName + ".disallowedapplications"); + if (disallowed != null) { + String[] packageArray = disallowed.split(","); + for (int i = 0; i < packageArray.length; i++) { + String disallowedPackage = packageArray[i]; + if (!TextUtils.isEmpty(disallowedPackage)) { + try { + builder.addDisallowedApplication(disallowedPackage); + } catch(NameNotFoundException e) { + continue; + } + } + } + } + + ArrayList underlyingNetworks = + intent.getParcelableArrayListExtra(packageName + ".underlyingNetworks"); + if (underlyingNetworks == null) { + // VPN tracks default network + builder.setUnderlyingNetworks(null); + } else { + builder.setUnderlyingNetworks(underlyingNetworks.toArray(new Network[0])); + } + + boolean isAlwaysMetered = intent.getBooleanExtra(packageName + ".isAlwaysMetered", false); + builder.setMetered(isAlwaysMetered); + + ProxyInfo vpnProxy = intent.getParcelableExtra(packageName + ".httpProxy"); + builder.setHttpProxy(vpnProxy); + builder.setMtu(MTU); + builder.setBlocking(true); + builder.setSession("MyVpnService"); + + Log.i(TAG, "Establishing VPN," + + " addresses=" + addresses + + " routes=" + routes + + " allowedApplications=" + allowed + + " disallowedApplications=" + disallowed); + + mFd = builder.establish(); + Log.i(TAG, "Established, fd=" + (mFd == null ? "null" : mFd.getFd())); + + broadcastEstablished(); + + mPacketReflector = new PacketReflector(mFd.getFileDescriptor(), MTU); + mPacketReflector.start(); + } + + private void broadcastEstablished() { + final Intent bcIntent = new Intent(ACTION_ESTABLISHED); + bcIntent.putExtra(EXTRA_ALWAYS_ON, isAlwaysOn()); + bcIntent.putExtra(EXTRA_LOCKDOWN_ENABLED, isLockdownEnabled()); + sendBroadcast(bcIntent); + } + + private void stop() { + if (mPacketReflector != null) { + mPacketReflector.interrupt(); + mPacketReflector = null; + } + try { + if (mFd != null) { + Log.i(TAG, "Closing filedescriptor"); + mFd.close(); + } + } catch(IOException e) { + } finally { + mFd = null; + } + } + + @Override + public void onDestroy() { + stop(); + super.onDestroy(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java new file mode 100644 index 0000000000..2ac29e77ff --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; +import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE; +import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.net.Network; +import android.net.NetworkCapabilities; +import android.util.Log; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.Objects; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase { + private Network mNetwork; + private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback(); + @Rule + public final MeterednessConfigurationRule mMeterednessConfiguration + = new MeterednessConfigurationRule(); + + enum CallbackState { + NONE, + AVAILABLE, + LOST, + BLOCKED_STATUS, + CAPABILITIES + } + + private static class CallbackInfo { + public final CallbackState state; + public final Network network; + public final Object arg; + + CallbackInfo(CallbackState s, Network n, Object o) { + state = s; network = n; arg = o; + } + + public String toString() { + return String.format("%s (%s) (%s)", state, network, arg); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof CallbackInfo)) return false; + // Ignore timeMs, since it's unpredictable. + final CallbackInfo other = (CallbackInfo) o; + return (state == other.state) && Objects.equals(network, other.network) + && Objects.equals(arg, other.arg); + } + + @Override + public int hashCode() { + return Objects.hash(state, network, arg); + } + } + + private class TestNetworkCallback extends INetworkCallback.Stub { + private static final int TEST_CONNECT_TIMEOUT_MS = 30_000; + private static final int TEST_CALLBACK_TIMEOUT_MS = 5_000; + + private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + protected void setLastCallback(CallbackState state, Network network, Object o) { + mCallbacks.offer(new CallbackInfo(state, network, o)); + } + + CallbackInfo nextCallback(int timeoutMs) { + CallbackInfo cb = null; + try { + cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + } + if (cb == null) { + fail("Did not receive callback after " + timeoutMs + "ms"); + } + return cb; + } + + CallbackInfo expectCallback(CallbackState state, Network expectedNetwork, Object o) { + final CallbackInfo expected = new CallbackInfo(state, expectedNetwork, o); + final CallbackInfo actual = nextCallback(TEST_CALLBACK_TIMEOUT_MS); + assertEquals("Unexpected callback:", expected, actual); + return actual; + } + + @Override + public void onAvailable(Network network) { + setLastCallback(CallbackState.AVAILABLE, network, null); + } + + @Override + public void onLost(Network network) { + setLastCallback(CallbackState.LOST, network, null); + } + + @Override + public void onBlockedStatusChanged(Network network, boolean blocked) { + setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked); + } + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities cap) { + setLastCallback(CallbackState.CAPABILITIES, network, cap); + } + + public Network expectAvailableCallbackAndGetNetwork() { + final CallbackInfo cb = nextCallback(TEST_CONNECT_TIMEOUT_MS); + if (cb.state != CallbackState.AVAILABLE) { + fail("Network is not available. Instead obtained the following callback :" + + cb); + } + return cb.network; + } + + public void expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) { + expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, expectBlocked); + } + + public void expectBlockedStatusCallbackEventually(Network expectedNetwork, + boolean expectBlocked) { + final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS; + do { + final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis())); + if (cb.state == CallbackState.BLOCKED_STATUS + && cb.network.equals(expectedNetwork)) { + assertEquals(expectBlocked, cb.arg); + return; + } + } while (System.currentTimeMillis() <= deadline); + fail("Didn't receive onBlockedStatusChanged()"); + } + + public void expectCapabilitiesCallbackEventually(Network expectedNetwork, boolean hasCap, + int cap) { + final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS; + do { + final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis())); + if (cb.state != CallbackState.CAPABILITIES + || !expectedNetwork.equals(cb.network) + || (hasCap != ((NetworkCapabilities) cb.arg).hasCapability(cap))) { + Log.i("NetworkCallbackTest#expectCapabilitiesCallback", + "Ignoring non-matching callback : " + cb); + continue; + } + // Found a match, return + return; + } while (System.currentTimeMillis() <= deadline); + fail("Didn't receive the expected callback to onCapabilitiesChanged(). Check the " + + "log for a list of received callbacks, if any."); + } + } + + @Before + public void setUp() throws Exception { + super.setUp(); + + assumeTrue(isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness()); + + registerBroadcastReceiver(); + + removeRestrictBackgroundWhitelist(mUid); + removeRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(0); + + // Initial state + setBatterySaverMode(false); + setRestrictBackground(false); + + // Make wifi a metered network. + mMeterednessConfiguration.configureNetworkMeteredness(true); + + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + // Once the wifi is marked as metered, the wifi will reconnect. Wait for onAvailable() + // callback to ensure wifi is connected before the test and store the default network. + mNetwork = mTestNetworkCallback.expectAvailableCallbackAndGetNetwork(); + // Check that the network is metered. + mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork, + false /* hasCapability */, NET_CAPABILITY_NOT_METERED); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + + setRestrictBackground(false); + setBatterySaverMode(false); + unregisterNetworkCallback(); + } + + @RequiredProperties({DATA_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_dataSaver() throws Exception { + try { + // Enable restrict background + setRestrictBackground(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true); + + // Add to whitelist + addRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false); + + // Remove from whitelist + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true); + } finally { + mMeterednessConfiguration.resetNetworkMeteredness(); + } + + // Set to non-metered network + mMeterednessConfiguration.configureNetworkMeteredness(false); + mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork, + true /* hasCapability */, NET_CAPABILITY_NOT_METERED); + try { + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false); + + // Disable restrict background, should not trigger callback + setRestrictBackground(false); + assertBackgroundNetworkAccess(true); + } finally { + mMeterednessConfiguration.resetNetworkMeteredness(); + } + } + + @RequiredProperties({BATTERY_SAVER_MODE}) + @Test + public void testOnBlockedStatusChanged_powerSaver() throws Exception { + try { + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true); + + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false); + } finally { + mMeterednessConfiguration.resetNetworkMeteredness(); + } + + // Set to non-metered network + mMeterednessConfiguration.configureNetworkMeteredness(false); + mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork, + true /* hasCapability */, NET_CAPABILITY_NOT_METERED); + try { + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true); + + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false); + } finally { + mMeterednessConfiguration.resetNetworkMeteredness(); + } + } + + // TODO: 1. test against VPN lockdown. + // 2. test against multiple networks. +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java new file mode 100644 index 0000000000..f340907ae5 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java @@ -0,0 +1,44 @@ +/* + * 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 com.android.cts.net.hostside; + +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner; + +import org.junit.rules.RunRules; +import org.junit.rules.TestRule; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; + +import java.util.List; + +/** + * Custom runner to allow dumping logs after a test failure before the @After methods get to run. + */ +public class NetworkPolicyTestRunner extends AndroidJUnit4ClassRunner { + private TestRule mDumpOnFailureRule = new DumpOnFailureRule(); + + public NetworkPolicyTestRunner(Class klass) throws InitializationError { + super(klass); + } + + @Override + public Statement methodInvoker(FrameworkMethod method, Object test) { + return new RunRules(super.methodInvoker(method, test), List.of(mDumpOnFailureRule), + describeChild(method)); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java new file mode 100644 index 0000000000..3807d79c35 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.ActivityManager; +import android.app.Instrumentation; +import android.content.Context; +import android.location.LocationManager; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.wifi.WifiManager; +import android.os.Process; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; + +import com.android.compatibility.common.util.AppStandbyUtils; +import com.android.compatibility.common.util.BatteryUtils; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import androidx.test.platform.app.InstrumentationRegistry; + +public class NetworkPolicyTestUtils { + + private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 5000; + + private static ConnectivityManager mCm; + private static WifiManager mWm; + + private static Boolean mBatterySaverSupported; + private static Boolean mDataSaverSupported; + private static Boolean mDozeModeSupported; + private static Boolean mAppStandbySupported; + + private NetworkPolicyTestUtils() {} + + public static boolean isBatterySaverSupported() { + if (mBatterySaverSupported == null) { + mBatterySaverSupported = BatteryUtils.isBatterySaverSupported(); + } + return mBatterySaverSupported; + } + + /** + * As per CDD requirements, if the device doesn't support data saver mode then + * ConnectivityManager.getRestrictBackgroundStatus() will always return + * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if + * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns + * RESTRICT_BACKGROUND_STATUS_DISABLED or not. + */ + public static boolean isDataSaverSupported() { + if (mDataSaverSupported == null) { + assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); + try { + setRestrictBackground(true); + mDataSaverSupported = !isMyRestrictBackgroundStatus( + RESTRICT_BACKGROUND_STATUS_DISABLED); + } finally { + setRestrictBackground(false); + } + } + return mDataSaverSupported; + } + + public static boolean isDozeModeSupported() { + if (mDozeModeSupported == null) { + final String result = executeShellCommand("cmd deviceidle enabled deep"); + mDozeModeSupported = result.equals("1"); + } + return mDozeModeSupported; + } + + public static boolean isAppStandbySupported() { + if (mAppStandbySupported == null) { + mAppStandbySupported = AppStandbyUtils.isAppStandbyEnabled(); + } + return mAppStandbySupported; + } + + public static boolean isLowRamDevice() { + final ActivityManager am = (ActivityManager) getContext().getSystemService( + Context.ACTIVITY_SERVICE); + return am.isLowRamDevice(); + } + + public static boolean isLocationEnabled() { + final LocationManager lm = (LocationManager) getContext().getSystemService( + Context.LOCATION_SERVICE); + return lm.isLocationEnabled(); + } + + public static void setLocationEnabled(boolean enabled) { + final LocationManager lm = (LocationManager) getContext().getSystemService( + Context.LOCATION_SERVICE); + lm.setLocationEnabledForUser(enabled, Process.myUserHandle()); + assertEquals("Couldn't change location enabled state", lm.isLocationEnabled(), enabled); + Log.d(TAG, "Changed location enabled state to " + enabled); + } + + public static boolean isActiveNetworkMetered(boolean metered) { + return getConnectivityManager().isActiveNetworkMetered() == metered; + } + + public static boolean canChangeActiveNetworkMeteredness() { + final Network activeNetwork = getConnectivityManager().getActiveNetwork(); + final NetworkCapabilities networkCapabilities + = getConnectivityManager().getNetworkCapabilities(activeNetwork); + return networkCapabilities.hasTransport(TRANSPORT_WIFI); + } + + public static Pair setupMeteredNetwork(boolean metered) throws Exception { + if (isActiveNetworkMetered(metered)) { + return null; + } + final boolean isLocationEnabled = isLocationEnabled(); + try { + if (!isLocationEnabled) { + setLocationEnabled(true); + } + final String ssid = unquoteSSID(getWifiManager().getConnectionInfo().getSSID()); + assertNotEquals(WifiManager.UNKNOWN_SSID, ssid); + setWifiMeteredStatus(ssid, metered); + return Pair.create(ssid, !metered); + } finally { + // Reset the location enabled state + if (!isLocationEnabled) { + setLocationEnabled(false); + } + } + } + + public static void resetMeteredNetwork(String ssid, boolean metered) throws Exception { + setWifiMeteredStatus(ssid, metered); + } + + public static void setWifiMeteredStatus(String ssid, boolean metered) throws Exception { + assertFalse("SSID should not be empty", TextUtils.isEmpty(ssid)); + final String cmd = "cmd netpolicy set metered-network " + ssid + " " + metered; + executeShellCommand(cmd); + assertWifiMeteredStatus(ssid, metered); + assertActiveNetworkMetered(metered); + } + + public static void assertWifiMeteredStatus(String ssid, boolean expectedMeteredStatus) { + final String result = executeShellCommand("cmd netpolicy list wifi-networks"); + final String expectedLine = ssid + ";" + expectedMeteredStatus; + assertTrue("Expected line: " + expectedLine + "; Actual result: " + result, + result.contains(expectedLine)); + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + public static void assertActiveNetworkMetered(boolean expectedMeteredStatus) throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final NetworkCallback networkCallback = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); + if (metered == expectedMeteredStatus) { + latch.countDown(); + } + } + }; + // Registering a callback here guarantees onCapabilitiesChanged is called immediately + // with the current setting. Therefore, if the setting has already been changed, + // this method will return right away, and if not it will wait for the setting to change. + getConnectivityManager().registerDefaultNetworkCallback(networkCallback); + if (!latch.await(TIMEOUT_CHANGE_METEREDNESS_MS, TimeUnit.MILLISECONDS)) { + fail("Timed out waiting for active network metered status to change to " + + expectedMeteredStatus + " ; network = " + + getConnectivityManager().getActiveNetwork()); + } + getConnectivityManager().unregisterNetworkCallback(networkCallback); + } + + public static void setRestrictBackground(boolean enabled) { + executeShellCommand("cmd netpolicy set restrict-background " + enabled); + final String output = executeShellCommand("cmd netpolicy get restrict-background"); + final String expectedSuffix = enabled ? "enabled" : "disabled"; + assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'", + output.endsWith(expectedSuffix)); + } + + public static boolean isMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "MyRestrictBackgroundStatus: " + + "Expected: " + restrictBackgroundValueToString(expectedStatus) + + "; Actual: " + restrictBackgroundValueToString(actualStatus)); + return false; + } + return true; + } + + // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java + private static String unquoteSSID(String ssid) { + // SSID is returned surrounded by quotes if it can be decoded as UTF-8. + // Otherwise it's guaranteed not to start with a quote. + if (ssid.charAt(0) == '"') { + return ssid.substring(1, ssid.length() - 1); + } else { + return ssid; + } + } + + public static String restrictBackgroundValueToString(int status) { + switch (status) { + case RESTRICT_BACKGROUND_STATUS_DISABLED: + return "DISABLED"; + case RESTRICT_BACKGROUND_STATUS_WHITELISTED: + return "WHITELISTED"; + case RESTRICT_BACKGROUND_STATUS_ENABLED: + return "ENABLED"; + default: + return "UNKNOWN_STATUS_" + status; + } + } + + public static String executeShellCommand(String command) { + final String result = runShellCommand(command).trim(); + Log.d(TAG, "Output of '" + command + "': '" + result + "'"); + return result; + } + + public static void assertMyRestrictBackgroundStatus(int expectedStatus) { + final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus(); + assertEquals(restrictBackgroundValueToString(expectedStatus), + restrictBackgroundValueToString(actualStatus)); + } + + public static ConnectivityManager getConnectivityManager() { + if (mCm == null) { + mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + } + return mCm; + } + + public static WifiManager getWifiManager() { + if (mWm == null) { + mWm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + } + return mWm; + } + + public static Context getContext() { + return getInstrumentation().getContext(); + } + + public static Instrumentation getInstrumentation() { + return InstrumentationRegistry.getInstrumentation(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java new file mode 100644 index 0000000000..124c2c3862 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import static android.system.OsConstants.ICMP6_ECHO_REPLY; +import static android.system.OsConstants.ICMP6_ECHO_REQUEST; +import static android.system.OsConstants.ICMP_ECHO; +import static android.system.OsConstants.ICMP_ECHOREPLY; + +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; + +public class PacketReflector extends Thread { + + private static int IPV4_HEADER_LENGTH = 20; + private static int IPV6_HEADER_LENGTH = 40; + + private static int IPV4_ADDR_OFFSET = 12; + private static int IPV6_ADDR_OFFSET = 8; + private static int IPV4_ADDR_LENGTH = 4; + private static int IPV6_ADDR_LENGTH = 16; + + private static int IPV4_PROTO_OFFSET = 9; + private static int IPV6_PROTO_OFFSET = 6; + + private static final byte IPPROTO_ICMP = 1; + private static final byte IPPROTO_TCP = 6; + private static final byte IPPROTO_UDP = 17; + private static final byte IPPROTO_ICMPV6 = 58; + + private static int ICMP_HEADER_LENGTH = 8; + private static int TCP_HEADER_LENGTH = 20; + private static int UDP_HEADER_LENGTH = 8; + + private static final byte ICMP_ECHO = 8; + private static final byte ICMP_ECHOREPLY = 0; + + private static String TAG = "PacketReflector"; + + private FileDescriptor mFd; + private byte[] mBuf; + + public PacketReflector(FileDescriptor fd, int mtu) { + super("PacketReflector"); + mFd = fd; + mBuf = new byte[mtu]; + } + + private static void swapBytes(byte[] buf, int pos1, int pos2, int len) { + for (int i = 0; i < len; i++) { + byte b = buf[pos1 + i]; + buf[pos1 + i] = buf[pos2 + i]; + buf[pos2 + i] = b; + } + } + + private static void swapAddresses(byte[] buf, int version) { + int addrPos, addrLen; + switch(version) { + case 4: + addrPos = IPV4_ADDR_OFFSET; + addrLen = IPV4_ADDR_LENGTH; + break; + case 6: + addrPos = IPV6_ADDR_OFFSET; + addrLen = IPV6_ADDR_LENGTH; + break; + default: + throw new IllegalArgumentException(); + } + swapBytes(buf, addrPos, addrPos + addrLen, addrLen); + } + + // Reflect TCP packets: swap the source and destination addresses, but don't change the ports. + // This is used by the test to "connect to itself" through the VPN. + private void processTcpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + TCP_HEADER_LENGTH) { + return; + } + + // Swap src and dst IP addresses. + swapAddresses(buf, version); + + // Send the packet back. + writePacket(buf, len); + } + + // Echo UDP packets: swap source and destination addresses, and source and destination ports. + // This is used by the test to check that the bytes it sends are echoed back. + private void processUdpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + UDP_HEADER_LENGTH) { + return; + } + + // Swap src and dst IP addresses. + swapAddresses(buf, version); + + // Swap dst and src ports. + int portOffset = hdrLen; + swapBytes(buf, portOffset, portOffset + 2, 2); + + // Send the packet back. + writePacket(buf, len); + } + + private void processIcmpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + ICMP_HEADER_LENGTH) { + return; + } + + byte type = buf[hdrLen]; + if (!(version == 4 && type == ICMP_ECHO) && + !(version == 6 && type == (byte) ICMP6_ECHO_REQUEST)) { + return; + } + + // Save the ping packet we received. + byte[] request = buf.clone(); + + // Swap src and dst IP addresses, and send the packet back. + // This effectively pings the device to see if it replies. + swapAddresses(buf, version); + writePacket(buf, len); + + // The device should have replied, and buf should now contain a ping response. + int received = readPacket(buf); + if (received != len) { + Log.i(TAG, "Reflecting ping did not result in ping response: " + + "read=" + received + " expected=" + len); + return; + } + + byte replyType = buf[hdrLen]; + if ((type == ICMP_ECHO && replyType != ICMP_ECHOREPLY) + || (type == (byte) ICMP6_ECHO_REQUEST && replyType != (byte) ICMP6_ECHO_REPLY)) { + Log.i(TAG, "Received unexpected ICMP reply: original " + type + + ", reply " + replyType); + return; + } + + // Compare the response we got with the original packet. + // The only thing that should have changed are addresses, type and checksum. + // Overwrite them with the received bytes and see if the packet is otherwise identical. + request[hdrLen] = buf[hdrLen]; // Type + request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1. + request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2. + + // Since Linux kernel 4.2, net.ipv6.auto_flowlabels is set by default, and therefore + // the request and reply may have different IPv6 flow label: ignore that as well. + if (version == 6) { + request[1] = (byte)(request[1] & 0xf0 | buf[1] & 0x0f); + request[2] = buf[2]; + request[3] = buf[3]; + } + + for (int i = 0; i < len; i++) { + if (buf[i] != request[i]) { + Log.i(TAG, "Received non-matching packet when expecting ping response."); + return; + } + } + + // Now swap the addresses again and reflect the packet. This sends a ping reply. + swapAddresses(buf, version); + writePacket(buf, len); + } + + private void writePacket(byte[] buf, int len) { + try { + Os.write(mFd, buf, 0, len); + } catch (ErrnoException|IOException e) { + Log.e(TAG, "Error writing packet: " + e.getMessage()); + } + } + + private int readPacket(byte[] buf) { + int len; + try { + len = Os.read(mFd, buf, 0, buf.length); + } catch (ErrnoException|IOException e) { + Log.e(TAG, "Error reading packet: " + e.getMessage()); + len = -1; + } + return len; + } + + // Reads one packet from our mFd, and possibly writes the packet back. + private void processPacket() { + int len = readPacket(mBuf); + if (len < 1) { + return; + } + + int version = mBuf[0] >> 4; + int addrPos, protoPos, hdrLen, addrLen; + if (version == 4) { + hdrLen = IPV4_HEADER_LENGTH; + protoPos = IPV4_PROTO_OFFSET; + addrPos = IPV4_ADDR_OFFSET; + addrLen = IPV4_ADDR_LENGTH; + } else if (version == 6) { + hdrLen = IPV6_HEADER_LENGTH; + protoPos = IPV6_PROTO_OFFSET; + addrPos = IPV6_ADDR_OFFSET; + addrLen = IPV6_ADDR_LENGTH; + } else { + return; + } + + if (len < hdrLen) { + return; + } + + byte proto = mBuf[protoPos]; + switch (proto) { + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + processIcmpPacket(mBuf, version, len, hdrLen); + break; + case IPPROTO_TCP: + processTcpPacket(mBuf, version, len, hdrLen); + break; + case IPPROTO_UDP: + processUdpPacket(mBuf, version, len, hdrLen); + break; + } + } + + public void run() { + Log.i(TAG, "PacketReflector starting fd=" + mFd + " valid=" + mFd.valid()); + while (!interrupted() && mFd.valid()) { + processPacket(); + } + Log.i(TAG, "PacketReflector exiting fd=" + mFd + " valid=" + mFd.valid()); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java new file mode 100644 index 0000000000..18805f9613 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDataSaverSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isLowRamDevice; + +public enum Property { + BATTERY_SAVER_MODE(1 << 0) { + public boolean isSupported() { return isBatterySaverSupported(); } + }, + + DATA_SAVER_MODE(1 << 1) { + public boolean isSupported() { return isDataSaverSupported(); } + }, + + NO_DATA_SAVER_MODE(~DATA_SAVER_MODE.getValue()) { + public boolean isSupported() { return !isDataSaverSupported(); } + }, + + DOZE_MODE(1 << 2) { + public boolean isSupported() { return isDozeModeSupported(); } + }, + + APP_STANDBY_MODE(1 << 3) { + public boolean isSupported() { return isAppStandbySupported(); } + }, + + NOT_LOW_RAM_DEVICE(1 << 4) { + public boolean isSupported() { return !isLowRamDevice(); } + }, + + METERED_NETWORK(1 << 5) { + public boolean isSupported() { + return isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness(); + } + }, + + NON_METERED_NETWORK(~METERED_NETWORK.getValue()) { + public boolean isSupported() { + return isActiveNetworkMetered(false) || canChangeActiveNetworkMeteredness(); + } + }; + + private int mValue; + + Property(int value) { mValue = value; } + + public int getValue() { return mValue; } + + abstract boolean isSupported(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java new file mode 100644 index 0000000000..80f99b6605 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.ConditionVariable; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.system.ErrnoException; +import android.system.Os; + +import com.android.cts.net.hostside.IRemoteSocketFactory; + +import java.io.FileDescriptor; +import java.io.IOException; + +public class RemoteSocketFactoryClient { + private static final int TIMEOUT_MS = 5000; + private static final String PACKAGE = RemoteSocketFactoryClient.class.getPackage().getName(); + private static final String APP2_PACKAGE = PACKAGE + ".app2"; + private static final String SERVICE_NAME = APP2_PACKAGE + ".RemoteSocketFactoryService"; + + private Context mContext; + private ServiceConnection mServiceConnection; + private IRemoteSocketFactory mService; + + public RemoteSocketFactoryClient(Context context) { + mContext = context; + } + + public void bind() { + if (mService != null) { + throw new IllegalStateException("Already bound"); + } + + final ConditionVariable cv = new ConditionVariable(); + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IRemoteSocketFactory.Stub.asInterface(service); + cv.open(); + } + @Override + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + }; + + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(APP2_PACKAGE, SERVICE_NAME)); + mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); + cv.block(TIMEOUT_MS); + if (mService == null) { + throw new IllegalStateException( + "Could not bind to RemoteSocketFactory service after " + TIMEOUT_MS + "ms"); + } + } + + public void unbind() { + if (mService != null) { + mContext.unbindService(mServiceConnection); + } + } + + public FileDescriptor openSocketFd(String host, int port, int timeoutMs) + throws RemoteException, ErrnoException, IOException { + // Dup the filedescriptor so ParcelFileDescriptor's finalizer doesn't garbage collect it + // and cause our fd to become invalid. http://b/35927643 . + ParcelFileDescriptor pfd = mService.openSocketFd(host, port, timeoutMs); + FileDescriptor fd = Os.dup(pfd.getFileDescriptor()); + pfd.close(); + return fd; + } + + public String getPackageName() throws RemoteException { + return mService.getPackageName(); + } + + public int getUid() throws RemoteException { + return mService.getUid(); + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java new file mode 100644 index 0000000000..96838bba0a --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({METHOD, TYPE}) +@Inherited +public @interface RequiredProperties { + Property[] value(); +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java new file mode 100644 index 0000000000..01f9f3ea81 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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 com.android.cts.net.hostside; + +import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG; + +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.Log; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.Assume; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.util.ArrayList; +import java.util.Collections; + +public class RequiredPropertiesRule extends BeforeAfterRule { + + private static ArraySet mRequiredProperties; + + @Override + public void onBefore(Statement base, Description description) { + mRequiredProperties = getAllRequiredProperties(description); + + final String testName = description.getClassName() + "#" + description.getMethodName(); + assertTestIsValid(testName, mRequiredProperties); + Log.i(TAG, "Running test " + testName + " with required properties: " + + propertiesToString(mRequiredProperties)); + } + + private ArraySet getAllRequiredProperties(Description description) { + final ArraySet allRequiredProperties = new ArraySet<>(); + RequiredProperties requiredProperties = description.getAnnotation(RequiredProperties.class); + if (requiredProperties != null) { + Collections.addAll(allRequiredProperties, requiredProperties.value()); + } + + for (Class clazz = description.getTestClass(); + clazz != null; clazz = clazz.getSuperclass()) { + requiredProperties = clazz.getDeclaredAnnotation(RequiredProperties.class); + if (requiredProperties == null) { + continue; + } + for (Property requiredProperty : requiredProperties.value()) { + for (Property p : Property.values()) { + if (p.getValue() == ~requiredProperty.getValue() + && allRequiredProperties.contains(p)) { + continue; + } + } + allRequiredProperties.add(requiredProperty); + } + } + return allRequiredProperties; + } + + private void assertTestIsValid(String testName, ArraySet requiredProperies) { + if (requiredProperies == null) { + return; + } + final ArrayList unsupportedProperties = new ArrayList<>(); + for (Property property : requiredProperies) { + if (!property.isSupported()) { + unsupportedProperties.add(property); + } + } + Assume.assumeTrue("Unsupported properties: " + + propertiesToString(unsupportedProperties), unsupportedProperties.isEmpty()); + } + + public static ArraySet getRequiredProperties() { + return mRequiredProperties; + } + + private static String propertiesToString(Iterable properties) { + return "[" + TextUtils.join(",", properties) + "]"; + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java new file mode 100755 index 0000000000..81a431cfda --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -0,0 +1,1165 @@ +/* + * Copyright (C) 2014 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 com.android.cts.net.hostside; + +import static android.os.Process.INVALID_UID; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.ECONNABORTED; +import static android.system.OsConstants.IPPROTO_ICMP; +import static android.system.OsConstants.IPPROTO_ICMPV6; +import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.POLLIN; +import static android.system.OsConstants.SOCK_DGRAM; + +import android.annotation.Nullable; +import android.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.Proxy; +import android.net.ProxyInfo; +import android.net.Uri; +import android.net.VpnService; +import android.net.wifi.WifiManager; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.os.SystemProperties; +import android.provider.Settings; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiSelector; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.system.StructPollfd; +import android.test.InstrumentationTestCase; +import android.test.MoreAsserts; +import android.text.TextUtils; +import android.util.Log; + +import com.android.compatibility.common.util.BlockingBroadcastReceiver; + +import java.io.Closeable; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Tests for the VpnService API. + * + * These tests establish a VPN via the VpnService API, and have the service reflect the packets back + * to the device without causing any network traffic. This allows testing the local VPN data path + * without a network connection or a VPN server. + * + * Note: in Lollipop, VPN functionality relies on kernel support for UID-based routing. If these + * tests fail, it may be due to the lack of kernel support. The necessary patches can be + * cherry-picked from the Android common kernel trees: + * + * android-3.10: + * https://android-review.googlesource.com/#/c/99220/ + * https://android-review.googlesource.com/#/c/100545/ + * + * android-3.4: + * https://android-review.googlesource.com/#/c/99225/ + * https://android-review.googlesource.com/#/c/100557/ + * + * To ensure that the kernel has the required commits, run the kernel unit + * tests described at: + * + * https://source.android.com/devices/tech/config/kernel_network_tests.html + * + */ +public class VpnTest extends InstrumentationTestCase { + + // These are neither public nor @TestApi. + // TODO: add them to @TestApi. + private static final String PRIVATE_DNS_MODE_SETTING = "private_dns_mode"; + private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname"; + private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; + private static final String PRIVATE_DNS_SPECIFIER_SETTING = "private_dns_specifier"; + + public static String TAG = "VpnTest"; + public static int TIMEOUT_MS = 3 * 1000; + public static int SOCKET_TIMEOUT_MS = 100; + public static String TEST_HOST = "connectivitycheck.gstatic.com"; + + private UiDevice mDevice; + private MyActivity mActivity; + private String mPackageName; + private ConnectivityManager mCM; + private WifiManager mWifiManager; + private RemoteSocketFactoryClient mRemoteSocketFactoryClient; + + Network mNetwork; + NetworkCallback mCallback; + final Object mLock = new Object(); + final Object mLockShutdown = new Object(); + + private String mOldPrivateDnsMode; + private String mOldPrivateDnsSpecifier; + + private boolean supportedHardware() { + final PackageManager pm = getInstrumentation().getContext().getPackageManager(); + return !pm.hasSystemFeature("android.hardware.type.watch"); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + mNetwork = null; + mCallback = null; + storePrivateDnsSetting(); + + mDevice = UiDevice.getInstance(getInstrumentation()); + mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(), + MyActivity.class, null); + mPackageName = mActivity.getPackageName(); + mCM = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE); + mWifiManager = (WifiManager) mActivity.getSystemService(Context.WIFI_SERVICE); + mRemoteSocketFactoryClient = new RemoteSocketFactoryClient(mActivity); + mRemoteSocketFactoryClient.bind(); + mDevice.waitForIdle(); + } + + @Override + public void tearDown() throws Exception { + restorePrivateDnsSetting(); + mRemoteSocketFactoryClient.unbind(); + if (mCallback != null) { + mCM.unregisterNetworkCallback(mCallback); + } + Log.i(TAG, "Stopping VPN"); + stopVpn(); + mActivity.finish(); + super.tearDown(); + } + + private void prepareVpn() throws Exception { + final int REQUEST_ID = 42; + + // Attempt to prepare. + Log.i(TAG, "Preparing VPN"); + Intent intent = VpnService.prepare(mActivity); + + if (intent != null) { + // Start the confirmation dialog and click OK. + mActivity.startActivityForResult(intent, REQUEST_ID); + mDevice.waitForIdle(); + + String packageName = intent.getComponent().getPackageName(); + String resourceIdRegex = "android:id/button1$|button_start_vpn"; + final UiObject okButton = new UiObject(new UiSelector() + .className("android.widget.Button") + .packageName(packageName) + .resourceIdMatches(resourceIdRegex)); + if (okButton.waitForExists(TIMEOUT_MS) == false) { + mActivity.finishActivity(REQUEST_ID); + fail("VpnService.prepare returned an Intent for '" + intent.getComponent() + "' " + + "to display the VPN confirmation dialog, but this test could not find the " + + "button to allow the VPN application to connect. Please ensure that the " + + "component displays a button with a resource ID matching the regexp: '" + + resourceIdRegex + "'."); + } + + // Click the button and wait for RESULT_OK. + okButton.click(); + try { + int result = mActivity.getResult(TIMEOUT_MS); + if (result != MyActivity.RESULT_OK) { + fail("The VPN confirmation dialog did not return RESULT_OK when clicking on " + + "the button matching the regular expression '" + resourceIdRegex + + "' of " + intent.getComponent() + "'. Please ensure that clicking on " + + "that button allows the VPN application to connect. " + + "Return value: " + result); + } + } catch (InterruptedException e) { + fail("VPN confirmation dialog did not return after " + TIMEOUT_MS + "ms"); + } + + // Now we should be prepared. + intent = VpnService.prepare(mActivity); + if (intent != null) { + fail("VpnService.prepare returned non-null even after the VPN dialog " + + intent.getComponent() + "returned RESULT_OK."); + } + } + } + + // TODO: Consider replacing arguments with a Builder. + private void startVpn( + String[] addresses, String[] routes, String allowedApplications, + String disallowedApplications, @Nullable ProxyInfo proxyInfo, + @Nullable ArrayList underlyingNetworks, boolean isAlwaysMetered) throws Exception { + prepareVpn(); + + // Register a callback so we will be notified when our VPN comes up. + final NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + mCallback = new NetworkCallback() { + public void onAvailable(Network network) { + synchronized (mLock) { + Log.i(TAG, "Got available callback for network=" + network); + mNetwork = network; + mLock.notify(); + } + } + }; + mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown. + + // Start the service and wait up for TIMEOUT_MS ms for the VPN to come up. + Intent intent = new Intent(mActivity, MyVpnService.class) + .putExtra(mPackageName + ".cmd", "connect") + .putExtra(mPackageName + ".addresses", TextUtils.join(",", addresses)) + .putExtra(mPackageName + ".routes", TextUtils.join(",", routes)) + .putExtra(mPackageName + ".allowedapplications", allowedApplications) + .putExtra(mPackageName + ".disallowedapplications", disallowedApplications) + .putExtra(mPackageName + ".httpProxy", proxyInfo) + .putParcelableArrayListExtra( + mPackageName + ".underlyingNetworks", underlyingNetworks) + .putExtra(mPackageName + ".isAlwaysMetered", isAlwaysMetered); + + mActivity.startService(intent); + synchronized (mLock) { + if (mNetwork == null) { + Log.i(TAG, "bf mLock"); + mLock.wait(TIMEOUT_MS); + Log.i(TAG, "af mLock"); + } + } + + if (mNetwork == null) { + fail("VPN did not become available after " + TIMEOUT_MS + "ms"); + } + + // Unfortunately, when the available callback fires, the VPN UID ranges are not yet + // configured. Give the system some time to do so. http://b/18436087 . + try { Thread.sleep(3000); } catch(InterruptedException e) {} + } + + private void stopVpn() { + // Register a callback so we will be notified when our VPN comes up. + final NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + mCallback = new NetworkCallback() { + public void onLost(Network network) { + synchronized (mLockShutdown) { + Log.i(TAG, "Got lost callback for network=" + network + + ",mNetwork = " + mNetwork); + if( mNetwork == network){ + mLockShutdown.notify(); + } + } + } + }; + mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown. + // Simply calling mActivity.stopService() won't stop the service, because the system binds + // to the service for the purpose of sending it a revoke command if another VPN comes up, + // and stopping a bound service has no effect. Instead, "start" the service again with an + // Intent that tells it to disconnect. + Intent intent = new Intent(mActivity, MyVpnService.class) + .putExtra(mPackageName + ".cmd", "disconnect"); + mActivity.startService(intent); + synchronized (mLockShutdown) { + try { + Log.i(TAG, "bf mLockShutdown"); + mLockShutdown.wait(TIMEOUT_MS); + Log.i(TAG, "af mLockShutdown"); + } catch(InterruptedException e) {} + } + } + + private static void closeQuietly(Closeable c) { + if (c != null) { + try { + c.close(); + } catch (IOException e) { + } + } + } + + private static void checkPing(String to) throws IOException, ErrnoException { + InetAddress address = InetAddress.getByName(to); + FileDescriptor s; + final int LENGTH = 64; + byte[] packet = new byte[LENGTH]; + byte[] header; + + // Construct a ping packet. + Random random = new Random(); + random.nextBytes(packet); + if (address instanceof Inet6Address) { + s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); + header = new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; + } else { + // Note that this doesn't actually work due to http://b/18558481 . + s = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); + header = new byte[] { (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; + } + System.arraycopy(header, 0, packet, 0, header.length); + + // Send the packet. + int port = random.nextInt(65534) + 1; + Os.connect(s, address, port); + Os.write(s, packet, 0, packet.length); + + // Expect a reply. + StructPollfd pollfd = new StructPollfd(); + pollfd.events = (short) POLLIN; // "error: possible loss of precision" + pollfd.fd = s; + int ret = Os.poll(new StructPollfd[] { pollfd }, SOCKET_TIMEOUT_MS); + assertEquals("Expected reply after sending ping", 1, ret); + + byte[] reply = new byte[LENGTH]; + int read = Os.read(s, reply, 0, LENGTH); + assertEquals(LENGTH, read); + + // Find out what the kernel set the ICMP ID to. + InetSocketAddress local = (InetSocketAddress) Os.getsockname(s); + port = local.getPort(); + packet[4] = (byte) ((port >> 8) & 0xff); + packet[5] = (byte) (port & 0xff); + + // Check the contents. + if (packet[0] == (byte) 0x80) { + packet[0] = (byte) 0x81; + } else { + packet[0] = 0; + } + // Zero out the checksum in the reply so it matches the uninitialized checksum in packet. + reply[2] = reply[3] = 0; + MoreAsserts.assertEquals(packet, reply); + } + + // Writes data to out and checks that it appears identically on in. + private static void writeAndCheckData( + OutputStream out, InputStream in, byte[] data) throws IOException { + out.write(data, 0, data.length); + out.flush(); + + byte[] read = new byte[data.length]; + int bytesRead = 0, totalRead = 0; + do { + bytesRead = in.read(read, totalRead, read.length - totalRead); + totalRead += bytesRead; + } while (bytesRead >= 0 && totalRead < data.length); + assertEquals(totalRead, data.length); + MoreAsserts.assertEquals(data, read); + } + + private void checkTcpReflection(String to, String expectedFrom) throws IOException { + // Exercise TCP over the VPN by "connecting to ourselves". We open a server socket and a + // client socket, and connect the client socket to a remote host, with the port of the + // server socket. The PacketReflector reflects the packets, changing the source addresses + // but not the ports, so our client socket is connected to our server socket, though both + // sockets think their peers are on the "remote" IP address. + + // Open a listening socket. + ServerSocket listen = new ServerSocket(0, 10, InetAddress.getByName("::")); + + // Connect the client socket to it. + InetAddress toAddr = InetAddress.getByName(to); + Socket client = new Socket(); + try { + client.connect(new InetSocketAddress(toAddr, listen.getLocalPort()), SOCKET_TIMEOUT_MS); + if (expectedFrom == null) { + closeQuietly(listen); + closeQuietly(client); + fail("Expected connection to fail, but it succeeded."); + } + } catch (IOException e) { + if (expectedFrom != null) { + closeQuietly(listen); + fail("Expected connection to succeed, but it failed."); + } else { + // We expected the connection to fail, and it did, so there's nothing more to test. + return; + } + } + + // The connection succeeded, and we expected it to succeed. Send some data; if things are + // working, the data will be sent to the VPN, reflected by the PacketReflector, and arrive + // at our server socket. For good measure, send some data in the other direction. + Socket server = null; + try { + // Accept the connection on the server side. + listen.setSoTimeout(SOCKET_TIMEOUT_MS); + server = listen.accept(); + checkConnectionOwnerUidTcp(client); + checkConnectionOwnerUidTcp(server); + // Check that the source and peer addresses are as expected. + assertEquals(expectedFrom, client.getLocalAddress().getHostAddress()); + assertEquals(expectedFrom, server.getLocalAddress().getHostAddress()); + assertEquals( + new InetSocketAddress(toAddr, client.getLocalPort()), + server.getRemoteSocketAddress()); + assertEquals( + new InetSocketAddress(toAddr, server.getLocalPort()), + client.getRemoteSocketAddress()); + + // Now write some data. + final int LENGTH = 32768; + byte[] data = new byte[LENGTH]; + new Random().nextBytes(data); + + // Make sure our writes don't block or time out, because we're single-threaded and can't + // read and write at the same time. + server.setReceiveBufferSize(LENGTH * 2); + client.setSendBufferSize(LENGTH * 2); + client.setSoTimeout(SOCKET_TIMEOUT_MS); + server.setSoTimeout(SOCKET_TIMEOUT_MS); + + // Send some data from client to server, then from server to client. + writeAndCheckData(client.getOutputStream(), server.getInputStream(), data); + writeAndCheckData(server.getOutputStream(), client.getInputStream(), data); + } finally { + closeQuietly(listen); + closeQuietly(client); + closeQuietly(server); + } + } + + private void checkConnectionOwnerUidUdp(DatagramSocket s, boolean expectSuccess) { + final int expectedUid = expectSuccess ? Process.myUid() : INVALID_UID; + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_UDP, loc, rem); + assertEquals(expectedUid, uid); + } + + private void checkConnectionOwnerUidTcp(Socket s) { + final int expectedUid = Process.myUid(); + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem); + assertEquals(expectedUid, uid); + } + + private void checkUdpEcho(String to, String expectedFrom) throws IOException { + DatagramSocket s; + InetAddress address = InetAddress.getByName(to); + if (address instanceof Inet6Address) { // http://b/18094870 + s = new DatagramSocket(0, InetAddress.getByName("::")); + } else { + s = new DatagramSocket(); + } + s.setSoTimeout(SOCKET_TIMEOUT_MS); + + Random random = new Random(); + byte[] data = new byte[random.nextInt(1650)]; + random.nextBytes(data); + DatagramPacket p = new DatagramPacket(data, data.length); + s.connect(address, 7); + + if (expectedFrom != null) { + assertEquals("Unexpected source address: ", + expectedFrom, s.getLocalAddress().getHostAddress()); + } + + try { + if (expectedFrom != null) { + s.send(p); + checkConnectionOwnerUidUdp(s, true); + s.receive(p); + MoreAsserts.assertEquals(data, p.getData()); + } else { + try { + s.send(p); + s.receive(p); + fail("Received unexpected reply"); + } catch (IOException expected) { + checkConnectionOwnerUidUdp(s, false); + } + } + } finally { + s.close(); + } + } + + private void checkTrafficOnVpn() throws Exception { + checkUdpEcho("192.0.2.251", "192.0.2.2"); + checkUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); + checkPing("2001:db8:dead:beef::f00"); + checkTcpReflection("192.0.2.252", "192.0.2.2"); + checkTcpReflection("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe"); + } + + private void checkNoTrafficOnVpn() throws Exception { + checkUdpEcho("192.0.2.251", null); + checkUdpEcho("2001:db8:dead:beef::f00", null); + checkTcpReflection("192.0.2.252", null); + checkTcpReflection("2001:db8:dead:beef::f00", null); + } + + private FileDescriptor openSocketFd(String host, int port, int timeoutMs) throws Exception { + Socket s = new Socket(host, port); + s.setSoTimeout(timeoutMs); + // Dup the filedescriptor so ParcelFileDescriptor's finalizer doesn't garbage collect it + // and cause our fd to become invalid. http://b/35927643 . + FileDescriptor fd = Os.dup(ParcelFileDescriptor.fromSocket(s).getFileDescriptor()); + s.close(); + return fd; + } + + private FileDescriptor openSocketFdInOtherApp( + String host, int port, int timeoutMs) throws Exception { + Log.d(TAG, String.format("Creating test socket in UID=%d, my UID=%d", + mRemoteSocketFactoryClient.getUid(), Os.getuid())); + FileDescriptor fd = mRemoteSocketFactoryClient.openSocketFd(host, port, TIMEOUT_MS); + return fd; + } + + private void sendRequest(FileDescriptor fd, String host) throws Exception { + String request = "GET /generate_204 HTTP/1.1\r\n" + + "Host: " + host + "\r\n" + + "Connection: keep-alive\r\n\r\n"; + byte[] requestBytes = request.getBytes(StandardCharsets.UTF_8); + int ret = Os.write(fd, requestBytes, 0, requestBytes.length); + Log.d(TAG, "Wrote " + ret + "bytes"); + + String expected = "HTTP/1.1 204 No Content\r\n"; + byte[] response = new byte[expected.length()]; + Os.read(fd, response, 0, response.length); + + String actual = new String(response, StandardCharsets.UTF_8); + assertEquals(expected, actual); + Log.d(TAG, "Got response: " + actual); + } + + private void assertSocketStillOpen(FileDescriptor fd, String host) throws Exception { + try { + assertTrue(fd.valid()); + sendRequest(fd, host); + assertTrue(fd.valid()); + } finally { + Os.close(fd); + } + } + + private void assertSocketClosed(FileDescriptor fd, String host) throws Exception { + try { + assertTrue(fd.valid()); + sendRequest(fd, host); + fail("Socket opened before VPN connects should be closed when VPN connects"); + } catch (ErrnoException expected) { + assertEquals(ECONNABORTED, expected.errno); + assertTrue(fd.valid()); + } finally { + Os.close(fd); + } + } + + private ContentResolver getContentResolver() { + return getInstrumentation().getContext().getContentResolver(); + } + + private boolean isPrivateDnsInStrictMode() { + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals( + Settings.Global.getString(getContentResolver(), PRIVATE_DNS_MODE_SETTING)); + } + + private void storePrivateDnsSetting() { + mOldPrivateDnsMode = Settings.Global.getString(getContentResolver(), + PRIVATE_DNS_MODE_SETTING); + mOldPrivateDnsSpecifier = Settings.Global.getString(getContentResolver(), + PRIVATE_DNS_SPECIFIER_SETTING); + } + + private void restorePrivateDnsSetting() { + Settings.Global.putString(getContentResolver(), PRIVATE_DNS_MODE_SETTING, + mOldPrivateDnsMode); + Settings.Global.putString(getContentResolver(), PRIVATE_DNS_SPECIFIER_SETTING, + mOldPrivateDnsSpecifier); + } + + // TODO: replace with CtsNetUtils.awaitPrivateDnsSetting in Q or above. + private void expectPrivateDnsHostname(final String hostname) throws Exception { + final NetworkRequest request = new NetworkRequest.Builder() + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .build(); + final CountDownLatch latch = new CountDownLatch(1); + final NetworkCallback callback = new NetworkCallback() { + @Override + public void onLinkPropertiesChanged(Network network, LinkProperties lp) { + if (network.equals(mNetwork) && + Objects.equals(lp.getPrivateDnsServerName(), hostname)) { + latch.countDown(); + } + } + }; + + mCM.registerNetworkCallback(request, callback); + + try { + assertTrue("Private DNS hostname was not " + hostname + " after " + TIMEOUT_MS + "ms", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } finally { + mCM.unregisterNetworkCallback(callback); + } + } + + private void setAndVerifyPrivateDns(boolean strictMode) throws Exception { + final ContentResolver cr = getInstrumentation().getContext().getContentResolver(); + String privateDnsHostname; + + if (strictMode) { + privateDnsHostname = "vpncts-nx.metric.gstatic.com"; + Settings.Global.putString(cr, PRIVATE_DNS_SPECIFIER_SETTING, privateDnsHostname); + Settings.Global.putString(cr, PRIVATE_DNS_MODE_SETTING, + PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); + } else { + Settings.Global.putString(cr, PRIVATE_DNS_MODE_SETTING, PRIVATE_DNS_MODE_OPPORTUNISTIC); + privateDnsHostname = null; + } + + expectPrivateDnsHostname(privateDnsHostname); + + String randomName = "vpncts-" + new Random().nextInt(1000000000) + "-ds.metric.gstatic.com"; + if (strictMode) { + // Strict mode private DNS is enabled. DNS lookups should fail, because the private DNS + // server name is invalid. + try { + InetAddress.getByName(randomName); + fail("VPN DNS lookup should fail with private DNS enabled"); + } catch (UnknownHostException expected) { + } + } else { + // Strict mode private DNS is disabled. DNS lookup should succeed, because the VPN + // provides no DNS servers, and thus DNS falls through to the default network. + assertNotNull("VPN DNS lookup should succeed with private DNS disabled", + InetAddress.getByName(randomName)); + } + } + + // Tests that strict mode private DNS is used on VPNs. + private void checkStrictModePrivateDns() throws Exception { + final boolean initialMode = isPrivateDnsInStrictMode(); + setAndVerifyPrivateDns(!initialMode); + setAndVerifyPrivateDns(initialMode); + } + + public void testDefault() throws Exception { + if (!supportedHardware()) return; + // If adb TCP port opened, this test may running by adb over network. + // All of socket would be destroyed in this test. So this test don't + // support adb over network, see b/119382723. + if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 + || SystemProperties.getInt("service.adb.tcp.port", -1) > -1) { + Log.i(TAG, "adb is running over the network, so skip this test"); + return; + } + + final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver( + getInstrumentation().getTargetContext(), MyVpnService.ACTION_ESTABLISHED); + receiver.register(); + + FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, + "", "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */); + + final Intent intent = receiver.awaitForBroadcast(TimeUnit.MINUTES.toMillis(1)); + assertNotNull("Failed to receive broadcast from VPN service", intent); + assertFalse("Wrong VpnService#isAlwaysOn", + intent.getBooleanExtra(MyVpnService.EXTRA_ALWAYS_ON, true)); + assertFalse("Wrong VpnService#isLockdownEnabled", + intent.getBooleanExtra(MyVpnService.EXTRA_LOCKDOWN_ENABLED, true)); + + assertSocketClosed(fd, TEST_HOST); + + checkTrafficOnVpn(); + + checkStrictModePrivateDns(); + + receiver.unregisterQuietly(); + } + + public void testAppAllowed() throws Exception { + if (!supportedHardware()) return; + + FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + + // Shell app must not be put in here or it would kill the ADB-over-network use case + String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"192.0.2.0/24", "2001:db8::/32"}, + allowedApps, "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */); + + assertSocketClosed(fd, TEST_HOST); + + checkTrafficOnVpn(); + + checkStrictModePrivateDns(); + } + + public void testAppDisallowed() throws Exception { + if (!supportedHardware()) return; + + FileDescriptor localFd = openSocketFd(TEST_HOST, 80, TIMEOUT_MS); + FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + + String disallowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + // If adb TCP port opened, this test may running by adb over TCP. + // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test, + // see b/119382723. + // Note: The test don't support running adb over network for root device + disallowedApps = disallowedApps + ",com.android.shell"; + Log.i(TAG, "Append shell app to disallowedApps: " + disallowedApps); + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"192.0.2.0/24", "2001:db8::/32"}, + "", disallowedApps, null, null /* underlyingNetworks */, + false /* isAlwaysMetered */); + + assertSocketStillOpen(localFd, TEST_HOST); + assertSocketStillOpen(remoteFd, TEST_HOST); + + checkNoTrafficOnVpn(); + } + + public void testGetConnectionOwnerUidSecurity() throws Exception { + if (!supportedHardware()) return; + + DatagramSocket s; + InetAddress address = InetAddress.getByName("localhost"); + s = new DatagramSocket(); + s.setSoTimeout(SOCKET_TIMEOUT_MS); + s.connect(address, 7); + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + try { + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem); + fail("Only an active VPN app may call this API."); + } catch (SecurityException expected) { + return; + } + } + + public void testSetProxy() throws Exception { + if (!supportedHardware()) return; + ProxyInfo initialProxy = mCM.getDefaultProxy(); + // Receiver for the proxy change broadcast. + BlockingBroadcastReceiver proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver(); + proxyBroadcastReceiver.register(); + + String allowedApps = mPackageName; + ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("10.0.0.1", 8888); + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", + testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */); + + // Check that the proxy change broadcast is received + try { + assertNotNull("No proxy change was broadcast when VPN is connected.", + proxyBroadcastReceiver.awaitForBroadcast()); + } finally { + proxyBroadcastReceiver.unregisterQuietly(); + } + + // Proxy is set correctly in network and in link properties. + assertNetworkHasExpectedProxy(testProxyInfo, mNetwork); + assertDefaultProxy(testProxyInfo); + + proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver(); + proxyBroadcastReceiver.register(); + stopVpn(); + try { + assertNotNull("No proxy change was broadcast when VPN was disconnected.", + proxyBroadcastReceiver.awaitForBroadcast()); + } finally { + proxyBroadcastReceiver.unregisterQuietly(); + } + + // After disconnecting from VPN, the proxy settings are the ones of the initial network. + assertDefaultProxy(initialProxy); + } + + public void testSetProxyDisallowedApps() throws Exception { + if (!supportedHardware()) return; + ProxyInfo initialProxy = mCM.getDefaultProxy(); + + // If adb TCP port opened, this test may running by adb over TCP. + // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test, + // see b/119382723. + // Note: The test don't support running adb over network for root device + String disallowedApps = mPackageName + ",com.android.shell"; + ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("10.0.0.1", 8888); + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, "", disallowedApps, + testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */); + + // The disallowed app does has the proxy configs of the default network. + assertNetworkHasExpectedProxy(initialProxy, mCM.getActiveNetwork()); + assertDefaultProxy(initialProxy); + } + + public void testNoProxy() throws Exception { + if (!supportedHardware()) return; + ProxyInfo initialProxy = mCM.getDefaultProxy(); + BlockingBroadcastReceiver proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver(); + proxyBroadcastReceiver.register(); + String allowedApps = mPackageName; + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + null /* underlyingNetworks */, false /* isAlwaysMetered */); + + try { + assertNotNull("No proxy change was broadcast.", + proxyBroadcastReceiver.awaitForBroadcast()); + } finally { + proxyBroadcastReceiver.unregisterQuietly(); + } + + // The VPN network has no proxy set. + assertNetworkHasExpectedProxy(null, mNetwork); + + proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver(); + proxyBroadcastReceiver.register(); + stopVpn(); + try { + assertNotNull("No proxy change was broadcast.", + proxyBroadcastReceiver.awaitForBroadcast()); + } finally { + proxyBroadcastReceiver.unregisterQuietly(); + } + // After disconnecting from VPN, the proxy settings are the ones of the initial network. + assertDefaultProxy(initialProxy); + assertNetworkHasExpectedProxy(initialProxy, mCM.getActiveNetwork()); + } + + public void testBindToNetworkWithProxy() throws Exception { + if (!supportedHardware()) return; + String allowedApps = mPackageName; + Network initialNetwork = mCM.getActiveNetwork(); + ProxyInfo initialProxy = mCM.getDefaultProxy(); + ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("10.0.0.1", 8888); + // Receiver for the proxy change broadcast. + BlockingBroadcastReceiver proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver(); + proxyBroadcastReceiver.register(); + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", + testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */); + + assertDefaultProxy(testProxyInfo); + mCM.bindProcessToNetwork(initialNetwork); + try { + assertNotNull("No proxy change was broadcast.", + proxyBroadcastReceiver.awaitForBroadcast()); + } finally { + proxyBroadcastReceiver.unregisterQuietly(); + } + assertDefaultProxy(initialProxy); + } + + public void testVpnMeterednessWithNoUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + // VPN is not routing any traffic i.e. its underlying networks is an empty array. + ArrayList underlyingNetworks = new ArrayList<>(); + String allowedApps = mPackageName; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, false /* isAlwaysMetered */); + + // VPN should now be the active network. + assertEquals(mNetwork, mCM.getActiveNetwork()); + assertVpnTransportContains(NetworkCapabilities.TRANSPORT_VPN); + // VPN with no underlying networks should be metered by default. + assertTrue(isNetworkMetered(mNetwork)); + assertTrue(mCM.isActiveNetworkMetered()); + } + + public void testVpnMeterednessWithNullUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + Network underlyingNetwork = mCM.getActiveNetwork(); + if (underlyingNetwork == null) { + Log.i(TAG, "testVpnMeterednessWithNullUnderlyingNetwork cannot execute" + + " unless there is an active network"); + return; + } + // VPN tracks platform default. + ArrayList underlyingNetworks = null; + String allowedApps = mPackageName; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, false /*isAlwaysMetered */); + + // Ensure VPN transports contains underlying network's transports. + assertVpnTransportContains(underlyingNetwork); + // Its meteredness should be same as that of underlying network. + assertEquals(isNetworkMetered(underlyingNetwork), isNetworkMetered(mNetwork)); + // Meteredness based on VPN capabilities and CM#isActiveNetworkMetered should be in sync. + assertEquals(isNetworkMetered(mNetwork), mCM.isActiveNetworkMetered()); + } + + public void testVpnMeterednessWithNonNullUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + Network underlyingNetwork = mCM.getActiveNetwork(); + if (underlyingNetwork == null) { + Log.i(TAG, "testVpnMeterednessWithNonNullUnderlyingNetwork cannot execute" + + " unless there is an active network"); + return; + } + // VPN explicitly declares WiFi to be its underlying network. + ArrayList underlyingNetworks = new ArrayList<>(1); + underlyingNetworks.add(underlyingNetwork); + String allowedApps = mPackageName; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, false /* isAlwaysMetered */); + + // Ensure VPN transports contains underlying network's transports. + assertVpnTransportContains(underlyingNetwork); + // Its meteredness should be same as that of underlying network. + assertEquals(isNetworkMetered(underlyingNetwork), isNetworkMetered(mNetwork)); + // Meteredness based on VPN capabilities and CM#isActiveNetworkMetered should be in sync. + assertEquals(isNetworkMetered(mNetwork), mCM.isActiveNetworkMetered()); + } + + public void testAlwaysMeteredVpnWithNullUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + Network underlyingNetwork = mCM.getActiveNetwork(); + if (underlyingNetwork == null) { + Log.i(TAG, "testAlwaysMeteredVpnWithNullUnderlyingNetwork cannot execute" + + " unless there is an active network"); + return; + } + // VPN tracks platform default. + ArrayList underlyingNetworks = null; + String allowedApps = mPackageName; + boolean isAlwaysMetered = true; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, isAlwaysMetered); + + // VPN's meteredness does not depend on underlying network since it is always metered. + assertTrue(isNetworkMetered(mNetwork)); + assertTrue(mCM.isActiveNetworkMetered()); + } + + public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + Network underlyingNetwork = mCM.getActiveNetwork(); + if (underlyingNetwork == null) { + Log.i(TAG, "testAlwaysMeteredVpnWithNonNullUnderlyingNetwork cannot execute" + + " unless there is an active network"); + return; + } + // VPN explicitly declares its underlying network. + ArrayList underlyingNetworks = new ArrayList<>(1); + underlyingNetworks.add(underlyingNetwork); + String allowedApps = mPackageName; + boolean isAlwaysMetered = true; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, isAlwaysMetered); + + // VPN's meteredness does not depend on underlying network since it is always metered. + assertTrue(isNetworkMetered(mNetwork)); + assertTrue(mCM.isActiveNetworkMetered()); + } + + public void testB141603906() throws Exception { + if (!supportedHardware()) { + return; + } + final InetSocketAddress src = new InetSocketAddress(0); + final InetSocketAddress dst = new InetSocketAddress(0); + final int NUM_THREADS = 8; + final int NUM_SOCKETS = 5000; + final Thread[] threads = new Thread[NUM_THREADS]; + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, + "" /* allowedApplications */, "com.android.shell" /* disallowedApplications */, + null /* proxyInfo */, null /* underlyingNetworks */, false /* isAlwaysMetered */); + + for (int i = 0; i < NUM_THREADS; i++) { + threads[i] = new Thread(() -> { + for (int j = 0; j < NUM_SOCKETS; j++) { + mCM.getConnectionOwnerUid(IPPROTO_TCP, src, dst); + } + }); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + stopVpn(); + } + + private boolean isNetworkMetered(Network network) { + NetworkCapabilities nc = mCM.getNetworkCapabilities(network); + return !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } + + private void assertVpnTransportContains(Network underlyingNetwork) { + int[] transports = mCM.getNetworkCapabilities(underlyingNetwork).getTransportTypes(); + assertVpnTransportContains(transports); + } + + private void assertVpnTransportContains(int... transports) { + NetworkCapabilities vpnCaps = mCM.getNetworkCapabilities(mNetwork); + for (int transport : transports) { + assertTrue(vpnCaps.hasTransport(transport)); + } + } + + private void assertDefaultProxy(ProxyInfo expected) { + assertEquals("Incorrect proxy config.", expected, mCM.getDefaultProxy()); + String expectedHost = expected == null ? null : expected.getHost(); + String expectedPort = expected == null ? null : String.valueOf(expected.getPort()); + assertEquals("Incorrect proxy host system property.", expectedHost, + System.getProperty("http.proxyHost")); + assertEquals("Incorrect proxy port system property.", expectedPort, + System.getProperty("http.proxyPort")); + } + + private void assertNetworkHasExpectedProxy(ProxyInfo expected, Network network) { + LinkProperties lp = mCM.getLinkProperties(network); + assertNotNull("The network link properties object is null.", lp); + assertEquals("Incorrect proxy config.", expected, lp.getHttpProxy()); + + assertEquals(expected, mCM.getProxyForNetwork(network)); + } + + class ProxyChangeBroadcastReceiver extends BlockingBroadcastReceiver { + private boolean received; + + public ProxyChangeBroadcastReceiver() { + super(VpnTest.this.getInstrumentation().getContext(), Proxy.PROXY_CHANGE_ACTION); + received = false; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (!received) { + // Do not call onReceive() more than once. + super.onReceive(context, intent); + } + received = true; + } + } + + /** + * Verifies that DownloadManager has CONNECTIVITY_USE_RESTRICTED_NETWORKS permission that can + * bind socket to VPN when it is in VPN disallowed list but requested downloading app is in VPN + * allowed list. + * See b/165774987. + */ + public void testDownloadWithDownloadManagerDisallowed() throws Exception { + if (!supportedHardware()) return; + + // Start a VPN with DownloadManager package in disallowed list. + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"192.0.2.0/24", "2001:db8::/32"}, + "" /* allowedApps */, "com.android.providers.downloads", null /* proxyInfo */, + null /* underlyingNetworks */, false /* isAlwaysMetered */); + + final Context context = VpnTest.this.getInstrumentation().getContext(); + final DownloadManager dm = context.getSystemService(DownloadManager.class); + final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver(); + try { + context.registerReceiver(receiver, + new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); + + // Enqueue a request and check only one download. + final long id = dm.enqueue(new Request(Uri.parse("https://www.google.com"))); + assertEquals(1, getTotalNumberDownloads(dm, new Query())); + assertEquals(1, getTotalNumberDownloads(dm, new Query().setFilterById(id))); + + // Wait for download complete and check status. + assertEquals(id, receiver.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertEquals(1, getTotalNumberDownloads(dm, + new Query().setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL))); + + // Remove download. + assertEquals(1, dm.remove(id)); + assertEquals(0, getTotalNumberDownloads(dm, new Query())); + } finally { + context.unregisterReceiver(receiver); + } + } + + private static int getTotalNumberDownloads(final DownloadManager dm, final Query query) { + try (Cursor cursor = dm.query(query)) { return cursor.getCount(); } + } + + private static class DownloadCompleteReceiver extends BroadcastReceiver { + private final CompletableFuture future = new CompletableFuture<>(); + + @Override + public void onReceive(Context context, Intent intent) { + future.complete(intent.getLongExtra( + DownloadManager.EXTRA_DOWNLOAD_ID, -1 /* defaultValue */)); + } + + public long get(long timeout, TimeUnit unit) throws Exception { + return future.get(timeout, unit); + } + } +} diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp new file mode 100644 index 0000000000..8e279311a8 --- /dev/null +++ b/tests/cts/hostside/app2/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2016 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. +// + +android_test_helper_app { + name: "CtsHostsideNetworkTestsApp2", + defaults: ["cts_support_defaults"], + sdk_version: "current", + static_libs: ["CtsHostsideNetworkTestsAidl"], + srcs: ["src/**/*.java"], + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "general-tests", + ], + certificate: ":cts-net-app", +} diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml new file mode 100644 index 0000000000..ad270b3170 --- /dev/null +++ b/tests/cts/hostside/app2/AndroidManifest.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cts/hostside/app2/res/drawable/ic_notification.png b/tests/cts/hostside/app2/res/drawable/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..6ae570b4db4da165fada0650079061cb56aa8793 GIT binary patch literal 3777 zcmV;y4nFaTP)<5O4m2Hnvj*wc>ks?G z2G34C@E_ZLZKgG#r9IGlue=QUde;x0&cEf}-^JJmm+rK2tvlk-Rei)^T;Dlp|J|h@ z^m+gPwY2+#Jp|DwyKZ{cr#D)vv<3?RYtkmp$A#M_scJjzTH4xNh5}{7UZcq4B{H*L zAbrC#D0V!CY|}%?3-2R&-YsP7u%Pze_gYZ0)AsviO2LRhr%`gXg-+>Ct8*6~gsguK z#ocE}dD{&cL$1D$Nahk|Gw0#KoMAkBPxj3Dsk7U=vbNLla&#_VG^p9{qm1aoZlq4X z^Cs&0V~Cl@NMI=QP@|Gq(}0&K#8vp=Jm%rVTTdK%=7x@k&di334&4O8uk5(sqd^Q_ zOZx$2J`a)j^giNo8q0Qj^e(~C7xVD# zBMhtX326_pU@IUwD0ag^9a#=8X??`t?%Wdb?IN60 zFU5H#fIN^s2jJ9e3jX;b?0@8i_S^2*cGVr<-K)a(^8r}3&jQ&SjUUMBc)a)44{XT~ zKlMpG`6^Vs@6j}zdy)c%>BZfb9XR-87LGiduL=0*b8mD$U4(;==VR}EFYLPIfh||3 zVcW$8=vDXN$A_m-+HT1LV5F7&O24xA)DN34P8+uS&iwD&Z+kG?ZaSg;#ynhn(2U*J z7o+`-JNDe0iH`fTu;=b9%D4zSZ+fEb+6-*E=!SLQIb-b!2XtJJqGfL^@-~|yYrPpH zDuess3cWG!rE%Avcd_4iaawO{mmOL!+JO`WtzC|EbjIc@u9RgrY^6+ZxiSr#F1cYt z*Hq9wXgcGBHOK8yeb|PmV}+va76iZo87&rwFVj~C$j1Kv_X7KXwa2GL)gQN2uQ_Rr zhSN5hW^6noMAKP&G@o-s%Q+|V$!I=1Src^QDMwA@bUv3^5H)(M zP^vZL9y0!PAE}eBBhux_lLe!GGl+Xg{I`3M7LZhacjB4%!EKjCzGcV#KFV+LG)%3v zI;ND*|Lq0kdwSp$Z!~oArwQR+?+d_E@5L2TL6@q&1o#akT(Z zndVr!!swDu+<3e83k&~x@|pkk9~tTM6EElYY`)@nyKIl?+yR4VyX-Qw{l?suT{mZ{ z*(PoMemYaUV^Z&mLId~RH+*9o4=!dxr6P}$-AS-}?D(>a?2OwLAAWHcK?T+U+_$Bd0H+2K@Gd&HJ$ zK4(wOI~lDPoJn0=(R6Yu>N}^R`de32>~TT)&M7Evb3nlsA@Vj^BY(3Mxh3+qS|V?Y zS)T$?52Vx^VMU=nGe2_lzTo7E%M}fVOhKEu=9<*CMoe%rr^|hz&R+)vpssD+Kj*gE zoK!aQ8D*m(lI!@IMw`3ro0N>T_T||djOZc8DBfj?(%oh#?=Xj|!-6<&si6w1GO7+M zjn0?06YqERQKxVl%Y9R1t~VwM89`oa2yq!7%hL^**`d070_B|8lzKkH2G1srz%hZc z-vXeM1z>wp(O|$R*76~zMvKYkFkT_Lsj1cWuKetqCS~lPR({m>_c<1>YplWIm~qkCnxIgemozS;3?C_$TSDl-C+CIqbEq zCX_fsCQz<-ZtC0-|1ux|s}J~mn%!!9EOm_mLm5F*l>q_Z!7FrBUUG$9S?XE?CUcz; zh+W9jM#wgUl9lC@J$q4J1?cr4@Xv zC^A5pf=2*!cl(LQ$CD~ia@YZ9!d8g!mvYVuy$9F>H9HpkDSMspa7w*ClU!#&57I|; z9v8DiM&-*^2@8_z^qKT#L$FoI-DHfStwL-&CZ*-U8CoX1!GAY~{=Iqo3RiC*M)Te% zDA$;id>WDp5j6|+5t7PNb`n)s9@BLZQJyhcxS9^XxCB1Yr?ld~MQ3=p1X3Q^FgE&dXYoUL}|I+_tJ#&iuIehCwfO`ksO(*Xf!Iu!m%R*UUE zc`c7&Ga^~VLu3w@nG>d4k)*QEOswKDiUvL{1B{Tj(Hi$2Uqb!HG^7>#;p~OOc=P79 zChz@$_w>BNkrTU-kg)*u>vM4V`UyzNjY!!H2ml`u>60+if7F(xV!hNvs&+;T+b6~v ziUmjwjtWJ?|2$v-+3W20CROujrO0C?6cJe*mZud`l`u20g3C~UKtrST7I@TsLlfxT zpRS;)H68_3;ka<=6nb9w;KbH)cE1ndBo=P5nsyo76C}JWC3gl zkZ|)7R`ck4S(P$IA`2jqf51ZY)h7cRWNo2CvsxUsCspx?K0I1%ar*#-=vF6`StTc| z=4yI_)CgJY`T+DB+q^gKoI_DyrXeZ{?DVDlFg` zpxfl1z|Bn{y0R*zXb@;9=AXddKX3q-^M_`)IJ8MCx%4Gm#FcQdJVTF}6FhpYq}WnU z=NLKl1}m|d&F23FK!4Ld>HZ1%bv}6cs{5C~`|aAz?+}rx&kisGV2EW3a}9tc@#FJY zx+*F7)U^UyW)lFh;cgcft)T+~P9Ff+?0|L;|Asv#_;@FTt0OHFyh%M6701yR@XhM%MVnb5s%)PZNAfoq&3TkEL;fEkdEzkO3~En?B5L zajKC}rsGQW5L2Ls5XCsgGjK$Mq}V!vK&jd0me&$r8_e+V>GgNy^9cdSsd^Ux+r$@t z1`w6QLrks(A{4f8U!q&(C*hQd2|!A{fWF%Z@g;^#fY_p$Li%998y97*V@6yFM;%+J zhsf-S2uK>I_E@4@oT74;usf*43Le-QL9+r%l?Z3fANpB7e+8iO*8mv2eobTfXUy;&SFz++{h$;;GQAtS4_Vq$VFUj<3*L;5#51F~?1#Tb8y zL3@D2^r?3g|EcHFi5)Jpzy7AMc}bkC!m1Ad^#NOjxKa*H%yGz41rWbaX%y#4_d^YU zS3S>YfW0Mvhat=L#{BRx@Jk$z@C-IFEC35cE8XDk!zmX^g+n5;Y^E!#yej1?&-!I4 z*7HL{U55VF4Vm_IpYfm03*qrZemoxgSt^x&P}~w2oLp(ECMgBm2W%DCBg%Eu?1ZCOGtXt46rC#51~p{aY#0c z`aGt9nm3n+@Jucu(`^teae7Gt>w0my z;V&Ln!n%O8UVy%9OsOf&5Lax5m^@RWkO0AQV|HnW#zhVNjC5 z&QD@+Hdsah<~Spv&<&Cz7l@0TATD-5La7szST==8DxV7Zs{bJOfUMjT(h?8E<+;)F z!Txoy+^oY-%AX;UzQ^EytyJMjQ?gy>e-5`rU&AY8B9^Q)L6}^K6uFI2=56;OsRLQ@nJU84FF?X+ZtcpuQhaRJtXG zD#wv5j=}th(WK?Nm^^zVY^Qx)p{04H1a1Eam)SPchpC-reSv9~ID z7K0BUr^!7&reGoynL827)AeXt>rs#sFm=wD@_tQ^l)HO)28`%k7(JSHS2WS3T=>T6 zVPTl%AOoP_((0%B#uRYWQ3QY;PNAthc*p87(-(~w_s@@*G!OGdG2?n@Z;MccKEjmj zCWXg%N1Cl3@FMN^ww3wT!Rl3Nx>pqNmCoPihHyw&svtvB z==>~sl?Ri&TGShnW^;H!%-D(l5HGuff;fK;5F6Qtr8xR6OL27eUe15#ClL1K1%cH| ruJZJht7Zygm5zVW`osRPe+>Ii)X|D+8y7?e00000NkvXXu0mjf#L-I; literal 0 HcmV?d00001 diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java new file mode 100644 index 0000000000..351733edc5 --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; + +import com.android.cts.net.hostside.INetworkStateObserver; + +public final class Common { + + static final String TAG = "CtsNetApp2"; + + // Constants below must match values defined on app's + // AbstractRestrictBackgroundNetworkTestCase.java + static final String MANIFEST_RECEIVER = "ManifestReceiver"; + static final String DYNAMIC_RECEIVER = "DynamicReceiver"; + + static final String ACTION_RECEIVER_READY = + "com.android.cts.net.hostside.app2.action.RECEIVER_READY"; + static final String ACTION_FINISH_ACTIVITY = + "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY"; + static final String ACTION_SHOW_TOAST = + "com.android.cts.net.hostside.app2.action.SHOW_TOAST"; + + static final String NOTIFICATION_TYPE_CONTENT = "CONTENT"; + static final String NOTIFICATION_TYPE_DELETE = "DELETE"; + static final String NOTIFICATION_TYPE_FULL_SCREEN = "FULL_SCREEN"; + static final String NOTIFICATION_TYPE_BUNDLE = "BUNDLE"; + static final String NOTIFICATION_TYPE_ACTION = "ACTION"; + static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE"; + static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT"; + + static final String TEST_PKG = "com.android.cts.net.hostside"; + static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; + + static int getUid(Context context) { + final String packageName = context.getPackageName(); + try { + return context.getPackageManager().getPackageUid(packageName, 0); + } catch (NameNotFoundException e) { + throw new IllegalStateException("Could not get UID for " + packageName, e); + } + } + + static void notifyNetworkStateObserver(Context context, Intent intent) { + if (intent == null) { + return; + } + final Bundle extras = intent.getExtras(); + if (extras == null) { + return; + } + final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface( + extras.getBinder(KEY_NETWORK_STATE_OBSERVER)); + if (observer != null) { + try { + if (!observer.isForeground()) { + Log.e(TAG, "App didn't come to foreground"); + observer.onNetworkStateChecked(null); + return; + } + } catch (RemoteException e) { + Log.e(TAG, "Error occurred while reading the proc state: " + e); + } + AsyncTask.execute(() -> { + try { + observer.onNetworkStateChecked( + MyBroadcastReceiver.checkNetworkStatus(context)); + } catch (RemoteException e) { + Log.e(TAG, "Error occurred while notifying the observer: " + e); + } + }); + } + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java new file mode 100644 index 0000000000..286cc2fb56 --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_ACTIVITY; +import static com.android.cts.net.hostside.app2.Common.TAG; +import static com.android.cts.net.hostside.app2.Common.TEST_PKG; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; + +import com.android.cts.net.hostside.INetworkStateObserver; + +/** + * Activity used to bring process to foreground. + */ +public class MyActivity extends Activity { + + private BroadcastReceiver finishCommandReceiver = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.d(TAG, "MyActivity.onCreate()"); + Common.notifyNetworkStateObserver(this, getIntent()); + finishCommandReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "Finishing MyActivity"); + MyActivity.this.finish(); + } + }; + registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY)); + } + + @Override + public void finish() { + if (finishCommandReceiver != null) { + unregisterReceiver(finishCommandReceiver); + } + super.finish(); + } + + @Override + protected void onStart() { + super.onStart(); + Log.d(TAG, "MyActivity.onStart()"); + } + + @Override + protected void onDestroy() { + Log.d(TAG, "MyActivity.onDestroy()"); + super.onDestroy(); + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java new file mode 100644 index 0000000000..aa54075783 --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; + +import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; +import static com.android.cts.net.hostside.app2.Common.ACTION_SHOW_TOAST; +import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_REMOTE_INPUT; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_BUNDLE; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_CONTENT; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_DELETE; +import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_FULL_SCREEN; +import static com.android.cts.net.hostside.app2.Common.TAG; +import static com.android.cts.net.hostside.app2.Common.getUid; + +import android.app.Notification; +import android.app.Notification.Action; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.RemoteInput; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.util.Log; +import android.widget.Toast; + +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * Receiver used to: + *

      + *
    1. Count number of {@code RESTRICT_BACKGROUND_CHANGED} broadcasts received. + *
    2. Show a toast. + *
    + */ +public class MyBroadcastReceiver extends BroadcastReceiver { + + private static final int NETWORK_TIMEOUT_MS = 5 * 1000; + + private final String mName; + + public MyBroadcastReceiver() { + this(MANIFEST_RECEIVER); + } + + MyBroadcastReceiver(String name) { + Log.d(TAG, "Constructing MyBroadcastReceiver named " + name); + mName = name; + } + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceive() for " + mName + ": " + intent); + final String action = intent.getAction(); + switch (action) { + case ACTION_RESTRICT_BACKGROUND_CHANGED: + increaseCounter(context, action); + break; + case ACTION_RECEIVER_READY: + final String message = mName + " is ready to rumble"; + Log.d(TAG, message); + setResultData(message); + break; + case ACTION_SHOW_TOAST: + showToast(context); + break; + default: + Log.e(TAG, "received unexpected action: " + action); + } + } + + @Override + public String toString() { + return "[MyBroadcastReceiver: mName=" + mName + "]"; + } + + private void increaseCounter(Context context, String action) { + final SharedPreferences prefs = context.getApplicationContext() + .getSharedPreferences(mName, Context.MODE_PRIVATE); + final int value = prefs.getInt(action, 0) + 1; + Log.d(TAG, "increaseCounter('" + action + "'): setting '" + mName + "' to " + value); + prefs.edit().putInt(action, value).apply(); + } + + static int getCounter(Context context, String action, String receiverName) { + final SharedPreferences prefs = context.getSharedPreferences(receiverName, + Context.MODE_PRIVATE); + final int value = prefs.getInt(action, 0); + Log.d(TAG, "getCounter('" + action + "', '" + receiverName + "'): " + value); + return value; + } + + static String getRestrictBackgroundStatus(Context context) { + final ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + final int apiStatus = cm.getRestrictBackgroundStatus(); + Log.d(TAG, "getRestrictBackgroundStatus: returning " + apiStatus); + return String.valueOf(apiStatus); + } + + private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s"; + /** + * Checks whether the network is available and return a string which can then be send as a + * result data for the ordered broadcast. + * + *

    + * The string has the following format: + * + *

    
    +     * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo
    +     * 
    + * + *

    Where: + * + *

      + *
    • {@code NetinfoState}: enum value of {@link NetworkInfo.State}. + *
    • {@code NetinfoDetailedState}: enum value of {@link NetworkInfo.DetailedState}. + *
    • {@code RealConnectionCheck}: boolean value of a real connection check (i.e., an attempt + * to access an external website. + *
    • {@code RealConnectionCheckDetails}: if HTTP output core or exception string of the real + * connection attempt + *
    • {@code Netinfo}: string representation of the {@link NetworkInfo}. + *
    + * + * For example, if the connection was established fine, the result would be something like: + *

    
    +     * CONNECTED|CONNECTED|true|200|[type: WIFI[], state: CONNECTED/CONNECTED, reason: ...]
    +     * 
    + * + */ + // TODO: now that it uses Binder, it counl return a Bundle with the data parts instead... + static String checkNetworkStatus(Context context) { + final ConnectivityManager cm = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + // TODO: connect to a hostside server instead + final String address = "http://example.com"; + final NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + Log.d(TAG, "Running checkNetworkStatus() on thread " + + Thread.currentThread().getName() + " for UID " + getUid(context) + + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address); + boolean checkStatus = false; + String checkDetails = "N/A"; + try { + final URL url = new URL(address); + final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setReadTimeout(NETWORK_TIMEOUT_MS); + conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2); + conn.setRequestMethod("GET"); + conn.setDoInput(true); + conn.connect(); + final int response = conn.getResponseCode(); + checkStatus = true; + checkDetails = "HTTP response for " + address + ": " + response; + } catch (Exception e) { + checkStatus = false; + checkDetails = "Exception getting " + address + ": " + e; + } + Log.d(TAG, checkDetails); + final String state, detailedState; + if (networkInfo != null) { + state = networkInfo.getState().name(); + detailedState = networkInfo.getDetailedState().name(); + } else { + state = detailedState = "null"; + } + final String status = String.format(NETWORK_STATUS_TEMPLATE, state, detailedState, + Boolean.valueOf(checkStatus), checkDetails, networkInfo); + Log.d(TAG, "Offering " + status); + return status; + } + + /** + * Sends a system notification containing actions with pending intents to launch the app's + * main activitiy or service. + */ + static void sendNotification(Context context, String channelId, int notificationId, + String notificationType ) { + Log.d(TAG, "sendNotification: id=" + notificationId + ", type=" + notificationType); + final Intent serviceIntent = new Intent(context, MyService.class); + final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, + notificationId); + final Bundle bundle = new Bundle(); + bundle.putCharSequence("parcelable", "I am not"); + + final Notification.Builder builder = new Notification.Builder(context, channelId) + .setSmallIcon(R.drawable.ic_notification); + + Action action = null; + switch (notificationType) { + case NOTIFICATION_TYPE_CONTENT: + builder + .setContentTitle("Light, Cameras...") + .setContentIntent(pendingIntent); + break; + case NOTIFICATION_TYPE_DELETE: + builder.setDeleteIntent(pendingIntent); + break; + case NOTIFICATION_TYPE_FULL_SCREEN: + builder.setFullScreenIntent(pendingIntent, true); + break; + case NOTIFICATION_TYPE_BUNDLE: + bundle.putParcelable("Magnum P.I. (Pending Intent)", pendingIntent); + builder.setExtras(bundle); + break; + case NOTIFICATION_TYPE_ACTION: + action = new Action.Builder( + R.drawable.ic_notification, "ACTION", pendingIntent) + .build(); + builder.addAction(action); + break; + case NOTIFICATION_TYPE_ACTION_BUNDLE: + bundle.putParcelable("Magnum A.P.I. (Action Pending Intent)", pendingIntent); + action = new Action.Builder( + R.drawable.ic_notification, "ACTION WITH BUNDLE", null) + .addExtras(bundle) + .build(); + builder.addAction(action); + break; + case NOTIFICATION_TYPE_ACTION_REMOTE_INPUT: + bundle.putParcelable("Magnum R.I. (Remote Input)", null); + final RemoteInput remoteInput = new RemoteInput.Builder("RI") + .addExtras(bundle) + .build(); + action = new Action.Builder( + R.drawable.ic_notification, "ACTION WITH REMOTE INPUT", pendingIntent) + .addRemoteInput(remoteInput) + .build(); + builder.addAction(action); + break; + default: + Log.e(TAG, "Unknown notification type: " + notificationType); + return; + } + + final Notification notification = builder.build(); + ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) + .notify(notificationId, notification); + } + + private void showToast(Context context) { + Toast.makeText(context, "Toast from CTS test", Toast.LENGTH_SHORT).show(); + setResultData("Shown"); + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java new file mode 100644 index 0000000000..ff4ba656b1 --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import static com.android.cts.net.hostside.app2.Common.TAG; +import static com.android.cts.net.hostside.app2.Common.TEST_PKG; + +import android.R; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.cts.net.hostside.INetworkStateObserver; + +/** + * Service used to change app state to FOREGROUND_SERVICE. + */ +public class MyForegroundService extends Service { + private static final String NOTIFICATION_CHANNEL_ID = "cts/MyForegroundService"; + private static final int FLAG_START_FOREGROUND = 1; + private static final int FLAG_STOP_FOREGROUND = 2; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.v(TAG, "MyForegroundService.onStartCommand(): " + intent); + NotificationManager notificationManager = getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(new NotificationChannel( + NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, + NotificationManager.IMPORTANCE_DEFAULT)); + switch (intent.getFlags()) { + case FLAG_START_FOREGROUND: + Log.d(TAG, "Starting foreground"); + startForeground(42, new Notification.Builder(this, NOTIFICATION_CHANNEL_ID) + .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine + .build()); + Common.notifyNetworkStateObserver(this, intent); + break; + case FLAG_STOP_FOREGROUND: + Log.d(TAG, "Stopping foreground"); + stopForeground(true); + break; + default: + Log.wtf(TAG, "Invalid flag on intent " + intent); + } + return START_STICKY; + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java new file mode 100644 index 0000000000..590e17e5e5 --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; + +import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; +import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER; +import static com.android.cts.net.hostside.app2.Common.TAG; + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.cts.net.hostside.IMyService; +import com.android.cts.net.hostside.INetworkCallback; + +/** + * Service used to dynamically register a broadcast receiver. + */ +public class MyService extends Service { + private static final String NOTIFICATION_CHANNEL_ID = "MyService"; + + ConnectivityManager mCm; + + private MyBroadcastReceiver mReceiver; + private ConnectivityManager.NetworkCallback mNetworkCallback; + + // TODO: move MyBroadcast static functions here - they were kept there to make git diff easier. + + private IMyService.Stub mBinder = + new IMyService.Stub() { + + @Override + public void registerBroadcastReceiver() { + if (mReceiver != null) { + Log.d(TAG, "receiver already registered: " + mReceiver); + return; + } + final Context context = getApplicationContext(); + mReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER); + context.registerReceiver(mReceiver, new IntentFilter(ACTION_RECEIVER_READY)); + context.registerReceiver(mReceiver, + new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED)); + Log.d(TAG, "receiver registered"); + } + + @Override + public int getCounters(String receiverName, String action) { + return MyBroadcastReceiver.getCounter(getApplicationContext(), action, receiverName); + } + + @Override + public String checkNetworkStatus() { + return MyBroadcastReceiver.checkNetworkStatus(getApplicationContext()); + } + + @Override + public String getRestrictBackgroundStatus() { + return MyBroadcastReceiver.getRestrictBackgroundStatus(getApplicationContext()); + } + + @Override + public void sendNotification(int notificationId, String notificationType) { + MyBroadcastReceiver .sendNotification(getApplicationContext(), NOTIFICATION_CHANNEL_ID, + notificationId, notificationType); + } + + @Override + public void registerNetworkCallback(INetworkCallback cb) { + if (mNetworkCallback != null) { + Log.d(TAG, "unregister previous network callback: " + mNetworkCallback); + unregisterNetworkCallback(); + } + Log.d(TAG, "registering network callback"); + + mNetworkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onBlockedStatusChanged(Network network, boolean blocked) { + try { + cb.onBlockedStatusChanged(network, blocked); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onBlockedStatusChanged: " + e); + unregisterNetworkCallback(); + } + } + + @Override + public void onAvailable(Network network) { + try { + cb.onAvailable(network); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onAvailable: " + e); + unregisterNetworkCallback(); + } + } + + @Override + public void onLost(Network network) { + try { + cb.onLost(network); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onLost: " + e); + unregisterNetworkCallback(); + } + } + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities cap) { + try { + cb.onCapabilitiesChanged(network, cap); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onCapabilitiesChanged: " + e); + unregisterNetworkCallback(); + } + } + }; + mCm.registerNetworkCallback(makeWifiNetworkRequest(), mNetworkCallback); + try { + cb.asBinder().linkToDeath(() -> unregisterNetworkCallback(), 0); + } catch (RemoteException e) { + unregisterNetworkCallback(); + } + } + + @Override + public void unregisterNetworkCallback() { + Log.d(TAG, "unregistering network callback"); + if (mNetworkCallback != null) { + mCm.unregisterNetworkCallback(mNetworkCallback); + mNetworkCallback = null; + } + } + }; + + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + public void onCreate() { + final Context context = getApplicationContext(); + ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) + .createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID, + NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT)); + mCm = (ConnectivityManager) getApplicationContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + } + + @Override + public void onDestroy() { + final Context context = getApplicationContext(); + ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) + .deleteNotificationChannel(NOTIFICATION_CHANNEL_ID); + if (mReceiver != null) { + Log.d(TAG, "onDestroy(): unregistering " + mReceiver); + getApplicationContext().unregisterReceiver(mReceiver); + } + + super.onDestroy(); + } +} diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java new file mode 100644 index 0000000000..b1b7d77ae1 --- /dev/null +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net.hostside.app2; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.util.Log; + +import com.android.cts.net.hostside.IRemoteSocketFactory; + +import java.net.Socket; + + +public class RemoteSocketFactoryService extends Service { + + private static final String TAG = RemoteSocketFactoryService.class.getSimpleName(); + + private IRemoteSocketFactory.Stub mBinder = new IRemoteSocketFactory.Stub() { + @Override + public ParcelFileDescriptor openSocketFd(String host, int port, int timeoutMs) { + try { + Socket s = new Socket(host, port); + s.setSoTimeout(timeoutMs); + return ParcelFileDescriptor.fromSocket(s); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public String getPackageName() { + return RemoteSocketFactoryService.this.getPackageName(); + } + + @Override + public int getUid() { + return Process.myUid(); + } + }; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } +} diff --git a/tests/cts/hostside/certs/Android.bp b/tests/cts/hostside/certs/Android.bp new file mode 100644 index 0000000000..ab4cf340d0 --- /dev/null +++ b/tests/cts/hostside/certs/Android.bp @@ -0,0 +1,4 @@ +android_app_certificate { + name: "cts-net-app", + certificate: "cts-net-app", +} diff --git a/tests/cts/hostside/certs/README b/tests/cts/hostside/certs/README new file mode 100644 index 0000000000..b660a82dc8 --- /dev/null +++ b/tests/cts/hostside/certs/README @@ -0,0 +1,2 @@ +# Generated with: +development/tools/make_key cts-net-app '/CN=cts-net-app' diff --git a/tests/cts/hostside/certs/cts-net-app.pk8 b/tests/cts/hostside/certs/cts-net-app.pk8 new file mode 100644 index 0000000000000000000000000000000000000000..1703e4ee340b7c7ab818097cefbbf95fb86f3747 GIT binary patch literal 1219 zcmV;!1U&mNf&{+;0RS)!1_>&LNQUrsW5^Br2+u}0)hbn0N#A&vRMl( z)K7&#gN-YqA(ePu&=E2o$Vjep&N^#?J+IQe_UD^8vWC4%PBxI-ME{s%p~72w0ZU@; zaXKTG43uCz5lGMl@ha*FIBFHPR{XV|cKf1`B_%f8?!Ujr zt-{>0C4_u?`%vIYq{z#o&|wc%#UbbC#EF~*3eXtI#Pu@b#2AEmesXH!;BA|+2B81W z!Zu8OMUNETxR$5$c?)i;hZYR4J*6YT$pCc&@}h3pQGsU#%?m@^a{>ba009Dm0RaHk zc>v0s8?m!kl+%O!>N@ze<-9;f(^2U#XFDru6^Rdi7GW7mTF+$(jvu=f&c6qwe0xQc z-YV8)osrJ&&LK`cr5XVSk|=+5h9S}kmdcGs++ig(JtFrKB&6at^XSEN7gbjf(l>>Q zW5q!7d>b5VnALd8DRw?XvqUfpAAaDQ)mpy#BAh*U&nzY5KA?dt?&F!_gTW_hO&aG? zFz!^L2yHTF#V@X&LqF|!Q4`{WkX^!rOP6AzE3-+ExKAD|AnK7^^w$v-bH;VQMuXQG z^wqpIj+;*3h|p36xkZ4_k2@ee;ehD~XA7iWt0O?}W4hlp!7008eHpZ&=5xtRJbcFmSVJik5H=O_+OcDr64K?)M2Tx(p#1Bj!W}szK*F#xG5_9njbtuN zvAj31ay#p;XUyF~^2T$(v1bpJYKX(0Hjh1=a0St$<@BH?5pD>(7CE0M%ug3w#-4iu zfq)5bl2l+u5>xWKztT8zHPHfrfdIA^X{1GXSD$}V6aG5WdD+aZ)3UOU)PA-Q{> z3qB8AR`51~p;B8g;f0T+gwBF{nn#RZ*xS3do08bdRK^ktwT+BuQ7nn@r4GbJz7x8u zX+HvifdH9pz)+xQ>TMce;8KGy?O90aj>ISS3b7$HM<}?=R_^2Dov>KX=fW4gZ0oL# z4TlXtL8u4+=w-H(!dkS=iZ?}Kj79RMiGFcJL@(@4Kz{D4>0IF9=(5M)>0ajZaHD0q hCv|>6qS`CJYwg-kjl|iF9l$*x resultEntry : + result.getTestResults().entrySet()) { + if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) { + errorBuilder.append(resultEntry.getKey().toString()); + errorBuilder.append(":\n"); + errorBuilder.append(resultEntry.getValue().getStackTrace()); + } + } + throw new AssertionError(errorBuilder.toString()); + } + } + + private static final Pattern UID_PATTERN = + Pattern.compile(".*userId=([0-9]+)$", Pattern.MULTILINE); + + protected int getUid(String packageName) throws DeviceNotAvailableException { + final String output = runCommand("dumpsys package " + packageName); + final Matcher matcher = UID_PATTERN.matcher(output); + while (matcher.find()) { + final String match = matcher.group(1); + return Integer.parseInt(match); + } + throw new RuntimeException("Did not find regexp '" + UID_PATTERN + "' on adb output\n" + + output); + } + + protected String runCommand(String command) throws DeviceNotAvailableException { + Log.d(TAG, "Command: '" + command + "'"); + final String output = getDevice().executeShellCommand(command); + if (DEBUG) Log.v(TAG, "Output: " + output.trim()); + return output; + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java new file mode 100644 index 0000000000..ac28c7ab63 --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net; + +import com.android.ddmlib.Log; +import com.android.tradefed.device.DeviceNotAvailableException; + +public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + + uninstallPackage(TEST_APP2_PKG, false); + installPackage(TEST_APP2_APK); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + uninstallPackage(TEST_APP2_PKG, true); + } + + /************************** + * Data Saver Mode tests. * + **************************/ + + public void testDataSaverMode_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", + "testGetRestrictBackgroundStatus_disabled"); + } + + public void testDataSaverMode_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", + "testGetRestrictBackgroundStatus_whitelisted"); + } + + public void testDataSaverMode_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", + "testGetRestrictBackgroundStatus_enabled"); + } + + public void testDataSaverMode_blacklisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", + "testGetRestrictBackgroundStatus_blacklisted"); + } + + public void testDataSaverMode_reinstall() throws Exception { + final int oldUid = getUid(TEST_APP2_PKG); + + // Make sure whitelist is revoked when package is removed + addRestrictBackgroundWhitelist(oldUid); + + uninstallPackage(TEST_APP2_PKG, true); + assertPackageUninstalled(TEST_APP2_PKG); + assertRestrictBackgroundWhitelist(oldUid, false); + + installPackage(TEST_APP2_APK); + final int newUid = getUid(TEST_APP2_PKG); + assertRestrictBackgroundWhitelist(oldUid, false); + assertRestrictBackgroundWhitelist(newUid, false); + } + + public void testDataSaverMode_requiredWhitelistedPackages() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", + "testGetRestrictBackgroundStatus_requiredWhitelistedPackages"); + } + + public void testDataSaverMode_broadcastNotSentOnUnsupportedDevices() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest", + "testBroadcastNotSentOnUnsupportedDevices"); + } + + /***************************** + * Battery Saver Mode tests. * + *****************************/ + + public void testBatterySaverModeMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testBatterySaverModeMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testBatterySaverModeMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + public void testBatterySaverMode_reinstall() throws Exception { + if (!isDozeModeEnabled()) { + Log.w(TAG, "testBatterySaverMode_reinstall() skipped because device does not support " + + "Doze Mode"); + return; + } + + addPowerSaveModeWhitelist(TEST_APP2_PKG); + + uninstallPackage(TEST_APP2_PKG, true); + assertPackageUninstalled(TEST_APP2_PKG); + assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); + + installPackage(TEST_APP2_APK); + assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); + } + + public void testBatterySaverModeNonMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testBatterySaverModeNonMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testBatterySaverModeNonMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + /******************* + * App idle tests. * + *******************/ + + public void testAppIdleMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testAppIdleMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testAppIdleMetered_tempWhitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testBackgroundNetworkAccess_tempWhitelisted"); + } + + public void testAppIdleMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + public void testAppIdleMetered_idleWhitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testAppIdleNetworkAccess_idleWhitelisted"); + } + + // TODO: currently power-save mode and idle uses the same whitelist, so this test would be + // redundant (as it would be testing the same as testBatterySaverMode_reinstall()) + // public void testAppIdle_reinstall() throws Exception { + // } + + public void testAppIdleNonMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testAppIdleNonMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testAppIdleNonMetered_tempWhitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testBackgroundNetworkAccess_tempWhitelisted"); + } + + public void testAppIdleNonMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + public void testAppIdleNonMetered_idleWhitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testAppIdleNetworkAccess_idleWhitelisted"); + } + + public void testAppIdleNonMetered_whenCharging() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testAppIdleNetworkAccess_whenCharging"); + } + + public void testAppIdleMetered_whenCharging() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testAppIdleNetworkAccess_whenCharging"); + } + + public void testAppIdle_toast() throws Exception { + // Check that showing a toast doesn't bring an app out of standby + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testAppIdle_toast"); + } + + /******************** + * Doze Mode tests. * + ********************/ + + public void testDozeModeMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testDozeModeMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testDozeModeMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + public void testDozeModeMetered_enabledButWhitelistedOnNotificationAction() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest", + "testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction"); + } + + // TODO: currently power-save mode and idle uses the same whitelist, so this test would be + // redundant (as it would be testing the same as testBatterySaverMode_reinstall()) + // public void testDozeMode_reinstall() throws Exception { + // } + + public void testDozeModeNonMetered_disabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest", + "testBackgroundNetworkAccess_disabled"); + } + + public void testDozeModeNonMetered_whitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest", + "testBackgroundNetworkAccess_whitelisted"); + } + + public void testDozeModeNonMetered_enabled() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest", + "testBackgroundNetworkAccess_enabled"); + } + + public void testDozeModeNonMetered_enabledButWhitelistedOnNotificationAction() + throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest", + "testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction"); + } + + /********************** + * Mixed modes tests. * + **********************/ + + public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDataAndBatterySaverModes_meteredNetwork"); + } + + public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDataAndBatterySaverModes_nonMeteredNetwork"); + } + + public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDozeAndBatterySaverMode_powerSaveWhitelists"); + } + + public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDozeAndAppIdle_powerSaveWhitelists"); + } + + public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testAppIdleAndDoze_tempPowerSaveWhitelists"); + } + + public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testAppIdleAndBatterySaver_tempPowerSaveWhitelists"); + } + + public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDozeAndAppIdle_appIdleWhitelist"); + } + + public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists"); + } + + public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists"); + } + + /******************* + * Helper methods. * + *******************/ + + private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception { + final int max_tries = 5; + boolean actual = false; + for (int i = 1; i <= max_tries; i++) { + final String output = runCommand("cmd netpolicy list restrict-background-whitelist "); + actual = output.contains(Integer.toString(uid)); + if (expected == actual) { + return; + } + Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected " + + expected + ", got " + actual + "); sleeping 1s before polling again"); + Thread.sleep(1000); + } + fail("whitelist check for uid " + uid + " failed: expected " + + expected + ", got " + actual); + } + + private void assertPowerSaveModeWhitelist(String packageName, boolean expected) + throws Exception { + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + assertDelayedCommand("dumpsys deviceidle whitelist =" + packageName, + Boolean.toString(expected)); + } + + /** + * Asserts the result of a command, wait and re-running it a couple times if necessary. + */ + private void assertDelayedCommand(String command, String expectedResult) + throws InterruptedException, DeviceNotAvailableException { + final int maxTries = 5; + for (int i = 1; i <= maxTries; i++) { + final String result = runCommand(command).trim(); + if (result.equals(expectedResult)) return; + Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" + + expectedResult + "' on attempt #; sleeping 1s before polling again"); + Thread.sleep(1000); + } + fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries + + " attempts"); + } + + protected void addRestrictBackgroundWhitelist(int uid) throws Exception { + runCommand("cmd netpolicy add restrict-background-whitelist " + uid); + assertRestrictBackgroundWhitelist(uid, true); + } + + private void addPowerSaveModeWhitelist(String packageName) throws Exception { + Log.i(TAG, "Adding package " + packageName + " to power-save-mode whitelist"); + // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll + // need to use netpolicy for whitelisting + runCommand("dumpsys deviceidle whitelist +" + packageName); + assertPowerSaveModeWhitelist(packageName, true); + } + + protected boolean isDozeModeEnabled() throws Exception { + final String result = runCommand("cmd deviceidle enabled deep").trim(); + return result.equals("1"); + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java new file mode 100644 index 0000000000..49b5f9dc96 --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 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 com.android.cts.net; + +public class HostsideVpnTests extends HostsideNetworkTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + + uninstallPackage(TEST_APP2_PKG, false); + installPackage(TEST_APP2_APK); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + uninstallPackage(TEST_APP2_PKG, true); + } + + public void testDefault() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testDefault"); + } + + public void testAppAllowed() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppAllowed"); + } + + public void testAppDisallowed() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppDisallowed"); + } + + public void testGetConnectionOwnerUidSecurity() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testGetConnectionOwnerUidSecurity"); + } + + public void testSetProxy() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSetProxy"); + } + + public void testSetProxyDisallowedApps() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSetProxyDisallowedApps"); + } + + public void testNoProxy() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testNoProxy"); + } + + public void testBindToNetworkWithProxy() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testBindToNetworkWithProxy"); + } + + public void testVpnMeterednessWithNoUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNoUnderlyingNetwork"); + } + + public void testVpnMeterednessWithNullUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNullUnderlyingNetwork"); + } + + public void testVpnMeterednessWithNonNullUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNonNullUnderlyingNetwork"); + } + + public void testAlwaysMeteredVpnWithNullUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testAlwaysMeteredVpnWithNullUnderlyingNetwork"); + } + + public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, + TEST_PKG + ".VpnTest", + "testAlwaysMeteredVpnWithNonNullUnderlyingNetwork"); + } + + public void testB141603906() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testB141603906"); + } + + public void testDownloadWithDownloadManagerDisallowed() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", + "testDownloadWithDownloadManagerDisallowed"); + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java b/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java new file mode 100644 index 0000000000..23aca24788 --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java @@ -0,0 +1,92 @@ +/* + * 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 com.android.cts.net; + +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.invoker.TestInformation; +import com.android.tradefed.log.LogUtil; +import com.android.tradefed.targetprep.ITargetPreparer; + +public class NetworkPolicyTestsPreparer implements ITargetPreparer { + private ITestDevice mDevice; + private boolean mOriginalAirplaneModeEnabled; + private String mOriginalAppStandbyEnabled; + private String mOriginalBatteryStatsConstants; + private final static String KEY_STABLE_CHARGING_DELAY_MS = "battery_charged_delay_ms"; + private final static int DESIRED_STABLE_CHARGING_DELAY_MS = 0; + + @Override + public void setUp(TestInformation testInformation) throws DeviceNotAvailableException { + mDevice = testInformation.getDevice(); + mOriginalAppStandbyEnabled = getAppStandbyEnabled(); + setAppStandbyEnabled("1"); + LogUtil.CLog.d("Original app_standby_enabled: " + mOriginalAppStandbyEnabled); + + mOriginalBatteryStatsConstants = getBatteryStatsConstants(); + setBatteryStatsConstants( + KEY_STABLE_CHARGING_DELAY_MS + "=" + DESIRED_STABLE_CHARGING_DELAY_MS); + LogUtil.CLog.d("Original battery_saver_constants: " + mOriginalBatteryStatsConstants); + + mOriginalAirplaneModeEnabled = getAirplaneModeEnabled(); + // Turn off airplane mode in case another test left the device in that state. + setAirplaneModeEnabled(false); + LogUtil.CLog.d("Original airplane mode state: " + mOriginalAirplaneModeEnabled); + } + + @Override + public void tearDown(TestInformation testInformation, Throwable e) + throws DeviceNotAvailableException { + setAirplaneModeEnabled(mOriginalAirplaneModeEnabled); + setAppStandbyEnabled(mOriginalAppStandbyEnabled); + setBatteryStatsConstants(mOriginalBatteryStatsConstants); + } + + private void setAirplaneModeEnabled(boolean enable) throws DeviceNotAvailableException { + executeCmd("cmd connectivity airplane-mode " + (enable ? "enable" : "disable")); + } + + private boolean getAirplaneModeEnabled() throws DeviceNotAvailableException { + return "enabled".equals(executeCmd("cmd connectivity airplane-mode").trim()); + } + + private void setAppStandbyEnabled(String appStandbyEnabled) throws DeviceNotAvailableException { + if ("null".equals(appStandbyEnabled)) { + executeCmd("settings delete global app_standby_enabled"); + } else { + executeCmd("settings put global app_standby_enabled " + appStandbyEnabled); + } + } + + private String getAppStandbyEnabled() throws DeviceNotAvailableException { + return executeCmd("settings get global app_standby_enabled").trim(); + } + + private void setBatteryStatsConstants(String batteryStatsConstants) + throws DeviceNotAvailableException { + executeCmd("settings put global battery_stats_constants \"" + batteryStatsConstants + "\""); + } + + private String getBatteryStatsConstants() throws DeviceNotAvailableException { + return executeCmd("settings get global battery_stats_constants"); + } + + private String executeCmd(String cmd) throws DeviceNotAvailableException { + final String output = mDevice.executeShellCommand(cmd).trim(); + LogUtil.CLog.d("Output for '%s': %s", cmd, output); + return output; + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java b/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java new file mode 100644 index 0000000000..19e61c62a0 --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2018 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.security.cts; + +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceTestCase; +import com.android.tradefed.testtype.IBuildReceiver; +import com.android.tradefed.testtype.IDeviceTest; + +import java.lang.Integer; +import java.lang.String; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; + +/** + * Host-side tests for values in /proc/net. + * + * These tests analyze /proc/net to verify that certain networking properties are correct. + */ +public class ProcNetTest extends DeviceTestCase implements IBuildReceiver, IDeviceTest { + private static final String SPI_TIMEOUT_SYSCTL = "/proc/sys/net/core/xfrm_acq_expires"; + private static final int MIN_ACQ_EXPIRES = 3600; + // Global sysctls. Must be present and set to 1. + private static final String[] GLOBAL_SYSCTLS = { + "/proc/sys/net/ipv4/fwmark_reflect", + "/proc/sys/net/ipv6/fwmark_reflect", + "/proc/sys/net/ipv4/tcp_fwmark_accept", + }; + + // Per-interface IPv6 autoconf sysctls. + private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf"; + private static final String AUTOCONF_SYSCTL = "accept_ra_rt_table"; + + // Expected values for MIN|MAX_PLEN. + private static final String ACCEPT_RA_RT_INFO_MIN_PLEN_STRING = "accept_ra_rt_info_min_plen"; + private static final int ACCEPT_RA_RT_INFO_MIN_PLEN_VALUE = 48; + private static final String ACCEPT_RA_RT_INFO_MAX_PLEN_STRING = "accept_ra_rt_info_max_plen"; + private static final int ACCEPT_RA_RT_INFO_MAX_PLEN_VALUE = 64; + // Expected values for RFC 7559 router soliciations. + // Maximum number of router solicitations to send. -1 means no limit. + private static final int IPV6_WIFI_ROUTER_SOLICITATIONS = -1; + private ITestDevice mDevice; + private IBuildInfo mBuild; + private String[] mSysctlDirs; + + /** + * {@inheritDoc} + */ + @Override + public void setBuild(IBuildInfo build) { + mBuild = build; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDevice(ITestDevice device) { + super.setDevice(device); + mDevice = device; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mSysctlDirs = getSysctlDirs(); + } + + private String[] getSysctlDirs() throws Exception { + String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1", + IPV6_SYSCTL_DIR).split("\n"); + List interfaceDirsList = new ArrayList(Arrays.asList(interfaceDirs)); + interfaceDirsList.remove("all"); + interfaceDirsList.remove("lo"); + return interfaceDirsList.toArray(new String[interfaceDirsList.size()]); + } + + + protected void assertLess(String sysctl, int a, int b) { + assertTrue("value of " + sysctl + ": expected < " + b + " but was: " + a, a < b); + } + + protected void assertAtLeast(String sysctl, int a, int b) { + assertTrue("value of " + sysctl + ": expected >= " + b + " but was: " + a, a >= b); + } + + public int readIntFromPath(String path) throws Exception { + String mode = mDevice.executeAdbCommand("shell", "stat", "-c", "%a", path).trim(); + String user = mDevice.executeAdbCommand("shell", "stat", "-c", "%u", path).trim(); + String group = mDevice.executeAdbCommand("shell", "stat", "-c", "%g", path).trim(); + assertEquals(mode, "644"); + assertEquals(user, "0"); + assertEquals(group, "0"); + return Integer.parseInt(mDevice.executeAdbCommand("shell", "cat", path).trim()); + } + + /** + * Checks that SPI default timeouts are overridden, and set to a reasonable length of time + */ + public void testMinAcqExpires() throws Exception { + int value = readIntFromPath(SPI_TIMEOUT_SYSCTL); + assertAtLeast(SPI_TIMEOUT_SYSCTL, value, MIN_ACQ_EXPIRES); + } + + /** + * Checks that the sysctls for multinetwork kernel features are present and + * enabled. + */ + public void testProcSysctls() throws Exception { + for (String sysctl : GLOBAL_SYSCTLS) { + int value = readIntFromPath(sysctl); + assertEquals(sysctl, 1, value); + } + + for (String interfaceDir : mSysctlDirs) { + String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + AUTOCONF_SYSCTL; + int value = readIntFromPath(path); + assertLess(path, value, 0); + } + } + + /** + * Verify that accept_ra_rt_info_{min,max}_plen exists and is set to the expected value + */ + public void testAcceptRaRtInfoMinMaxPlen() throws Exception { + for (String interfaceDir : mSysctlDirs) { + String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "accept_ra_rt_info_min_plen"; + int value = readIntFromPath(path); + assertEquals(path, value, ACCEPT_RA_RT_INFO_MIN_PLEN_VALUE); + path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "accept_ra_rt_info_max_plen"; + value = readIntFromPath(path); + assertEquals(path, value, ACCEPT_RA_RT_INFO_MAX_PLEN_VALUE); + } + } + + /** + * Verify that router_solicitations exists and is set to the expected value + * and verify that router_solicitation_max_interval exists and is in an acceptable interval. + */ + public void testRouterSolicitations() throws Exception { + for (String interfaceDir : mSysctlDirs) { + String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "router_solicitations"; + int value = readIntFromPath(path); + assertEquals(IPV6_WIFI_ROUTER_SOLICITATIONS, value); + path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "router_solicitation_max_interval"; + int interval = readIntFromPath(path); + final int lowerBoundSec = 15 * 60; + final int upperBoundSec = 60 * 60; + assertTrue(lowerBoundSec <= interval); + assertTrue(interval <= upperBoundSec); + } + } +} diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp new file mode 100644 index 0000000000..528171a036 --- /dev/null +++ b/tests/cts/net/Android.bp @@ -0,0 +1,84 @@ +// Copyright (C) 2008 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. + +java_defaults { + name: "CtsNetTestCasesDefaults", + defaults: ["cts_defaults"], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", + + libs: [ + "voip-common", + "android.test.base", + ], + + jni_libs: [ + "libcts_jni", + "libnativedns_jni", + "libnativemultinetwork_jni", + "libnativehelper_compat_libc++", + ], + + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + jarjar_rules: "jarjar-rules-shared.txt", + static_libs: [ + "FrameworksNetCommonTests", + "TestNetworkStackLib", + "core-tests-support", + "cts-net-utils", + "ctstestrunner-axt", + "junit", + "junit-params", + "net-utils-framework-common", + "truth-prebuilt", + ], + + // uncomment when b/13249961 is fixed + // sdk_version: "current", + platform_apis: true, +} + +// Networking CTS tests for development and release. These tests always target the platform SDK +// version, and are subject to all the restrictions appropriate to that version. Before SDK +// finalization, these tests have a min_sdk_version of 10000, and cannot be installed on release +// devices. +android_test { + name: "CtsNetTestCases", + defaults: ["CtsNetTestCasesDefaults"], + test_suites: [ + "cts", + "general-tests", + ], + test_config_template: "AndroidTestTemplate.xml", +} + +// Networking CTS tests that target the latest released SDK. These tests can be installed on release +// devices at any point in the Android release cycle and are useful for qualifying mainline modules +// on release devices. +android_test { + name: "CtsNetTestCasesLatestSdk", + defaults: ["CtsNetTestCasesDefaults"], + jni_uses_sdk_apis: true, + min_sdk_version: "29", + target_sdk_version: "30", + test_suites: [ + "general-tests", + "mts", + ], + test_config_template: "AndroidTestTemplate.xml", +} diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml new file mode 100644 index 0000000000..a7e2bd780a --- /dev/null +++ b/tests/cts/net/AndroidManifest.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml new file mode 100644 index 0000000000..78a01e29c1 --- /dev/null +++ b/tests/cts/net/AndroidTestTemplate.xml @@ -0,0 +1,35 @@ + + + diff --git a/tests/cts/net/OWNERS b/tests/cts/net/OWNERS new file mode 100644 index 0000000000..d55855650f --- /dev/null +++ b/tests/cts/net/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 31808 +lorenzo@google.com +satk@google.com diff --git a/tests/cts/net/TEST_MAPPING b/tests/cts/net/TEST_MAPPING new file mode 100644 index 0000000000..7545cb0c30 --- /dev/null +++ b/tests/cts/net/TEST_MAPPING @@ -0,0 +1,23 @@ +{ + // TODO: move to mainline-presubmit once supported + "presubmit": [ + { + "name": "CtsNetTestCasesLatestSdk", + "options": [ + { + "exclude-annotation": "com.android.testutils.SkipPresubmit" + } + ] + } + ], + "mainline-presubmit": [ + { + "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]", + "options": [ + { + "exclude-annotation": "com.android.testutils.SkipPresubmit" + } + ] + } + ] +} diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp new file mode 100644 index 0000000000..e43a5e82d0 --- /dev/null +++ b/tests/cts/net/api23Test/Android.bp @@ -0,0 +1,51 @@ +// Copyright (C) 2019 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. + +android_test { + name: "CtsNetApi23TestCases", + defaults: ["cts_defaults"], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", + + libs: [ + "android.test.base", + ], + + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + + static_libs: [ + "core-tests-support", + "compatibility-device-util-axt", + "cts-net-utils", + "ctstestrunner-axt", + "ctstestserver", + "mockwebserver", + "junit", + "junit-params", + "truth-prebuilt", + ], + + platform_apis: true, + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "general-tests", + ], + +} diff --git a/tests/cts/net/api23Test/AndroidManifest.xml b/tests/cts/net/api23Test/AndroidManifest.xml new file mode 100644 index 0000000000..4889660b97 --- /dev/null +++ b/tests/cts/net/api23Test/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cts/net/api23Test/AndroidTest.xml b/tests/cts/net/api23Test/AndroidTest.xml new file mode 100644 index 0000000000..8042d5067d --- /dev/null +++ b/tests/cts/net/api23Test/AndroidTest.xml @@ -0,0 +1,31 @@ + + + diff --git a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java new file mode 100644 index 0000000000..cdb66e3d5a --- /dev/null +++ b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2019 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.api23test; + +import static android.content.pm.PackageManager.FEATURE_WIFI; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.cts.util.CtsNetUtils; +import android.os.Looper; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class ConnectivityManagerApi23Test extends AndroidTestCase { + private static final String TAG = ConnectivityManagerApi23Test.class.getSimpleName(); + private static final int SEND_BROADCAST_TIMEOUT = 30000; + // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen + public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT = + "android.net.cts.appForApi23.getWifiConnectivityActionCount"; + // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. + + private Context mContext; + private PackageManager mPackageManager; + private CtsNetUtils mCtsNetUtils; + + @Override + protected void setUp() throws Exception { + super.setUp(); + Looper.prepare(); + mContext = getContext(); + mPackageManager = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); + } + + /** + * Tests reporting of connectivity changed. + */ + public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent cannot execute unless device supports WiFi"); + return; + } + ConnectivityReceiver.prepare(); + + mCtsNetUtils.toggleWifi(); + + // The connectivity broadcast has been sent; push through a terminal broadcast + // to wait for in the receive to confirm it didn't see the connectivity change. + Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION); + finalIntent.setClass(mContext, ConnectivityReceiver.class); + mContext.sendBroadcast(finalIntent); + assertFalse(ConnectivityReceiver.waitForBroadcast()); + } + + public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent() + throws InterruptedException { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot" + + "execute unless device supports WiFi"); + return; + } + mContext.startActivity(new Intent() + .setComponent(new ComponentName("android.net.cts.appForApi23", + "android.net.cts.appForApi23.ConnectivityListeningActivity")) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + Thread.sleep(200); + + mCtsNetUtils.toggleWifi(); + + Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT); + assertEquals(2, sendOrderedBroadcastAndReturnResultCode( + getConnectivityCount, SEND_BROADCAST_TIMEOUT)); + } + + public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testConnectivityChanged_whenRegistered_shouldReceiveIntent cannot execute unless device supports WiFi"); + return; + } + ConnectivityReceiver.prepare(); + ConnectivityReceiver receiver = new ConnectivityReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + mCtsNetUtils.toggleWifi(); + Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION); + finalIntent.setClass(mContext, ConnectivityReceiver.class); + mContext.sendBroadcast(finalIntent); + + assertTrue(ConnectivityReceiver.waitForBroadcast()); + } + + private int sendOrderedBroadcastAndReturnResultCode( + Intent intent, int timeoutMs) throws InterruptedException { + final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); + mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + result.offer(getResultCode()); + } + }, null, 0, null, null); + + Integer resultCode = result.poll(timeoutMs, TimeUnit.MILLISECONDS); + assertNotNull("Timed out (more than " + timeoutMs + + " milliseconds) waiting for result code for broadcast", resultCode); + return resultCode; + } + +} \ No newline at end of file diff --git a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java new file mode 100644 index 0000000000..9d2b8ad2f6 --- /dev/null +++ b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 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.api23test; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.util.Log; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class ConnectivityReceiver extends BroadcastReceiver { + static boolean sReceivedConnectivity; + static boolean sReceivedFinal; + static CountDownLatch sLatch; + + static void prepare() { + synchronized (ConnectivityReceiver.class) { + sReceivedConnectivity = sReceivedFinal = false; + sLatch = new CountDownLatch(1); + } + } + + static boolean waitForBroadcast() { + try { + sLatch.await(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } + synchronized (ConnectivityReceiver.class) { + sLatch = null; + if (!sReceivedFinal) { + throw new IllegalStateException("Never received final broadcast"); + } + return sReceivedConnectivity; + } + } + + static final String FINAL_ACTION = "android.net.cts.action.FINAL"; + + @Override + public void onReceive(Context context, Intent intent) { + Log.i("ConnectivityReceiver", "Received: " + intent.getAction()); + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { + sReceivedConnectivity = true; + } else if (FINAL_ACTION.equals(intent.getAction())) { + sReceivedFinal = true; + if (sLatch != null) { + sLatch.countDown(); + } + } + } +} diff --git a/tests/cts/net/appForApi23/Android.bp b/tests/cts/net/appForApi23/Android.bp new file mode 100644 index 0000000000..cec6d7f5a1 --- /dev/null +++ b/tests/cts/net/appForApi23/Android.bp @@ -0,0 +1,32 @@ +// Copyright (C) 2016 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. + +android_test { + name: "CtsNetTestAppForApi23", + defaults: ["cts_defaults"], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", + + srcs: ["src/**/*.java"], + + sdk_version: "23", + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "general-tests", + ], + +} diff --git a/tests/cts/net/appForApi23/AndroidManifest.xml b/tests/cts/net/appForApi23/AndroidManifest.xml new file mode 100644 index 0000000000..ed4cedbc1d --- /dev/null +++ b/tests/cts/net/appForApi23/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityListeningActivity.java b/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityListeningActivity.java new file mode 100644 index 0000000000..24fb68e8cd --- /dev/null +++ b/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityListeningActivity.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2016 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.appForApi23; + +import android.app.Activity; + +// Stub activity used to start the app +public class ConnectivityListeningActivity extends Activity { +} \ No newline at end of file diff --git a/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java b/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java new file mode 100644 index 0000000000..8039a4f943 --- /dev/null +++ b/tests/cts/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 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.appForApi23; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; + +public class ConnectivityReceiver extends BroadcastReceiver { + public static String GET_WIFI_CONNECTIVITY_ACTION_COUNT = + "android.net.cts.appForApi23.getWifiConnectivityActionCount"; + + private static int sWifiConnectivityActionCount = 0; + + @Override + public void onReceive(Context context, Intent intent) { + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { + int networkType = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 0); + if (networkType == ConnectivityManager.TYPE_WIFI) { + sWifiConnectivityActionCount++; + } + } + if (GET_WIFI_CONNECTIVITY_ACTION_COUNT.equals(intent.getAction())) { + setResultCode(sWifiConnectivityActionCount); + } + } +} diff --git a/tests/cts/net/assets/network_watchlist_config_empty_for_test.xml b/tests/cts/net/assets/network_watchlist_config_empty_for_test.xml new file mode 100644 index 0000000000..19628d14ed --- /dev/null +++ b/tests/cts/net/assets/network_watchlist_config_empty_for_test.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/tests/cts/net/assets/network_watchlist_config_for_test.xml b/tests/cts/net/assets/network_watchlist_config_for_test.xml new file mode 100644 index 0000000000..835ae0fea2 --- /dev/null +++ b/tests/cts/net/assets/network_watchlist_config_for_test.xml @@ -0,0 +1,34 @@ + + + + + + F0905DA7549614957B449034C281EF7BDEFDBC2B6E050AD1E78D6DE18FBD0D5F + + + 18DD41C9F2E8E4879A1575FB780514EF33CF6E1F66578C4AE7CCA31F49B9F2EC + + + AAAAAAAA + + + BBBBBBBB + + diff --git a/tests/cts/net/jarjar-rules-shared.txt b/tests/cts/net/jarjar-rules-shared.txt new file mode 100644 index 0000000000..11dba74096 --- /dev/null +++ b/tests/cts/net/jarjar-rules-shared.txt @@ -0,0 +1,2 @@ +# Module library in frameworks/libs/net +rule com.android.net.module.util.** android.net.cts.util.@1 \ No newline at end of file diff --git a/tests/cts/net/jni/Android.bp b/tests/cts/net/jni/Android.bp new file mode 100644 index 0000000000..3953aeb701 --- /dev/null +++ b/tests/cts/net/jni/Android.bp @@ -0,0 +1,51 @@ +// Copyright (C) 2013 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. + +cc_library_shared { + name: "libnativedns_jni", + + srcs: ["NativeDnsJni.c"], + sdk_version: "current", + + shared_libs: [ + "libnativehelper_compat_libc++", + "liblog", + ], + stl: "libc++_static", + + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + +} + +cc_library_shared { + name: "libnativemultinetwork_jni", + + srcs: ["NativeMultinetworkJni.cpp"], + sdk_version: "current", + cflags: [ + "-Wall", + "-Werror", + "-Wno-format", + ], + shared_libs: [ + "libandroid", + "libnativehelper_compat_libc++", + "liblog", + ], + stl: "libc++_static", +} diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c new file mode 100644 index 0000000000..4ec800e555 --- /dev/null +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include +#include +#include +#include + +#include + +#define LOG_TAG "NativeDns-JNI" +#define LOGD(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) + +const char *GoogleDNSIpV4Address="8.8.8.8"; +const char *GoogleDNSIpV4Address2="8.8.4.4"; +const char *GoogleDNSIpV6Address="2001:4860:4860::8888"; +const char *GoogleDNSIpV6Address2="2001:4860:4860::8844"; + +JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclass class) +{ + const char *node = "www.google.com"; + char *service = NULL; + struct addrinfo *answer; + + int res = getaddrinfo(node, service, NULL, &answer); + LOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res)); + if (res != 0) return JNI_FALSE; + + // check for v4 & v6 + { + int foundv4 = 0; + int foundv6 = 0; + struct addrinfo *current = answer; + while (current != NULL) { + char buf[256]; + if (current->ai_addr->sa_family == AF_INET) { + inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, + buf, sizeof(buf)); + foundv4 = 1; + LOGD(" %s", buf); + } else if (current->ai_addr->sa_family == AF_INET6) { + inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, + buf, sizeof(buf)); + foundv6 = 1; + LOGD(" %s", buf); + } + current = current->ai_next; + } + + freeaddrinfo(answer); + answer = NULL; + if (foundv4 != 1 && foundv6 != 1) { + LOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address"); + return JNI_FALSE; + } + } + + node = "ipv6.google.com"; + res = getaddrinfo(node, service, NULL, &answer); + LOGD("getaddrinfo(ipv6.google.com) gave res=%d", res); + if (res != 0) return JNI_FALSE; + + { + int foundv4 = 0; + int foundv6 = 0; + struct addrinfo *current = answer; + while (current != NULL) { + char buf[256]; + if (current->ai_addr->sa_family == AF_INET) { + inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, + buf, sizeof(buf)); + LOGD(" %s", buf); + foundv4 = 1; + } else if (current->ai_addr->sa_family == AF_INET6) { + inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, + buf, sizeof(buf)); + LOGD(" %s", buf); + foundv6 = 1; + } + current = current->ai_next; + } + + freeaddrinfo(answer); + answer = NULL; + if (foundv4 == 1 || foundv6 != 1) { + LOGD("getaddrinfo(ipv6.google.com) didn't find only v6"); + return JNI_FALSE; + } + } + + // getnameinfo + struct sockaddr_in sa4; + sa4.sin_family = AF_INET; + sa4.sin_port = 0; + inet_pton(AF_INET, GoogleDNSIpV4Address, &(sa4.sin_addr)); + + struct sockaddr_in6 sa6; + sa6.sin6_family = AF_INET6; + sa6.sin6_port = 0; + sa6.sin6_flowinfo = 0; + sa6.sin6_scope_id = 0; + inet_pton(AF_INET6, GoogleDNSIpV6Address2, &(sa6.sin6_addr)); + + char buf[NI_MAXHOST]; + int flags = NI_NAMEREQD; + + res = getnameinfo((const struct sockaddr*)&sa4, sizeof(sa4), buf, sizeof(buf), NULL, 0, flags); + if (res != 0) { + LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res, + gai_strerror(res)); + return JNI_FALSE; + } + if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { + LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + GoogleDNSIpV4Address, buf); + return JNI_FALSE; + } + + memset(buf, 0, sizeof(buf)); + res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags); + if (res != 0) { + LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, + res, gai_strerror(res)); + return JNI_FALSE; + } + if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { + LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + GoogleDNSIpV6Address2, buf); + return JNI_FALSE; + } + + // gethostbyname + struct hostent *my_hostent = gethostbyname("www.youtube.com"); + if (my_hostent == NULL) { + LOGD("gethostbyname(www.youtube.com) gave null response"); + return JNI_FALSE; + } + if ((my_hostent->h_addr_list == NULL) || (*my_hostent->h_addr_list == NULL)) { + LOGD("gethostbyname(www.youtube.com) gave 0 addresses"); + return JNI_FALSE; + } + { + char **current = my_hostent->h_addr_list; + while (*current != NULL) { + char buf[256]; + inet_ntop(my_hostent->h_addrtype, *current, buf, sizeof(buf)); + LOGD("gethostbyname(www.youtube.com) gave %s", buf); + current++; + } + } + + // gethostbyaddr + char addr6[16]; + inet_pton(AF_INET6, GoogleDNSIpV6Address, addr6); + my_hostent = gethostbyaddr(addr6, sizeof(addr6), AF_INET6); + if (my_hostent == NULL) { + LOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address); + return JNI_FALSE; + } + + LOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address, + my_hostent->h_name ? my_hostent->h_name : "null"); + + if (my_hostent->h_name == NULL) return JNI_FALSE; + return JNI_TRUE; +} diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp new file mode 100644 index 0000000000..60e31bc78a --- /dev/null +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -0,0 +1,515 @@ +/* + * Copyright (C) 2019 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. + */ + + +#define LOG_TAG "MultinetworkApiTest" + +#include +#include +#include +#include +#include +#include +#include /* poll */ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define LOGD(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) + +#define EXPECT_GE(env, actual, expected, msg) \ + do { \ + if (actual < expected) { \ + jniThrowExceptionFmt(env, "java/lang/AssertionError", \ + "%s:%d: %s EXPECT_GE: expected %d, got %d", \ + __FILE__, __LINE__, msg, expected, actual); \ + } \ + } while (0) + +#define EXPECT_GT(env, actual, expected, msg) \ + do { \ + if (actual <= expected) { \ + jniThrowExceptionFmt(env, "java/lang/AssertionError", \ + "%s:%d: %s EXPECT_GT: expected %d, got %d", \ + __FILE__, __LINE__, msg, expected, actual); \ + } \ + } while (0) + +#define EXPECT_EQ(env, expected, actual, msg) \ + do { \ + if (actual != expected) { \ + jniThrowExceptionFmt(env, "java/lang/AssertionError", \ + "%s:%d: %s EXPECT_EQ: expected %d, got %d", \ + __FILE__, __LINE__, msg, expected, actual); \ + } \ + } while (0) + +static const int MAXPACKET = 8 * 1024; +static const int TIMEOUT_MS = 15000; +static const char kHostname[] = "connectivitycheck.android.com"; +static const char kNxDomainName[] = "test1-nx.metric.gstatic.com"; +static const char kGoogleName[] = "www.google.com"; + +int makeQuery(const char* name, int qtype, uint8_t* buf, size_t buflen) { + return res_mkquery(ns_o_query, name, ns_c_in, qtype, NULL, 0, NULL, buf, buflen); +} + +int getAsyncResponse(JNIEnv* env, int fd, int timeoutMs, int* rcode, uint8_t* buf, size_t bufLen) { + struct pollfd wait_fd = { .fd = fd, .events = POLLIN }; + + poll(&wait_fd, 1, timeoutMs); + if (wait_fd.revents & POLLIN) { + int n = android_res_nresult(fd, rcode, buf, bufLen); + // Verify that android_res_nresult() closed the fd + char dummy; + EXPECT_EQ(env, -1, read(fd, &dummy, sizeof(dummy)), "res_nresult check for closing fd"); + EXPECT_EQ(env, EBADF, errno, "res_nresult check for errno"); + return n; + } + + return -ETIMEDOUT; +} + +int extractIpAddressAnswers(uint8_t* buf, size_t bufLen, int family) { + ns_msg handle; + if (ns_initparse((const uint8_t*) buf, bufLen, &handle) < 0) { + return -errno; + } + const int ancount = ns_msg_count(handle, ns_s_an); + // Answer count = 0 is valid(e.g. response of query with root) + if (!ancount) { + return 0; + } + ns_rr rr; + bool hasValidAns = false; + for (int i = 0; i < ancount; i++) { + if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) { + // If there is no valid answer, test will fail. + continue; + } + const uint8_t* rdata = ns_rr_rdata(rr); + char buffer[INET6_ADDRSTRLEN]; + if (inet_ntop(family, (const char*) rdata, buffer, sizeof(buffer)) == NULL) { + return -errno; + } + hasValidAns = true; + } + return hasValidAns ? 0 : -EBADMSG; +} + +int expectAnswersValid(JNIEnv* env, int fd, int family, int expectedRcode) { + int rcode = -1; + uint8_t buf[MAXPACKET] = {}; + int res = getAsyncResponse(env, fd, TIMEOUT_MS, &rcode, buf, MAXPACKET); + if (res < 0) { + return res; + } + + EXPECT_EQ(env, expectedRcode, rcode, "rcode is not expected"); + + if (expectedRcode == ns_r_noerror && res > 0) { + return extractIpAddressAnswers(buf, res, family); + } + return 0; +} + +int expectAnswersNotValid(JNIEnv* env, int fd, int expectedErrno) { + int rcode = -1; + uint8_t buf[MAXPACKET] = {}; + int res = getAsyncResponse(env, fd, TIMEOUT_MS, &rcode, buf, MAXPACKET); + if (res != expectedErrno) { + LOGD("res:%d, expectedErrno = %d", res, expectedErrno); + return (res > 0) ? -EREMOTEIO : res; + } + return 0; +} + +extern "C" +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck( + JNIEnv* env, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + + // V4 + int fd = android_res_nquery(handle, kHostname, ns_c_in, ns_t_a, 0); + EXPECT_GE(env, fd, 0, "v4 res_nquery"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror), + "v4 res_nquery check answers"); + + // V6 + fd = android_res_nquery(handle, kHostname, ns_c_in, ns_t_aaaa, 0); + EXPECT_GE(env, fd, 0, "v6 res_nquery"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror), + "v6 res_nquery check answers"); +} + +extern "C" +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNsendCheck( + JNIEnv* env, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + // V4 + uint8_t buf1[MAXPACKET] = {}; + + int len1 = makeQuery(kGoogleName, ns_t_a, buf1, sizeof(buf1)); + EXPECT_GT(env, len1, 0, "v4 res_mkquery 1st"); + + uint8_t buf2[MAXPACKET] = {}; + int len2 = makeQuery(kHostname, ns_t_a, buf2, sizeof(buf2)); + EXPECT_GT(env, len2, 0, "v4 res_mkquery 2nd"); + + int fd1 = android_res_nsend(handle, buf1, len1, 0); + EXPECT_GE(env, fd1, 0, "v4 res_nsend 1st"); + int fd2 = android_res_nsend(handle, buf2, len2, 0); + EXPECT_GE(env, fd2, 0, "v4 res_nsend 2nd"); + + EXPECT_EQ(env, 0, expectAnswersValid(env, fd2, AF_INET, ns_r_noerror), + "v4 res_nsend 2nd check answers"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_noerror), + "v4 res_nsend 1st check answers"); + + // V6 + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); + len1 = makeQuery(kGoogleName, ns_t_aaaa, buf1, sizeof(buf1)); + EXPECT_GT(env, len1, 0, "v6 res_mkquery 1st"); + len2 = makeQuery(kHostname, ns_t_aaaa, buf2, sizeof(buf2)); + EXPECT_GT(env, len2, 0, "v6 res_mkquery 2nd"); + + fd1 = android_res_nsend(handle, buf1, len1, 0); + EXPECT_GE(env, fd1, 0, "v6 res_nsend 1st"); + fd2 = android_res_nsend(handle, buf2, len2, 0); + EXPECT_GE(env, fd2, 0, "v6 res_nsend 2nd"); + + EXPECT_EQ(env, 0, expectAnswersValid(env, fd2, AF_INET6, ns_r_noerror), + "v6 res_nsend 2nd check answers"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_noerror), + "v6 res_nsend 1st check answers"); +} + +extern "C" +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNnxDomainCheck( + JNIEnv* env, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + + // res_nquery V4 NXDOMAIN + int fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0); + EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain), + "v4 res_nquery NXDOMAIN check answers"); + + // res_nquery V6 NXDOMAIN + fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0); + EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain), + "v6 res_nquery NXDOMAIN check answers"); + + uint8_t buf[MAXPACKET] = {}; + // res_nsend V4 NXDOMAIN + int len = makeQuery(kNxDomainName, ns_t_a, buf, sizeof(buf)); + EXPECT_GT(env, len, 0, "v4 res_mkquery NXDOMAIN"); + fd = android_res_nsend(handle, buf, len, 0); + EXPECT_GE(env, fd, 0, "v4 res_nsend NXDOMAIN"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain), + "v4 res_nsend NXDOMAIN check answers"); + + // res_nsend V6 NXDOMAIN + memset(buf, 0, sizeof(buf)); + len = makeQuery(kNxDomainName, ns_t_aaaa, buf, sizeof(buf)); + EXPECT_GT(env, len, 0, "v6 res_mkquery NXDOMAIN"); + fd = android_res_nsend(handle, buf, len, 0); + EXPECT_GE(env, fd, 0, "v6 res_nsend NXDOMAIN"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain), + "v6 res_nsend NXDOMAIN check answers"); +} + + +extern "C" +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck( + JNIEnv* env, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + + int fd = android_res_nquery(handle, kGoogleName, ns_c_in, ns_t_a, 0); + errno = 0; + android_res_cancel(fd); + int err = errno; + EXPECT_EQ(env, 0, err, "res_cancel"); + // DO NOT call cancel or result with the same fd more than once, + // otherwise it will hit fdsan double-close fd. +} + +extern "C" +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck( + JNIEnv* env, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + + // It is the equivalent of "dig . a", Query with an empty name. + int fd = android_res_nquery(handle, "", ns_c_in, ns_t_a, 0); + EXPECT_GE(env, fd, 0, "res_nquery root"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror), + "res_nquery root check answers"); + + // Label limit 63 + std::string exceedingLabelQuery = "www." + std::string(70, 'g') + ".com"; + // Name limit 255 + std::string exceedingDomainQuery = "www." + std::string(255, 'g') + ".com"; + + fd = android_res_nquery(handle, exceedingLabelQuery.c_str(), ns_c_in, ns_t_a, 0); + EXPECT_EQ(env, -EMSGSIZE, fd, "res_nquery exceedingLabelQuery"); + fd = android_res_nquery(handle, exceedingDomainQuery.c_str(), ns_c_in, ns_t_aaaa, 0); + EXPECT_EQ(env, -EMSGSIZE, fd, "res_nquery exceedingDomainQuery"); + + uint8_t buf[10] = {}; + // empty BLOB + fd = android_res_nsend(handle, buf, 10, 0); + EXPECT_GE(env, fd, 0, "res_nsend empty BLOB"); + EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL), + "res_nsend empty BLOB check answers"); + + uint8_t largeBuf[2 * MAXPACKET] = {}; + // A buffer larger than 8KB + fd = android_res_nsend(handle, largeBuf, sizeof(largeBuf), 0); + EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend buffer larger than 8KB"); + + // 5000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of + // commands to 4096 bytes. + fd = android_res_nsend(handle, largeBuf, 5000, 0); + EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 5000 bytes filled with 0"); + + // 500 bytes filled with 0 + fd = android_res_nsend(handle, largeBuf, 500, 0); + EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0"); + EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL), + "res_nsend 500 bytes filled with 0 check answers"); + + // 5000 bytes filled with 0xFF + uint8_t ffBuf[5001] = {}; + memset(ffBuf, 0xFF, sizeof(ffBuf)); + ffBuf[5000] = '\0'; + fd = android_res_nsend(handle, ffBuf, sizeof(ffBuf), 0); + EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 5000 bytes filled with 0xFF"); + + // 500 bytes filled with 0xFF + ffBuf[500] = '\0'; + fd = android_res_nsend(handle, ffBuf, 501, 0); + EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0xFF"); + EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL), + "res_nsend 500 bytes filled with 0xFF check answers"); +} + +extern "C" +JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runGetaddrinfoCheck( + JNIEnv*, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + struct addrinfo *res = NULL; + + errno = 0; + int rval = android_getaddrinfofornetwork(handle, kHostname, NULL, NULL, &res); + const int saved_errno = errno; + freeaddrinfo(res); + + LOGD("android_getaddrinfofornetwork(%" PRIu64 ", %s) returned rval=%d errno=%d", + handle, kHostname, rval, saved_errno); + return rval == 0 ? 0 : -saved_errno; +} + +extern "C" +JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetprocnetwork( + JNIEnv*, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + + errno = 0; + int rval = android_setprocnetwork(handle); + const int saved_errno = errno; + LOGD("android_setprocnetwork(%" PRIu64 ") returned rval=%d errno=%d", + handle, rval, saved_errno); + return rval == 0 ? 0 : -saved_errno; +} + +extern "C" +JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetsocknetwork( + JNIEnv*, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + + errno = 0; + int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + LOGD("socket() failed, errno=%d", errno); + return -errno; + } + + errno = 0; + int rval = android_setsocknetwork(handle, fd); + const int saved_errno = errno; + LOGD("android_setprocnetwork(%" PRIu64 ", %d) returned rval=%d errno=%d", + handle, fd, rval, saved_errno); + close(fd); + return rval == 0 ? 0 : -saved_errno; +} + +// Use sizeof("x") - 1 because we need a compile-time constant, and strlen("x") +// isn't guaranteed to fold to a constant. +static const int kSockaddrStrLen = INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; + +void sockaddr_ntop(const struct sockaddr *sa, socklen_t salen, char *dst, const size_t size) { + char addrstr[INET6_ADDRSTRLEN]; + char portstr[sizeof("65535")]; + char buf[kSockaddrStrLen+1]; + + int ret = getnameinfo(sa, salen, + addrstr, sizeof(addrstr), + portstr, sizeof(portstr), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret == 0) { + snprintf(buf, sizeof(buf), + (sa->sa_family == AF_INET6) ? "[%s]:%s" : "%s:%s", + addrstr, portstr); + } else { + sprintf(buf, "???"); + } + + strlcpy(dst, buf, size); +} + +extern "C" +JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( + JNIEnv*, jclass, jlong nethandle) { + const struct addrinfo kHints = { + .ai_flags = AI_ADDRCONFIG, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + .ai_protocol = IPPROTO_UDP, + }; + struct addrinfo *res = NULL; + net_handle_t handle = (net_handle_t) nethandle; + + static const char kPort[] = "443"; + int rval = android_getaddrinfofornetwork(handle, kHostname, kPort, &kHints, &res); + if (rval != 0) { + LOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", + handle, kHostname, rval, errno); + freeaddrinfo(res); + return -errno; + } + + // Rely upon getaddrinfo sorting the best destination to the front. + int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (fd < 0) { + LOGD("socket(%d, %d, %d) failed, errno=%d", + res->ai_family, res->ai_socktype, res->ai_protocol, errno); + freeaddrinfo(res); + return -errno; + } + + rval = android_setsocknetwork(handle, fd); + LOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", + handle, fd, rval, errno); + if (rval != 0) { + close(fd); + freeaddrinfo(res); + return -errno; + } + + char addrstr[kSockaddrStrLen+1]; + sockaddr_ntop(res->ai_addr, res->ai_addrlen, addrstr, sizeof(addrstr)); + LOGD("Attempting connect() to %s ...", addrstr); + + rval = connect(fd, res->ai_addr, res->ai_addrlen); + if (rval != 0) { + close(fd); + freeaddrinfo(res); + return -errno; + } + freeaddrinfo(res); + + struct sockaddr_storage src_addr; + socklen_t src_addrlen = sizeof(src_addr); + if (getsockname(fd, (struct sockaddr *)&src_addr, &src_addrlen) != 0) { + close(fd); + return -errno; + } + sockaddr_ntop((const struct sockaddr *)&src_addr, sizeof(src_addr), addrstr, sizeof(addrstr)); + LOGD("... from %s", addrstr); + + // Don't let reads or writes block indefinitely. + const struct timeval timeo = { 2, 0 }; // 2 seconds + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); + + // For reference see: + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-invariants + uint8_t quic_packet[1200] = { + 0xc0, // long header + 0xaa, 0xda, 0xca, 0xca, // reserved-space version number + 0x08, // destination connection ID length + 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID + 0x00, // source connection ID length + }; + + arc4random_buf(quic_packet + 6, 8); // random connection ID + + uint8_t response[1500]; + ssize_t sent, rcvd; + static const int MAX_RETRIES = 5; + int i, errnum = 0; + + for (i = 0; i < MAX_RETRIES; i++) { + sent = send(fd, quic_packet, sizeof(quic_packet), 0); + if (sent < (ssize_t)sizeof(quic_packet)) { + errnum = errno; + LOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum); + close(fd); + return -errnum; + } + + rcvd = recv(fd, response, sizeof(response), 0); + if (rcvd > 0) { + break; + } else { + errnum = errno; + LOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d", + i + 1, MAX_RETRIES, rcvd, errnum); + } + } + if (rcvd < 15) { + LOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); + if (rcvd <= 0) { + LOGD("Does this network block UDP port %s?", kPort); + } + close(fd); + return -EPROTO; + } + + int conn_id_cmp = memcmp(quic_packet + 6, response + 7, 8); + if (conn_id_cmp != 0) { + LOGD("sent and received connection IDs do not match"); + close(fd); + return -EPROTO; + } + + // TODO: Replace this quick 'n' dirty test with proper QUIC-capable code. + + close(fd); + return 0; +} diff --git a/tests/cts/net/native/dns/Android.bp b/tests/cts/net/native/dns/Android.bp new file mode 100644 index 0000000000..6defd359ab --- /dev/null +++ b/tests/cts/net/native/dns/Android.bp @@ -0,0 +1,41 @@ +cc_defaults { + name: "dns_async_defaults", + + cflags: [ + "-fstack-protector-all", + "-g", + "-Wall", + "-Wextra", + "-Werror", + "-Wnullable-to-nonnull-conversion", + "-Wsign-compare", + "-Wthread-safety", + "-Wunused-parameter", + ], + srcs: [ + "NativeDnsAsyncTest.cpp", + ], + shared_libs: [ + "libandroid", + "liblog", + "libutils", + ], +} + +cc_test { + name: "CtsNativeNetDnsTestCases", + defaults: ["dns_async_defaults"], + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + test_suites: [ + "cts", + "general-tests", + "mts", + ], +} diff --git a/tests/cts/net/native/dns/AndroidTest.xml b/tests/cts/net/native/dns/AndroidTest.xml new file mode 100644 index 0000000000..6d03c23448 --- /dev/null +++ b/tests/cts/net/native/dns/AndroidTest.xml @@ -0,0 +1,32 @@ + + + + diff --git a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp new file mode 100644 index 0000000000..e501475996 --- /dev/null +++ b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2018 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* poll */ +#include +#include +#include + +#include +#include + +namespace { +constexpr int MAXPACKET = 8 * 1024; +constexpr int PTON_MAX = 16; +constexpr int TIMEOUT_MS = 10000; + +int getAsyncResponse(int fd, int timeoutMs, int* rcode, uint8_t* buf, size_t bufLen) { + struct pollfd wait_fd[1]; + wait_fd[0].fd = fd; + wait_fd[0].events = POLLIN; + short revents; + int ret; + ret = poll(wait_fd, 1, timeoutMs); + revents = wait_fd[0].revents; + if (revents & POLLIN) { + int n = android_res_nresult(fd, rcode, buf, bufLen); + // Verify that android_res_nresult() closed the fd + char dummy; + EXPECT_EQ(-1, read(fd, &dummy, sizeof dummy)); + EXPECT_EQ(EBADF, errno); + return n; + } + + return -1; +} + +std::vector extractIpAddressAnswers(uint8_t* buf, size_t bufLen, int ipType) { + ns_msg handle; + if (ns_initparse((const uint8_t*) buf, bufLen, &handle) < 0) { + return {}; + } + const int ancount = ns_msg_count(handle, ns_s_an); + ns_rr rr; + std::vector answers; + for (int i = 0; i < ancount; i++) { + if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) { + continue; + } + const uint8_t* rdata = ns_rr_rdata(rr); + char buffer[INET6_ADDRSTRLEN]; + if (inet_ntop(ipType, (const char*) rdata, buffer, sizeof(buffer))) { + answers.push_back(buffer); + } + } + return answers; +} + +void expectAnswersValid(int fd, int ipType, int expectedRcode) { + int rcode = -1; + uint8_t buf[MAXPACKET] = {}; + int res = getAsyncResponse(fd, TIMEOUT_MS, &rcode, buf, MAXPACKET); + EXPECT_GE(res, 0); + EXPECT_EQ(rcode, expectedRcode); + + if (expectedRcode == ns_r_noerror) { + auto answers = extractIpAddressAnswers(buf, res, ipType); + EXPECT_GE(answers.size(), 0U); + for (auto &answer : answers) { + char pton[PTON_MAX]; + EXPECT_EQ(1, inet_pton(ipType, answer.c_str(), pton)); + } + } +} + +void expectAnswersNotValid(int fd, int expectedErrno) { + int rcode = -1; + uint8_t buf[MAXPACKET] = {}; + int res = getAsyncResponse(fd, TIMEOUT_MS, &rcode, buf, MAXPACKET); + EXPECT_EQ(expectedErrno, res); +} + +} // namespace + +TEST (NativeDnsAsyncTest, Async_Query) { + // V4 + int fd1 = android_res_nquery( + NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0); + EXPECT_GE(fd1, 0); + int fd2 = android_res_nquery( + NETWORK_UNSPECIFIED, "www.youtube.com", ns_c_in, ns_t_a, 0); + EXPECT_GE(fd2, 0); + expectAnswersValid(fd2, AF_INET, ns_r_noerror); + expectAnswersValid(fd1, AF_INET, ns_r_noerror); + + // V6 + fd1 = android_res_nquery( + NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_aaaa, 0); + EXPECT_GE(fd1, 0); + fd2 = android_res_nquery( + NETWORK_UNSPECIFIED, "www.youtube.com", ns_c_in, ns_t_aaaa, 0); + EXPECT_GE(fd2, 0); + expectAnswersValid(fd2, AF_INET6, ns_r_noerror); + expectAnswersValid(fd1, AF_INET6, ns_r_noerror); +} + +TEST (NativeDnsAsyncTest, Async_Send) { + // V4 + uint8_t buf1[MAXPACKET] = {}; + int len1 = res_mkquery(ns_o_query, "www.googleapis.com", + ns_c_in, ns_t_a, nullptr, 0, nullptr, buf1, sizeof(buf1)); + EXPECT_GT(len1, 0); + + uint8_t buf2[MAXPACKET] = {}; + int len2 = res_mkquery(ns_o_query, "play.googleapis.com", + ns_c_in, ns_t_a, nullptr, 0, nullptr, buf2, sizeof(buf2)); + EXPECT_GT(len2, 0); + + int fd1 = android_res_nsend(NETWORK_UNSPECIFIED, buf1, len1, 0); + EXPECT_GE(fd1, 0); + int fd2 = android_res_nsend(NETWORK_UNSPECIFIED, buf2, len2, 0); + EXPECT_GE(fd2, 0); + + expectAnswersValid(fd2, AF_INET, ns_r_noerror); + expectAnswersValid(fd1, AF_INET, ns_r_noerror); + + // V6 + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); + len1 = res_mkquery(ns_o_query, "www.googleapis.com", + ns_c_in, ns_t_aaaa, nullptr, 0, nullptr, buf1, sizeof(buf1)); + EXPECT_GT(len1, 0); + len2 = res_mkquery(ns_o_query, "play.googleapis.com", + ns_c_in, ns_t_aaaa, nullptr, 0, nullptr, buf2, sizeof(buf2)); + EXPECT_GT(len2, 0); + + fd1 = android_res_nsend(NETWORK_UNSPECIFIED, buf1, len1, 0); + EXPECT_GE(fd1, 0); + fd2 = android_res_nsend(NETWORK_UNSPECIFIED, buf2, len2, 0); + EXPECT_GE(fd2, 0); + + expectAnswersValid(fd2, AF_INET6, ns_r_noerror); + expectAnswersValid(fd1, AF_INET6, ns_r_noerror); +} + +TEST (NativeDnsAsyncTest, Async_NXDOMAIN) { + uint8_t buf[MAXPACKET] = {}; + int len = res_mkquery(ns_o_query, "test1-nx.metric.gstatic.com", + ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf)); + EXPECT_GT(len, 0); + int fd1 = android_res_nsend(NETWORK_UNSPECIFIED, buf, len, ANDROID_RESOLV_NO_CACHE_LOOKUP); + EXPECT_GE(fd1, 0); + + len = res_mkquery(ns_o_query, "test2-nx.metric.gstatic.com", + ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf)); + EXPECT_GT(len, 0); + int fd2 = android_res_nsend(NETWORK_UNSPECIFIED, buf, len, ANDROID_RESOLV_NO_CACHE_LOOKUP); + EXPECT_GE(fd2, 0); + + expectAnswersValid(fd2, AF_INET, ns_r_nxdomain); + expectAnswersValid(fd1, AF_INET, ns_r_nxdomain); + + fd1 = android_res_nquery( + NETWORK_UNSPECIFIED, "test3-nx.metric.gstatic.com", + ns_c_in, ns_t_aaaa, ANDROID_RESOLV_NO_CACHE_LOOKUP); + EXPECT_GE(fd1, 0); + fd2 = android_res_nquery( + NETWORK_UNSPECIFIED, "test4-nx.metric.gstatic.com", + ns_c_in, ns_t_aaaa, ANDROID_RESOLV_NO_CACHE_LOOKUP); + EXPECT_GE(fd2, 0); + expectAnswersValid(fd2, AF_INET6, ns_r_nxdomain); + expectAnswersValid(fd1, AF_INET6, ns_r_nxdomain); +} + +TEST (NativeDnsAsyncTest, Async_Cancel) { + int fd = android_res_nquery( + NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0); + errno = 0; + android_res_cancel(fd); + int err = errno; + EXPECT_EQ(err, 0); + // DO NOT call cancel or result with the same fd more than once, + // otherwise it will hit fdsan double-close fd. +} + +TEST (NativeDnsAsyncTest, Async_Query_MALFORMED) { + // Empty string to create BLOB and query, we will get empty result and rcode = 0 + // on DNSTLS. + int fd = android_res_nquery( + NETWORK_UNSPECIFIED, "", ns_c_in, ns_t_a, 0); + EXPECT_GE(fd, 0); + expectAnswersValid(fd, AF_INET, ns_r_noerror); + + std::string exceedingLabelQuery = "www." + std::string(70, 'g') + ".com"; + std::string exceedingDomainQuery = "www." + std::string(255, 'g') + ".com"; + + fd = android_res_nquery(NETWORK_UNSPECIFIED, + exceedingLabelQuery.c_str(), ns_c_in, ns_t_a, 0); + EXPECT_EQ(-EMSGSIZE, fd); + fd = android_res_nquery(NETWORK_UNSPECIFIED, + exceedingDomainQuery.c_str(), ns_c_in, ns_t_a, 0); + EXPECT_EQ(-EMSGSIZE, fd); +} + +TEST (NativeDnsAsyncTest, Async_Send_MALFORMED) { + uint8_t buf[10] = {}; + // empty BLOB + int fd = android_res_nsend(NETWORK_UNSPECIFIED, buf, 10, 0); + EXPECT_GE(fd, 0); + expectAnswersNotValid(fd, -EINVAL); + + std::vector largeBuf(2 * MAXPACKET, 0); + // A buffer larger than 8KB + fd = android_res_nsend( + NETWORK_UNSPECIFIED, largeBuf.data(), largeBuf.size(), 0); + EXPECT_EQ(-EMSGSIZE, fd); + + // 5000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of + // commands to 4096 bytes. + fd = android_res_nsend(NETWORK_UNSPECIFIED, largeBuf.data(), 5000, 0); + EXPECT_EQ(-EMSGSIZE, fd); + + // 500 bytes filled with 0 + fd = android_res_nsend(NETWORK_UNSPECIFIED, largeBuf.data(), 500, 0); + EXPECT_GE(fd, 0); + expectAnswersNotValid(fd, -EINVAL); + + // 5000 bytes filled with 0xFF + std::vector ffBuf(5000, 0xFF); + fd = android_res_nsend( + NETWORK_UNSPECIFIED, ffBuf.data(), ffBuf.size(), 0); + EXPECT_EQ(-EMSGSIZE, fd); + + // 500 bytes filled with 0xFF + fd = android_res_nsend(NETWORK_UNSPECIFIED, ffBuf.data(), 500, 0); + EXPECT_GE(fd, 0); + expectAnswersNotValid(fd, -EINVAL); +} diff --git a/tests/cts/net/native/qtaguid/Android.bp b/tests/cts/net/native/qtaguid/Android.bp new file mode 100644 index 0000000000..4861651504 --- /dev/null +++ b/tests/cts/net/native/qtaguid/Android.bp @@ -0,0 +1,53 @@ +// Copyright (C) 2017 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. + +// Build the unit tests. + +cc_test { + name: "CtsNativeNetTestCases", + + compile_multilib: "both", + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + + srcs: ["src/NativeQtaguidTest.cpp"], + + shared_libs: [ + "libutils", + "liblog", + ], + + static_libs: [ + "libgtest", + "libqtaguid", + ], + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "general-tests", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + +} diff --git a/tests/cts/net/native/qtaguid/AndroidTest.xml b/tests/cts/net/native/qtaguid/AndroidTest.xml new file mode 100644 index 0000000000..fa4b2cf577 --- /dev/null +++ b/tests/cts/net/native/qtaguid/AndroidTest.xml @@ -0,0 +1,32 @@ + + + + diff --git a/tests/cts/net/native/qtaguid/src/NativeQtaguidTest.cpp b/tests/cts/net/native/qtaguid/src/NativeQtaguidTest.cpp new file mode 100644 index 0000000000..7dc6240667 --- /dev/null +++ b/tests/cts/net/native/qtaguid/src/NativeQtaguidTest.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int canAccessQtaguidFile() { + int fd = open("/proc/net/xt_qtaguid/ctrl", O_RDONLY | O_CLOEXEC); + close(fd); + return fd != -1; +} + +#define SKIP_IF_QTAGUID_NOT_SUPPORTED() \ + do { \ + int res = canAccessQtaguidFile(); \ + ASSERT_LE(0, res); \ + if (!res) { \ + GTEST_LOG_(INFO) << "This test is skipped since kernel may not have the module\n"; \ + return; \ + } \ + } while (0) + +int getCtrlSkInfo(int tag, uid_t uid, uint64_t* sk_addr, int* ref_cnt) { + FILE *fp; + fp = fopen("/proc/net/xt_qtaguid/ctrl", "r"); + if (!fp) + return -ENOENT; + uint64_t full_tag = (uint64_t)tag << 32 | uid; + char pattern[40]; + snprintf(pattern, sizeof(pattern), " tag=0x%" PRIx64 " (uid=%" PRIu32 ")", full_tag, uid); + + size_t len; + char *line_buffer = NULL; + while(getline(&line_buffer, &len, fp) != -1) { + if (strstr(line_buffer, pattern) == NULL) + continue; + int res; + pid_t dummy_pid; + uint64_t k_tag; + uint32_t k_uid; + const int TOTAL_PARAM = 5; + res = sscanf(line_buffer, "sock=%" PRIx64 " tag=0x%" PRIx64 " (uid=%" PRIu32 ") " + "pid=%u f_count=%u", sk_addr, &k_tag, &k_uid, + &dummy_pid, ref_cnt); + if (!(res == TOTAL_PARAM && k_tag == full_tag && k_uid == uid)) + return -EINVAL; + free(line_buffer); + return 0; + } + free(line_buffer); + return -ENOENT; +} + +void checkNoSocketPointerLeaks(int family) { + int sockfd = socket(family, SOCK_STREAM, 0); + uid_t uid = getuid(); + int tag = arc4random(); + int ref_cnt; + uint64_t sk_addr; + uint64_t expect_addr = 0; + + EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid)); + EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &sk_addr, &ref_cnt)); + EXPECT_EQ(expect_addr, sk_addr); + close(sockfd); + EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &sk_addr, &ref_cnt)); +} + +TEST (NativeQtaguidTest, close_socket_without_untag) { + SKIP_IF_QTAGUID_NOT_SUPPORTED(); + + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + uid_t uid = getuid(); + int tag = arc4random(); + int ref_cnt; + uint64_t dummy_sk; + EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid)); + EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt)); + EXPECT_EQ(2, ref_cnt); + close(sockfd); + EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt)); +} + +TEST (NativeQtaguidTest, close_socket_without_untag_ipv6) { + SKIP_IF_QTAGUID_NOT_SUPPORTED(); + + int sockfd = socket(AF_INET6, SOCK_STREAM, 0); + uid_t uid = getuid(); + int tag = arc4random(); + int ref_cnt; + uint64_t dummy_sk; + EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid)); + EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt)); + EXPECT_EQ(2, ref_cnt); + close(sockfd); + EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt)); +} + +TEST (NativeQtaguidTest, no_socket_addr_leak) { + SKIP_IF_QTAGUID_NOT_SUPPORTED(); + + checkNoSocketPointerLeaks(AF_INET); + checkNoSocketPointerLeaks(AF_INET6); +} + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/cts/net/src/android/net/cts/AirplaneModeTest.java b/tests/cts/net/src/android/net/cts/AirplaneModeTest.java new file mode 100644 index 0000000000..524e549ab7 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/AirplaneModeTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 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 android.content.ContentResolver; +import android.content.Context; +import android.platform.test.annotations.AppModeFull; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.lang.Thread; + +@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") +public class AirplaneModeTest extends AndroidTestCase { + private static final String TAG = "AirplaneModeTest"; + private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; + private static final String FEATURE_WIFI = "android.hardware.wifi"; + private static final int TIMEOUT_MS = 10 * 1000; + private boolean mHasFeature; + private Context mContext; + private ContentResolver resolver; + + public void setup() { + mContext= getContext(); + resolver = mContext.getContentResolver(); + mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH) + || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI)); + } + + public void testAirplaneMode() { + setup(); + if (!mHasFeature) { + Log.i(TAG, "The device doesn't support network bluetooth or wifi feature"); + return; + } + + for (int testCount = 0; testCount < 2; testCount++) { + if (!doOneTest()) { + fail("Airplane mode failed to change in " + TIMEOUT_MS + "msec"); + return; + } + } + } + + private boolean doOneTest() { + boolean airplaneModeOn = isAirplaneModeOn(); + setAirplaneModeOn(!airplaneModeOn); + + try { + Thread.sleep(TIMEOUT_MS); + } catch (InterruptedException e) { + Log.e(TAG, "Sleep time interrupted.", e); + } + + if (airplaneModeOn == isAirplaneModeOn()) { + return false; + } + return true; + } + + private void setAirplaneModeOn(boolean enabling) { + // Change the system setting for airplane mode + Settings.Global.putInt(resolver, Settings.Global.AIRPLANE_MODE_ON, enabling ? 1 : 0); + } + + private boolean isAirplaneModeOn() { + // Read the system setting for airplane mode + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) != 0; + } +} diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt new file mode 100644 index 0000000000..eb5048fa9b --- /dev/null +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -0,0 +1,194 @@ +/* + * 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 android.Manifest.permission.CONNECTIVITY_INTERNAL +import android.Manifest.permission.NETWORK_SETTINGS +import android.Manifest.permission.READ_DEVICE_CONFIG +import android.content.pm.PackageManager.FEATURE_TELEPHONY +import android.content.pm.PackageManager.FEATURE_WIFI +import android.net.ConnectivityManager +import android.net.ConnectivityManager.NetworkCallback +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import android.net.NetworkRequest +import android.net.Uri +import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig +import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig +import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig +import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig +import android.net.cts.util.CtsNetUtils +import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL +import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL +import android.net.wifi.WifiManager +import android.os.Build +import android.platform.test.annotations.AppModeFull +import android.provider.DeviceConfig +import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY +import android.text.TextUtils +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.TestHttpServer +import com.android.testutils.TestHttpServer.Request +import com.android.testutils.isDevSdkInRange +import com.android.testutils.runAsShell +import fi.iki.elonen.NanoHTTPD.Response.Status +import junit.framework.AssertionFailedError +import org.junit.After +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.runner.RunWith +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException +import kotlin.test.Test +import kotlin.test.assertNotEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +private const val TEST_HTTPS_URL_PATH = "/https_path" +private const val TEST_HTTP_URL_PATH = "/http_path" +private const val TEST_PORTAL_URL_PATH = "/portal_path" + +private const val LOCALHOST_HOSTNAME = "localhost" + +// Re-connecting to the AP, obtaining an IP address, revalidating can take a long time +private const val WIFI_CONNECT_TIMEOUT_MS = 120_000L +private const val TEST_TIMEOUT_MS = 10_000L + +private fun CompletableFuture.assertGet(timeoutMs: Long, message: String): T { + try { + return get(timeoutMs, TimeUnit.MILLISECONDS) + } catch (e: TimeoutException) { + throw AssertionFailedError(message) + } +} + +@AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") +@RunWith(AndroidJUnit4::class) +class CaptivePortalTest { + private val context: android.content.Context by lazy { getInstrumentation().context } + private val wm by lazy { context.getSystemService(WifiManager::class.java) } + private val cm by lazy { context.getSystemService(ConnectivityManager::class.java) } + private val pm by lazy { context.packageManager } + private val utils by lazy { CtsNetUtils(context) } + + private val server = TestHttpServer("localhost") + + @Before + fun setUp() { + runAsShell(READ_DEVICE_CONFIG) { + // Verify that the test URLs are not normally set on the device, but do not fail if the + // test URLs are set to what this test uses (URLs on localhost), in case the test was + // interrupted manually and rerun. + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL) + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL) + } + clearValidationTestUrlsDeviceConfig() + server.start() + } + + @After + fun tearDown() { + clearValidationTestUrlsDeviceConfig() + if (pm.hasSystemFeature(FEATURE_WIFI)) { + reconnectWifi() + } + server.stop() + } + + private fun assertEmptyOrLocalhostUrl(urlKey: String) { + val url = DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, urlKey) + assertTrue(TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME == Uri.parse(url).host, + "$urlKey must not be set in production scenarios (current value: $url)") + } + + @Test + fun testCaptivePortalIsNotDefaultNetwork() { + assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY)) + assumeTrue(pm.hasSystemFeature(FEATURE_WIFI)) + utils.ensureWifiConnected() + utils.connectToCell() + + // Have network validation use a local server that serves a HTTPS error / HTTP redirect + server.addResponse(Request(TEST_PORTAL_URL_PATH), Status.OK, + content = "Test captive portal content") + server.addResponse(Request(TEST_HTTPS_URL_PATH), Status.INTERNAL_ERROR) + server.addResponse(Request(TEST_HTTP_URL_PATH), Status.REDIRECT, + locationHeader = makeUrl(TEST_PORTAL_URL_PATH)) + setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH)) + setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH)) + // URL expiration needs to be in the next 10 minutes + setUrlExpirationDeviceConfig(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)) + + // Wait for a captive portal to be detected on the network + val wifiNetworkFuture = CompletableFuture() + val wifiCb = object : NetworkCallback() { + override fun onCapabilitiesChanged( + network: Network, + nc: NetworkCapabilities + ) { + if (nc.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) { + wifiNetworkFuture.complete(network) + } + } + } + cm.requestNetwork(NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(), wifiCb) + + try { + reconnectWifi() + val network = wifiNetworkFuture.assertGet(WIFI_CONNECT_TIMEOUT_MS, + "Captive portal not detected after ${WIFI_CONNECT_TIMEOUT_MS}ms") + + val wifiDefaultMessage = "Wifi should not be the default network when a captive " + + "portal was detected and another network (mobile data) can provide internet " + + "access." + assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) + + val startPortalAppPermission = + if (isDevSdkInRange(0, Build.VERSION_CODES.Q)) CONNECTIVITY_INTERNAL + else NETWORK_SETTINGS + runAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) } + + // Expect the portal content to be fetched at some point after detecting the portal. + // Some implementations may fetch the URL before startCaptivePortalApp is called. + assertNotNull(server.requestsRecord.poll(TEST_TIMEOUT_MS, pos = 0) { + it.path == TEST_PORTAL_URL_PATH + }, "The captive portal login page was still not fetched ${TEST_TIMEOUT_MS}ms " + + "after startCaptivePortalApp.") + + assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage) + } finally { + cm.unregisterNetworkCallback(wifiCb) + server.stop() + // disconnectFromCell should be called after connectToCell + utils.disconnectFromCell() + } + } + + /** + * Create a URL string that, when fetched, will hit the test server with the given URL [path]. + */ + private fun makeUrl(path: String) = "http://localhost:${server.listeningPort}" + path + + private fun reconnectWifi() { + utils.ensureWifiDisconnected(null /* wifiNetworkToCheck */) + utils.ensureWifiConnected() + } +} \ No newline at end of file diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java new file mode 100644 index 0000000000..54509cd1df --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -0,0 +1,576 @@ +/* + * 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.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_TCP_METRICS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE; +import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; + +import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.annotation.NonNull; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.ConnectivityDiagnosticsManager; +import android.net.ConnectivityManager; +import android.net.LinkAddress; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.os.Binder; +import android.os.Build; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; +import android.os.Process; +import android.platform.test.annotations.AppModeFull; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.util.Pair; + +import androidx.test.InstrumentationRegistry; + +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.util.ArrayUtils; +import com.android.net.module.util.ArrayTrackRecord; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.SkipPresubmit; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +@RunWith(DevSdkIgnoreRunner.class) +@IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q +@AppModeFull(reason = "CHANGE_NETWORK_STATE, MANAGE_TEST_NETWORKS not grantable to instant apps") +public class ConnectivityDiagnosticsManagerTest { + private static final int CALLBACK_TIMEOUT_MILLIS = 5000; + private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500; + private static final long TIMESTAMP = 123456789L; + private static final int DNS_CONSECUTIVE_TIMEOUTS = 5; + private static final int COLLECTION_PERIOD_MILLIS = 5000; + private static final int FAIL_RATE_PERCENTAGE = 100; + private static final int UNKNOWN_DETECTION_METHOD = 4; + private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; + private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000; + private static final int DELAY_FOR_ADMIN_UIDS_MILLIS = 2000; + + private static final Executor INLINE_EXECUTOR = x -> x.run(); + + private static final NetworkRequest TEST_NETWORK_REQUEST = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_TEST) + .removeCapability(NET_CAPABILITY_TRUSTED) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .build(); + + private static final String SHA_256 = "SHA-256"; + + private static final NetworkRequest CELLULAR_NETWORK_REQUEST = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + + private static final IBinder BINDER = new Binder(); + + private Context mContext; + private ConnectivityManager mConnectivityManager; + private ConnectivityDiagnosticsManager mCdm; + private CarrierConfigManager mCarrierConfigManager; + private PackageManager mPackageManager; + private TelephonyManager mTelephonyManager; + + // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests + // for it. + private TestNetworkCallback mTestNetworkCallback; + private Network mTestNetwork; + private ParcelFileDescriptor mTestNetworkFD; + + private List mRegisteredCallbacks; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getContext(); + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class); + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mPackageManager = mContext.getPackageManager(); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + + mTestNetworkCallback = new TestNetworkCallback(); + mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, mTestNetworkCallback); + + mRegisteredCallbacks = new ArrayList<>(); + } + + @After + public void tearDown() throws Exception { + mConnectivityManager.unregisterNetworkCallback(mTestNetworkCallback); + if (mTestNetwork != null) { + runWithShellPermissionIdentity(() -> { + final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); + tnm.teardownTestNetwork(mTestNetwork); + }); + mTestNetwork = null; + } + + if (mTestNetworkFD != null) { + mTestNetworkFD.close(); + mTestNetworkFD = null; + } + + for (TestConnectivityDiagnosticsCallback cb : mRegisteredCallbacks) { + mCdm.unregisterConnectivityDiagnosticsCallback(cb); + } + } + + @Test + public void testRegisterConnectivityDiagnosticsCallback() throws Exception { + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); + + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); + } + + @SkipPresubmit(reason = "Flaky: b/159718782; add to presubmit after fixing") + @Test + public void testRegisterCallbackWithCarrierPrivileges() throws Exception { + assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); + + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + fail("Need an active subscription. Please ensure that the device has working mobile" + + " data."); + } + + final CarrierConfigReceiver carrierConfigReceiver = new CarrierConfigReceiver(subId); + mContext.registerReceiver( + carrierConfigReceiver, + new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + + final TestNetworkCallback testNetworkCallback = new TestNetworkCallback(); + + try { + doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( + subId, carrierConfigReceiver, testNetworkCallback); + } finally { + runWithShellPermissionIdentity( + () -> mCarrierConfigManager.overrideConfig(subId, null), + android.Manifest.permission.MODIFY_PHONE_STATE); + mConnectivityManager.unregisterNetworkCallback(testNetworkCallback); + mContext.unregisterReceiver(carrierConfigReceiver); + } + } + + private String getCertHashForThisPackage() throws Exception { + final PackageInfo pkgInfo = + mPackageManager.getPackageInfo( + mContext.getOpPackageName(), PackageManager.GET_SIGNATURES); + final MessageDigest md = MessageDigest.getInstance(SHA_256); + final byte[] certHash = md.digest(pkgInfo.signatures[0].toByteArray()); + return IccUtils.bytesToHexString(certHash); + } + + private void doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( + int subId, + @NonNull CarrierConfigReceiver carrierConfigReceiver, + @NonNull TestNetworkCallback testNetworkCallback) + throws Exception { + final PersistableBundle carrierConfigs = new PersistableBundle(); + carrierConfigs.putStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, + new String[] {getCertHashForThisPackage()}); + + runWithShellPermissionIdentity( + () -> { + mCarrierConfigManager.overrideConfig(subId, carrierConfigs); + mCarrierConfigManager.notifyConfigChangedForSubId(subId); + }, + android.Manifest.permission.MODIFY_PHONE_STATE); + + // TODO(b/157779832): This should use android.permission.CHANGE_NETWORK_STATE. However, the + // shell does not have CHANGE_NETWORK_STATE, so use CONNECTIVITY_INTERNAL until the shell + // permissions are updated. + runWithShellPermissionIdentity( + () -> mConnectivityManager.requestNetwork( + CELLULAR_NETWORK_REQUEST, testNetworkCallback), + android.Manifest.permission.CONNECTIVITY_INTERNAL); + + final Network network = testNetworkCallback.waitForAvailable(); + assertNotNull(network); + + assertTrue("Didn't receive broadcast for ACTION_CARRIER_CONFIG_CHANGED for subId=" + subId, + carrierConfigReceiver.waitForCarrierConfigChanged()); + assertTrue("Don't have Carrier Privileges after adding cert for this package", + mTelephonyManager.createForSubscriptionId(subId).hasCarrierPrivileges()); + + // Wait for CarrierPrivilegesTracker to receive the ACTION_CARRIER_CONFIG_CHANGED + // broadcast. CPT then needs to update the corresponding DataConnection, which then + // updates ConnectivityService. Unfortunately, this update to the NetworkCapabilities in + // CS does not trigger NetworkCallback#onCapabilitiesChanged as changing the + // administratorUids is not a publicly visible change. In lieu of a better signal to + // detministically wait for, use Thread#sleep here. + // TODO(b/157949581): replace this Thread#sleep with a deterministic signal + Thread.sleep(DELAY_FOR_ADMIN_UIDS_MILLIS); + + final TestConnectivityDiagnosticsCallback connDiagsCallback = + createAndRegisterConnectivityDiagnosticsCallback(CELLULAR_NETWORK_REQUEST); + + final String interfaceName = + mConnectivityManager.getLinkProperties(network).getInterfaceName(); + connDiagsCallback.expectOnConnectivityReportAvailable( + network, interfaceName, TRANSPORT_CELLULAR); + connDiagsCallback.assertNoCallback(); + } + + @Test + public void testRegisterDuplicateConnectivityDiagnosticsCallback() { + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); + + try { + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + fail("Registering the same callback twice should throw an IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testUnregisterConnectivityDiagnosticsCallback() { + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + mCdm.unregisterConnectivityDiagnosticsCallback(cb); + } + + @Test + public void testUnregisterUnknownConnectivityDiagnosticsCallback() { + // Expected to silently ignore the unregister() call + mCdm.unregisterConnectivityDiagnosticsCallback(new TestConnectivityDiagnosticsCallback()); + } + + @Test + public void testOnConnectivityReportAvailable() throws Exception { + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); + + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); + } + + @Test + public void testOnDataStallSuspected_DnsEvents() throws Exception { + final PersistableBundle extras = new PersistableBundle(); + extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, DNS_CONSECUTIVE_TIMEOUTS); + + verifyOnDataStallSuspected(DETECTION_METHOD_DNS_EVENTS, TIMESTAMP, extras); + } + + @Test + public void testOnDataStallSuspected_TcpMetrics() throws Exception { + final PersistableBundle extras = new PersistableBundle(); + extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS, COLLECTION_PERIOD_MILLIS); + extras.putInt(KEY_TCP_PACKET_FAIL_RATE, FAIL_RATE_PERCENTAGE); + + verifyOnDataStallSuspected(DETECTION_METHOD_TCP_METRICS, TIMESTAMP, extras); + } + + @Test + public void testOnDataStallSuspected_UnknownDetectionMethod() throws Exception { + verifyOnDataStallSuspected( + UNKNOWN_DETECTION_METHOD, + FILTERED_UNKNOWN_DETECTION_METHOD, + TIMESTAMP, + PersistableBundle.EMPTY); + } + + private void verifyOnDataStallSuspected( + int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras) + throws Exception { + // Input detection method is expected to match received detection method + verifyOnDataStallSuspected(detectionMethod, detectionMethod, timestampMillis, extras); + } + + private void verifyOnDataStallSuspected( + int inputDetectionMethod, + int expectedDetectionMethod, + long timestampMillis, + @NonNull PersistableBundle extras) + throws Exception { + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); + + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); + + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + + runWithShellPermissionIdentity( + () -> mConnectivityManager.simulateDataStall( + inputDetectionMethod, timestampMillis, mTestNetwork, extras), + android.Manifest.permission.MANAGE_TEST_NETWORKS); + + cb.expectOnDataStallSuspected( + mTestNetwork, interfaceName, expectedDetectionMethod, timestampMillis, extras); + cb.assertNoCallback(); + } + + @Test + public void testOnNetworkConnectivityReportedTrue() throws Exception { + verifyOnNetworkConnectivityReported(true /* hasConnectivity */); + } + + @Test + public void testOnNetworkConnectivityReportedFalse() throws Exception { + verifyOnNetworkConnectivityReported(false /* hasConnectivity */); + } + + private void verifyOnNetworkConnectivityReported(boolean hasConnectivity) throws Exception { + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); + + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); + + // onConnectivityReportAvailable always invoked when the test network is established + final String interfaceName = + mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + cb.assertNoCallback(); + + mConnectivityManager.reportNetworkConnectivity(mTestNetwork, hasConnectivity); + + cb.expectOnNetworkConnectivityReported(mTestNetwork, hasConnectivity); + + // if hasConnectivity does not match the network's known connectivity, it will be + // revalidated which will trigger another onConnectivityReportAvailable callback. + if (!hasConnectivity) { + cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); + } + + cb.assertNoCallback(); + } + + private TestConnectivityDiagnosticsCallback createAndRegisterConnectivityDiagnosticsCallback( + NetworkRequest request) { + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, cb); + mRegisteredCallbacks.add(cb); + return cb; + } + + /** + * Registers a test NetworkAgent with ConnectivityService with limited capabilities, which leads + * to the Network being validated. + */ + @NonNull + private TestNetworkInterface setUpTestNetwork() throws Exception { + final int[] administratorUids = new int[] {Process.myUid()}; + return callWithShellPermissionIdentity( + () -> { + final TestNetworkManager tnm = + mContext.getSystemService(TestNetworkManager.class); + final TestNetworkInterface tni = tnm.createTunInterface(new LinkAddress[0]); + tnm.setupTestNetwork(tni.getInterfaceName(), administratorUids, BINDER); + return tni; + }); + } + + private static class TestConnectivityDiagnosticsCallback + extends ConnectivityDiagnosticsCallback { + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + + @Override + public void onConnectivityReportAvailable(ConnectivityReport report) { + mHistory.add(report); + } + + @Override + public void onDataStallSuspected(DataStallReport report) { + mHistory.add(report); + } + + @Override + public void onNetworkConnectivityReported(Network network, boolean hasConnectivity) { + mHistory.add(new Pair(network, hasConnectivity)); + } + + public void expectOnConnectivityReportAvailable( + @NonNull Network network, @NonNull String interfaceName) { + expectOnConnectivityReportAvailable(network, interfaceName, TRANSPORT_TEST); + } + + public void expectOnConnectivityReportAvailable( + @NonNull Network network, @NonNull String interfaceName, int transportType) { + final ConnectivityReport result = + (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.getNetwork()); + + final NetworkCapabilities nc = result.getNetworkCapabilities(); + assertNotNull(nc); + assertTrue(nc.hasTransport(transportType)); + assertNotNull(result.getLinkProperties()); + assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); + + final PersistableBundle extras = result.getAdditionalInfo(); + assertTrue(extras.containsKey(KEY_NETWORK_VALIDATION_RESULT)); + final int validationResult = extras.getInt(KEY_NETWORK_VALIDATION_RESULT); + assertEquals("Network validation result is not 'valid'", + NETWORK_VALIDATION_RESULT_VALID, validationResult); + + assertTrue(extras.containsKey(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK)); + final int probesSucceeded = extras.getInt(KEY_NETWORK_VALIDATION_RESULT); + assertTrue("PROBES_SUCCEEDED mask not in expected range", probesSucceeded >= 0); + + assertTrue(extras.containsKey(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK)); + final int probesAttempted = extras.getInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK); + assertTrue("PROBES_ATTEMPTED mask not in expected range", probesAttempted >= 0); + } + + public void expectOnDataStallSuspected( + @NonNull Network network, + @NonNull String interfaceName, + int detectionMethod, + long timestampMillis, + @NonNull PersistableBundle extras) { + final DataStallReport result = + (DataStallReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.getNetwork()); + assertEquals(detectionMethod, result.getDetectionMethod()); + assertEquals(timestampMillis, result.getReportTimestamp()); + + final NetworkCapabilities nc = result.getNetworkCapabilities(); + assertNotNull(nc); + assertTrue(nc.hasTransport(TRANSPORT_TEST)); + assertNotNull(result.getLinkProperties()); + assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); + + assertTrue(persistableBundleEquals(extras, result.getStallDetails())); + } + + public void expectOnNetworkConnectivityReported( + @NonNull Network network, boolean hasConnectivity) { + final Pair result = + (Pair) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); + assertEquals(network, result.first /* network */); + assertEquals(hasConnectivity, result.second /* hasConnectivity */); + } + + public void assertNoCallback() { + // If no more callbacks exist, there should be nothing left in the ReadHead + assertNull("Unexpected event in history", + mHistory.poll(NO_CALLBACK_INVOKED_TIMEOUT, x -> true)); + } + } + + private class CarrierConfigReceiver extends BroadcastReceiver { + private final CountDownLatch mLatch = new CountDownLatch(1); + private final int mSubId; + + CarrierConfigReceiver(int subId) { + mSubId = subId; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { + return; + } + + final int subId = + intent.getIntExtra( + CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (mSubId != subId) return; + + final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) return; + + final String[] certs = + carrierConfigs.getStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); + try { + if (ArrayUtils.contains(certs, getCertHashForThisPackage())) { + mLatch.countDown(); + } + } catch (Exception e) { + } + } + + boolean waitForCarrierConfigChanged() throws Exception { + return mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java new file mode 100644 index 0000000000..db4e3e744a --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -0,0 +1,1530 @@ +/* + * Copyright (C) 2009 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.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; +import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.content.pm.PackageManager.FEATURE_ETHERNET; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.content.pm.PackageManager.FEATURE_USB_HOST; +import static android.content.pm.PackageManager.FEATURE_WIFI; +import static android.content.pm.PackageManager.GET_PERMISSIONS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver; +import static android.net.cts.util.CtsNetUtils.HTTP_PORT; +import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION; +import static android.net.cts.util.CtsNetUtils.TEST_HOST; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.AF_UNSPEC; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; +import static com.android.testutils.TestPermissionUtil.runAsShell; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.annotation.NonNull; +import android.app.Instrumentation; +import android.app.PendingIntent; +import android.app.UiAutomation; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.IpSecManager; +import android.net.IpSecManager.UdpEncapsulationSocket; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkConfig; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; +import android.net.NetworkRequest; +import android.net.NetworkUtils; +import android.net.SocketKeepalive; +import android.net.cts.util.CtsNetUtils; +import android.net.util.KeepaliveUtils; +import android.net.wifi.WifiManager; +import android.os.Binder; +import android.os.Build; +import android.os.Looper; +import android.os.MessageQueue; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.VintfRuntimeInfo; +import android.platform.test.annotations.AppModeFull; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.util.ArrayUtils; +import com.android.testutils.RecorderCallback.CallbackEntry; +import com.android.testutils.SkipPresubmit; +import com.android.testutils.TestableNetworkCallback; + +import libcore.io.Streams; + +import junit.framework.AssertionFailedError; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.URL; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@RunWith(AndroidJUnit4.class) +public class ConnectivityManagerTest { + + private static final String TAG = ConnectivityManagerTest.class.getSimpleName(); + + public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; + public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; + + private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 + private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000; + private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500; + private static final int MAX_KEEPALIVE_RETRY_COUNT = 3; + private static final int MIN_KEEPALIVE_INTERVAL = 10; + + // Changing meteredness on wifi involves reconnecting, which can take several seconds (involves + // re-associating, DHCP...) + private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 30_000; + private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; + private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; + // device could have only one interface: data, wifi. + private static final int MIN_NUM_NETWORK_TYPES = 1; + + // Airplane Mode BroadcastReceiver Timeout + private static final long AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 10_000L; + + // Minimum supported keepalive counts for wifi and cellular. + public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1; + public static final int MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT = 3; + + private static final String NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME = + "config_networkMeteredMultipathPreference"; + private static final String KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME = + "config_allowedUnprivilegedKeepalivePerUid"; + private static final String KEEPALIVE_RESERVED_PER_SLOT_RES_NAME = + "config_reservedPrivilegedKeepaliveSlots"; + + private Context mContext; + private Instrumentation mInstrumentation; + private ConnectivityManager mCm; + private WifiManager mWifiManager; + private PackageManager mPackageManager; + private final HashMap mNetworks = + new HashMap(); + boolean mWifiWasDisabled; + private UiAutomation mUiAutomation; + private CtsNetUtils mCtsNetUtils; + + @Before + public void setUp() throws Exception { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mContext = mInstrumentation.getContext(); + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mPackageManager = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); + mWifiWasDisabled = false; + + // Get com.android.internal.R.array.networkAttributes + int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android"); + String[] naStrings = mContext.getResources().getStringArray(resId); + //TODO: What is the "correct" way to determine if this is a wifi only device? + boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false); + for (String naString : naStrings) { + try { + NetworkConfig n = new NetworkConfig(naString); + if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) { + continue; + } + mNetworks.put(n.type, n); + } catch (Exception e) {} + } + mUiAutomation = mInstrumentation.getUiAutomation(); + + assertNotNull("CTS requires a working Internet connection", mCm.getActiveNetwork()); + } + + @After + public void tearDown() throws Exception { + // Return WiFi to its original disabled state after tests that explicitly connect. + if (mWifiWasDisabled) { + mCtsNetUtils.disconnectFromWifi(null); + } + if (mCtsNetUtils.cellConnectAttempted()) { + mCtsNetUtils.disconnectFromCell(); + } + + // All tests in this class require a working Internet connection as they start. Make + // sure there is still one as they end that's ready to use for the next test to use. + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(callback); + try { + assertNotNull("Couldn't restore Internet connectivity", callback.waitForAvailable()); + } finally { + mCm.unregisterNetworkCallback(callback); + } + } + + /** + * Make sure WiFi is connected to an access point if it is not already. If + * WiFi is enabled as a result of this function, it will be disabled + * automatically in tearDown(). + */ + private Network ensureWifiConnected() { + mWifiWasDisabled = !mWifiManager.isWifiEnabled(); + // Even if wifi is enabled, the network may not be connected or ready yet + return mCtsNetUtils.connectToWifi(); + } + + @Test + public void testIsNetworkTypeValid() { + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_MMS)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_SUPL)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_DUN)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_HIPRI)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIMAX)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_BLUETOOTH)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_DUMMY)); + assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_ETHERNET)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_FOTA)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IA)); + assertFalse(mCm.isNetworkTypeValid(-1)); + assertTrue(mCm.isNetworkTypeValid(0)); + assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE)); + assertFalse(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE+1)); + + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + + for (NetworkInfo n: ni) { + assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType())); + } + + } + + @Test + public void testSetNetworkPreference() { + // getNetworkPreference() and setNetworkPreference() are both deprecated so they do + // not preform any action. Verify they are at least still callable. + mCm.setNetworkPreference(mCm.getNetworkPreference()); + } + + @Test + public void testGetActiveNetworkInfo() { + NetworkInfo ni = mCm.getActiveNetworkInfo(); + + assertNotNull("You must have an active network connection to complete CTS", ni); + assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); + assertTrue(ni.getState() == State.CONNECTED); + } + + @Test + public void testGetActiveNetwork() { + Network network = mCm.getActiveNetwork(); + assertNotNull("You must have an active network connection to complete CTS", network); + + NetworkInfo ni = mCm.getNetworkInfo(network); + assertNotNull("Network returned from getActiveNetwork was invalid", ni); + + // Similar to testGetActiveNetworkInfo above. + assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); + assertTrue(ni.getState() == State.CONNECTED); + } + + @Test + public void testGetNetworkInfo() { + for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { + if (shouldBeSupported(type)) { + NetworkInfo ni = mCm.getNetworkInfo(type); + assertTrue("Info shouldn't be null for " + type, ni != null); + State state = ni.getState(); + assertTrue("Bad state for " + type, State.UNKNOWN.ordinal() >= state.ordinal() + && state.ordinal() >= State.CONNECTING.ordinal()); + DetailedState ds = ni.getDetailedState(); + assertTrue("Bad detailed state for " + type, + DetailedState.FAILED.ordinal() >= ds.ordinal() + && ds.ordinal() >= DetailedState.IDLE.ordinal()); + } else { + assertNull("Info should be null for " + type, mCm.getNetworkInfo(type)); + } + } + } + + @Test + public void testGetAllNetworkInfo() { + NetworkInfo[] ni = mCm.getAllNetworkInfo(); + assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); + for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { + int desiredFoundCount = (shouldBeSupported(type) ? 1 : 0); + int foundCount = 0; + for (NetworkInfo i : ni) { + if (i.getType() == type) foundCount++; + } + if (foundCount != desiredFoundCount) { + Log.e(TAG, "failure in testGetAllNetworkInfo. Dump of returned NetworkInfos:"); + for (NetworkInfo networkInfo : ni) Log.e(TAG, " " + networkInfo); + } + assertTrue("Unexpected foundCount of " + foundCount + " for type " + type, + foundCount == desiredFoundCount); + } + } + + /** + * Tests that connections can be opened on WiFi and cellphone networks, + * and that they are made from different IP addresses. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + @SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks") + public void testOpenConnection() throws Exception { + boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) + && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); + if (!canRunTest) { + Log.i(TAG,"testOpenConnection cannot execute unless device supports both WiFi " + + "and a cellular connection"); + return; + } + + Network wifiNetwork = mCtsNetUtils.connectToWifi(); + Network cellNetwork = mCtsNetUtils.connectToCell(); + // This server returns the requestor's IP address as the response body. + URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text"); + String wifiAddressString = httpGet(wifiNetwork, url); + String cellAddressString = httpGet(cellNetwork, url); + + assertFalse(String.format("Same address '%s' on two different networks (%s, %s)", + wifiAddressString, wifiNetwork, cellNetwork), + wifiAddressString.equals(cellAddressString)); + + // Verify that the IP addresses that the requests appeared to come from are actually on the + // respective networks. + assertOnNetwork(wifiAddressString, wifiNetwork); + assertOnNetwork(cellAddressString, cellNetwork); + + assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork)); + } + + /** + * Performs a HTTP GET to the specified URL on the specified Network, and returns + * the response body decoded as UTF-8. + */ + private static String httpGet(Network network, URL httpUrl) throws IOException { + HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl); + try { + InputStream inputStream = connection.getInputStream(); + return Streams.readFully(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + } finally { + connection.disconnect(); + } + } + + private void assertOnNetwork(String adressString, Network network) throws UnknownHostException { + InetAddress address = InetAddress.getByName(adressString); + LinkProperties linkProperties = mCm.getLinkProperties(network); + // To make sure that the request went out on the right network, check that + // the IP address seen by the server is assigned to the expected network. + // We can only do this for IPv6 addresses, because in IPv4 we will likely + // have a private IPv4 address, and that won't match what the server sees. + if (address instanceof Inet6Address) { + assertContains(linkProperties.getAddresses(), address); + } + } + + private static void assertContains(Collection collection, T element) { + assertTrue(element + " not found in " + collection, collection.contains(element)); + } + + private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) { + try { + mCm.startUsingNetworkFeature(networkType, feature); + fail("startUsingNetworkFeature is no longer supported in the current API version"); + } catch (UnsupportedOperationException expected) {} + } + + private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) { + try { + mCm.startUsingNetworkFeature(networkType, feature); + fail("stopUsingNetworkFeature is no longer supported in the current API version"); + } catch (UnsupportedOperationException expected) {} + } + + private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) { + try { + mCm.requestRouteToHost(networkType, hostAddress); + fail("requestRouteToHost is no longer supported in the current API version"); + } catch (UnsupportedOperationException expected) {} + } + + @Test + public void testStartUsingNetworkFeature() { + + final String invalidateFeature = "invalidateFeature"; + final String mmsFeature = "enableMMS"; + + assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature); + assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature); + assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature); + } + + private boolean shouldEthernetBeSupported() { + // Instant mode apps aren't allowed to query the Ethernet service due to selinux policies. + // When in instant mode, don't fail if the Ethernet service is available. Instead, rely on + // the fact that Ethernet should be supported if the device has a hardware Ethernet port, or + // if the device can be a USB host and thus can use USB Ethernet adapters. + // + // Note that this test this will still fail in instant mode if a device supports Ethernet + // via other hardware means. We are not currently aware of any such device. + return (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) || + mPackageManager.hasSystemFeature(FEATURE_ETHERNET) || + mPackageManager.hasSystemFeature(FEATURE_USB_HOST); + } + + private boolean shouldBeSupported(int networkType) { + return mNetworks.containsKey(networkType) || + (networkType == ConnectivityManager.TYPE_VPN) || + (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported()); + } + + @Test + public void testIsNetworkSupported() { + for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { + boolean supported = mCm.isNetworkSupported(type); + if (shouldBeSupported(type)) { + assertTrue("Network type " + type + " should be supported", supported); + } else { + assertFalse("Network type " + type + " should not be supported", supported); + } + } + } + + @Test + public void testRequestRouteToHost() { + for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { + assertRequestRouteToHostUnsupported(type, HOST_ADDRESS); + } + } + + @Test + public void testTest() { + mCm.getBackgroundDataSetting(); + } + + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + + private NetworkRequest makeCellNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .build(); + } + + /** + * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to + * see if we get a callback for the TRANSPORT_WIFI transport type being available. + * + *

    In order to test that a NetworkCallback occurs, we need some change in the network + * state (either a transport or capability is now available). The most straightforward is + * WiFi. We could add a version that uses the telephony data connection but it's not clear + * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?). + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + public void testRegisterNetworkCallback() { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); + return; + } + + // We will register for a WIFI network being available or lost. + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + + final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultTrackingCallback); + + Network wifiNetwork = null; + + try { + ensureWifiConnected(); + + // Now we should expect to get a network callback about availability of the wifi + // network even if it was already connected as a state-based action when the callback + // is registered. + wifiNetwork = callback.waitForAvailable(); + assertNotNull("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI", + wifiNetwork); + + assertNotNull("Did not receive NetworkCallback.onAvailable for any default network", + defaultTrackingCallback.waitForAvailable()); + } catch (InterruptedException e) { + fail("Broadcast receiver or NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + mCm.unregisterNetworkCallback(defaultTrackingCallback); + } + } + + /** + * Tests both registerNetworkCallback and unregisterNetworkCallback similarly to + * {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead + * of a {@code NetworkCallback}. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + public void testRegisterNetworkCallback_withPendingIntent() { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); + return; + } + + // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined + // action, NETWORK_CALLBACK_ACTION. + IntentFilter filter = new IntentFilter(); + filter.addAction(NETWORK_CALLBACK_ACTION); + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + mContext.registerReceiver(receiver, filter); + + // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION. + Intent intent = new Intent(NETWORK_CALLBACK_ACTION); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + + // We will register for a WIFI network being available or lost. + mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent); + + try { + ensureWifiConnected(); + + // Now we expect to get the Intent delivered notifying of the availability of the wifi + // network even if it was already connected as a state-based action when the callback + // is registered. + assertTrue("Did not receive expected Intent " + intent + " for TRANSPORT_WIFI", + receiver.waitForState()); + } catch (InterruptedException e) { + fail("Broadcast receiver or NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(pendingIntent); + pendingIntent.cancel(); + mContext.unregisterReceiver(receiver); + } + } + + /** + * Exercises the requestNetwork with NetworkCallback API. This checks to + * see if we get a callback for an INTERNET request. + */ + @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + @Test + public void testRequestNetworkCallback() { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.requestNetwork(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), callback); + + try { + // Wait to get callback for availability of internet + Network internetNetwork = callback.waitForAvailable(); + assertNotNull("Did not receive NetworkCallback#onAvailable for INTERNET", + internetNetwork); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + } + } + + /** + * Exercises the requestNetwork with NetworkCallback API with timeout - expected to + * fail. Use WIFI and switch Wi-Fi off. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + public void testRequestNetworkCallback_onUnavailable() { + final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); + if (previousWifiEnabledState) { + mCtsNetUtils.ensureWifiDisconnected(null); + } + + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.requestNetwork(new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .build(), callback, 100); + + try { + // Wait to get callback for unavailability of requested network + assertTrue("Did not receive NetworkCallback#onUnavailable", + callback.waitForUnavailable()); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + if (previousWifiEnabledState) { + mCtsNetUtils.connectToWifi(); + } + } + } + + private InetAddress getFirstV4Address(Network network) { + LinkProperties linkProperties = mCm.getLinkProperties(network); + for (InetAddress address : linkProperties.getAddresses()) { + if (address instanceof Inet4Address) { + return address; + } + } + return null; + } + + /** Verify restricted networks cannot be requested. */ + @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + @Test + public void testRestrictedNetworks() { + // Verify we can request unrestricted networks: + NetworkRequest request = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_INTERNET).build(); + NetworkCallback callback = new NetworkCallback(); + mCm.requestNetwork(request, callback); + mCm.unregisterNetworkCallback(callback); + // Verify we cannot request restricted networks: + request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build(); + callback = new NetworkCallback(); + try { + mCm.requestNetwork(request, callback); + fail("No exception thrown when restricted network requested."); + } catch (SecurityException expected) {} + } + + // Returns "true", "false" or "none" + private String getWifiMeteredStatus(String ssid) throws Exception { + // Interestingly giving the SSID as an argument to list wifi-networks + // only works iff the network in question has the "false" policy. + // Also unfortunately runShellCommand does not pass the command to the interpreter + // so it's not possible to | grep the ssid. + final String command = "cmd netpolicy list wifi-networks"; + final String policyString = runShellCommand(mInstrumentation, command); + + final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$", + Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString); + if (!m.find()) { + fail("Unexpected format from cmd netpolicy"); + } + return m.group(1); + } + + // metered should be "true", "false" or "none" + private void setWifiMeteredStatus(String ssid, String metered) throws Exception { + final String setCommand = "cmd netpolicy set metered-network " + ssid + " " + metered; + runShellCommand(mInstrumentation, setCommand); + assertEquals(getWifiMeteredStatus(ssid), metered); + } + + private String unquoteSSID(String ssid) { + // SSID is returned surrounded by quotes if it can be decoded as UTF-8. + // Otherwise it's guaranteed not to start with a quote. + if (ssid.charAt(0) == '"') { + return ssid.substring(1, ssid.length() - 1); + } else { + return ssid; + } + } + + private void waitForActiveNetworkMetered(int targetTransportType, boolean requestedMeteredness) + throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final NetworkCallback networkCallback = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + if (!nc.hasTransport(targetTransportType)) return; + + final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); + if (metered == requestedMeteredness) { + latch.countDown(); + } + } + }; + // Registering a callback here guarantees onCapabilitiesChanged is called immediately + // with the current setting. Therefore, if the setting has already been changed, + // this method will return right away, and if not it will wait for the setting to change. + mCm.registerDefaultNetworkCallback(networkCallback); + if (!latch.await(NETWORK_CHANGE_METEREDNESS_TIMEOUT, TimeUnit.MILLISECONDS)) { + fail("Timed out waiting for active network metered status to change to " + + requestedMeteredness + " ; network = " + mCm.getActiveNetwork()); + } + mCm.unregisterNetworkCallback(networkCallback); + } + + private void assertMultipathPreferenceIsEventually(Network network, int oldValue, + int expectedValue) { + // Quick check : if oldValue == expectedValue, there is no way to guarantee the test + // is not flaky. + assertNotSame(oldValue, expectedValue); + + for (int i = 0; i < NUM_TRIES_MULTIPATH_PREF_CHECK; ++i) { + final int actualValue = mCm.getMultipathPreference(network); + if (actualValue == expectedValue) { + return; + } + if (actualValue != oldValue) { + fail("Multipath preference is neither previous (" + oldValue + + ") nor expected (" + expectedValue + ")"); + } + SystemClock.sleep(INTERVAL_MULTIPATH_PREF_CHECK_MS); + } + fail("Timed out waiting for multipath preference to change. expected = " + + expectedValue + " ; actual = " + mCm.getMultipathPreference(network)); + } + + private int getCurrentMeteredMultipathPreference(ContentResolver resolver) { + final String rawMeteredPref = Settings.Global.getString(resolver, + NETWORK_METERED_MULTIPATH_PREFERENCE); + return TextUtils.isEmpty(rawMeteredPref) + ? getIntResourceForName(NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME) + : Integer.parseInt(rawMeteredPref); + } + + private int findNextPrefValue(ContentResolver resolver) { + // A bit of a nuclear hammer, but race conditions in CTS are bad. To be able to + // detect a correct setting value without race conditions, the next pref must + // be a valid value (range 0..3) that is different from the old setting of the + // metered preference and from the unmetered preference. + final int meteredPref = getCurrentMeteredMultipathPreference(resolver); + final int unmeteredPref = ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED; + if (0 != meteredPref && 0 != unmeteredPref) return 0; + if (1 != meteredPref && 1 != unmeteredPref) return 1; + return 2; + } + + /** + * Verify that getMultipathPreference does return appropriate values + * for metered and unmetered networks. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + public void testGetMultipathPreference() throws Exception { + final ContentResolver resolver = mContext.getContentResolver(); + ensureWifiConnected(); + final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID()); + final String oldMeteredSetting = getWifiMeteredStatus(ssid); + final String oldMeteredMultipathPreference = Settings.Global.getString( + resolver, NETWORK_METERED_MULTIPATH_PREFERENCE); + try { + final int initialMeteredPreference = getCurrentMeteredMultipathPreference(resolver); + int newMeteredPreference = findNextPrefValue(resolver); + Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, + Integer.toString(newMeteredPreference)); + setWifiMeteredStatus(ssid, "true"); + waitForActiveNetworkMetered(TRANSPORT_WIFI, true); + // Wifi meterness changes from unmetered to metered will disconnect and reconnect since + // R. + final Network network = ensureWifiConnected(); + assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID())); + assertEquals(mCm.getNetworkCapabilities(network).hasCapability( + NET_CAPABILITY_NOT_METERED), false); + assertMultipathPreferenceIsEventually(network, initialMeteredPreference, + newMeteredPreference); + + final int oldMeteredPreference = newMeteredPreference; + newMeteredPreference = findNextPrefValue(resolver); + Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, + Integer.toString(newMeteredPreference)); + assertEquals(mCm.getNetworkCapabilities(network).hasCapability( + NET_CAPABILITY_NOT_METERED), false); + assertMultipathPreferenceIsEventually(network, + oldMeteredPreference, newMeteredPreference); + + setWifiMeteredStatus(ssid, "false"); + // No disconnect from unmetered to metered. + waitForActiveNetworkMetered(TRANSPORT_WIFI, false); + assertEquals(mCm.getNetworkCapabilities(network).hasCapability( + NET_CAPABILITY_NOT_METERED), true); + assertMultipathPreferenceIsEventually(network, newMeteredPreference, + ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED); + } finally { + Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, + oldMeteredMultipathPreference); + setWifiMeteredStatus(ssid, oldMeteredSetting); + } + } + + // TODO: move the following socket keep alive test to dedicated test class. + /** + * Callback used in tcp keepalive offload that allows caller to wait callback fires. + */ + private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback { + public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; + + public static class CallbackValue { + public final CallbackType callbackType; + public final int error; + + private CallbackValue(final CallbackType type, final int error) { + this.callbackType = type; + this.error = error; + } + + public static class OnStartedCallback extends CallbackValue { + OnStartedCallback() { super(CallbackType.ON_STARTED, 0); } + } + + public static class OnStoppedCallback extends CallbackValue { + OnStoppedCallback() { super(CallbackType.ON_STOPPED, 0); } + } + + public static class OnErrorCallback extends CallbackValue { + OnErrorCallback(final int error) { super(CallbackType.ON_ERROR, error); } + } + + @Override + public boolean equals(Object o) { + return o.getClass() == this.getClass() + && this.callbackType == ((CallbackValue) o).callbackType + && this.error == ((CallbackValue) o).error; + } + + @Override + public String toString() { + return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error); + } + } + + private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + @Override + public void onStarted() { + mCallbacks.add(new CallbackValue.OnStartedCallback()); + } + + @Override + public void onStopped() { + mCallbacks.add(new CallbackValue.OnStoppedCallback()); + } + + @Override + public void onError(final int error) { + mCallbacks.add(new CallbackValue.OnErrorCallback(error)); + } + + public CallbackValue pollCallback() { + try { + return mCallbacks.poll(KEEPALIVE_CALLBACK_TIMEOUT_MS, + TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + fail("Callback not seen after " + KEEPALIVE_CALLBACK_TIMEOUT_MS + " ms"); + } + return null; + } + private void expectCallback(CallbackValue expectedCallback) { + final CallbackValue actualCallback = pollCallback(); + assertEquals(expectedCallback, actualCallback); + } + + public void expectStarted() { + expectCallback(new CallbackValue.OnStartedCallback()); + } + + public void expectStopped() { + expectCallback(new CallbackValue.OnStoppedCallback()); + } + + public void expectError(int error) { + expectCallback(new CallbackValue.OnErrorCallback(error)); + } + } + + private InetAddress getAddrByName(final String hostname, final int family) throws Exception { + final InetAddress[] allAddrs = InetAddress.getAllByName(hostname); + for (InetAddress addr : allAddrs) { + if (family == AF_INET && addr instanceof Inet4Address) return addr; + + if (family == AF_INET6 && addr instanceof Inet6Address) return addr; + + if (family == AF_UNSPEC) return addr; + } + return null; + } + + private Socket getConnectedSocket(final Network network, final String host, final int port, + final int family) throws Exception { + final Socket s = network.getSocketFactory().createSocket(); + try { + final InetAddress addr = getAddrByName(host, family); + if (addr == null) fail("Fail to get destination address for " + family); + + final InetSocketAddress sockAddr = new InetSocketAddress(addr, port); + s.connect(sockAddr); + } catch (Exception e) { + s.close(); + throw e; + } + return s; + } + + private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception { + final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + + // Get number of supported concurrent keepalives for testing network. + final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); + return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + keepalivesPerTransport, nc); + } + + private static boolean isTcpKeepaliveSupportedByKernel() { + final String kVersionString = VintfRuntimeInfo.getKernelVersion(); + return compareMajorMinorVersion(kVersionString, "4.8") >= 0; + } + + private static Pair getVersionFromString(String version) { + // Only gets major and minor number of the version string. + final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); + final Matcher m = versionPattern.matcher(version); + if (m.matches()) { + final int major = Integer.parseInt(m.group(1)); + final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3)); + return new Pair<>(major, minor); + } else { + return new Pair<>(0, 0); + } + } + + // TODO: Move to util class. + private static int compareMajorMinorVersion(final String s1, final String s2) { + final Pair v1 = getVersionFromString(s1); + final Pair v2 = getVersionFromString(s2); + + if (v1.first == v2.first) { + return Integer.compare(v1.second, v2.second); + } else { + return Integer.compare(v1.first, v2.first); + } + } + + /** + * Verifies that version string compare logic returns expected result for various cases. + * Note that only major and minor number are compared. + */ + @Test + public void testMajorMinorVersionCompare() { + assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8")); + assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1")); + assertEquals(1, compareMajorMinorVersion("5.0", "4.8")); + assertEquals(1, compareMajorMinorVersion("5", "4.8")); + assertEquals(0, compareMajorMinorVersion("5", "5.0")); + assertEquals(1, compareMajorMinorVersion("5-beta1", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8.0.0", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8-RC1", "4.8")); + assertEquals(0, compareMajorMinorVersion("4.8", "4.8")); + assertEquals(-1, compareMajorMinorVersion("3.10", "4.8.0")); + assertEquals(-1, compareMajorMinorVersion("4.7.10.10", "4.8")); + } + + /** + * Verifies that the keepalive API cannot create any keepalive when the maximum number of + * keepalives is set to 0. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + public void testKeepaliveWifiUnsupported() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + if (getSupportedKeepalivesForNet(network) != 0) return; + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); + + runWithShellPermissionIdentity(() -> { + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0)); + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); + }); + } + + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") + public void testCreateTcpKeepalive() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + if (getSupportedKeepalivesForNet(network) == 0) return; + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); + + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support + // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive + // needs to be supported except if the kernel doesn't support it. + if (!isTcpKeepaliveSupportedByKernel()) { + // Verify that the callback result is expected. + runWithShellPermissionIdentity(() -> { + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); + }); + Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " + + VintfRuntimeInfo.getKernelVersion()); + return; + } + + final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8"); + // So far only ipv4 tcp keepalive offload is supported. + // TODO: add test case for ipv6 tcp keepalive offload when it is supported. + try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, AF_INET)) { + + // Should able to start keep alive offload when socket is idle. + final Executor executor = mContext.getMainExecutor(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + + mUiAutomation.adoptShellPermissionIdentity(); + try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { + sk.start(MIN_KEEPALIVE_INTERVAL); + callback.expectStarted(); + + // App should not able to write during keepalive offload. + final OutputStream out = s.getOutputStream(); + try { + out.write(requestBytes); + fail("Should not able to write"); + } catch (IOException e) { } + // App should not able to read during keepalive offload. + final InputStream in = s.getInputStream(); + byte[] responseBytes = new byte[4096]; + try { + in.read(responseBytes); + fail("Should not able to read"); + } catch (IOException e) { } + + // Stop. + sk.stop(); + callback.expectStopped(); + } finally { + mUiAutomation.dropShellPermissionIdentity(); + } + + // Ensure socket is still connected. + assertTrue(s.isConnected()); + assertFalse(s.isClosed()); + + // Let socket be not idle. + try { + final OutputStream out = s.getOutputStream(); + out.write(requestBytes); + } catch (IOException e) { + fail("Failed to write data " + e); + } + // Make sure response data arrives. + final MessageQueue fdHandlerQueue = Looper.getMainLooper().getQueue(); + final FileDescriptor fd = s.getFileDescriptor$(); + final CountDownLatch mOnReceiveLatch = new CountDownLatch(1); + fdHandlerQueue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, (readyFd, events) -> { + mOnReceiveLatch.countDown(); + return 0; // Unregister listener. + }); + if (!mOnReceiveLatch.await(2, TimeUnit.SECONDS)) { + fdHandlerQueue.removeOnFileDescriptorEventListener(fd); + fail("Timeout: no response data"); + } + + // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue + // that has not been read. + mUiAutomation.adoptShellPermissionIdentity(); + try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { + sk.start(MIN_KEEPALIVE_INTERVAL); + callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); + } finally { + mUiAutomation.dropShellPermissionIdentity(); + } + } + } + + private ArrayList createConcurrentKeepalivesOfType( + int requestCount, @NonNull TestSocketKeepaliveCallback callback, + Supplier kaFactory) { + final ArrayList kalist = new ArrayList<>(); + + int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT; + + // Test concurrent keepalives with the given supplier. + while (kalist.size() < requestCount) { + final SocketKeepalive ka = kaFactory.get(); + ka.start(MIN_KEEPALIVE_INTERVAL); + TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); + assertNotNull(cv); + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { + if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { + // Unsupported. + break; + } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached or temporary unavailable due to stopped slot is not yet + // released. + if (remainingRetries > 0) { + SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS); + remainingRetries--; + continue; + } + break; + } + } + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { + kalist.add(ka); + } else { + fail("Unexpected error when creating " + (kalist.size() + 1) + " " + + ka.getClass().getSimpleName() + ": " + cv); + } + } + + return kalist; + } + + private @NonNull ArrayList createConcurrentNattSocketKeepalives( + @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount, + @NonNull TestSocketKeepaliveCallback callback) throws Exception { + + final Executor executor = mContext.getMainExecutor(); + + // Initialize a real NaT-T socket. + final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); + final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); + final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); + assertNotNull(srcAddr); + assertNotNull(dstAddr); + + // Test concurrent Nat-T keepalives. + final ArrayList result = createConcurrentKeepalivesOfType(requestCount, + callback, () -> mCm.createSocketKeepalive(network, nattSocket, + srcAddr, dstAddr, executor, callback)); + + nattSocket.close(); + return result; + } + + private @NonNull ArrayList createConcurrentTcpSocketKeepalives( + @NonNull Network network, int requestCount, + @NonNull TestSocketKeepaliveCallback callback) { + final Executor executor = mContext.getMainExecutor(); + + // Create concurrent TCP keepalives. + return createConcurrentKeepalivesOfType(requestCount, callback, () -> { + // Assert that TCP connections can be established. The file descriptor of tcp + // sockets will be duplicated and kept valid in service side if the keepalives are + // successfully started. + try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, + AF_INET)) { + return mCm.createSocketKeepalive(network, tcpSocket, executor, callback); + } catch (Exception e) { + fail("Unexpected error when creating TCP socket: " + e); + } + return null; + }); + } + + /** + * Creates concurrent keepalives until the specified counts of each type of keepalives are + * reached or the expected error callbacks are received for each type of keepalives. + * + * @return the total number of keepalives created. + */ + private int createConcurrentSocketKeepalives( + @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount) + throws Exception { + final ArrayList kalist = new ArrayList<>(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + + kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback)); + kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback)); + + final int ret = kalist.size(); + + // Clean up. + for (final SocketKeepalive ka : kalist) { + ka.stop(); + callback.expectStopped(); + } + kalist.clear(); + + return ret; + } + + /** + * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't + * get leaked after iterations. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") + public void testSocketKeepaliveLimitWifi() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + final int supported = getSupportedKeepalivesForNet(network); + if (supported == 0) { + return; + } + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); + + runWithShellPermissionIdentity(() -> { + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. + assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); + + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, + 0)); + }); + + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support + // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. + if (!isTcpKeepaliveSupportedByKernel()) return; + + runWithShellPermissionIdentity(() -> { + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, + supported + 1)); + + // Verifies that different types can be established at the same time. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported / 2, supported - supported / 2)); + + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, + supported)); + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported / 2, supported - supported / 2)); + }); + } + + /** + * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and + * don't get leaked after iterations. + */ + @AppModeFull(reason = "Cannot request network in instant app mode") + @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") + public void testSocketKeepaliveLimitTelephony() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { + Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" + + " supports telephony"); + return; + } + + final int firstSdk = Build.VERSION.FIRST_SDK_INT; + if (firstSdk < Build.VERSION_CODES.Q) { + Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching" + + " before Q: " + firstSdk); + return; + } + + final Network network = mCtsNetUtils.connectToCell(); + final int supported = getSupportedKeepalivesForNet(network); + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); + + runWithShellPermissionIdentity(() -> { + // Verifies that the supported keepalive slots meet minimum requirement. + assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, + 0)); + }); + } + + private int getIntResourceForName(@NonNull String resName) { + final Resources r = mContext.getResources(); + final int resId = r.getIdentifier(resName, "integer", "android"); + return r.getInteger(resId); + } + + /** + * Verifies that the keepalive slots are limited as customized for unprivileged requests. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") + public void testSocketKeepaliveUnprivileged() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + final int supported = getSupportedKeepalivesForNet(network); + if (supported == 0) { + return; + } + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); + + // Resource ID might be shifted on devices that compiled with different symbols. + // Thus, resolve ID at runtime is needed. + final int allowedUnprivilegedPerUid = + getIntResourceForName(KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME); + final int reservedPrivilegedSlots = + getIntResourceForName(KEEPALIVE_RESERVED_PER_SLOT_RES_NAME); + // Verifies that unprivileged request per uid cannot exceed the limit customized in the + // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test + // does not apply to TCP. + assertGreaterOrEqual(supported, reservedPrivilegedSlots); + assertGreaterOrEqual(supported, allowedUnprivilegedPerUid); + final int expectedUnprivileged = + Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); + assertEquals(expectedUnprivileged, + createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0)); + } + + private static void assertGreaterOrEqual(long greater, long lesser) { + assertTrue("" + greater + " expected to be greater than or equal to " + lesser, + greater >= lesser); + } + + /** + * Verifies that apps are not allowed to access restricted networks even if they declare the + * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests. + * See. b/144679405. + */ + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + public void testRestrictedNetworkPermission() throws Exception { + // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package. + final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(), + GET_PERMISSIONS); + final int index = ArrayUtils.indexOf( + app.requestedPermissions, CONNECTIVITY_USE_RESTRICTED_NETWORKS); + assertTrue(index >= 0); + assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED); + + // Ensure that NetworkUtils.queryUserAccess always returns false since this package should + // not have netd system permission to call this function. + final Network wifiNetwork = ensureWifiConnected(); + assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId)); + + // Ensure that this package cannot bind to any restricted network that's currently + // connected. + Network[] networks = mCm.getAllNetworks(); + for (Network network : networks) { + NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { + try { + network.bindSocket(new Socket()); + fail("Bind to restricted network " + network + " unexpectedly succeeded"); + } catch (IOException expected) {} + } + } + } + + /** + * Verifies that apps are allowed to call setAirplaneMode if they declare + * NETWORK_AIRPLANE_MODE permission in their manifests. + * See b/145164696. + */ + @AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps") + @Test + public void testSetAirplaneMode() throws Exception{ + final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI); + final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); + // store the current state of airplane mode + final boolean isAirplaneModeEnabled = isAirplaneModeEnabled(); + final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); + final TestableNetworkCallback telephonyCb = new TestableNetworkCallback(); + // disable airplane mode to reach a known state + runShellCommand("cmd connectivity airplane-mode disable"); + // Verify that networks are available as expected if wifi or cell is supported. Continue the + // test if none of them are supported since test should still able to verify the permission + // mechanism. + if (supportWifi) requestAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb); + if (supportTelephony) requestAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb); + + try { + // Verify we cannot set Airplane Mode without correct permission: + try { + setAndVerifyAirplaneMode(true); + fail("SecurityException should have been thrown when setAirplaneMode was called" + + "without holding permission NETWORK_AIRPLANE_MODE."); + } catch (SecurityException expected) {} + + // disable airplane mode again to reach a known state + runShellCommand("cmd connectivity airplane-mode disable"); + + // adopt shell permission which holds NETWORK_AIRPLANE_MODE + mUiAutomation.adoptShellPermissionIdentity(); + + // Verify we can enable Airplane Mode with correct permission: + try { + setAndVerifyAirplaneMode(true); + } catch (SecurityException e) { + fail("SecurityException should not have been thrown when setAirplaneMode(true) was" + + "called whilst holding the NETWORK_AIRPLANE_MODE permission."); + } + // Verify that the enabling airplane mode takes effect as expected to prevent flakiness + // caused by fast airplane mode switches. Ensure network lost before turning off + // airplane mode. + if (supportWifi) waitForLost(wifiCb); + if (supportTelephony) waitForLost(telephonyCb); + + // Verify we can disable Airplane Mode with correct permission: + try { + setAndVerifyAirplaneMode(false); + } catch (SecurityException e) { + fail("SecurityException should not have been thrown when setAirplaneMode(false) was" + + "called whilst holding the NETWORK_AIRPLANE_MODE permission."); + } + // Verify that turning airplane mode off takes effect as expected. + if (supportWifi) waitForAvailable(wifiCb); + if (supportTelephony) waitForAvailable(telephonyCb); + } finally { + if (supportWifi) mCm.unregisterNetworkCallback(wifiCb); + if (supportTelephony) mCm.unregisterNetworkCallback(telephonyCb); + // Restore the previous state of airplane mode and permissions: + runShellCommand("cmd connectivity airplane-mode " + + (isAirplaneModeEnabled ? "enable" : "disable")); + mUiAutomation.dropShellPermissionIdentity(); + } + } + + private void requestAndWaitForAvailable(@NonNull final NetworkRequest request, + @NonNull final TestableNetworkCallback cb) { + mCm.registerNetworkCallback(request, cb); + waitForAvailable(cb); + } + + private void waitForAvailable(@NonNull final TestableNetworkCallback cb) { + cb.eventuallyExpect(CallbackEntry.AVAILABLE, AIRPLANE_MODE_CHANGE_TIMEOUT_MS, + c -> c instanceof CallbackEntry.Available); + } + + private void waitForLost(@NonNull final TestableNetworkCallback cb) { + cb.eventuallyExpect(CallbackEntry.LOST, AIRPLANE_MODE_CHANGE_TIMEOUT_MS, + c -> c instanceof CallbackEntry.Lost); + } + + private void setAndVerifyAirplaneMode(Boolean expectedResult) + throws Exception { + final CompletableFuture actualResult = new CompletableFuture(); + BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // The defaultValue of getExtraBoolean should be the opposite of what is + // expected, thus ensuring a test failure if the extra is absent. + actualResult.complete(intent.getBooleanExtra("state", !expectedResult)); + } + }; + try { + mContext.registerReceiver(receiver, + new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); + mCm.setAirplaneMode(expectedResult); + final String msg = "Setting Airplane Mode failed,"; + assertEquals(msg, expectedResult, actualResult.get(AIRPLANE_MODE_CHANGE_TIMEOUT_MS, + TimeUnit.MILLISECONDS)); + } finally { + mContext.unregisterReceiver(receiver); + } + } + + private static boolean isAirplaneModeEnabled() { + return runShellCommand("cmd connectivity airplane-mode") + .trim().equals("enabled"); + } + + @Test + public void testGetCaptivePortalServerUrl() { + final String url = runAsShell(NETWORK_SETTINGS, mCm::getCaptivePortalServerUrl); + assertNotNull("getCaptivePortalServerUrl must not be null", url); + try { + final URL parsedUrl = new URL(url); + // As per the javadoc, the URL must be HTTP + assertEquals("Invalid captive portal URL protocol", "http", parsedUrl.getProtocol()); + } catch (MalformedURLException e) { + throw new AssertionFailedError("Captive portal server URL is invalid: " + e); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/CredentialsTest.java b/tests/cts/net/src/android/net/cts/CredentialsTest.java new file mode 100644 index 0000000000..91c3621eab --- /dev/null +++ b/tests/cts/net/src/android/net/cts/CredentialsTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 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 android.net.Credentials; +import android.test.AndroidTestCase; + +public class CredentialsTest extends AndroidTestCase { + + public void testCredentials() { + // new the Credentials instance + // Test with zero inputs + Credentials cred = new Credentials(0, 0, 0); + assertEquals(0, cred.getGid()); + assertEquals(0, cred.getPid()); + assertEquals(0, cred.getUid()); + + // Test with big integer + cred = new Credentials(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + assertEquals(Integer.MAX_VALUE, cred.getGid()); + assertEquals(Integer.MAX_VALUE, cred.getPid()); + assertEquals(Integer.MAX_VALUE, cred.getUid()); + + // Test with big negative integer + cred = new Credentials(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); + assertEquals(Integer.MIN_VALUE, cred.getGid()); + assertEquals(Integer.MIN_VALUE, cred.getPid()); + assertEquals(Integer.MIN_VALUE, cred.getUid()); + } +} diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java new file mode 100644 index 0000000000..4acbbcfbdd --- /dev/null +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -0,0 +1,756 @@ +/* + * Copyright (C) 2019 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.net.DnsResolver.CLASS_IN; +import static android.net.DnsResolver.FLAG_EMPTY; +import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; +import static android.net.DnsResolver.TYPE_A; +import static android.net.DnsResolver.TYPE_AAAA; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.system.OsConstants.ETIMEDOUT; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.ContentResolver; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.DnsResolver; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.ParseException; +import android.net.cts.util.CtsNetUtils; +import android.os.CancellationSignal; +import android.os.Handler; +import android.os.Looper; +import android.platform.test.annotations.AppModeFull; +import android.provider.Settings; +import android.system.ErrnoException; +import android.test.AndroidTestCase; +import android.util.Log; + +import com.android.net.module.util.DnsPacket; +import com.android.testutils.SkipPresubmit; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") +public class DnsResolverTest extends AndroidTestCase { + private static final String TAG = "DnsResolverTest"; + private static final char[] HEX_CHARS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + static final String TEST_DOMAIN = "www.google.com"; + static final String TEST_NX_DOMAIN = "test1-nx.metric.gstatic.com"; + static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google"; + static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; + static final byte[] TEST_BLOB = new byte[]{ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ + }; + static final int TIMEOUT_MS = 12_000; + static final int CANCEL_TIMEOUT_MS = 3_000; + static final int CANCEL_RETRY_TIMES = 5; + static final int QUERY_TIMES = 10; + static final int NXDOMAIN = 3; + + private ContentResolver mCR; + private ConnectivityManager mCM; + private CtsNetUtils mCtsNetUtils; + private Executor mExecutor; + private Executor mExecutorInline; + private DnsResolver mDns; + + private String mOldMode; + private String mOldDnsSpecifier; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mDns = DnsResolver.getInstance(); + mExecutor = new Handler(Looper.getMainLooper())::post; + mExecutorInline = (Runnable r) -> r.run(); + mCR = getContext().getContentResolver(); + mCtsNetUtils = new CtsNetUtils(getContext()); + mCtsNetUtils.storePrivateDnsSetting(); + } + + @Override + protected void tearDown() throws Exception { + mCtsNetUtils.restorePrivateDnsSetting(); + super.tearDown(); + } + + private static String byteArrayToHexString(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int i = 0; i < bytes.length; ++i) { + int b = bytes[i] & 0xFF; + hexChars[i * 2] = HEX_CHARS[b >>> 4]; + hexChars[i * 2 + 1] = HEX_CHARS[b & 0x0F]; + } + return new String(hexChars); + } + + private Network[] getTestableNetworks() { + final ArrayList testableNetworks = new ArrayList(); + for (Network network : mCM.getAllNetworks()) { + final NetworkCapabilities nc = mCM.getNetworkCapabilities(network); + if (nc != null + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + testableNetworks.add(network); + } + } + + assertTrue( + "This test requires that at least one network be connected. " + + "Please ensure that the device is connected to a network.", + testableNetworks.size() >= 1); + // In order to test query with null network, add null as an element. + // Test cases which query with null network will go on default network. + testableNetworks.add(null); + return testableNetworks.toArray(new Network[0]); + } + + static private void assertGreaterThan(String msg, int first, int second) { + assertTrue(msg + " Excepted " + first + " to be greater than " + second, first > second); + } + + private static class DnsParseException extends Exception { + public DnsParseException(String msg) { + super(msg); + } + } + + private static class DnsAnswer extends DnsPacket { + DnsAnswer(@NonNull byte[] data) throws DnsParseException { + super(data); + + // Check QR field.(query (0), or a response (1)). + if ((mHeader.flags & (1 << 15)) == 0) { + throw new DnsParseException("Not an answer packet"); + } + } + + int getRcode() { + return mHeader.rcode; + } + + int getANCount() { + return mHeader.getRecordCount(ANSECTION); + } + + int getQDCount() { + return mHeader.getRecordCount(QDSECTION); + } + } + + /** + * A query callback that ensures that the query is cancelled and that onAnswer is never + * called. If the query succeeds before it is cancelled, needRetry will return true so the + * test can retry. + */ + class VerifyCancelCallback implements DnsResolver.Callback { + private final CountDownLatch mLatch = new CountDownLatch(1); + private final String mMsg; + private final CancellationSignal mCancelSignal; + private int mRcode; + private DnsAnswer mDnsAnswer; + private String mErrorMsg = null; + + VerifyCancelCallback(@NonNull String msg, @Nullable CancellationSignal cancel) { + mMsg = msg; + mCancelSignal = cancel; + } + + VerifyCancelCallback(@NonNull String msg) { + this(msg, null); + } + + public boolean waitForAnswer(int timeout) throws InterruptedException { + return mLatch.await(timeout, TimeUnit.MILLISECONDS); + } + + public boolean waitForAnswer() throws InterruptedException { + return waitForAnswer(TIMEOUT_MS); + } + + public boolean needRetry() throws InterruptedException { + return mLatch.await(CANCEL_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + @Override + public void onAnswer(@NonNull byte[] answer, int rcode) { + if (mCancelSignal != null && mCancelSignal.isCanceled()) { + mErrorMsg = mMsg + " should not have returned any answers"; + mLatch.countDown(); + return; + } + + mRcode = rcode; + try { + mDnsAnswer = new DnsAnswer(answer); + } catch (ParseException | DnsParseException e) { + mErrorMsg = mMsg + e.getMessage(); + mLatch.countDown(); + return; + } + Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); + mLatch.countDown(); + } + + @Override + public void onError(@NonNull DnsResolver.DnsException error) { + mErrorMsg = mMsg + error.getMessage(); + mLatch.countDown(); + } + + private void assertValidAnswer() { + assertNull(mErrorMsg); + assertNotNull(mMsg + " No valid answer", mDnsAnswer); + assertEquals(mMsg + " Unexpected error: reported rcode" + mRcode + + " blob's rcode " + mDnsAnswer.getRcode(), mRcode, mDnsAnswer.getRcode()); + } + + public void assertHasAnswer() { + assertValidAnswer(); + // Check rcode field.(0, No error condition). + assertEquals(mMsg + " Response error, rcode: " + mRcode, mRcode, 0); + // Check answer counts. + assertGreaterThan(mMsg + " No answer found", mDnsAnswer.getANCount(), 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); + } + + public void assertNXDomain() { + assertValidAnswer(); + // Check rcode field.(3, NXDomain). + assertEquals(mMsg + " Unexpected rcode: " + mRcode, mRcode, NXDOMAIN); + // Check answer counts. Expect 0 answer. + assertEquals(mMsg + " Not an empty answer", mDnsAnswer.getANCount(), 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); + } + + public void assertEmptyAnswer() { + assertValidAnswer(); + // Check rcode field.(0, No error condition). + assertEquals(mMsg + " Response error, rcode: " + mRcode, mRcode, 0); + // Check answer counts. Expect 0 answer. + assertEquals(mMsg + " Not an empty answer", mDnsAnswer.getANCount(), 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); + } + } + + public void testRawQuery() throws Exception { + doTestRawQuery(mExecutor); + } + + public void testRawQueryInline() throws Exception { + doTestRawQuery(mExecutorInline); + } + + public void testRawQueryBlob() throws Exception { + doTestRawQueryBlob(mExecutor); + } + + public void testRawQueryBlobInline() throws Exception { + doTestRawQueryBlob(mExecutorInline); + } + + public void testRawQueryRoot() throws Exception { + doTestRawQueryRoot(mExecutor); + } + + public void testRawQueryRootInline() throws Exception { + doTestRawQueryRoot(mExecutorInline); + } + + public void testRawQueryNXDomain() throws Exception { + doTestRawQueryNXDomain(mExecutor); + } + + public void testRawQueryNXDomainInline() throws Exception { + doTestRawQueryNXDomain(mExecutorInline); + } + + public void testRawQueryNXDomainWithPrivateDns() throws Exception { + doTestRawQueryNXDomainWithPrivateDns(mExecutor); + } + + public void testRawQueryNXDomainInlineWithPrivateDns() throws Exception { + doTestRawQueryNXDomainWithPrivateDns(mExecutorInline); + } + + public void doTestRawQuery(Executor executor) throws InterruptedException { + final String msg = "RawQuery " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertHasAnswer(); + } + } + + public void doTestRawQueryBlob(Executor executor) throws InterruptedException { + final byte[] blob = new byte[]{ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ + }; + final String msg = "RawQuery blob " + byteArrayToHexString(blob); + for (Network network : getTestableNetworks()) { + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertHasAnswer(); + } + } + + public void doTestRawQueryRoot(Executor executor) throws InterruptedException { + final String dname = ""; + final String msg = "RawQuery empty dname(ROOT) "; + for (Network network : getTestableNetworks()) { + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + // Except no answer record because the root does not have AAAA records. + callback.assertEmptyAnswer(); + } + } + + public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException { + final String msg = "RawQuery " + TEST_NX_DOMAIN; + + for (Network network : getTestableNetworks()) { + final NetworkCapabilities nc = (network != null) + ? mCM.getNetworkCapabilities(network) + : mCM.getNetworkCapabilities(mCM.getActiveNetwork()); + assertNotNull("Couldn't determine NetworkCapabilities for " + network, nc); + // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't + // test NXDOMAIN on these DNS servers. + // b/144521720 + if (nc.hasTransport(TRANSPORT_CELLULAR)) continue; + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNXDomain(); + } + } + + public void doTestRawQueryNXDomainWithPrivateDns(Executor executor) + throws InterruptedException { + final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; + // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. + // b/144521720 + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); + for (Network network : getTestableNetworks()) { + final Network networkForPrivateDns = + (network != null) ? network : mCM.getActiveNetwork(); + assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); + mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", + networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, true); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNXDomain(); + } + } + + public void testRawQueryCancel() throws InterruptedException { + final String msg = "Test cancel RawQuery " + TEST_DOMAIN; + // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect + // that the query is cancelled before it succeeds. If it is not cancelled before it + // succeeds, retry the test until it is. + for (Network network : getTestableNetworks()) { + boolean retry = false; + int round = 0; + do { + if (++round > CANCEL_RETRY_TIMES) { + fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times"); + } + final CountDownLatch latch = new CountDownLatch(1); + final CancellationSignal cancelSignal = new CancellationSignal(); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mExecutor, cancelSignal, callback); + mExecutor.execute(() -> { + cancelSignal.cancel(); + latch.countDown(); + }); + + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } while (retry); + } + } + + public void testRawQueryBlobCancel() throws InterruptedException { + final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(TEST_BLOB); + // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect + // that the query is cancelled before it succeeds. If it is not cancelled before it + // succeeds, retry the test until it is. + for (Network network : getTestableNetworks()) { + boolean retry = false; + int round = 0; + do { + if (++round > CANCEL_RETRY_TIMES) { + fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times"); + } + final CountDownLatch latch = new CountDownLatch(1); + final CancellationSignal cancelSignal = new CancellationSignal(); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); + mDns.rawQuery(network, TEST_BLOB, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mExecutor.execute(() -> { + cancelSignal.cancel(); + latch.countDown(); + }); + + retry = callback.needRetry(); + assertTrue(msg + " cancel is not done", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } while (retry); + } + } + + public void testCancelBeforeQuery() throws InterruptedException { + final String msg = "Test cancelled RawQuery " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + final CancellationSignal cancelSignal = new CancellationSignal(); + cancelSignal.cancel(); + mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mExecutor, cancelSignal, callback); + + assertTrue(msg + " should not return any answers", + !callback.waitForAnswer(CANCEL_TIMEOUT_MS)); + } + } + + /** + * A query callback for InetAddress that ensures that the query is + * cancelled and that onAnswer is never called. If the query succeeds + * before it is cancelled, needRetry will return true so the + * test can retry. + */ + class VerifyCancelInetAddressCallback implements DnsResolver.Callback> { + private final CountDownLatch mLatch = new CountDownLatch(1); + private final String mMsg; + private final List mAnswers; + private final CancellationSignal mCancelSignal; + private String mErrorMsg = null; + + VerifyCancelInetAddressCallback(@NonNull String msg, @Nullable CancellationSignal cancel) { + this.mMsg = msg; + this.mCancelSignal = cancel; + mAnswers = new ArrayList<>(); + } + + public boolean waitForAnswer() throws InterruptedException { + return mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public boolean needRetry() throws InterruptedException { + return mLatch.await(CANCEL_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public boolean isAnswerEmpty() { + return mAnswers.isEmpty(); + } + + public boolean hasIpv6Answer() { + for (InetAddress answer : mAnswers) { + if (answer instanceof Inet6Address) return true; + } + return false; + } + + public boolean hasIpv4Answer() { + for (InetAddress answer : mAnswers) { + if (answer instanceof Inet4Address) return true; + } + return false; + } + + public void assertNoError() { + assertNull(mErrorMsg); + } + + @Override + public void onAnswer(@NonNull List answerList, int rcode) { + if (mCancelSignal != null && mCancelSignal.isCanceled()) { + mErrorMsg = mMsg + " should not have returned any answers"; + mLatch.countDown(); + return; + } + for (InetAddress addr : answerList) { + Log.d(TAG, "Reported addr: " + addr.toString()); + } + mAnswers.clear(); + mAnswers.addAll(answerList); + mLatch.countDown(); + } + + @Override + public void onError(@NonNull DnsResolver.DnsException error) { + mErrorMsg = mMsg + error.getMessage(); + } + } + + public void testQueryForInetAddress() throws Exception { + doTestQueryForInetAddress(mExecutor); + } + + public void testQueryForInetAddressInline() throws Exception { + doTestQueryForInetAddress(mExecutorInline); + } + + public void testQueryForInetAddressIpv4() throws Exception { + doTestQueryForInetAddressIpv4(mExecutor); + } + + public void testQueryForInetAddressIpv4Inline() throws Exception { + doTestQueryForInetAddressIpv4(mExecutorInline); + } + + public void testQueryForInetAddressIpv6() throws Exception { + doTestQueryForInetAddressIpv6(mExecutor); + } + + public void testQueryForInetAddressIpv6Inline() throws Exception { + doTestQueryForInetAddressIpv6(mExecutorInline); + } + + public void testContinuousQueries() throws Exception { + doTestContinuousQueries(mExecutor); + } + + @SkipPresubmit(reason = "Flaky: b/159762682; add to presubmit after fixing") + public void testContinuousQueriesInline() throws Exception { + doTestContinuousQueries(mExecutorInline); + } + + public void doTestQueryForInetAddress(Executor executor) throws InterruptedException { + final String msg = "Test query for InetAddress " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNoError(); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + } + } + + public void testQueryCancelForInetAddress() throws InterruptedException { + final String msg = "Test cancel query for InetAddress " + TEST_DOMAIN; + // Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to + // expect that the query is cancelled before it succeeds. If it is not cancelled before it + // succeeds, retry the test until it is. + for (Network network : getTestableNetworks()) { + boolean retry = false; + int round = 0; + do { + if (++round > CANCEL_RETRY_TIMES) { + fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times"); + } + final CountDownLatch latch = new CountDownLatch(1); + final CancellationSignal cancelSignal = new CancellationSignal(); + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, cancelSignal); + mDns.query(network, TEST_DOMAIN, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mExecutor.execute(() -> { + cancelSignal.cancel(); + latch.countDown(); + }); + + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } while (retry); + } + } + + public void doTestQueryForInetAddressIpv4(Executor executor) throws InterruptedException { + final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP, + executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNoError(); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer()); + } + } + + public void doTestQueryForInetAddressIpv6(Executor executor) throws InterruptedException { + final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNoError(); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer()); + } + } + + public void testPrivateDnsBypass() throws InterruptedException { + final Network[] testNetworks = getTestableNetworks(); + + // Set an invalid private DNS server + mCtsNetUtils.setPrivateDnsStrictMode(INVALID_PRIVATE_DNS_SERVER); + final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; + for (Network network : testNetworks) { + // This test cannot be ran with null network because we need to explicitly pass a + // private DNS bypassable network or bind one. + if (network == null) continue; + + // wait for private DNS setting propagating + mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", + network, INVALID_PRIVATE_DNS_SERVER, false); + + final CountDownLatch latch = new CountDownLatch(1); + final DnsResolver.Callback> errorCallback = + new DnsResolver.Callback>() { + @Override + public void onAnswer(@NonNull List answerList, int rcode) { + fail(msg + " should not get valid answer"); + } + + @Override + public void onError(@NonNull DnsResolver.DnsException error) { + assertEquals(DnsResolver.ERROR_SYSTEM, error.code); + assertEquals(ETIMEDOUT, ((ErrnoException) error.getCause()).errno); + latch.countDown(); + } + }; + // Private DNS strict mode with invalid DNS server is set + // Expect no valid answer returned but ErrnoException with ETIMEDOUT + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, errorCallback); + + assertTrue(msg + " invalid server round. No response after " + TIMEOUT_MS + "ms.", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + // Bypass privateDns, expect query works fine + mDns.query(network.getPrivateDnsBypassingCopy(), + TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + + assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNoError(); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + + // To ensure private DNS bypass still work even if passing null network. + // Bind process network with a private DNS bypassable network. + mCM.bindProcessToNetwork(network.getPrivateDnsBypassingCopy()); + final VerifyCancelInetAddressCallback callbackWithNullNetwork = + new VerifyCancelInetAddressCallback(msg + " with null network ", null); + mDns.query(null, + TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callbackWithNullNetwork); + + assertTrue(msg + " with null network bypass private DNS round. No answer after " + + TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer()); + callbackWithNullNetwork.assertNoError(); + assertTrue(msg + " with null network returned 0 results", + !callbackWithNullNetwork.isAnswerEmpty()); + + // Reset process network to default. + mCM.bindProcessToNetwork(null); + } + } + + public void doTestContinuousQueries(Executor executor) throws InterruptedException { + final String msg = "Test continuous " + QUERY_TIMES + " queries " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + for (int i = 0; i < QUERY_TIMES ; ++i) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + // query v6/v4 in turn + boolean queryV6 = (i % 2 == 0); + mDns.query(network, TEST_DOMAIN, queryV6 ? TYPE_AAAA : TYPE_A, + FLAG_NO_CACHE_LOOKUP, executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNoError(); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results", + queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer()); + } + } + } +} diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java new file mode 100644 index 0000000000..fde27e9f12 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2013 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 android.content.Context; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkInfo; +import android.os.SystemClock; +import android.test.AndroidTestCase; +import android.util.Log; + +import com.android.testutils.SkipPresubmit; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class DnsTest extends AndroidTestCase { + + static { + System.loadLibrary("nativedns_jni"); + } + + private static final boolean DBG = false; + private static final String TAG = "DnsTest"; + private static final String PROXY_NETWORK_TYPE = "PROXY"; + + private ConnectivityManager mCm; + + public void setUp() { + mCm = getContext().getSystemService(ConnectivityManager.class); + } + + /** + * @return true on success + */ + private static native boolean testNativeDns(); + + /** + * Verify: + * DNS works - forwards and backwards, giving ipv4 and ipv6 + * Test that DNS work on v4 and v6 networks + * Test Native dns calls (4) + * Todo: + * Cache is flushed when we change networks + * have per-network caches + * No cache when there's no network + * Perf - measure size of first and second tier caches and their effect + * Assert requires network permission + */ + @SkipPresubmit(reason = "IPv6 support may be missing on presubmit virtual hardware") + public void testDnsWorks() throws Exception { + ensureIpv6Connectivity(); + + InetAddress addrs[] = {}; + try { + addrs = InetAddress.getAllByName("www.google.com"); + } catch (UnknownHostException e) {} + assertTrue("[RERUN] DNS could not resolve www.google.com. Check internet connection", + addrs.length != 0); + boolean foundV4 = false, foundV6 = false; + for (InetAddress addr : addrs) { + if (addr instanceof Inet4Address) foundV4 = true; + else if (addr instanceof Inet6Address) foundV6 = true; + if (DBG) Log.e(TAG, "www.google.com gave " + addr.toString()); + } + + // We should have at least one of the addresses to connect! + assertTrue("www.google.com must have IPv4 and/or IPv6 address", foundV4 || foundV6); + + // Skip the rest of the test if the active network for watch is PROXY. + // TODO: Check NetworkInfo type in addition to type name once ag/601257 is merged. + if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH) + && activeNetworkInfoIsProxy()) { + Log.i(TAG, "Skipping test because the active network type name is PROXY."); + return; + } + + // Clear test state so we don't get confused with the previous results. + addrs = new InetAddress[0]; + foundV4 = foundV6 = false; + try { + addrs = InetAddress.getAllByName("ipv6.google.com"); + } catch (UnknownHostException e) {} + String msg = + "[RERUN] DNS could not resolve ipv6.google.com, check the network supports IPv6. lp=" + + mCm.getActiveLinkProperties(); + assertTrue(msg, addrs.length != 0); + for (InetAddress addr : addrs) { + msg = "[RERUN] ipv6.google.com returned IPv4 address: " + addr.getHostAddress() + + ", check your network's DNS server. lp=" + mCm.getActiveLinkProperties(); + assertFalse (msg, addr instanceof Inet4Address); + foundV6 |= (addr instanceof Inet6Address); + if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString()); + } + + assertTrue(foundV6); + + assertTrue(testNativeDns()); + } + + private static final String[] URLS = { "www.google.com", "ipv6.google.com", "www.yahoo.com", + "facebook.com", "youtube.com", "blogspot.com", "baidu.com", "wikipedia.org", +// live.com fails rev lookup. + "twitter.com", "qq.com", "msn.com", "yahoo.co.jp", "linkedin.com", + "taobao.com", "google.co.in", "sina.com.cn", "amazon.com", "wordpress.com", + "google.co.uk", "ebay.com", "yandex.ru", "163.com", "google.co.jp", "google.fr", + "microsoft.com", "paypal.com", "google.com.br", "flickr.com", + "mail.ru", "craigslist.org", "fc2.com", "google.it", +// "apple.com", fails rev lookup + "google.es", + "imdb.com", "google.ru", "soho.com", "bbc.co.uk", "vkontakte.ru", "ask.com", + "tumblr.com", "weibo.com", "go.com", "xvideos.com", "livejasmin.com", "cnn.com", + "youku.com", "blogspot.com", "soso.com", "google.ca", "aol.com", "tudou.com", + "xhamster.com", "megaupload.com", "ifeng.com", "zedo.com", "mediafire.com", "ameblo.jp", + "pornhub.com", "google.co.id", "godaddy.com", "adobe.com", "rakuten.co.jp", "about.com", + "espn.go.com", "4shared.com", "alibaba.com","ebay.de", "yieldmanager.com", + "wordpress.org", "livejournal.com", "google.com.tr", "google.com.mx", "renren.com", + "livedoor.com", "google.com.au", "youporn.com", "uol.com.br", "cnet.com", "conduit.com", + "google.pl", "myspace.com", "nytimes.com", "ebay.co.uk", "chinaz.com", "hao123.com", + "thepiratebay.org", "doubleclick.com", "alipay.com", "netflix.com", "cnzz.com", + "huffingtonpost.com", "twitpic.com", "weather.com", "babylon.com", "amazon.de", + "dailymotion.com", "orkut.com", "orkut.com.br", "google.com.sa", "odnoklassniki.ru", + "amazon.co.jp", "google.nl", "goo.ne.jp", "stumbleupon.com", "tube8.com", "tmall.com", + "imgur.com", "globo.com", "secureserver.net", "fileserve.com", "tianya.cn", "badoo.com", + "ehow.com", "photobucket.com", "imageshack.us", "xnxx.com", "deviantart.com", + "filestube.com", "addthis.com", "douban.com", "vimeo.com", "sogou.com", + "stackoverflow.com", "reddit.com", "dailymail.co.uk", "redtube.com", "megavideo.com", + "taringa.net", "pengyou.com", "amazon.co.uk", "fbcdn.net", "aweber.com", "spiegel.de", + "rapidshare.com", "mixi.jp", "360buy.com", "google.cn", "digg.com", "answers.com", + "bit.ly", "indiatimes.com", "skype.com", "yfrog.com", "optmd.com", "google.com.eg", + "google.com.pk", "58.com", "hotfile.com", "google.co.th", + "bankofamerica.com", "sourceforge.net", "maktoob.com", "warriorforum.com", "rediff.com", + "google.co.za", "56.com", "torrentz.eu", "clicksor.com", "avg.com", + "download.com", "ku6.com", "statcounter.com", "foxnews.com", "google.com.ar", + "nicovideo.jp", "reference.com", "liveinternet.ru", "ucoz.ru", "xinhuanet.com", + "xtendmedia.com", "naver.com", "youjizz.com", "domaintools.com", "sparkstudios.com", + "rambler.ru", "scribd.com", "kaixin001.com", "mashable.com", "adultfirendfinder.com", + "files.wordpress.com", "guardian.co.uk", "bild.de", "yelp.com", "wikimedia.org", + "chase.com", "onet.pl", "ameba.jp", "pconline.com.cn", "free.fr", "etsy.com", + "typepad.com", "youdao.com", "megaclick.com", "digitalpoint.com", "blogfa.com", + "salesforce.com", "adf.ly", "ganji.com", "wikia.com", "archive.org", "terra.com.br", + "w3schools.com", "ezinearticles.com", "wjs.com", "google.com.my", "clickbank.com", + "squidoo.com", "hulu.com", "repubblica.it", "google.be", "allegro.pl", "comcast.net", + "narod.ru", "zol.com.cn", "orange.fr", "soufun.com", "hatena.ne.jp", "google.gr", + "in.com", "techcrunch.com", "orkut.co.in", "xunlei.com", + "reuters.com", "google.com.vn", "hostgator.com", "kaskus.us", "espncricinfo.com", + "hootsuite.com", "qiyi.com", "gmx.net", "xing.com", "php.net", "soku.com", "web.de", + "libero.it", "groupon.com", "51.la", "slideshare.net", "booking.com", "seesaa.net", + "126.com", "telegraph.co.uk", "wretch.cc", "twimg.com", "rutracker.org", "angege.com", + "nba.com", "dell.com", "leboncoin.fr", "people.com", "google.com.tw", "walmart.com", + "daum.net", "2ch.net", "constantcontact.com", "nifty.com", "mywebsearch.com", + "tripadvisor.com", "google.se", "paipai.com", "google.com.ua", "ning.com", "hp.com", + "google.at", "joomla.org", "icio.us", "hudong.com", "csdn.net", "getfirebug.com", + "ups.com", "cj.com", "google.ch", "camzap.com", "wordreference.com", "tagged.com", + "wp.pl", "mozilla.com", "google.ru", "usps.com", "china.com", "themeforest.net", + "search-results.com", "tribalfusion.com", "thefreedictionary.com", "isohunt.com", + "linkwithin.com", "cam4.com", "plentyoffish.com", "wellsfargo.com", "metacafe.com", + "depositfiles.com", "freelancer.com", "opendns.com", "homeway.com", "engadget.com", + "10086.cn", "360.cn", "marca.com", "dropbox.com", "ign.com", "match.com", "google.pt", + "facemoods.com", "hardsextube.com", "google.com.ph", "lockerz.com", "istockphoto.com", + "partypoker.com", "netlog.com", "outbrain.com", "elpais.com", "fiverr.com", + "biglobe.ne.jp", "corriere.it", "love21cn.com", "yesky.com", "spankwire.com", + "ig.com.br", "imagevenue.com", "hubpages.com", "google.co.ve"}; + +// TODO - this works, but is slow and cts doesn't do anything with the result. +// Maybe require a min performance, a min cache size (detectable) and/or move +// to perf testing + private static final int LOOKUP_COUNT_GOAL = URLS.length; + public void skiptestDnsPerf() { + ArrayList results = new ArrayList(); + int failures = 0; + try { + for (int numberOfUrls = URLS.length; numberOfUrls > 0; numberOfUrls--) { + failures = 0; + int iterationLimit = LOOKUP_COUNT_GOAL / numberOfUrls; + long startTime = SystemClock.elapsedRealtimeNanos(); + for (int iteration = 0; iteration < iterationLimit; iteration++) { + for (int urlIndex = 0; urlIndex < numberOfUrls; urlIndex++) { + try { + InetAddress addr = InetAddress.getByName(URLS[urlIndex]); + } catch (UnknownHostException e) { + Log.e(TAG, "failed first lookup of " + URLS[urlIndex]); + failures++; + try { + InetAddress addr = InetAddress.getByName(URLS[urlIndex]); + } catch (UnknownHostException ee) { + failures++; + Log.e(TAG, "failed SECOND lookup of " + URLS[urlIndex]); + } + } + } + } + long endTime = SystemClock.elapsedRealtimeNanos(); + float nsPer = ((float)(endTime-startTime) / iterationLimit) / numberOfUrls/ 1000; + String thisResult = new String("getByName for " + numberOfUrls + " took " + + (endTime - startTime)/1000 + "(" + nsPer + ") with " + + failures + " failures\n"); + Log.d(TAG, thisResult); + results.add(thisResult); + } + // build up a list of addresses + ArrayList addressList = new ArrayList(); + for (String url : URLS) { + try { + InetAddress addr = InetAddress.getByName(url); + addressList.add(addr.getAddress()); + } catch (UnknownHostException e) { + Log.e(TAG, "Exception making reverseDNS list: " + e.toString()); + } + } + for (int numberOfAddrs = addressList.size(); numberOfAddrs > 0; numberOfAddrs--) { + int iterationLimit = LOOKUP_COUNT_GOAL / numberOfAddrs; + failures = 0; + long startTime = SystemClock.elapsedRealtimeNanos(); + for (int iteration = 0; iteration < iterationLimit; iteration++) { + for (int addrIndex = 0; addrIndex < numberOfAddrs; addrIndex++) { + try { + InetAddress addr = InetAddress.getByAddress(addressList.get(addrIndex)); + String hostname = addr.getHostName(); + } catch (UnknownHostException e) { + failures++; + Log.e(TAG, "Failure doing reverse DNS lookup: " + e.toString()); + try { + InetAddress addr = + InetAddress.getByAddress(addressList.get(addrIndex)); + String hostname = addr.getHostName(); + + } catch (UnknownHostException ee) { + failures++; + Log.e(TAG, "Failure doing SECOND reverse DNS lookup: " + + ee.toString()); + } + } + } + } + long endTime = SystemClock.elapsedRealtimeNanos(); + float nsPer = ((endTime-startTime) / iterationLimit) / numberOfAddrs / 1000; + String thisResult = new String("getHostName for " + numberOfAddrs + " took " + + (endTime - startTime)/1000 + "(" + nsPer + ") with " + + failures + " failures\n"); + Log.d(TAG, thisResult); + results.add(thisResult); + } + for (String result : results) Log.d(TAG, result); + + InetAddress exit = InetAddress.getByName("exitrightnow.com"); + Log.e(TAG, " exit address= "+exit.toString()); + + } catch (Exception e) { + Log.e(TAG, "bad URL in testDnsPerf: " + e.toString()); + } + } + + private boolean activeNetworkInfoIsProxy() { + NetworkInfo info = mCm.getActiveNetworkInfo(); + if (PROXY_NETWORK_TYPE.equals(info.getTypeName())) { + return true; + } + + return false; + } + + private void ensureIpv6Connectivity() throws InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + final int TIMEOUT_MS = 5_000; + + final NetworkCallback callback = new NetworkCallback() { + @Override + public void onLinkPropertiesChanged(Network network, LinkProperties lp) { + if (lp.hasGlobalIpv6Address()) { + latch.countDown(); + } + } + }; + mCm.registerDefaultNetworkCallback(callback); + + String msg = "Default network did not provide IPv6 connectivity after " + TIMEOUT_MS + + "ms. Please connect to an IPv6-capable network. lp=" + + mCm.getActiveLinkProperties(); + try { + assertTrue(msg, latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } finally { + mCm.unregisterNetworkCallback(callback); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/IkeTunUtils.java b/tests/cts/net/src/android/net/cts/IkeTunUtils.java new file mode 100644 index 0000000000..fc25292b27 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IkeTunUtils.java @@ -0,0 +1,188 @@ +/* + * 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.net.cts.PacketUtils.BytePayload; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.IpHeader; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.net.cts.PacketUtils.UdpHeader; +import static android.net.cts.PacketUtils.getIpHeader; +import static android.system.OsConstants.IPPROTO_UDP; + +import android.os.ParcelFileDescriptor; + +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.Arrays; + +// TODO: Merge this with the version in the IPsec module (IKEv2 library) CTS tests. +/** An extension of the TunUtils class with IKE-specific packet handling. */ +public class IkeTunUtils extends TunUtils { + private static final int PORT_LEN = 2; + + private static final byte[] NON_ESP_MARKER = new byte[] {0, 0, 0, 0}; + + private static final int IKE_HEADER_LEN = 28; + private static final int IKE_SPI_LEN = 8; + private static final int IKE_IS_RESP_BYTE_OFFSET = 19; + private static final int IKE_MSG_ID_OFFSET = 20; + private static final int IKE_MSG_ID_LEN = 4; + + public IkeTunUtils(ParcelFileDescriptor tunFd) { + super(tunFd); + } + + /** + * Await an expected IKE request and inject an IKE response. + * + * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER. + */ + public byte[] awaitReqAndInjectResp(long expectedInitIkeSpi, int expectedMsgId, + boolean encapExpected, byte[] respIkePkt) throws Exception { + final byte[] request = awaitIkePacket(expectedInitIkeSpi, expectedMsgId, encapExpected); + + // Build response header by flipping address and port + final InetAddress srcAddr = getDstAddress(request); + final InetAddress dstAddr = getSrcAddress(request); + final int srcPort = getDstPort(request); + final int dstPort = getSrcPort(request); + + final byte[] response = + buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, encapExpected, respIkePkt); + injectPacket(response); + return request; + } + + private byte[] awaitIkePacket(long expectedInitIkeSpi, int expectedMsgId, boolean expectEncap) + throws Exception { + return super.awaitPacket(pkt -> isIke(pkt, expectedInitIkeSpi, expectedMsgId, expectEncap)); + } + + private static boolean isIke( + byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, boolean encapExpected) { + final int ipProtocolOffset; + final int ikeOffset; + + if (isIpv6(pkt)) { + ipProtocolOffset = IP6_PROTO_OFFSET; + ikeOffset = IP6_HDRLEN + UDP_HDRLEN; + } else { + if (encapExpected && !hasNonEspMarkerv4(pkt)) { + return false; + } + + // Use default IPv4 header length (assuming no options) + final int encapMarkerLen = encapExpected ? NON_ESP_MARKER.length : 0; + ipProtocolOffset = IP4_PROTO_OFFSET; + ikeOffset = IP4_HDRLEN + UDP_HDRLEN + encapMarkerLen; + } + + return pkt[ipProtocolOffset] == IPPROTO_UDP + && areSpiAndMsgIdEqual(pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId); + } + + /** Checks if the provided IPv4 packet has a UDP-encapsulation NON-ESP marker */ + private static boolean hasNonEspMarkerv4(byte[] ipv4Pkt) { + final int nonEspMarkerOffset = IP4_HDRLEN + UDP_HDRLEN; + if (ipv4Pkt.length < nonEspMarkerOffset + NON_ESP_MARKER.length) { + return false; + } + + final byte[] nonEspMarker = Arrays.copyOfRange( + ipv4Pkt, nonEspMarkerOffset, nonEspMarkerOffset + NON_ESP_MARKER.length); + return Arrays.equals(NON_ESP_MARKER, nonEspMarker); + } + + private static boolean areSpiAndMsgIdEqual( + byte[] pkt, int ikeOffset, long expectedIkeInitSpi, int expectedMsgId) { + if (pkt.length <= ikeOffset + IKE_HEADER_LEN) { + return false; + } + + final ByteBuffer buffer = ByteBuffer.wrap(pkt); + final long spi = buffer.getLong(ikeOffset); + final int msgId = buffer.getInt(ikeOffset + IKE_MSG_ID_OFFSET); + + return expectedIkeInitSpi == spi && expectedMsgId == msgId; + } + + private static InetAddress getSrcAddress(byte[] pkt) throws Exception { + return getAddress(pkt, true); + } + + private static InetAddress getDstAddress(byte[] pkt) throws Exception { + return getAddress(pkt, false); + } + + private static InetAddress getAddress(byte[] pkt, boolean getSrcAddr) throws Exception { + final int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; + final int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; + final int ipOffset = getSrcAddr ? srcIpOffset : srcIpOffset + ipLen; + + if (pkt.length < ipOffset + ipLen) { + // Should be impossible; getAddress() is only called with a full IKE request including + // the IP and UDP headers. + throw new IllegalArgumentException("Packet was too short to contain IP address"); + } + + return InetAddress.getByAddress(Arrays.copyOfRange(pkt, ipOffset, ipOffset + ipLen)); + } + + private static int getSrcPort(byte[] pkt) throws Exception { + return getPort(pkt, true); + } + + private static int getDstPort(byte[] pkt) throws Exception { + return getPort(pkt, false); + } + + private static int getPort(byte[] pkt, boolean getSrcPort) { + final int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; + final int portOffset = getSrcPort ? srcPortOffset : srcPortOffset + PORT_LEN; + + if (pkt.length < portOffset + PORT_LEN) { + // Should be impossible; getPort() is only called with a full IKE request including the + // IP and UDP headers. + throw new IllegalArgumentException("Packet was too short to contain port"); + } + + final ByteBuffer buffer = ByteBuffer.wrap(pkt); + return Short.toUnsignedInt(buffer.getShort(portOffset)); + } + + private static byte[] buildIkePacket( + InetAddress srcAddr, + InetAddress dstAddr, + int srcPort, + int dstPort, + boolean useEncap, + byte[] payload) + throws Exception { + // Append non-ESP marker if encap is enabled + if (useEncap) { + final ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER.length + payload.length); + buffer.put(NON_ESP_MARKER); + buffer.put(payload); + payload = buffer.array(); + } + + final UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(payload)); + final IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt); + return ipPkt.getPacketBytes(); + } +} diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java new file mode 100644 index 0000000000..9eab024cf0 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java @@ -0,0 +1,535 @@ +/* + * 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.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; + +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.Manifest; +import android.annotation.NonNull; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.Ikev2VpnProfile; +import android.net.IpSecAlgorithm; +import android.net.LinkAddress; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.ProxyInfo; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.VpnManager; +import android.net.cts.util.CtsNetUtils; +import android.os.Build; +import android.os.Process; +import android.platform.test.annotations.AppModeFull; + +import androidx.test.InstrumentationRegistry; + +import com.android.internal.util.HexDump; +import com.android.org.bouncycastle.x509.X509V1CertificateGenerator; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.security.auth.x500.X500Principal; + +@RunWith(DevSdkIgnoreRunner.class) +@IgnoreUpTo(Build.VERSION_CODES.Q) +@AppModeFull(reason = "Appops state changes disallowed for instant apps (OP_ACTIVATE_PLATFORM_VPN)") +public class Ikev2VpnTest { + private static final String TAG = Ikev2VpnTest.class.getSimpleName(); + + // Test vectors for IKE negotiation in test mode. + private static final String SUCCESSFUL_IKE_INIT_RESP_V4 = + "46b8eca1e0d72a18b2b5d9006d47a0022120222000000000000002d0220000300000002c01010004030000" + + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800" + + "100000b8070f159fe5141d8754ca86f72ecc28d66f514927e96cbe9eec0adb42bf2c276a0ab7" + + "a97fa93555f4be9218c14e7f286bb28c6b4fb13825a420f2ffc165854f200bab37d69c8963d4" + + "0acb831d983163aa50622fd35c182efe882cf54d6106222abcfaa597255d302f1b95ab71c142" + + "c279ea5839a180070bff73f9d03fab815f0d5ee2adec7e409d1e35979f8bd92ffd8aab13d1a0" + + "0657d816643ae767e9ae84d2ccfa2bcce1a50572be8d3748ae4863c41ae90da16271e014270f" + + "77edd5cd2e3299f3ab27d7203f93d770bacf816041cdcecd0f9af249033979da4369cb242dd9" + + "6d172e60513ff3db02de63e50eb7d7f596ada55d7946cad0af0669d1f3e2804846ab3f2a930d" + + "df56f7f025f25c25ada694e6231abbb87ee8cfd072c8481dc0b0f6b083fdc3bd89b080e49feb" + + "0288eef6fdf8a26ee2fc564a11e7385215cf2deaf2a9965638fc279c908ccdf04094988d91a2" + + "464b4a8c0326533aff5119ed79ecbd9d99a218b44f506a5eb09351e67da86698b4c58718db25" + + "d55f426fb4c76471b27a41fbce00777bc233c7f6e842e39146f466826de94f564cad8b92bfbe" + + "87c99c4c7973ec5f1eea8795e7da82819753aa7c4fcfdab77066c56b939330c4b0d354c23f83" + + "ea82fa7a64c4b108f1188379ea0eb4918ee009d804100e6bf118771b9058d42141c847d5ec37" + + "6e5ec591c71fc9dac01063c2bd31f9c783b28bf1182900002430f3d5de3449462b31dd28bc27" + + "297b6ad169bccce4f66c5399c6e0be9120166f2900001c0000400428b8df2e66f69c8584a186" + + "c5eac66783551d49b72900001c000040054e7a622e802d5cbfb96d5f30a6e433994370173529" + + "0000080000402e290000100000402f00020003000400050000000800004014"; + private static final String SUCCESSFUL_IKE_INIT_RESP_V6 = + "46b8eca1e0d72a1800d9ea1babce26bf2120222000000000000002d0220000300000002c01010004030000" + + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800" + + "100000ea0e6dd9ca5930a9a45c323a41f64bfd8cdef7730f5fbff37d7c377da427f489a42aa8" + + "c89233380e6e925990d49de35c2cdcf63a61302c731a4b3569df1ee1bf2457e55a6751838ede" + + "abb75cc63ba5c9e4355e8e784f383a5efe8a44727dc14aeaf8dacc2620fb1c8875416dc07739" + + "7fe4decc1bd514a9c7d270cf21fd734c63a25c34b30b68686e54e8a198f37f27cb491fe27235" + + "fab5476b036d875ccab9a68d65fbf3006197f9bebbf94de0d3802b4fafe1d48d931ce3a1a346" + + "2d65bd639e9bd7fa46299650a9dbaf9b324e40b466942d91a59f41ef8042f8474c4850ed0f63" + + "e9238949d41cd8bbaea9aefdb65443a6405792839563aa5dc5c36b5ce8326ccf8a94d9622b85" + + "038d390d5fc0299e14e1f022966d4ac66515f6108ca04faec44821fe5bbf2ed4f84ff5671219" + + "608cb4c36b44a31ba010c9088f8d5ff943bb9ff857f74be1755f57a5783874adc57f42bb174e" + + "4ad3215de628707014dbcb1707bd214658118fdd7a42b3e1638b991ce5b812a667f1145be811" + + "685e3cd3baf9b18d062657b64c206a4d19a531c252a6a51a04aeaf42c618620cdbab65baca23" + + "82c57ed888422aeaacf7f1bc3fe2247ff7e7eaca218b74d7b31d02f2b0afa123f802529e7e6c" + + "3259d418290740ddbf55686e26998d7edcbbf895664972fed666f2f20af40503aa2af436ec6d" + + "4ec981ab19b9088755d94ae7a7c2066ea331d4e56e290000243fefe5555fce552d57a84e682c" + + "d4a6dfb3f2f94a94464d5bec3d88b88e9559642900001c00004004eb4afff764e7b79bca78b1" + + "3a89100d36d678ae982900001c00004005d177216a3c26f782076e12570d40bfaaa148822929" + + "0000080000402e290000100000402f00020003000400050000000800004014"; + private static final String SUCCESSFUL_IKE_AUTH_RESP_V4 = + "46b8eca1e0d72a18b2b5d9006d47a0022e20232000000001000000e0240000c420a2500a3da4c66fa6929e" + + "600f36349ba0e38de14f78a3ad0416cba8c058735712a3d3f9a0a6ed36de09b5e9e02697e7c4" + + "2d210ac86cfbd709503cfa51e2eab8cfdc6427d136313c072968f6506a546eb5927164200592" + + "6e36a16ee994e63f029432a67bc7d37ca619e1bd6e1678df14853067ecf816b48b81e8746069" + + "406363e5aa55f13cb2afda9dbebee94256c29d630b17dd7f1ee52351f92b6e1c3d8551c513f1" + + "d74ac52a80b2041397e109fe0aeb3c105b0d4be0ae343a943398764281"; + private static final String SUCCESSFUL_IKE_AUTH_RESP_V6 = + "46b8eca1e0d72a1800d9ea1babce26bf2e20232000000001000000f0240000d4aaf6eaa6c06b50447e6f54" + + "827fd8a9d9d6ac8015c1ebb3e8cb03fc6e54b49a107441f50004027cc5021600828026367f03" + + "bc425821cd7772ee98637361300c9b76056e874fea2bd4a17212370b291894264d8c023a01d1" + + "c3b691fd4b7c0b534e8c95af4c4638e2d125cb21c6267e2507cd745d72e8da109c47b9259c6c" + + "57a26f6bc5b337b9b9496d54bdde0333d7a32e6e1335c9ee730c3ecd607a8689aa7b0577b74f" + + "3bf437696a9fd5fc0aee3ed346cd9e15d1dda293df89eb388a8719388a60ca7625754de12cdb" + + "efe4c886c5c401"; + private static final long IKE_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); + + private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); + private static final InetAddress LOCAL_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8::1"); + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 128; + + // TODO: Use IPv6 address when we can generate test vectors (GCE does not allow IPv6 yet). + private static final String TEST_SERVER_ADDR_V4 = "192.0.2.2"; + private static final String TEST_SERVER_ADDR_V6 = "2001:db8::2"; + private static final String TEST_IDENTITY = "client.cts.android.com"; + private static final List TEST_ALLOWED_ALGORITHMS = + Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM); + + private static final ProxyInfo TEST_PROXY_INFO = + ProxyInfo.buildDirectProxy("proxy.cts.android.com", 1234); + private static final int TEST_MTU = 1300; + + private static final byte[] TEST_PSK = "ikeAndroidPsk".getBytes(); + private static final String TEST_USER = "username"; + private static final String TEST_PASSWORD = "pa55w0rd"; + + // Static state to reduce setup/teardown + private static final Context sContext = InstrumentationRegistry.getContext(); + private static final ConnectivityManager sCM = + (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + private static final VpnManager sVpnMgr = + (VpnManager) sContext.getSystemService(Context.VPN_MANAGEMENT_SERVICE); + private static final CtsNetUtils mCtsNetUtils = new CtsNetUtils(sContext); + + private final X509Certificate mServerRootCa; + private final CertificateAndKey mUserCertKey; + + public Ikev2VpnTest() throws Exception { + // Build certificates + mServerRootCa = generateRandomCertAndKeyPair().cert; + mUserCertKey = generateRandomCertAndKeyPair(); + } + + @After + public void tearDown() { + setAppop(AppOpsManager.OP_ACTIVATE_VPN, false); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + } + + /** + * Sets the given appop using shell commands + * + *

    This method must NEVER be called from within a shell permission, as it will attempt to + * acquire, and then drop the shell permission identity. This results in the caller losing the + * shell permission identity due to these calls not being reference counted. + */ + public void setAppop(int appop, boolean allow) { + // Requires shell permission to update appops. + runWithShellPermissionIdentity(() -> { + mCtsNetUtils.setAppopPrivileged(appop, allow); + }, Manifest.permission.MANAGE_TEST_NETWORKS); + } + + private Ikev2VpnProfile buildIkev2VpnProfileCommon( + Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks) throws Exception { + if (isRestrictedToTestNetworks) { + builder.restrictToTestNetworks(); + } + + return builder.setBypassable(true) + .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS) + .setProxy(TEST_PROXY_INFO) + .setMaxMtu(TEST_MTU) + .setMetered(false) + .build(); + } + + private Ikev2VpnProfile buildIkev2VpnProfilePsk(boolean isRestrictedToTestNetworks) + throws Exception { + return buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfilePsk( + String remote, boolean isRestrictedToTestNetworks) throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY).setAuthPsk(TEST_PSK); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks) + throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY) + .setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks) + throws Exception { + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY) + .setAuthDigitalSignature( + mUserCertKey.cert, mUserCertKey.key, mServerRootCa); + + return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks); + } + + private void checkBasicIkev2VpnProfile(@NonNull Ikev2VpnProfile profile) throws Exception { + assertEquals(TEST_SERVER_ADDR_V6, profile.getServerAddr()); + assertEquals(TEST_IDENTITY, profile.getUserIdentity()); + assertEquals(TEST_PROXY_INFO, profile.getProxyInfo()); + assertEquals(TEST_ALLOWED_ALGORITHMS, profile.getAllowedAlgorithms()); + assertTrue(profile.isBypassable()); + assertFalse(profile.isMetered()); + assertEquals(TEST_MTU, profile.getMaxMtu()); + assertFalse(profile.isRestrictedToTestNetworks()); + } + + @Test + public void testBuildIkev2VpnProfilePsk() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertArrayEquals(TEST_PSK, profile.getPresharedKey()); + + // Verify nothing else is set. + assertNull(profile.getUsername()); + assertNull(profile.getPassword()); + assertNull(profile.getServerRootCaCert()); + assertNull(profile.getRsaPrivateKey()); + assertNull(profile.getUserCert()); + } + + @Test + public void testBuildIkev2VpnProfileUsernamePassword() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfileUsernamePassword(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertEquals(TEST_USER, profile.getUsername()); + assertEquals(TEST_PASSWORD, profile.getPassword()); + assertEquals(mServerRootCa, profile.getServerRootCaCert()); + + // Verify nothing else is set. + assertNull(profile.getPresharedKey()); + assertNull(profile.getRsaPrivateKey()); + assertNull(profile.getUserCert()); + } + + @Test + public void testBuildIkev2VpnProfileDigitalSignature() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfileDigitalSignature(false /* isRestrictedToTestNetworks */); + + checkBasicIkev2VpnProfile(profile); + assertEquals(mUserCertKey.cert, profile.getUserCert()); + assertEquals(mUserCertKey.key, profile.getRsaPrivateKey()); + assertEquals(mServerRootCa, profile.getServerRootCaCert()); + + // Verify nothing else is set. + assertNull(profile.getUsername()); + assertNull(profile.getPassword()); + assertNull(profile.getPresharedKey()); + } + + private void verifyProvisionVpnProfile( + boolean hasActivateVpn, boolean hasActivatePlatformVpn, boolean expectIntent) + throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_VPN, hasActivateVpn); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, hasActivatePlatformVpn); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + final Intent intent = sVpnMgr.provisionVpnProfile(profile); + assertEquals(expectIntent, intent != null); + } + + @Test + public void testProvisionVpnProfileNoPreviousConsent() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(false /* hasActivateVpn */, + false /* hasActivatePlatformVpn */, true /* expectIntent */); + } + + @Test + public void testProvisionVpnProfilePlatformVpnConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(false /* hasActivateVpn */, + true /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testProvisionVpnProfileVpnServiceConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(true /* hasActivateVpn */, + false /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testProvisionVpnProfileAllPreConsented() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + verifyProvisionVpnProfile(true /* hasActivateVpn */, + true /* hasActivatePlatformVpn */, false /* expectIntent */); + } + + @Test + public void testDeleteVpnProfile() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */); + assertNull(sVpnMgr.provisionVpnProfile(profile)); + + // Verify that deleting the profile works (even without the appop) + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + sVpnMgr.deleteProvisionedVpnProfile(); + + // Test that the profile was deleted - starting it should throw an IAE. + try { + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + sVpnMgr.startProvisionedVpnProfile(); + fail("Expected IllegalArgumentException due to missing profile"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testStartVpnProfileNoPreviousConsent() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + setAppop(AppOpsManager.OP_ACTIVATE_VPN, false); + setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false); + + // Make sure the VpnProfile is not provisioned already. + sVpnMgr.stopProvisionedVpnProfile(); + + try { + sVpnMgr.startProvisionedVpnProfile(); + fail("Expected SecurityException for missing consent"); + } catch (SecurityException expected) { + } + } + + private void checkStartStopVpnProfileBuildsNetworks(IkeTunUtils tunUtils, boolean testIpv6) + throws Exception { + String serverAddr = testIpv6 ? TEST_SERVER_ADDR_V6 : TEST_SERVER_ADDR_V4; + String initResp = testIpv6 ? SUCCESSFUL_IKE_INIT_RESP_V6 : SUCCESSFUL_IKE_INIT_RESP_V4; + String authResp = testIpv6 ? SUCCESSFUL_IKE_AUTH_RESP_V6 : SUCCESSFUL_IKE_AUTH_RESP_V4; + boolean hasNat = !testIpv6; + + // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile. + mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true); + + final Ikev2VpnProfile profile = + buildIkev2VpnProfilePsk(serverAddr, true /* isRestrictedToTestNetworks */); + assertNull(sVpnMgr.provisionVpnProfile(profile)); + + sVpnMgr.startProvisionedVpnProfile(); + + // Inject IKE negotiation + int expectedMsgId = 0; + tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, false /* isEncap */, + HexDump.hexStringToByteArray(initResp)); + tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, hasNat /* isEncap */, + HexDump.hexStringToByteArray(authResp)); + + // Verify the VPN network came up + final NetworkRequest nr = new NetworkRequest.Builder() + .clearCapabilities().addTransportType(TRANSPORT_VPN).build(); + + final TestNetworkCallback cb = new TestNetworkCallback(); + sCM.requestNetwork(nr, cb); + cb.waitForAvailable(); + final Network vpnNetwork = cb.currentNetwork; + assertNotNull(vpnNetwork); + + final NetworkCapabilities caps = sCM.getNetworkCapabilities(vpnNetwork); + assertTrue(caps.hasTransport(TRANSPORT_VPN)); + assertTrue(caps.hasCapability(NET_CAPABILITY_INTERNET)); + assertEquals(Process.myUid(), caps.getOwnerUid()); + + sVpnMgr.stopProvisionedVpnProfile(); + cb.waitForLost(); + assertEquals(vpnNetwork, cb.lastLostNetwork); + } + + private void doTestStartStopVpnProfile(boolean testIpv6) throws Exception { + // Non-final; these variables ensure we clean up properly after our test if we have + // allocated test network resources + final TestNetworkManager tnm = sContext.getSystemService(TestNetworkManager.class); + TestNetworkInterface testIface = null; + TestNetworkCallback tunNetworkCallback = null; + + try { + // Build underlying test network + testIface = tnm.createTunInterface( + new LinkAddress[] { + new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), + new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)}); + + // Hold on to this callback to ensure network does not get reaped. + tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork( + testIface.getInterfaceName()); + final IkeTunUtils tunUtils = new IkeTunUtils(testIface.getFileDescriptor()); + + checkStartStopVpnProfileBuildsNetworks(tunUtils, testIpv6); + } finally { + // Make sure to stop the VPN profile. This is safe to call multiple times. + sVpnMgr.stopProvisionedVpnProfile(); + + if (testIface != null) { + testIface.getFileDescriptor().close(); + } + + if (tunNetworkCallback != null) { + sCM.unregisterNetworkCallback(tunNetworkCallback); + } + + final Network testNetwork = tunNetworkCallback.currentNetwork; + if (testNetwork != null) { + tnm.teardownTestNetwork(testNetwork); + } + } + } + + @Test + public void testStartStopVpnProfileV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + // Requires shell permission to update appops. + runWithShellPermissionIdentity(() -> { + doTestStartStopVpnProfile(false); + }); + } + + @Test + public void testStartStopVpnProfileV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + // Requires shell permission to update appops. + runWithShellPermissionIdentity(() -> { + doTestStartStopVpnProfile(true); + }); + } + + private static class CertificateAndKey { + public final X509Certificate cert; + public final PrivateKey key; + + CertificateAndKey(X509Certificate cert, PrivateKey key) { + this.cert = cert; + this.key = key; + } + } + + private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception { + final Date validityBeginDate = + new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L)); + final Date validityEndDate = + new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L)); + + // Generate a keypair + final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(512); + final KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + final X500Principal dnName = new X500Principal("CN=test.android.com"); + final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator(); + certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis())); + certGen.setSubjectDN(dnName); + certGen.setIssuerDN(dnName); + certGen.setNotBefore(validityBeginDate); + certGen.setNotAfter(validityEndDate); + certGen.setPublicKey(keyPair.getPublic()); + certGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); + + final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL"); + return new CertificateAndKey(cert, keyPair.getPrivate()); + } +} diff --git a/tests/cts/net/src/android/net/cts/InetAddressesTest.java b/tests/cts/net/src/android/net/cts/InetAddressesTest.java new file mode 100644 index 0000000000..7837ce9ed5 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/InetAddressesTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 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 android.net.InetAddresses; +import java.net.InetAddress; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +@RunWith(JUnitParamsRunner.class) +public class InetAddressesTest { + + public static String[][] validNumericAddressesAndStringRepresentation() { + return new String[][] { + // Regular IPv4. + { "1.2.3.4", "1.2.3.4" }, + + // Regular IPv6. + { "2001:4860:800d::68", "2001:4860:800d::68" }, + { "1234:5678::9ABC:DEF0", "1234:5678::9abc:def0" }, + { "2001:cdba:9abc:5678::", "2001:cdba:9abc:5678::" }, + { "::2001:cdba:9abc:5678", "::2001:cdba:9abc:5678" }, + { "64:ff9b::1.2.3.4", "64:ff9b::102:304" }, + + { "::9abc:5678", "::154.188.86.120" }, + + // Mapped IPv4 + { "::ffff:127.0.0.1", "127.0.0.1" }, + + // Android does not recognize Octal (leading 0) cases: they are treated as decimal. + { "0177.00.00.01", "177.0.0.1" }, + + // Verify that examples from JavaDoc work correctly. + { "192.0.2.1", "192.0.2.1" }, + { "2001:db8::1:2", "2001:db8::1:2" }, + }; + } + + public static String[] invalidNumericAddresses() { + return new String[] { + "", + " ", + "\t", + "\n", + "1.2.3.4.", + "1.2.3", + "1.2", + "1", + "1234", + "0", + "0x1.0x2.0x3.0x4", + "0x7f.0x00.0x00.0x01", + "0256.00.00.01", + "fred", + "www.google.com", + // IPv6 encoded for use in URL as defined in RFC 2732 + "[fe80::6:2222]", + }; + } + + @Parameters(method = "validNumericAddressesAndStringRepresentation") + @Test + public void parseNumericAddress(String address, String expectedString) { + InetAddress inetAddress = InetAddresses.parseNumericAddress(address); + assertEquals(expectedString, inetAddress.getHostAddress()); + } + + @Parameters(method = "invalidNumericAddresses") + @Test + public void test_parseNonNumericAddress(String address) { + try { + InetAddress inetAddress = InetAddresses.parseNumericAddress(address); + fail(String.format( + "Address %s is not numeric but was parsed as %s", address, inetAddress)); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains(address); + } + } + + @Test + public void test_parseNumericAddress_null() { + try { + InetAddress inetAddress = InetAddresses.parseNumericAddress(null); + fail(String.format("null is not numeric but was parsed as %s", inetAddress)); + } catch (NullPointerException e) { + // expected + } + } + + @Parameters(method = "validNumericAddressesAndStringRepresentation") + @Test + public void test_isNumericAddress(String address, String unused) { + assertTrue("expected '" + address + "' to be treated as numeric", + InetAddresses.isNumericAddress(address)); + } + + @Parameters(method = "invalidNumericAddresses") + @Test + public void test_isNotNumericAddress(String address) { + assertFalse("expected '" + address + "' to be treated as non-numeric", + InetAddresses.isNumericAddress(address)); + } + + @Test + public void test_isNumericAddress_null() { + try { + InetAddresses.isNumericAddress(null); + fail("expected null to throw a NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } +} diff --git a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java new file mode 100644 index 0000000000..56ab2a7531 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2019 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 com.android.testutils.ParcelUtils.assertParcelSane; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.net.IpConfiguration; +import android.net.LinkAddress; +import android.net.ProxyInfo; +import android.net.StaticIpConfiguration; + +import androidx.test.runner.AndroidJUnit4; + +import libcore.net.InetAddressUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.ArrayList; + +@RunWith(AndroidJUnit4.class) +public final class IpConfigurationTest { + private static final LinkAddress LINKADDR = new LinkAddress("192.0.2.2/25"); + private static final InetAddress GATEWAY = InetAddressUtils.parseNumericAddress("192.0.2.1"); + private static final InetAddress DNS1 = InetAddressUtils.parseNumericAddress("8.8.8.8"); + private static final InetAddress DNS2 = InetAddressUtils.parseNumericAddress("8.8.4.4"); + private static final String DOMAINS = "example.com"; + + private static final ArrayList dnsServers = new ArrayList<>(); + + private StaticIpConfiguration mStaticIpConfig; + private ProxyInfo mProxy; + + @Before + public void setUp() { + dnsServers.add(DNS1); + dnsServers.add(DNS2); + mStaticIpConfig = new StaticIpConfiguration.Builder() + .setIpAddress(LINKADDR) + .setGateway(GATEWAY) + .setDnsServers(dnsServers) + .setDomains(DOMAINS) + .build(); + + mProxy = ProxyInfo.buildDirectProxy("test", 8888); + } + + @Test + public void testConstructor() { + IpConfiguration ipConfig = new IpConfiguration(); + checkEmpty(ipConfig); + assertIpConfigurationEqual(ipConfig, new IpConfiguration()); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig.setStaticIpConfiguration(mStaticIpConfig); + ipConfig.setHttpProxy(mProxy); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE); + assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig)); + } + + private void checkEmpty(IpConfiguration config) { + assertEquals(IpConfiguration.IpAssignment.UNASSIGNED, + config.getIpAssignment().UNASSIGNED); + assertEquals(IpConfiguration.ProxySettings.UNASSIGNED, + config.getProxySettings().UNASSIGNED); + assertNull(config.getStaticIpConfiguration()); + assertNull(config.getHttpProxy()); + } + + private void assertIpConfigurationEqual(IpConfiguration source, IpConfiguration target) { + assertEquals(source.getIpAssignment(), target.getIpAssignment()); + assertEquals(source.getProxySettings(), target.getProxySettings()); + assertEquals(source.getHttpProxy(), target.getHttpProxy()); + assertEquals(source.getStaticIpConfiguration(), target.getStaticIpConfiguration()); + } + + @Test + public void testParcel() { + final IpConfiguration config = new IpConfiguration(); + assertParcelSane(config, 4); + } +} diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java new file mode 100644 index 0000000000..10e43e7b6a --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2018 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 org.junit.Assert.assertArrayEquals; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.IpSecAlgorithm; +import android.net.IpSecManager; +import android.net.IpSecTransform; +import android.platform.test.annotations.AppModeFull; +import android.system.Os; +import android.system.OsConstants; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class IpSecBaseTest { + + private static final String TAG = IpSecBaseTest.class.getSimpleName(); + + protected static final String IPV4_LOOPBACK = "127.0.0.1"; + protected static final String IPV6_LOOPBACK = "::1"; + protected static final String[] LOOPBACK_ADDRS = new String[] {IPV4_LOOPBACK, IPV6_LOOPBACK}; + protected static final int[] DIRECTIONS = + new int[] {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}; + + protected static final byte[] TEST_DATA = "Best test data ever!".getBytes(); + protected static final int DATA_BUFFER_LEN = 4096; + protected static final int SOCK_TIMEOUT = 500; + + private static final byte[] KEY_DATA = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 + }; + + protected static final byte[] AUTH_KEY = getKey(256); + protected static final byte[] CRYPT_KEY = getKey(256); + + protected ConnectivityManager mCM; + protected IpSecManager mISM; + + @Before + public void setUp() throws Exception { + mISM = + (IpSecManager) + InstrumentationRegistry.getContext() + .getSystemService(Context.IPSEC_SERVICE); + mCM = + (ConnectivityManager) + InstrumentationRegistry.getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + } + + protected static byte[] getKey(int bitLength) { + return Arrays.copyOf(KEY_DATA, bitLength / 8); + } + + protected static int getDomain(InetAddress address) { + int domain; + if (address instanceof Inet6Address) { + domain = OsConstants.AF_INET6; + } else { + domain = OsConstants.AF_INET; + } + return domain; + } + + protected static int getPort(FileDescriptor sock) throws Exception { + return ((InetSocketAddress) Os.getsockname(sock)).getPort(); + } + + public static interface GenericSocket extends AutoCloseable { + void send(byte[] data) throws Exception; + + byte[] receive() throws Exception; + + int getPort() throws Exception; + + void close() throws Exception; + + void applyTransportModeTransform( + IpSecManager ism, int direction, IpSecTransform transform) throws Exception; + + void removeTransportModeTransforms(IpSecManager ism) throws Exception; + } + + public static interface GenericTcpSocket extends GenericSocket {} + + public static interface GenericUdpSocket extends GenericSocket { + void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception; + } + + public abstract static class NativeSocket implements GenericSocket { + public FileDescriptor mFd; + + public NativeSocket(FileDescriptor fd) { + mFd = fd; + } + + @Override + public void send(byte[] data) throws Exception { + Os.write(mFd, data, 0, data.length); + } + + @Override + public byte[] receive() throws Exception { + byte[] in = new byte[DATA_BUFFER_LEN]; + AtomicInteger bytesRead = new AtomicInteger(-1); + + Thread readSockThread = new Thread(() -> { + long startTime = System.currentTimeMillis(); + while (bytesRead.get() < 0 && System.currentTimeMillis() < startTime + SOCK_TIMEOUT) { + try { + bytesRead.set(Os.recvfrom(mFd, in, 0, DATA_BUFFER_LEN, 0, null)); + } catch (Exception e) { + Log.e(TAG, "Error encountered reading from socket", e); + } + } + }); + + readSockThread.start(); + readSockThread.join(SOCK_TIMEOUT); + + if (bytesRead.get() < 0) { + throw new IOException("No data received from socket"); + } + + return Arrays.copyOfRange(in, 0, bytesRead.get()); + } + + @Override + public int getPort() throws Exception { + return IpSecBaseTest.getPort(mFd); + } + + @Override + public void close() throws Exception { + Os.close(mFd); + } + + @Override + public void applyTransportModeTransform( + IpSecManager ism, int direction, IpSecTransform transform) throws Exception { + ism.applyTransportModeTransform(mFd, direction, transform); + } + + @Override + public void removeTransportModeTransforms(IpSecManager ism) throws Exception { + ism.removeTransportModeTransforms(mFd); + } + } + + public static class NativeTcpSocket extends NativeSocket implements GenericTcpSocket { + public NativeTcpSocket(FileDescriptor fd) { + super(fd); + } + } + + public static class NativeUdpSocket extends NativeSocket implements GenericUdpSocket { + public NativeUdpSocket(FileDescriptor fd) { + super(fd); + } + + @Override + public void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception { + Os.sendto(mFd, data, 0, data.length, 0, dstAddr, port); + } + } + + public static class JavaUdpSocket implements GenericUdpSocket { + public final DatagramSocket mSocket; + + public JavaUdpSocket(InetAddress localAddr, int port) { + try { + mSocket = new DatagramSocket(port, localAddr); + mSocket.setSoTimeout(SOCK_TIMEOUT); + } catch (SocketException e) { + // Fail loudly if we can't set up sockets properly. And without the timeout, we + // could easily end up in an endless wait. + throw new RuntimeException(e); + } + } + + public JavaUdpSocket(InetAddress localAddr) { + try { + mSocket = new DatagramSocket(0, localAddr); + mSocket.setSoTimeout(SOCK_TIMEOUT); + } catch (SocketException e) { + // Fail loudly if we can't set up sockets properly. And without the timeout, we + // could easily end up in an endless wait. + throw new RuntimeException(e); + } + } + + @Override + public void send(byte[] data) throws Exception { + mSocket.send(new DatagramPacket(data, data.length)); + } + + @Override + public void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception { + mSocket.send(new DatagramPacket(data, data.length, dstAddr, port)); + } + + @Override + public int getPort() throws Exception { + return mSocket.getLocalPort(); + } + + @Override + public void close() throws Exception { + mSocket.close(); + } + + @Override + public byte[] receive() throws Exception { + DatagramPacket data = new DatagramPacket(new byte[DATA_BUFFER_LEN], DATA_BUFFER_LEN); + mSocket.receive(data); + return Arrays.copyOfRange(data.getData(), 0, data.getLength()); + } + + @Override + public void applyTransportModeTransform( + IpSecManager ism, int direction, IpSecTransform transform) throws Exception { + ism.applyTransportModeTransform(mSocket, direction, transform); + } + + @Override + public void removeTransportModeTransforms(IpSecManager ism) throws Exception { + ism.removeTransportModeTransforms(mSocket); + } + } + + public static class JavaTcpSocket implements GenericTcpSocket { + public final Socket mSocket; + + public JavaTcpSocket(Socket socket) { + mSocket = socket; + try { + mSocket.setSoTimeout(SOCK_TIMEOUT); + } catch (SocketException e) { + // Fail loudly if we can't set up sockets properly. And without the timeout, we + // could easily end up in an endless wait. + throw new RuntimeException(e); + } + } + + @Override + public void send(byte[] data) throws Exception { + mSocket.getOutputStream().write(data); + } + + @Override + public byte[] receive() throws Exception { + byte[] in = new byte[DATA_BUFFER_LEN]; + int bytesRead = mSocket.getInputStream().read(in); + return Arrays.copyOfRange(in, 0, bytesRead); + } + + @Override + public int getPort() throws Exception { + return mSocket.getLocalPort(); + } + + @Override + public void close() throws Exception { + mSocket.close(); + } + + @Override + public void applyTransportModeTransform( + IpSecManager ism, int direction, IpSecTransform transform) throws Exception { + ism.applyTransportModeTransform(mSocket, direction, transform); + } + + @Override + public void removeTransportModeTransforms(IpSecManager ism) throws Exception { + ism.removeTransportModeTransforms(mSocket); + } + } + + public static class SocketPair { + public final T mLeftSock; + public final T mRightSock; + + public SocketPair(T leftSock, T rightSock) { + mLeftSock = leftSock; + mRightSock = rightSock; + } + } + + protected static void applyTransformBidirectionally( + IpSecManager ism, IpSecTransform transform, GenericSocket socket) throws Exception { + for (int direction : DIRECTIONS) { + socket.applyTransportModeTransform(ism, direction, transform); + } + } + + public static SocketPair getNativeUdpSocketPair( + InetAddress localAddr, IpSecManager ism, IpSecTransform transform, boolean connected) + throws Exception { + int domain = getDomain(localAddr); + + NativeUdpSocket leftSock = new NativeUdpSocket( + Os.socket(domain, OsConstants.SOCK_DGRAM, OsConstants.IPPROTO_UDP)); + NativeUdpSocket rightSock = new NativeUdpSocket( + Os.socket(domain, OsConstants.SOCK_DGRAM, OsConstants.IPPROTO_UDP)); + + for (NativeUdpSocket sock : new NativeUdpSocket[] {leftSock, rightSock}) { + applyTransformBidirectionally(ism, transform, sock); + Os.bind(sock.mFd, localAddr, 0); + } + + if (connected) { + Os.connect(leftSock.mFd, localAddr, rightSock.getPort()); + Os.connect(rightSock.mFd, localAddr, leftSock.getPort()); + } + + return new SocketPair<>(leftSock, rightSock); + } + + public static SocketPair getNativeTcpSocketPair( + InetAddress localAddr, IpSecManager ism, IpSecTransform transform) throws Exception { + int domain = getDomain(localAddr); + + NativeTcpSocket server = new NativeTcpSocket( + Os.socket(domain, OsConstants.SOCK_STREAM, OsConstants.IPPROTO_TCP)); + NativeTcpSocket client = new NativeTcpSocket( + Os.socket(domain, OsConstants.SOCK_STREAM, OsConstants.IPPROTO_TCP)); + + Os.bind(server.mFd, localAddr, 0); + + applyTransformBidirectionally(ism, transform, server); + applyTransformBidirectionally(ism, transform, client); + + Os.listen(server.mFd, 10); + Os.connect(client.mFd, localAddr, server.getPort()); + NativeTcpSocket accepted = new NativeTcpSocket(Os.accept(server.mFd, null)); + + applyTransformBidirectionally(ism, transform, accepted); + server.close(); + + return new SocketPair<>(client, accepted); + } + + public static SocketPair getJavaUdpSocketPair( + InetAddress localAddr, IpSecManager ism, IpSecTransform transform, boolean connected) + throws Exception { + JavaUdpSocket leftSock = new JavaUdpSocket(localAddr); + JavaUdpSocket rightSock = new JavaUdpSocket(localAddr); + + applyTransformBidirectionally(ism, transform, leftSock); + applyTransformBidirectionally(ism, transform, rightSock); + + if (connected) { + leftSock.mSocket.connect(localAddr, rightSock.mSocket.getLocalPort()); + rightSock.mSocket.connect(localAddr, leftSock.mSocket.getLocalPort()); + } + + return new SocketPair<>(leftSock, rightSock); + } + + public static SocketPair getJavaTcpSocketPair( + InetAddress localAddr, IpSecManager ism, IpSecTransform transform) throws Exception { + JavaTcpSocket clientSock = new JavaTcpSocket(new Socket()); + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(new InetSocketAddress(localAddr, 0)); + + // While technically the client socket does not need to be bound, the OpenJDK implementation + // of Socket only allocates an FD when bind() or connect() or other similar methods are + // called. So we call bind to force the FD creation, so that we can apply a transform to it + // prior to socket connect. + clientSock.mSocket.bind(new InetSocketAddress(localAddr, 0)); + + // IpSecService doesn't support serverSockets at the moment; workaround using FD + FileDescriptor serverFd = serverSocket.getImpl().getFD$(); + + applyTransformBidirectionally(ism, transform, new NativeTcpSocket(serverFd)); + applyTransformBidirectionally(ism, transform, clientSock); + + clientSock.mSocket.connect(new InetSocketAddress(localAddr, serverSocket.getLocalPort())); + JavaTcpSocket acceptedSock = new JavaTcpSocket(serverSocket.accept()); + + applyTransformBidirectionally(ism, transform, acceptedSock); + serverSocket.close(); + + return new SocketPair<>(clientSock, acceptedSock); + } + + private void checkSocketPair(GenericSocket left, GenericSocket right) throws Exception { + left.send(TEST_DATA); + assertArrayEquals(TEST_DATA, right.receive()); + + right.send(TEST_DATA); + assertArrayEquals(TEST_DATA, left.receive()); + + left.close(); + right.close(); + } + + private void checkUnconnectedUdpSocketPair( + GenericUdpSocket left, GenericUdpSocket right, InetAddress localAddr) throws Exception { + left.sendTo(TEST_DATA, localAddr, right.getPort()); + assertArrayEquals(TEST_DATA, right.receive()); + + right.sendTo(TEST_DATA, localAddr, left.getPort()); + assertArrayEquals(TEST_DATA, left.receive()); + + left.close(); + right.close(); + } + + protected static IpSecTransform buildIpSecTransform( + Context context, + IpSecManager.SecurityParameterIndex spi, + IpSecManager.UdpEncapsulationSocket encapSocket, + InetAddress remoteAddr) + throws Exception { + IpSecTransform.Builder builder = + new IpSecTransform.Builder(context) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 4)); + + if (encapSocket != null) { + builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); + } + + return builder.buildTransportModeTransform(remoteAddr, spi); + } + + private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { + try (IpSecManager.SecurityParameterIndex spi = + mISM.allocateSecurityParameterIndex(localAddr)) { + return buildIpSecTransform(InstrumentationRegistry.getContext(), spi, null, localAddr); + } + } + + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testJavaTcpSocketPair() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = getJavaTcpSocketPair(local, mISM, transform); + checkSocketPair(sockets.mLeftSock, sockets.mRightSock); + } + } + } + + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testJavaUdpSocketPair() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getJavaUdpSocketPair(local, mISM, transform, true); + checkSocketPair(sockets.mLeftSock, sockets.mRightSock); + } + } + } + + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testJavaUdpSocketPairUnconnected() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getJavaUdpSocketPair(local, mISM, transform, false); + checkUnconnectedUdpSocketPair(sockets.mLeftSock, sockets.mRightSock, local); + } + } + } + + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testNativeTcpSocketPair() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getNativeTcpSocketPair(local, mISM, transform); + checkSocketPair(sockets.mLeftSock, sockets.mRightSock); + } + } + } + + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testNativeUdpSocketPair() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getNativeUdpSocketPair(local, mISM, transform, true); + checkSocketPair(sockets.mLeftSock, sockets.mRightSock); + } + } + } + + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testNativeUdpSocketPairUnconnected() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getNativeUdpSocketPair(local, mISM, transform, false); + checkUnconnectedUdpSocketPair(sockets.mLeftSock, sockets.mRightSock, local); + } + } + } +} diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java new file mode 100644 index 0000000000..355b496829 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -0,0 +1,1189 @@ +/* + * Copyright (C) 2017 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.net.cts.PacketUtils.AES_CBC_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; +import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_GCM_IV_LEN; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.TCP_HDRLEN_WITH_TIMESTAMP_OPT; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.IPPROTO_UDP; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.net.IpSecAlgorithm; +import android.net.IpSecManager; +import android.net.IpSecTransform; +import android.net.TrafficStats; +import android.platform.test.annotations.AppModeFull; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "Socket cannot bind in instant app mode") +public class IpSecManagerTest extends IpSecBaseTest { + + private static final String TAG = IpSecManagerTest.class.getSimpleName(); + + private static final InetAddress GOOGLE_DNS_4 = InetAddress.parseNumericAddress("8.8.8.8"); + private static final InetAddress GOOGLE_DNS_6 = + InetAddress.parseNumericAddress("2001:4860:4860::8888"); + + private static final InetAddress[] GOOGLE_DNS_LIST = + new InetAddress[] {GOOGLE_DNS_4, GOOGLE_DNS_6}; + + private static final int DROID_SPI = 0xD1201D; + private static final int MAX_PORT_BIND_ATTEMPTS = 10; + + private static final byte[] AEAD_KEY = getKey(288); + + /* + * Allocate a random SPI + * Allocate a specific SPI using previous randomly created SPI value + * Realloc the same SPI that was specifically created (expect SpiUnavailable) + * Close SPIs + */ + @Test + public void testAllocSpi() throws Exception { + for (InetAddress addr : GOOGLE_DNS_LIST) { + IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null; + randomSpi = mISM.allocateSecurityParameterIndex(addr); + assertTrue( + "Failed to receive a valid SPI", + randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + + droidSpi = mISM.allocateSecurityParameterIndex(addr, DROID_SPI); + assertTrue("Failed to allocate specified SPI, " + DROID_SPI, + droidSpi.getSpi() == DROID_SPI); + + try { + mISM.allocateSecurityParameterIndex(addr, DROID_SPI); + fail("Duplicate SPI was allowed to be created"); + } catch (IpSecManager.SpiUnavailableException expected) { + // This is a success case because we expect a dupe SPI to throw + } + + randomSpi.close(); + droidSpi.close(); + } + } + + /** This function finds an available port */ + private static int findUnusedPort() throws Exception { + // Get an available port. + DatagramSocket s = new DatagramSocket(); + int port = s.getLocalPort(); + s.close(); + return port; + } + + private static FileDescriptor getBoundUdpSocket(InetAddress address) throws Exception { + FileDescriptor sock = + Os.socket(getDomain(address), OsConstants.SOCK_DGRAM, OsConstants.IPPROTO_UDP); + + for (int i = 0; i < MAX_PORT_BIND_ATTEMPTS; i++) { + try { + int port = findUnusedPort(); + Os.bind(sock, address, port); + break; + } catch (ErrnoException e) { + // Someone claimed the port since we called findUnusedPort. + if (e.errno == OsConstants.EADDRINUSE) { + if (i == MAX_PORT_BIND_ATTEMPTS - 1) { + + fail("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); + } + continue; + } + throw e.rethrowAsIOException(); + } + } + return sock; + } + + private void checkUnconnectedUdp(IpSecTransform transform, InetAddress local, int sendCount, + boolean useJavaSockets) throws Exception { + GenericUdpSocket sockLeft = null, sockRight = null; + if (useJavaSockets) { + SocketPair sockets = getJavaUdpSocketPair(local, mISM, transform, false); + sockLeft = sockets.mLeftSock; + sockRight = sockets.mRightSock; + } else { + SocketPair sockets = + getNativeUdpSocketPair(local, mISM, transform, false); + sockLeft = sockets.mLeftSock; + sockRight = sockets.mRightSock; + } + + for (int i = 0; i < sendCount; i++) { + byte[] in; + + sockLeft.sendTo(TEST_DATA, local, sockRight.getPort()); + in = sockRight.receive(); + assertArrayEquals("Left-to-right encrypted data did not match.", TEST_DATA, in); + + sockRight.sendTo(TEST_DATA, local, sockLeft.getPort()); + in = sockLeft.receive(); + assertArrayEquals("Right-to-left encrypted data did not match.", TEST_DATA, in); + } + + sockLeft.close(); + sockRight.close(); + } + + private void checkTcp(IpSecTransform transform, InetAddress local, int sendCount, + boolean useJavaSockets) throws Exception { + GenericTcpSocket client = null, accepted = null; + if (useJavaSockets) { + SocketPair sockets = getJavaTcpSocketPair(local, mISM, transform); + client = sockets.mLeftSock; + accepted = sockets.mRightSock; + } else { + SocketPair sockets = getNativeTcpSocketPair(local, mISM, transform); + client = sockets.mLeftSock; + accepted = sockets.mRightSock; + } + + // Wait for TCP handshake packets to be counted + StatsChecker.waitForNumPackets(3); // (SYN, SYN+ACK, ACK) + + // Reset StatsChecker, to ignore negotiation overhead. + StatsChecker.initStatsChecker(); + for (int i = 0; i < sendCount; i++) { + byte[] in; + + client.send(TEST_DATA); + in = accepted.receive(); + assertArrayEquals("Client-to-server encrypted data did not match.", TEST_DATA, in); + + // Allow for newest data + ack packets to be returned before sending next packet + // Also add the number of expected packets in each of the previous runs (4 per run) + StatsChecker.waitForNumPackets(2 + (4 * i)); + + accepted.send(TEST_DATA); + in = client.receive(); + assertArrayEquals("Server-to-client encrypted data did not match.", TEST_DATA, in); + + // Allow for all data + ack packets to be returned before sending next packet + // Also add the number of expected packets in each of the previous runs (4 per run) + StatsChecker.waitForNumPackets(4 * (i + 1)); + } + + // Transforms should not be removed from the sockets, otherwise FIN packets will be sent + // unencrypted. + // This test also unfortunately happens to rely on a nuance of the cleanup order. By + // keeping the policy on the socket, but removing the SA before lingering FIN packets + // are sent (at an undetermined later time), the FIN packets are dropped. Without this, + // we run into all kinds of headaches trying to test data accounting (unsolicited + // packets mysteriously appearing and messing up our counters) + // The right way to close sockets is to set SO_LINGER to ensure synchronous closure, + // closing the sockets, and then closing the transforms. See documentation for the + // Socket or FileDescriptor flavors of applyTransportModeTransform() in IpSecManager + // for more details. + + client.close(); + accepted.close(); + } + + /* + * Alloc outbound SPI + * Alloc inbound SPI + * Create transport mode transform + * open socket + * apply transform to socket + * send data on socket + * release transform + * send data (expect exception) + */ + @Test + public void testCreateTransform() throws Exception { + InetAddress localAddr = InetAddress.getByName(IPV4_LOOPBACK); + IpSecManager.SecurityParameterIndex spi = + mISM.allocateSecurityParameterIndex(localAddr); + + IpSecTransform transform = + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 8)) + .buildTransportModeTransform(localAddr, spi); + + final boolean [][] applyInApplyOut = { + {false, false}, {false, true}, {true, false}, {true,true}}; + final byte[] data = new String("Best test data ever!").getBytes("UTF-8"); + final DatagramPacket outPacket = new DatagramPacket(data, 0, data.length, localAddr, 0); + + byte[] in = new byte[data.length]; + DatagramPacket inPacket = new DatagramPacket(in, in.length); + DatagramSocket localSocket; + int localPort; + + for(boolean[] io : applyInApplyOut) { + boolean applyIn = io[0]; + boolean applyOut = io[1]; + // Bind localSocket to a random available port. + localSocket = new DatagramSocket(0); + localPort = localSocket.getLocalPort(); + localSocket.setSoTimeout(200); + outPacket.setPort(localPort); + if (applyIn) { + mISM.applyTransportModeTransform( + localSocket, IpSecManager.DIRECTION_IN, transform); + } + if (applyOut) { + mISM.applyTransportModeTransform( + localSocket, IpSecManager.DIRECTION_OUT, transform); + } + if (applyIn == applyOut) { + localSocket.send(outPacket); + localSocket.receive(inPacket); + assertTrue("Encapsulated data did not match.", + Arrays.equals(outPacket.getData(), inPacket.getData())); + mISM.removeTransportModeTransforms(localSocket); + localSocket.close(); + } else { + try { + localSocket.send(outPacket); + localSocket.receive(inPacket); + } catch (IOException e) { + continue; + } finally { + mISM.removeTransportModeTransforms(localSocket); + localSocket.close(); + } + // FIXME: This check is disabled because sockets currently receive data + // if there is a valid SA for decryption, even when the input policy is + // not applied to a socket. + // fail("Data IO should fail on asymmetrical transforms! + Input=" + // + applyIn + " Output=" + applyOut); + } + } + transform.close(); + } + + /** Snapshot of TrafficStats as of initStatsChecker call for later comparisons */ + private static class StatsChecker { + private static final double ERROR_MARGIN_BYTES = 1.05; + private static final double ERROR_MARGIN_PKTS = 1.05; + private static final int MAX_WAIT_TIME_MILLIS = 1000; + + private static long uidTxBytes; + private static long uidRxBytes; + private static long uidTxPackets; + private static long uidRxPackets; + + private static long ifaceTxBytes; + private static long ifaceRxBytes; + private static long ifaceTxPackets; + private static long ifaceRxPackets; + + /** + * This method counts the number of incoming packets, polling intermittently up to + * MAX_WAIT_TIME_MILLIS. + */ + private static void waitForNumPackets(int numPackets) throws Exception { + long uidTxDelta = 0; + long uidRxDelta = 0; + for (int i = 0; i < 100; i++) { + uidTxDelta = TrafficStats.getUidTxPackets(Os.getuid()) - uidTxPackets; + uidRxDelta = TrafficStats.getUidRxPackets(Os.getuid()) - uidRxPackets; + + // TODO: Check Rx packets as well once kernel security policy bug is fixed. + // (b/70635417) + if (uidTxDelta >= numPackets) { + return; + } + Thread.sleep(MAX_WAIT_TIME_MILLIS / 100); + } + fail( + "Not enough traffic was recorded to satisfy the provided conditions: wanted " + + numPackets + + ", got " + + uidTxDelta + + " tx and " + + uidRxDelta + + " rx packets"); + } + + private static void assertUidStatsDelta( + int expectedTxByteDelta, + int expectedTxPacketDelta, + int minRxByteDelta, + int maxRxByteDelta, + int expectedRxPacketDelta) { + long newUidTxBytes = TrafficStats.getUidTxBytes(Os.getuid()); + long newUidRxBytes = TrafficStats.getUidRxBytes(Os.getuid()); + long newUidTxPackets = TrafficStats.getUidTxPackets(Os.getuid()); + long newUidRxPackets = TrafficStats.getUidRxPackets(Os.getuid()); + + assertEquals(expectedTxByteDelta, newUidTxBytes - uidTxBytes); + assertTrue( + newUidRxBytes - uidRxBytes >= minRxByteDelta + && newUidRxBytes - uidRxBytes <= maxRxByteDelta); + assertEquals(expectedTxPacketDelta, newUidTxPackets - uidTxPackets); + assertEquals(expectedRxPacketDelta, newUidRxPackets - uidRxPackets); + } + + private static void assertIfaceStatsDelta( + int expectedTxByteDelta, + int expectedTxPacketDelta, + int expectedRxByteDelta, + int expectedRxPacketDelta) + throws IOException { + long newIfaceTxBytes = TrafficStats.getLoopbackTxBytes(); + long newIfaceRxBytes = TrafficStats.getLoopbackRxBytes(); + long newIfaceTxPackets = TrafficStats.getLoopbackTxPackets(); + long newIfaceRxPackets = TrafficStats.getLoopbackRxPackets(); + + // Check that iface stats are within an acceptable range; data might be sent + // on the local interface by other apps. + assertApproxEquals( + ifaceTxBytes, newIfaceTxBytes, expectedTxByteDelta, ERROR_MARGIN_BYTES); + assertApproxEquals( + ifaceRxBytes, newIfaceRxBytes, expectedRxByteDelta, ERROR_MARGIN_BYTES); + assertApproxEquals( + ifaceTxPackets, newIfaceTxPackets, expectedTxPacketDelta, ERROR_MARGIN_PKTS); + assertApproxEquals( + ifaceRxPackets, newIfaceRxPackets, expectedRxPacketDelta, ERROR_MARGIN_PKTS); + } + + private static void assertApproxEquals( + long oldStats, long newStats, int expectedDelta, double errorMargin) { + assertTrue(expectedDelta <= newStats - oldStats); + assertTrue((expectedDelta * errorMargin) > newStats - oldStats); + } + + private static void initStatsChecker() throws Exception { + uidTxBytes = TrafficStats.getUidTxBytes(Os.getuid()); + uidRxBytes = TrafficStats.getUidRxBytes(Os.getuid()); + uidTxPackets = TrafficStats.getUidTxPackets(Os.getuid()); + uidRxPackets = TrafficStats.getUidRxPackets(Os.getuid()); + + ifaceTxBytes = TrafficStats.getLoopbackTxBytes(); + ifaceRxBytes = TrafficStats.getLoopbackRxBytes(); + ifaceTxPackets = TrafficStats.getLoopbackTxPackets(); + ifaceRxPackets = TrafficStats.getLoopbackRxPackets(); + } + } + + private int getTruncLenBits(IpSecAlgorithm authOrAead) { + return authOrAead == null ? 0 : authOrAead.getTruncationLengthBits(); + } + + private int getIvLen(IpSecAlgorithm cryptOrAead) { + if (cryptOrAead == null) { return 0; } + + switch (cryptOrAead.getName()) { + case IpSecAlgorithm.CRYPT_AES_CBC: + return AES_CBC_IV_LEN; + case IpSecAlgorithm.AUTH_CRYPT_AES_GCM: + return AES_GCM_IV_LEN; + default: + throw new IllegalArgumentException( + "IV length unknown for algorithm" + cryptOrAead.getName()); + } + } + + private int getBlkSize(IpSecAlgorithm cryptOrAead) { + // RFC 4303, section 2.4 states that ciphertext plus pad_len, next_header fields must + // terminate on a 4-byte boundary. Thus, the minimum ciphertext block size is 4 bytes. + if (cryptOrAead == null) { return 4; } + + switch (cryptOrAead.getName()) { + case IpSecAlgorithm.CRYPT_AES_CBC: + return AES_CBC_BLK_SIZE; + case IpSecAlgorithm.AUTH_CRYPT_AES_GCM: + return AES_GCM_BLK_SIZE; + default: + throw new IllegalArgumentException( + "Blk size unknown for algorithm" + cryptOrAead.getName()); + } + } + + public void checkTransform( + int protocol, + String localAddress, + IpSecAlgorithm crypt, + IpSecAlgorithm auth, + IpSecAlgorithm aead, + boolean doUdpEncap, + int sendCount, + boolean useJavaSockets) + throws Exception { + StatsChecker.initStatsChecker(); + InetAddress local = InetAddress.getByName(localAddress); + + try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket(); + IpSecManager.SecurityParameterIndex spi = + mISM.allocateSecurityParameterIndex(local)) { + + IpSecTransform.Builder transformBuilder = + new IpSecTransform.Builder(InstrumentationRegistry.getContext()); + if (crypt != null) { + transformBuilder.setEncryption(crypt); + } + if (auth != null) { + transformBuilder.setAuthentication(auth); + } + if (aead != null) { + transformBuilder.setAuthenticatedEncryption(aead); + } + + if (doUdpEncap) { + transformBuilder = + transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); + } + + int ipHdrLen = local instanceof Inet6Address ? IP6_HDRLEN : IP4_HDRLEN; + int transportHdrLen = 0; + int udpEncapLen = doUdpEncap ? UDP_HDRLEN : 0; + + try (IpSecTransform transform = + transformBuilder.buildTransportModeTransform(local, spi)) { + if (protocol == IPPROTO_TCP) { + transportHdrLen = TCP_HDRLEN_WITH_TIMESTAMP_OPT; + checkTcp(transform, local, sendCount, useJavaSockets); + } else if (protocol == IPPROTO_UDP) { + transportHdrLen = UDP_HDRLEN; + + // TODO: Also check connected udp. + checkUnconnectedUdp(transform, local, sendCount, useJavaSockets); + } else { + throw new IllegalArgumentException("Invalid protocol"); + } + } + + checkStatsChecker( + protocol, + ipHdrLen, + transportHdrLen, + udpEncapLen, + sendCount, + getIvLen(crypt != null ? crypt : aead), + getBlkSize(crypt != null ? crypt : aead), + getTruncLenBits(auth != null ? auth : aead)); + } + } + + private void checkStatsChecker( + int protocol, + int ipHdrLen, + int transportHdrLen, + int udpEncapLen, + int sendCount, + int ivLen, + int blkSize, + int truncLenBits) + throws Exception { + + int innerPacketSize = TEST_DATA.length + transportHdrLen + ipHdrLen; + int outerPacketSize = + PacketUtils.calculateEspPacketSize( + TEST_DATA.length + transportHdrLen, ivLen, blkSize, truncLenBits) + + udpEncapLen + + ipHdrLen; + + int expectedOuterBytes = outerPacketSize * sendCount; + int expectedInnerBytes = innerPacketSize * sendCount; + int expectedPackets = sendCount; + + // Each run sends two packets, one in each direction. + sendCount *= 2; + expectedOuterBytes *= 2; + expectedInnerBytes *= 2; + expectedPackets *= 2; + + // Add TCP ACKs for data packets + if (protocol == IPPROTO_TCP) { + int encryptedTcpPktSize = + PacketUtils.calculateEspPacketSize( + TCP_HDRLEN_WITH_TIMESTAMP_OPT, ivLen, blkSize, truncLenBits); + + // Add data packet ACKs + expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount); + expectedInnerBytes += (TCP_HDRLEN_WITH_TIMESTAMP_OPT + ipHdrLen) * (sendCount); + expectedPackets += sendCount; + } + + StatsChecker.waitForNumPackets(expectedPackets); + + // eBPF only counts inner packets, whereas xt_qtaguid counts outer packets. Allow both + StatsChecker.assertUidStatsDelta( + expectedOuterBytes, + expectedPackets, + expectedInnerBytes, + expectedOuterBytes, + expectedPackets); + + // Unreliable at low numbers due to potential interference from other processes. + if (sendCount >= 1000) { + StatsChecker.assertIfaceStatsDelta( + expectedOuterBytes, expectedPackets, expectedOuterBytes, expectedPackets); + } + } + + private void checkIkePacket( + NativeUdpSocket wrappedEncapSocket, InetAddress localAddr) throws Exception { + StatsChecker.initStatsChecker(); + + try (NativeUdpSocket remoteSocket = new NativeUdpSocket(getBoundUdpSocket(localAddr))) { + + // Append IKE/ESP header - 4 bytes of SPI, 4 bytes of seq number, all zeroed out + // If the first four bytes are zero, assume non-ESP (IKE traffic) + byte[] dataWithEspHeader = new byte[TEST_DATA.length + 8]; + System.arraycopy(TEST_DATA, 0, dataWithEspHeader, 8, TEST_DATA.length); + + // Send the IKE packet from remoteSocket to wrappedEncapSocket. Since IKE packets + // are multiplexed over the socket, we expect them to appear on the encap socket + // (as opposed to being decrypted and received on the non-encap socket) + remoteSocket.sendTo(dataWithEspHeader, localAddr, wrappedEncapSocket.getPort()); + byte[] in = wrappedEncapSocket.receive(); + assertArrayEquals("Encapsulated data did not match.", dataWithEspHeader, in); + + // Also test that the IKE socket can send data out. + wrappedEncapSocket.sendTo(dataWithEspHeader, localAddr, remoteSocket.getPort()); + in = remoteSocket.receive(); + assertArrayEquals("Encapsulated data did not match.", dataWithEspHeader, in); + + // Calculate expected packet sizes. Always use IPv4 header, since our kernels only + // guarantee support of UDP encap on IPv4. + int expectedNumPkts = 2; + int expectedPacketSize = + expectedNumPkts * (dataWithEspHeader.length + UDP_HDRLEN + IP4_HDRLEN); + + StatsChecker.waitForNumPackets(expectedNumPkts); + StatsChecker.assertUidStatsDelta( + expectedPacketSize, + expectedNumPkts, + expectedPacketSize, + expectedPacketSize, + expectedNumPkts); + StatsChecker.assertIfaceStatsDelta( + expectedPacketSize, expectedNumPkts, expectedPacketSize, expectedNumPkts); + } + } + + @Test + public void testIkeOverUdpEncapSocket() throws Exception { + // IPv6 not supported for UDP-encap-ESP + InetAddress local = InetAddress.getByName(IPV4_LOOPBACK); + try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + NativeUdpSocket wrappedEncapSocket = + new NativeUdpSocket(encapSocket.getFileDescriptor()); + checkIkePacket(wrappedEncapSocket, local); + + // Now try with a transform applied to a socket using this Encap socket + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + + try (IpSecManager.SecurityParameterIndex spi = + mISM.allocateSecurityParameterIndex(local); + IpSecTransform transform = + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) + .setEncryption(crypt) + .setAuthentication(auth) + .setIpv4Encapsulation(encapSocket, encapSocket.getPort()) + .buildTransportModeTransform(local, spi); + JavaUdpSocket localSocket = new JavaUdpSocket(local)) { + applyTransformBidirectionally(mISM, transform, localSocket); + + checkIkePacket(wrappedEncapSocket, local); + } + } + } + + // TODO: Check IKE over ESP sockets (IPv4, IPv6) - does this need SOCK_RAW? + + /* TODO: Re-enable these when policy matcher works for reflected packets + * + * The issue here is that A sends to B, and everything is new; therefore PREROUTING counts + * correctly. But it appears that the security path is not cleared afterwards, thus when A + * sends an ACK back to B, the policy matcher flags it as a "IPSec" packet. See b/70635417 + */ + + // public void testInterfaceCountersTcp4() throws Exception { + // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + // IpSecAlgorithm auth = new IpSecAlgorithm( + // IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + // checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1000); + // } + + // public void testInterfaceCountersTcp6() throws Exception { + // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + // IpSecAlgorithm auth = new IpSecAlgorithm( + // IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + // checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1000); + // } + + // public void testInterfaceCountersTcp4UdpEncap() throws Exception { + // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + // IpSecAlgorithm auth = + // new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + // checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1000); + // } + + @Test + public void testInterfaceCountersUdp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1000, false); + } + + @Test + public void testInterfaceCountersUdp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1000, false); + } + + @Test + public void testInterfaceCountersUdp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1000, false); + } + + @Test + public void testAesCbcHmacMd5Tcp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacMd5Tcp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacMd5Udp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacMd5Udp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha1Tcp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha1Tcp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha1Udp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha1Udp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha256Tcp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha256Tcp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha256Udp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha256Udp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha384Tcp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha384Tcp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha384Udp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha384Udp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha512Tcp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha512Tcp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha512Udp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesCbcHmacSha512Udp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + @Test + public void testAesGcm64Tcp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm64Tcp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm64Udp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm64Udp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm96Tcp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm96Tcp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm96Udp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm96Udp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm128Tcp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm128Tcp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm128Udp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesGcm128Udp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + @Test + public void testAesCbcHmacMd5Tcp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacMd5Udp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacSha1Tcp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacSha1Udp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacSha256Tcp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacSha256Udp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacSha384Tcp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacSha384Udp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacSha512Tcp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesCbcHmacSha512Udp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + @Test + public void testAesGcm64Tcp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + @Test + public void testAesGcm64Udp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + @Test + public void testAesGcm96Tcp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + @Test + public void testAesGcm96Udp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + @Test + public void testAesGcm128Tcp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + @Test + public void testAesGcm128Udp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + @Test + public void testCryptUdp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, true); + } + + @Test + public void testAuthUdp4() throws Exception { + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, true); + } + + @Test + public void testCryptUdp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, true); + } + + @Test + public void testAuthUdp6() throws Exception { + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, true); + } + + @Test + public void testCryptTcp4() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, true); + } + + @Test + public void testAuthTcp4() throws Exception { + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, true); + } + + @Test + public void testCryptTcp6() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, true); + } + + @Test + public void testAuthTcp6() throws Exception { + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, true); + } + + @Test + public void testCryptUdp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, true); + } + + @Test + public void testAuthUdp4UdpEncap() throws Exception { + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, true); + } + + @Test + public void testCryptTcp4UdpEncap() throws Exception { + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, true); + } + + @Test + public void testAuthTcp4UdpEncap() throws Exception { + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, true); + } + + @Test + public void testOpenUdpEncapSocketSpecificPort() throws Exception { + IpSecManager.UdpEncapsulationSocket encapSocket = null; + int port = -1; + for (int i = 0; i < MAX_PORT_BIND_ATTEMPTS; i++) { + try { + port = findUnusedPort(); + encapSocket = mISM.openUdpEncapsulationSocket(port); + break; + } catch (ErrnoException e) { + if (e.errno == OsConstants.EADDRINUSE) { + // Someone claimed the port since we called findUnusedPort. + continue; + } + throw e; + } finally { + if (encapSocket != null) { + encapSocket.close(); + } + } + } + + if (encapSocket == null) { + fail("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); + } + + assertTrue("Returned invalid port", encapSocket.getPort() == port); + } + + @Test + public void testOpenUdpEncapSocketRandomPort() throws Exception { + try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + assertTrue("Returned invalid port", encapSocket.getPort() != 0); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java new file mode 100644 index 0000000000..ae38faa124 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -0,0 +1,899 @@ +/* + * Copyright (C) 2018 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.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.IpSecManager.UdpEncapsulationSocket; +import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; +import static android.net.cts.PacketUtils.BytePayload; +import static android.net.cts.PacketUtils.EspHeader; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.IpHeader; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.net.cts.PacketUtils.UdpHeader; +import static android.net.cts.PacketUtils.getIpHeader; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.IpSecAlgorithm; +import android.net.IpSecManager; +import android.net.IpSecTransform; +import android.net.LinkAddress; +import android.net.Network; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.cts.PacketUtils.Payload; +import android.net.cts.util.CtsNetUtils; +import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.AppModeFull; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +public class IpSecManagerTunnelTest extends IpSecBaseTest { + private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName(); + + private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); + private static final InetAddress REMOTE_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.2"); + private static final InetAddress LOCAL_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::1"); + private static final InetAddress REMOTE_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::2"); + + private static final InetAddress LOCAL_INNER_4 = + InetAddress.parseNumericAddress("198.51.100.1"); + private static final InetAddress REMOTE_INNER_4 = + InetAddress.parseNumericAddress("198.51.100.2"); + private static final InetAddress LOCAL_INNER_6 = + InetAddress.parseNumericAddress("2001:db8:2::1"); + private static final InetAddress REMOTE_INNER_6 = + InetAddress.parseNumericAddress("2001:db8:2::2"); + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 128; + + private static final int TIMEOUT_MS = 500; + + // Static state to reduce setup/teardown + private static ConnectivityManager sCM; + private static TestNetworkManager sTNM; + private static ParcelFileDescriptor sTunFd; + private static TestNetworkCallback sTunNetworkCallback; + private static Network sTunNetwork; + private static TunUtils sTunUtils; + + private static Context sContext = InstrumentationRegistry.getContext(); + private static final CtsNetUtils mCtsNetUtils = new CtsNetUtils(sContext); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and + // a standard permission is insufficient. So we shell out the appop, to give us the + // right appop permissions. + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, true); + + TestNetworkInterface testIface = + sTNM.createTunInterface( + new LinkAddress[] { + new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), + new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN) + }); + + sTunFd = testIface.getFileDescriptor(); + sTunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName()); + sTunNetworkCallback.waitForAvailable(); + sTunNetwork = sTunNetworkCallback.currentNetwork; + + sTunUtils = new TunUtils(sTunFd); + } + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + + // Set to true before every run; some tests flip this. + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, true); + + // Clear sTunUtils state + sTunUtils.reset(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false); + + sCM.unregisterNetworkCallback(sTunNetworkCallback); + + sTNM.teardownTestNetwork(sTunNetwork); + sTunFd.close(); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } + + @Test + public void testSecurityExceptionCreateTunnelInterfaceWithoutAppop() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + // Ensure we don't have the appop. Permission is not requested in the Manifest + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false); + + // Security exceptions are thrown regardless of IPv4/IPv6. Just test one + try { + mISM.createIpSecTunnelInterface(LOCAL_INNER_6, REMOTE_INNER_6, sTunNetwork); + fail("Did not throw SecurityException for Tunnel creation without appop"); + } catch (SecurityException expected) { + } + } + + @Test + public void testSecurityExceptionBuildTunnelTransformWithoutAppop() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + + // Ensure we don't have the appop. Permission is not requested in the Manifest + mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false); + + // Security exceptions are thrown regardless of IPv4/IPv6. Just test one + try (IpSecManager.SecurityParameterIndex spi = + mISM.allocateSecurityParameterIndex(LOCAL_INNER_4); + IpSecTransform transform = + new IpSecTransform.Builder(sContext) + .buildTunnelModeTransform(REMOTE_INNER_4, spi)) { + fail("Did not throw SecurityException for Transform creation without appop"); + } catch (SecurityException expected) { + } + } + + /* Test runnables for callbacks after IPsec tunnels are set up. */ + private abstract class IpSecTunnelTestRunnable { + /** + * Runs the test code, and returns the inner socket port, if any. + * + * @param ipsecNetwork The IPsec Interface based Network for binding sockets on + * @return the integer port of the inner socket if outbound, or 0 if inbound + * IpSecTunnelTestRunnable + * @throws Exception if any part of the test failed. + */ + public abstract int run(Network ipsecNetwork) throws Exception; + } + + private int getPacketSize( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) { + int expectedPacketSize = TEST_DATA.length + UDP_HDRLEN; + + // Inner Transport mode packet size + if (transportInTunnelMode) { + expectedPacketSize = + PacketUtils.calculateEspPacketSize( + expectedPacketSize, + AES_CBC_IV_LEN, + AES_CBC_BLK_SIZE, + AUTH_KEY.length * 4); + } + + // Inner IP Header + expectedPacketSize += innerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN; + + // Tunnel mode transform size + expectedPacketSize = + PacketUtils.calculateEspPacketSize( + expectedPacketSize, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, AUTH_KEY.length * 4); + + // UDP encap size + expectedPacketSize += useEncap ? UDP_HDRLEN : 0; + + // Outer IP Header + expectedPacketSize += outerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN; + + return expectedPacketSize; + } + + private interface IpSecTunnelTestRunnableFactory { + IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int innerSocketPort, + int expectedPacketSize) + throws Exception; + } + + private class OutputIpSecTunnelTestRunnableFactory implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int unusedInnerSocketPort, + int expectedPacketSize) { + return new IpSecTunnelTestRunnable() { + @Override + public int run(Network ipsecNetwork) throws Exception { + // Build a socket and send traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner); + ipsecNetwork.bindSocket(socket.mSocket); + int innerSocketPort = socket.getPort(); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, inTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, outTransportTransform); + } + + socket.sendTo(TEST_DATA, remoteInner, socket.getPort()); + + // Verify that an encrypted packet is sent. As of right now, checking encrypted + // body is not possible, due to the test not knowing some of the fields of the + // inner IP header (flow label, flags, etc) + sTunUtils.awaitEspPacketNoPlaintext( + spi, TEST_DATA, encapPort != 0, expectedPacketSize); + + socket.close(); + + return innerSocketPort; + } + }; + } + } + + private class InputReflectedIpSecTunnelTestRunnableFactory + implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int innerSocketPort, + int expectedPacketSize) + throws Exception { + return new IpSecTunnelTestRunnable() { + @Override + public int run(Network ipsecNetwork) throws Exception { + // Build a socket and receive traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner, innerSocketPort); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform); + } + + sTunUtils.reflectPackets(); + + // Receive packet from socket, and validate that the payload is correct + receiveAndValidatePacket(socket); + + socket.close(); + + return 0; + } + }; + } + } + + private class InputPacketGeneratorIpSecTunnelTestRunnableFactory + implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int innerSocketPort, + int expectedPacketSize) + throws Exception { + return new IpSecTunnelTestRunnable() { + @Override + public int run(Network ipsecNetwork) throws Exception { + // Build a socket and receive traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform); + } + + byte[] pkt; + if (transportInTunnelMode) { + pkt = + getTransportInTunnelModePacket( + spi, + spi, + remoteInner, + localInner, + remoteOuter, + localOuter, + socket.getPort(), + encapPort); + } else { + pkt = + getTunnelModePacket( + spi, + remoteInner, + localInner, + remoteOuter, + localOuter, + socket.getPort(), + encapPort); + } + sTunUtils.injectPacket(pkt); + + // Receive packet from socket, and validate + receiveAndValidatePacket(socket); + + socket.close(); + + return 0; + } + }; + } + } + + private void checkTunnelOutput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new OutputIpSecTunnelTestRunnableFactory()); + } + + private void checkTunnelInput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new InputPacketGeneratorIpSecTunnelTestRunnableFactory()); + } + + /** + * Validates that the kernel can talk to itself. + * + *

    This test takes an outbound IPsec packet, reflects it (by flipping IP src/dst), and + * injects it back into the TUN. This test then verifies that a packet with the correct payload + * is found on the specified socket/port. + */ + public void checkTunnelReflected( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; + + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + // Run output direction tests + IpSecTunnelTestRunnable outputIpSecTunnelTestRunnable = + new OutputIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + 0, + expectedPacketSize); + int innerSocketPort = + buildTunnelNetworkAndRunTests( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + outputIpSecTunnelTestRunnable); + + // Input direction tests, with matching inner socket ports. + IpSecTunnelTestRunnable inputIpSecTunnelTestRunnable = + new InputReflectedIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + remoteInner, + localInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + innerSocketPort, + expectedPacketSize); + buildTunnelNetworkAndRunTests( + remoteInner, + localInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + inputIpSecTunnelTestRunnable); + } + } + + public void checkTunnel( + int innerFamily, + int outerFamily, + boolean useEncap, + boolean transportInTunnelMode, + IpSecTunnelTestRunnableFactory factory) + throws Exception { + + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; + + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + // Re-uses the same SPI to ensure that even in cases of symmetric SPIs shared across tunnel + // and transport mode, packets are encrypted/decrypted properly based on the src/dst. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + buildTunnelNetworkAndRunTests( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + factory.getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + 0, + expectedPacketSize)); + } + } + + private int buildTunnelNetworkAndRunTests( + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + int spi, + UdpEncapsulationSocket encapSocket, + IpSecTunnelTestRunnable test) + throws Exception { + int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; + TestNetworkCallback testNetworkCb = null; + int innerSocketPort; + + try (IpSecManager.SecurityParameterIndex inSpi = + mISM.allocateSecurityParameterIndex(localOuter, spi); + IpSecManager.SecurityParameterIndex outSpi = + mISM.allocateSecurityParameterIndex(remoteOuter, spi); + IpSecManager.IpSecTunnelInterface tunnelIface = + mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) { + // Build the test network + tunnelIface.addAddress(localInner, innerPrefixLen); + testNetworkCb = mCtsNetUtils.setupAndGetTestNetwork(tunnelIface.getInterfaceName()); + testNetworkCb.waitForAvailable(); + Network testNetwork = testNetworkCb.currentNetwork; + + // Check interface was created + assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); + + // Verify address was added + final NetworkInterface netIface = NetworkInterface.getByInetAddress(localInner); + assertNotNull(netIface); + assertEquals(tunnelIface.getInterfaceName(), netIface.getDisplayName()); + + // Configure Transform parameters + IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); + transformBuilder.setEncryption( + new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)); + transformBuilder.setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4)); + + if (encapSocket != null) { + transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); + } + + // Apply transform and check that traffic is properly encrypted + try (IpSecTransform inTransform = + transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi); + IpSecTransform outTransform = + transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) { + mISM.applyTunnelModeTransform(tunnelIface, IpSecManager.DIRECTION_IN, inTransform); + mISM.applyTunnelModeTransform( + tunnelIface, IpSecManager.DIRECTION_OUT, outTransform); + + innerSocketPort = test.run(testNetwork); + } + + // Teardown the test network + sTNM.teardownTestNetwork(testNetwork); + + // Remove addresses and check that interface is still present, but fails lookup-by-addr + tunnelIface.removeAddress(localInner, innerPrefixLen); + assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); + assertNull(NetworkInterface.getByInetAddress(localInner)); + + // Check interface was cleaned up + tunnelIface.close(); + assertNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); + } finally { + if (testNetworkCb != null) { + sCM.unregisterNetworkCallback(testNetworkCb); + } + } + + return innerSocketPort; + } + + private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { + byte[] socketResponseBytes = socket.receive(); + assertArrayEquals(TEST_DATA, socketResponseBytes); + } + + private int getRandomSpi(InetAddress localOuter, InetAddress remoteOuter) throws Exception { + // Try to allocate both in and out SPIs using the same requested SPI value. + try (IpSecManager.SecurityParameterIndex inSpi = + mISM.allocateSecurityParameterIndex(localOuter); + IpSecManager.SecurityParameterIndex outSpi = + mISM.allocateSecurityParameterIndex(remoteOuter, inSpi.getSpi()); ) { + return inSpi.getSpi(); + } + } + + private EspHeader buildTransportModeEspPacket( + int spi, InetAddress src, InetAddress dst, int port, Payload payload) throws Exception { + IpHeader preEspIpHeader = getIpHeader(payload.getProtocolId(), src, dst, payload); + + return new EspHeader( + payload.getProtocolId(), + spi, + 1, // sequence number + CRYPT_KEY, // Same key for auth and crypt + payload.getPacketBytes(preEspIpHeader)); + } + + private EspHeader buildTunnelModeEspPacket( + int spi, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort, + Payload payload) + throws Exception { + IpHeader innerIp = getIpHeader(payload.getProtocolId(), srcInner, dstInner, payload); + return new EspHeader( + innerIp.getProtocolId(), + spi, + 1, // sequence number + CRYPT_KEY, // Same key for auth and crypt + innerIp.getPacketBytes()); + } + + private IpHeader maybeEncapPacket( + InetAddress src, InetAddress dst, int encapPort, EspHeader espPayload) + throws Exception { + + Payload payload = espPayload; + if (encapPort != 0) { + payload = new UdpHeader(encapPort, encapPort, espPayload); + } + + return getIpHeader(payload.getProtocolId(), src, dst, payload); + } + + private byte[] getTunnelModePacket( + int spi, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort) + throws Exception { + UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); + + EspHeader espPayload = + buildTunnelModeEspPacket( + spi, srcInner, dstInner, srcOuter, dstOuter, port, encapPort, udp); + return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); + } + + private byte[] getTransportInTunnelModePacket( + int spiInner, + int spiOuter, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort) + throws Exception { + UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); + + EspHeader espPayload = buildTransportModeEspPacket(spiInner, srcInner, dstInner, port, udp); + espPayload = + buildTunnelModeEspPacket( + spiOuter, + srcInner, + dstInner, + srcOuter, + dstOuter, + port, + encapPort, + espPayload); + return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); + } + + // Transport-in-Tunnel mode tests + @Test + public void testTransportInTunnelModeV4InV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET, AF_INET, false, true); + checkTunnelInput(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV4InV4Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET, AF_INET, true, true); + checkTunnelInput(AF_INET, AF_INET, true, true); + } + + @Test + public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV4InV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET, AF_INET6, false, true); + checkTunnelInput(AF_INET, AF_INET6, false, true); + } + + @Test + public void testTransportInTunnelModeV4InV6Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET6, AF_INET, false, true); + checkTunnelInput(AF_INET6, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET6, AF_INET, true, true); + checkTunnelInput(AF_INET6, AF_INET, true, true); + } + + @Test + public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET, AF_INET6, false, true); + checkTunnelInput(AF_INET, AF_INET6, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV6Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + + // Tunnel mode tests + @Test + public void testTunnelV4InV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET, AF_INET, false, false); + checkTunnelInput(AF_INET, AF_INET, false, false); + } + + @Test + public void testTunnelV4InV4Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET, false, false); + } + + @Test + public void testTunnelV4InV4UdpEncap() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET, AF_INET, true, false); + checkTunnelInput(AF_INET, AF_INET, true, false); + } + + @Test + public void testTunnelV4InV4UdpEncapReflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET, true, false); + } + + @Test + public void testTunnelV4InV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET, AF_INET6, false, false); + checkTunnelInput(AF_INET, AF_INET6, false, false); + } + + @Test + public void testTunnelV4InV6Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET, AF_INET6, false, false); + } + + @Test + public void testTunnelV6InV4() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET6, AF_INET, false, false); + checkTunnelInput(AF_INET6, AF_INET, false, false); + } + + @Test + public void testTunnelV6InV4Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET6, AF_INET, false, false); + } + + @Test + public void testTunnelV6InV4UdpEncap() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET6, AF_INET, true, false); + checkTunnelInput(AF_INET6, AF_INET, true, false); + } + + @Test + public void testTunnelV6InV4UdpEncapReflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET6, AF_INET, true, false); + } + + @Test + public void testTunnelV6InV6() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelOutput(AF_INET6, AF_INET6, false, false); + checkTunnelInput(AF_INET6, AF_INET6, false, false); + } + + @Test + public void testTunnelV6InV6Reflected() throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkTunnelReflected(AF_INET6, AF_INET6, false, false); + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java new file mode 100644 index 0000000000..7c5a1b353d --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalServerSocketTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009 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 junit.framework.TestCase; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import android.net.LocalServerSocket; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; + +public class LocalServerSocketTest extends TestCase { + + public void testLocalServerSocket() throws IOException { + String address = "com.android.net.LocalServerSocketTest_testLocalServerSocket"; + LocalServerSocket localServerSocket = new LocalServerSocket(address); + assertNotNull(localServerSocket.getLocalSocketAddress()); + + // create client socket + LocalSocket clientSocket = new LocalSocket(); + + // establish connection between client and server + clientSocket.connect(new LocalSocketAddress(address)); + LocalSocket serverSocket = localServerSocket.accept(); + + assertTrue(serverSocket.isConnected()); + assertTrue(serverSocket.isBound()); + + // send data from client to server + OutputStream clientOutStream = clientSocket.getOutputStream(); + clientOutStream.write(12); + InputStream serverInStream = serverSocket.getInputStream(); + assertEquals(12, serverInStream.read()); + + // send data from server to client + OutputStream serverOutStream = serverSocket.getOutputStream(); + serverOutStream.write(3); + InputStream clientInStream = clientSocket.getInputStream(); + assertEquals(3, clientInStream.read()); + + // close server socket + assertNotNull(localServerSocket.getFileDescriptor()); + localServerSocket.close(); + assertNull(localServerSocket.getFileDescriptor()); + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java new file mode 100644 index 0000000000..6ef003b26f --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddressTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 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 android.net.LocalSocketAddress; +import android.net.LocalSocketAddress.Namespace; +import android.test.AndroidTestCase; + +public class LocalSocketAddressTest extends AndroidTestCase { + + public void testNewLocalSocketAddressWithDefaultNamespace() { + // default namespace + LocalSocketAddress localSocketAddress = new LocalSocketAddress("name"); + assertEquals("name", localSocketAddress.getName()); + assertEquals(Namespace.ABSTRACT, localSocketAddress.getNamespace()); + + // specify the namespace + LocalSocketAddress localSocketAddress2 = + new LocalSocketAddress("name2", Namespace.ABSTRACT); + assertEquals("name2", localSocketAddress2.getName()); + assertEquals(Namespace.ABSTRACT, localSocketAddress2.getNamespace()); + + LocalSocketAddress localSocketAddress3 = + new LocalSocketAddress("name3", Namespace.FILESYSTEM); + assertEquals("name3", localSocketAddress3.getName()); + assertEquals(Namespace.FILESYSTEM, localSocketAddress3.getNamespace()); + + LocalSocketAddress localSocketAddress4 = + new LocalSocketAddress("name4", Namespace.RESERVED); + assertEquals("name4", localSocketAddress4.getName()); + assertEquals(Namespace.RESERVED, localSocketAddress4.getNamespace()); + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java new file mode 100644 index 0000000000..97dfa435fa --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009 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 android.net.LocalSocketAddress.Namespace; +import android.test.AndroidTestCase; + +public class LocalSocketAddress_NamespaceTest extends AndroidTestCase { + + public void testValueOf() { + assertEquals(Namespace.ABSTRACT, Namespace.valueOf("ABSTRACT")); + assertEquals(Namespace.RESERVED, Namespace.valueOf("RESERVED")); + assertEquals(Namespace.FILESYSTEM, Namespace.valueOf("FILESYSTEM")); + } + + public void testValues() { + Namespace[] expected = Namespace.values(); + assertEquals(Namespace.ABSTRACT, expected[0]); + assertEquals(Namespace.RESERVED, expected[1]); + assertEquals(Namespace.FILESYSTEM, expected[2]); + } +} diff --git a/tests/cts/net/src/android/net/cts/LocalSocketTest.java b/tests/cts/net/src/android/net/cts/LocalSocketTest.java new file mode 100644 index 0000000000..6e61705b92 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/LocalSocketTest.java @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2008 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 junit.framework.TestCase; + +import android.net.Credentials; +import android.net.LocalServerSocket; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.system.Os; +import android.system.OsConstants; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +public class LocalSocketTest extends TestCase { + private final static String ADDRESS_PREFIX = "com.android.net.LocalSocketTest"; + + public void testLocalConnections() throws IOException { + String address = ADDRESS_PREFIX + "_testLocalConnections"; + // create client and server socket + LocalServerSocket localServerSocket = new LocalServerSocket(address); + LocalSocket clientSocket = new LocalSocket(); + + // establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(address); + assertFalse(clientSocket.isConnected()); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + + LocalSocket serverSocket = localServerSocket.accept(); + assertTrue(serverSocket.isConnected()); + assertTrue(serverSocket.isBound()); + try { + serverSocket.bind(localServerSocket.getLocalSocketAddress()); + fail("Cannot bind a LocalSocket from accept()"); + } catch (IOException expected) { + } + try { + serverSocket.connect(locSockAddr); + fail("Cannot connect a LocalSocket from accept()"); + } catch (IOException expected) { + } + + Credentials credent = clientSocket.getPeerCredentials(); + assertTrue(0 != credent.getPid()); + + // send data from client to server + OutputStream clientOutStream = clientSocket.getOutputStream(); + clientOutStream.write(12); + InputStream serverInStream = serverSocket.getInputStream(); + assertEquals(12, serverInStream.read()); + + //send data from server to client + OutputStream serverOutStream = serverSocket.getOutputStream(); + serverOutStream.write(3); + InputStream clientInStream = clientSocket.getInputStream(); + assertEquals(3, clientInStream.read()); + + // Test sending and receiving file descriptors + clientSocket.setFileDescriptorsForSend(new FileDescriptor[]{FileDescriptor.in}); + clientOutStream.write(32); + assertEquals(32, serverInStream.read()); + + FileDescriptor[] out = serverSocket.getAncillaryFileDescriptors(); + assertEquals(1, out.length); + FileDescriptor fd = clientSocket.getFileDescriptor(); + assertTrue(fd.valid()); + + //shutdown input stream of client + clientSocket.shutdownInput(); + assertEquals(-1, clientInStream.read()); + + //shutdown output stream of client + clientSocket.shutdownOutput(); + try { + clientOutStream.write(10); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //shutdown input stream of server + serverSocket.shutdownInput(); + assertEquals(-1, serverInStream.read()); + + //shutdown output stream of server + serverSocket.shutdownOutput(); + try { + serverOutStream.write(10); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //close client socket + clientSocket.close(); + try { + clientInStream.read(); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + + //close server socket + serverSocket.close(); + try { + serverInStream.read(); + fail("testLocalSocket shouldn't come to here"); + } catch (IOException e) { + // expected + } + } + + public void testAccessors() throws IOException { + String address = ADDRESS_PREFIX + "_testAccessors"; + LocalSocket socket = new LocalSocket(); + LocalSocketAddress addr = new LocalSocketAddress(address); + + assertFalse(socket.isBound()); + socket.bind(addr); + assertTrue(socket.isBound()); + assertEquals(addr, socket.getLocalSocketAddress()); + + String str = socket.toString(); + assertTrue(str.contains("impl:android.net.LocalSocketImpl")); + + socket.setReceiveBufferSize(1999); + assertEquals(1999 << 1, socket.getReceiveBufferSize()); + + socket.setSendBufferSize(3998); + assertEquals(3998 << 1, socket.getSendBufferSize()); + + assertEquals(0, socket.getSoTimeout()); + socket.setSoTimeout(1996); + assertTrue(socket.getSoTimeout() > 0); + + try { + socket.getRemoteSocketAddress(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isClosed(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isInputShutdown(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.isOutputShutdown(); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + socket.connect(addr, 2005); + fail("testLocalSocketSecondary shouldn't come to here"); + } catch (UnsupportedOperationException e) { + // expected + } + + socket.close(); + } + + // http://b/31205169 + public void testSetSoTimeout_readTimeout() throws Exception { + String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + final LocalSocket clientSocket = socketPair.clientSocket; + + // Set the timeout in millis. + int timeoutMillis = 1000; + clientSocket.setSoTimeout(timeoutMillis); + + // Avoid blocking the test run if timeout doesn't happen by using a separate thread. + Callable reader = () -> { + try { + clientSocket.getInputStream().read(); + return Result.noException("Did not block"); + } catch (IOException e) { + return Result.exception(e); + } + }; + // Allow the configured timeout, plus some slop. + int allowedTime = timeoutMillis + 2000; + Result result = runInSeparateThread(allowedTime, reader); + + // Check the message was a timeout, it's all we have to go on. + String expectedMessage = Os.strerror(OsConstants.EAGAIN); + result.assertThrewIOException(expectedMessage); + } + } + + // http://b/31205169 + public void testSetSoTimeout_writeTimeout() throws Exception { + String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + final LocalSocket clientSocket = socketPair.clientSocket; + + // Set the timeout in millis. + int timeoutMillis = 1000; + clientSocket.setSoTimeout(timeoutMillis); + + // Set a small buffer size so we know we can flood it. + clientSocket.setSendBufferSize(100); + final int bufferSize = clientSocket.getSendBufferSize(); + + // Avoid blocking the test run if timeout doesn't happen by using a separate thread. + Callable writer = () -> { + try { + byte[] toWrite = new byte[bufferSize * 2]; + clientSocket.getOutputStream().write(toWrite); + return Result.noException("Did not block"); + } catch (IOException e) { + return Result.exception(e); + } + }; + // Allow the configured timeout, plus some slop. + int allowedTime = timeoutMillis + 2000; + + Result result = runInSeparateThread(allowedTime, writer); + + // Check the message was a timeout, it's all we have to go on. + String expectedMessage = Os.strerror(OsConstants.EAGAIN); + result.assertThrewIOException(expectedMessage); + } + } + + public void testAvailable() throws Exception { + String address = ADDRESS_PREFIX + "_testAvailable"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + LocalSocket clientSocket = socketPair.clientSocket; + LocalSocket serverSocket = socketPair.serverSocket.accept(); + + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + assertEquals(0, serverInputStream.available()); + + byte[] buffer = new byte[50]; + clientOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); + + InputStream clientInputStream = clientSocket.getInputStream(); + OutputStream serverOutputStream = serverSocket.getOutputStream(); + assertEquals(0, clientInputStream.available()); + serverOutputStream.write(buffer); + assertEquals(50, serverInputStream.available()); + + serverSocket.close(); + } + } + + // http://b/34095140 + public void testLocalSocketCreatedFromFileDescriptor() throws Exception { + String address = ADDRESS_PREFIX + "_testLocalSocketCreatedFromFileDescriptor"; + + // Establish connection between a local client and server to get a valid client socket file + // descriptor. + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + // Extract the client FileDescriptor we can use. + FileDescriptor fileDescriptor = socketPair.clientSocket.getFileDescriptor(); + assertTrue(fileDescriptor.valid()); + + // Create the LocalSocket we want to test. + LocalSocket clientSocketCreatedFromFileDescriptor = + LocalSocket.createConnectedLocalSocket(fileDescriptor); + assertTrue(clientSocketCreatedFromFileDescriptor.isConnected()); + assertTrue(clientSocketCreatedFromFileDescriptor.isBound()); + + // Test the LocalSocket can be used for communication. + LocalSocket serverSocket = socketPair.serverSocket.accept(); + OutputStream clientOutputStream = + clientSocketCreatedFromFileDescriptor.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + + clientOutputStream.write(12); + assertEquals(12, serverInputStream.read()); + + // Closing clientSocketCreatedFromFileDescriptor does not close the file descriptor. + clientSocketCreatedFromFileDescriptor.close(); + assertTrue(fileDescriptor.valid()); + + // .. while closing the LocalSocket that owned the file descriptor does. + socketPair.clientSocket.close(); + assertFalse(fileDescriptor.valid()); + } + } + + public void testFlush() throws Exception { + String address = ADDRESS_PREFIX + "_testFlush"; + + try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) { + LocalSocket clientSocket = socketPair.clientSocket; + LocalSocket serverSocket = socketPair.serverSocket.accept(); + + OutputStream clientOutputStream = clientSocket.getOutputStream(); + InputStream serverInputStream = serverSocket.getInputStream(); + testFlushWorks(clientOutputStream, serverInputStream); + + OutputStream serverOutputStream = serverSocket.getOutputStream(); + InputStream clientInputStream = clientSocket.getInputStream(); + testFlushWorks(serverOutputStream, clientInputStream); + + serverSocket.close(); + } + } + + private void testFlushWorks(OutputStream outputStream, InputStream inputStream) + throws Exception { + final int bytesToTransfer = 50; + StreamReader inputStreamReader = new StreamReader(inputStream, bytesToTransfer); + + byte[] buffer = new byte[bytesToTransfer]; + outputStream.write(buffer); + assertEquals(bytesToTransfer, inputStream.available()); + + // Start consuming the data. + inputStreamReader.start(); + + // This doesn't actually flush any buffers, it just polls until the reader has read all the + // bytes. + outputStream.flush(); + + inputStreamReader.waitForCompletion(5000); + inputStreamReader.assertBytesRead(bytesToTransfer); + assertEquals(0, inputStream.available()); + } + + private static class StreamReader extends Thread { + private final InputStream is; + private final int expectedByteCount; + private final CountDownLatch completeLatch = new CountDownLatch(1); + + private volatile Exception exception; + private int bytesRead; + + private StreamReader(InputStream is, int expectedByteCount) { + this.is = is; + this.expectedByteCount = expectedByteCount; + } + + @Override + public void run() { + try { + byte[] buffer = new byte[10]; + int readCount; + while ((readCount = is.read(buffer)) >= 0) { + bytesRead += readCount; + if (bytesRead >= expectedByteCount) { + break; + } + } + } catch (IOException e) { + exception = e; + } finally { + completeLatch.countDown(); + } + } + + public void waitForCompletion(long waitMillis) throws Exception { + if (!completeLatch.await(waitMillis, TimeUnit.MILLISECONDS)) { + fail("Timeout waiting for completion"); + } + if (exception != null) { + throw new Exception("Read failed", exception); + } + } + + public void assertBytesRead(int expected) { + assertEquals(expected, bytesRead); + } + } + + private static class Result { + private final String type; + private final Exception e; + + private Result(String type, Exception e) { + this.type = type; + this.e = e; + } + + static Result noException(String description) { + return new Result(description, null); + } + + static Result exception(Exception e) { + return new Result(e.getClass().getName(), e); + } + + void assertThrewIOException(String expectedMessage) { + assertEquals("Unexpected result type", IOException.class.getName(), type); + assertEquals("Unexpected exception message", expectedMessage, e.getMessage()); + } + } + + private static Result runInSeparateThread(int allowedTime, final Callable callable) + throws Exception { + ExecutorService service = Executors.newSingleThreadScheduledExecutor(); + Future future = service.submit(callable); + Result result = future.get(allowedTime, TimeUnit.MILLISECONDS); + if (!future.isDone()) { + fail("Worker thread appears blocked"); + } + return result; + } + + private static class LocalSocketPair implements AutoCloseable { + static LocalSocketPair createConnectedSocketPair(String address) throws Exception { + LocalServerSocket localServerSocket = new LocalServerSocket(address); + final LocalSocket clientSocket = new LocalSocket(); + + // Establish connection between client and server + LocalSocketAddress locSockAddr = new LocalSocketAddress(address); + clientSocket.connect(locSockAddr); + assertTrue(clientSocket.isConnected()); + return new LocalSocketPair(localServerSocket, clientSocket); + } + + final LocalServerSocket serverSocket; + final LocalSocket clientSocket; + + LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) { + this.serverSocket = serverSocket; + this.clientSocket = clientSocket; + } + + public void close() throws Exception { + serverSocket.close(); + clientSocket.close(); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/MacAddressTest.java b/tests/cts/net/src/android/net/cts/MacAddressTest.java new file mode 100644 index 0000000000..3fd3bbac8c --- /dev/null +++ b/tests/cts/net/src/android/net/cts/MacAddressTest.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2018 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.net.MacAddress.TYPE_BROADCAST; +import static android.net.MacAddress.TYPE_MULTICAST; +import static android.net.MacAddress.TYPE_UNICAST; + +import static com.android.testutils.ParcelUtils.assertParcelSane; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.net.MacAddress; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet6Address; +import java.util.Arrays; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class MacAddressTest { + + static class TestCase { + final String macAddress; + final String ouiString; + final int addressType; + final boolean isLocallyAssigned; + + TestCase(String macAddress, String ouiString, int addressType, boolean isLocallyAssigned) { + this.macAddress = macAddress; + this.ouiString = ouiString; + this.addressType = addressType; + this.isLocallyAssigned = isLocallyAssigned; + } + } + + static final boolean LOCALLY_ASSIGNED = true; + static final boolean GLOBALLY_UNIQUE = false; + + static String typeToString(int addressType) { + switch (addressType) { + case TYPE_UNICAST: + return "TYPE_UNICAST"; + case TYPE_BROADCAST: + return "TYPE_BROADCAST"; + case TYPE_MULTICAST: + return "TYPE_MULTICAST"; + default: + return "UNKNOWN"; + } + } + + static String localAssignedToString(boolean isLocallyAssigned) { + return isLocallyAssigned ? "LOCALLY_ASSIGNED" : "GLOBALLY_UNIQUE"; + } + + @Test + public void testMacAddress() { + TestCase[] tests = { + new TestCase("ff:ff:ff:ff:ff:ff", "ff:ff:ff", TYPE_BROADCAST, LOCALLY_ASSIGNED), + new TestCase("d2:c4:22:4d:32:a8", "d2:c4:22", TYPE_UNICAST, LOCALLY_ASSIGNED), + new TestCase("33:33:aa:bb:cc:dd", "33:33:aa", TYPE_MULTICAST, LOCALLY_ASSIGNED), + new TestCase("06:00:00:00:00:00", "06:00:00", TYPE_UNICAST, LOCALLY_ASSIGNED), + new TestCase("07:00:d3:56:8a:c4", "07:00:d3", TYPE_MULTICAST, LOCALLY_ASSIGNED), + new TestCase("00:01:44:55:66:77", "00:01:44", TYPE_UNICAST, GLOBALLY_UNIQUE), + new TestCase("08:00:22:33:44:55", "08:00:22", TYPE_UNICAST, GLOBALLY_UNIQUE), + }; + + for (TestCase tc : tests) { + MacAddress mac = MacAddress.fromString(tc.macAddress); + + if (!tc.ouiString.equals(mac.toOuiString())) { + fail(String.format("expected OUI string %s, got %s", + tc.ouiString, mac.toOuiString())); + } + + if (tc.isLocallyAssigned != mac.isLocallyAssigned()) { + fail(String.format("expected %s to be %s, got %s", mac, + localAssignedToString(tc.isLocallyAssigned), + localAssignedToString(mac.isLocallyAssigned()))); + } + + if (tc.addressType != mac.getAddressType()) { + fail(String.format("expected %s address type to be %s, got %s", mac, + typeToString(tc.addressType), typeToString(mac.getAddressType()))); + } + + if (!tc.macAddress.equals(mac.toString())) { + fail(String.format("expected toString() to return %s, got %s", + tc.macAddress, mac.toString())); + } + + if (!mac.equals(MacAddress.fromBytes(mac.toByteArray()))) { + byte[] bytes = mac.toByteArray(); + fail(String.format("expected mac address from bytes %s to be %s, got %s", + Arrays.toString(bytes), + MacAddress.fromBytes(bytes), + mac)); + } + } + } + + @Test + public void testConstructorInputValidation() { + String[] invalidStringAddresses = { + "", + "abcd", + "1:2:3:4:5", + "1:2:3:4:5:6:7", + "10000:2:3:4:5:6", + }; + + for (String s : invalidStringAddresses) { + try { + MacAddress mac = MacAddress.fromString(s); + fail("MacAddress.fromString(" + s + ") should have failed, but returned " + mac); + } catch (IllegalArgumentException excepted) { + } + } + + try { + MacAddress mac = MacAddress.fromString(null); + fail("MacAddress.fromString(null) should have failed, but returned " + mac); + } catch (NullPointerException excepted) { + } + + byte[][] invalidBytesAddresses = { + {}, + {1,2,3,4,5}, + {1,2,3,4,5,6,7}, + }; + + for (byte[] b : invalidBytesAddresses) { + try { + MacAddress mac = MacAddress.fromBytes(b); + fail("MacAddress.fromBytes(" + Arrays.toString(b) + + ") should have failed, but returned " + mac); + } catch (IllegalArgumentException excepted) { + } + } + + try { + MacAddress mac = MacAddress.fromBytes(null); + fail("MacAddress.fromBytes(null) should have failed, but returned " + mac); + } catch (NullPointerException excepted) { + } + } + + @Test + public void testMatches() { + // match 4 bytes prefix + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:00:00"), + MacAddress.fromString("ff:ff:ff:ff:00:00"))); + + // match bytes 0,1,2 and 5 + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:00:00:11"), + MacAddress.fromString("ff:ff:ff:00:00:ff"))); + + // match 34 bit prefix + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:c0:00"), + MacAddress.fromString("ff:ff:ff:ff:c0:00"))); + + // fail to match 36 bit prefix + assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:40:00"), + MacAddress.fromString("ff:ff:ff:ff:f0:00"))); + + // match all 6 bytes + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:ee:11"), + MacAddress.fromString("ff:ff:ff:ff:ff:ff"))); + + // match none of 6 bytes + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("00:00:00:00:00:00"), + MacAddress.fromString("00:00:00:00:00:00"))); + } + + /** + * Tests that link-local address generation from MAC is valid. + */ + @Test + public void testLinkLocalFromMacGeneration() { + final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f"); + final byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x74, (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f}; + final Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac(); + assertTrue(llv6.isLinkLocalAddress()); + assertArrayEquals(inet6ll, llv6.getAddress()); + } + + @Test + public void testParcelMacAddress() { + final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f"); + + assertParcelSane(mac, 1); + } +} diff --git a/tests/cts/net/src/android/net/cts/MailToTest.java b/tests/cts/net/src/android/net/cts/MailToTest.java new file mode 100644 index 0000000000..e454d20628 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/MailToTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2008 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 android.net.MailTo; +import android.test.AndroidTestCase; +import android.util.Log; + +public class MailToTest extends AndroidTestCase { + private static final String MAILTOURI_1 = "mailto:chris@example.com"; + private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue"; + private static final String MAILTOURI_3 = + "mailto:infobot@example.com?body=send%20current-issue"; + private static final String MAILTOURI_4 = "mailto:infobot@example.com?body=send%20current-" + + "issue%0D%0Asend%20index"; + private static final String MAILTOURI_5 = "mailto:joe@example.com?" + + "cc=bob@example.com&body=hello"; + private static final String MAILTOURI_6 = "mailto:?to=joe@example.com&" + + "cc=bob@example.com&body=hello"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + public void testParseMailToURI() { + assertFalse(MailTo.isMailTo(null)); + assertFalse(MailTo.isMailTo("")); + assertFalse(MailTo.isMailTo("http://www.google.com")); + + assertTrue(MailTo.isMailTo(MAILTOURI_1)); + MailTo mailTo_1 = MailTo.parse(MAILTOURI_1); + Log.d("Trace", mailTo_1.toString()); + assertEquals("chris@example.com", mailTo_1.getTo()); + assertEquals(1, mailTo_1.getHeaders().size()); + assertNull(mailTo_1.getBody()); + assertNull(mailTo_1.getCc()); + assertNull(mailTo_1.getSubject()); + assertEquals("mailto:?to=chris%40example.com&", mailTo_1.toString()); + + assertTrue(MailTo.isMailTo(MAILTOURI_2)); + MailTo mailTo_2 = MailTo.parse(MAILTOURI_2); + Log.d("Trace", mailTo_2.toString()); + assertEquals(2, mailTo_2.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_2.getTo()); + assertEquals("current-issue", mailTo_2.getSubject()); + assertNull(mailTo_2.getBody()); + assertNull(mailTo_2.getCc()); + String stringUrl = mailTo_2.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("subject=current-issue&")); + + assertTrue(MailTo.isMailTo(MAILTOURI_3)); + MailTo mailTo_3 = MailTo.parse(MAILTOURI_3); + Log.d("Trace", mailTo_3.toString()); + assertEquals(2, mailTo_3.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_3.getTo()); + assertEquals("send current-issue", mailTo_3.getBody()); + assertNull(mailTo_3.getCc()); + assertNull(mailTo_3.getSubject()); + stringUrl = mailTo_3.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("body=send%20current-issue&")); + + assertTrue(MailTo.isMailTo(MAILTOURI_4)); + MailTo mailTo_4 = MailTo.parse(MAILTOURI_4); + Log.d("Trace", mailTo_4.toString() + " " + mailTo_4.getBody()); + assertEquals(2, mailTo_4.getHeaders().size()); + assertEquals("infobot@example.com", mailTo_4.getTo()); + assertEquals("send current-issue\r\nsend index", mailTo_4.getBody()); + assertNull(mailTo_4.getCc()); + assertNull(mailTo_4.getSubject()); + stringUrl = mailTo_4.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("to=infobot%40example.com&")); + assertTrue(stringUrl.contains("body=send%20current-issue%0D%0Asend%20index&")); + + + assertTrue(MailTo.isMailTo(MAILTOURI_5)); + MailTo mailTo_5 = MailTo.parse(MAILTOURI_5); + Log.d("Trace", mailTo_5.toString() + mailTo_5.getHeaders().toString() + + mailTo_5.getHeaders().size()); + assertEquals(3, mailTo_5.getHeaders().size()); + assertEquals("joe@example.com", mailTo_5.getTo()); + assertEquals("bob@example.com", mailTo_5.getCc()); + assertEquals("hello", mailTo_5.getBody()); + assertNull(mailTo_5.getSubject()); + stringUrl = mailTo_5.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("cc=bob%40example.com&")); + assertTrue(stringUrl.contains("body=hello&")); + assertTrue(stringUrl.contains("to=joe%40example.com&")); + + assertTrue(MailTo.isMailTo(MAILTOURI_6)); + MailTo mailTo_6 = MailTo.parse(MAILTOURI_6); + Log.d("Trace", mailTo_6.toString() + mailTo_6.getHeaders().toString() + + mailTo_6.getHeaders().size()); + assertEquals(3, mailTo_6.getHeaders().size()); + assertEquals(", joe@example.com", mailTo_6.getTo()); + assertEquals("bob@example.com", mailTo_6.getCc()); + assertEquals("hello", mailTo_6.getBody()); + assertNull(mailTo_6.getSubject()); + stringUrl = mailTo_6.toString(); + assertTrue(stringUrl.startsWith("mailto:?")); + assertTrue(stringUrl.contains("cc=bob%40example.com&")); + assertTrue(stringUrl.contains("body=hello&")); + assertTrue(stringUrl.contains("to=%2C%20joe%40example.com&")); + } +} diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java new file mode 100644 index 0000000000..691ab99235 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -0,0 +1,242 @@ +/* + * 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.net.cts; + +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + +import android.content.Context; +import android.content.ContentResolver; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkUtils; +import android.net.cts.util.CtsNetUtils; +import android.platform.test.annotations.AppModeFull; +import android.provider.Settings; +import android.system.ErrnoException; +import android.system.OsConstants; +import android.test.AndroidTestCase; + +import java.util.ArrayList; + +public class MultinetworkApiTest extends AndroidTestCase { + + static { + System.loadLibrary("nativemultinetwork_jni"); + } + + private static final String TAG = "MultinetworkNativeApiTest"; + static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; + + /** + * @return 0 on success + */ + private static native int runGetaddrinfoCheck(long networkHandle); + private static native int runSetprocnetwork(long networkHandle); + private static native int runSetsocknetwork(long networkHandle); + private static native int runDatagramCheck(long networkHandle); + private static native void runResNapiMalformedCheck(long networkHandle); + private static native void runResNcancelCheck(long networkHandle); + private static native void runResNqueryCheck(long networkHandle); + private static native void runResNsendCheck(long networkHandle); + private static native void runResNnxDomainCheck(long networkHandle); + + + private ContentResolver mCR; + private ConnectivityManager mCM; + private CtsNetUtils mCtsNetUtils; + private String mOldMode; + private String mOldDnsSpecifier; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mCR = getContext().getContentResolver(); + mCtsNetUtils = new CtsNetUtils(getContext()); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + private Network[] getTestableNetworks() { + final ArrayList testableNetworks = new ArrayList(); + for (Network network : mCM.getAllNetworks()) { + final NetworkCapabilities nc = mCM.getNetworkCapabilities(network); + if (nc != null + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + testableNetworks.add(network); + } + } + + assertTrue( + "This test requires that at least one network be connected. " + + "Please ensure that the device is connected to a network.", + testableNetworks.size() >= 1); + return testableNetworks.toArray(new Network[0]); + } + + public void testGetaddrinfo() throws ErrnoException { + for (Network network : getTestableNetworks()) { + int errno = runGetaddrinfoCheck(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "getaddrinfo on " + mCM.getNetworkInfo(network), -errno); + } + } + } + + @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + public void testSetprocnetwork() throws ErrnoException { + // Hopefully no prior test in this process space has set a default network. + assertNull(mCM.getProcessDefaultNetwork()); + assertEquals(0, NetworkUtils.getBoundNetworkForProcess()); + + for (Network network : getTestableNetworks()) { + mCM.setProcessDefaultNetwork(null); + assertNull(mCM.getProcessDefaultNetwork()); + + int errno = runSetprocnetwork(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "setprocnetwork on " + mCM.getNetworkInfo(network), -errno); + } + Network processDefault = mCM.getProcessDefaultNetwork(); + assertNotNull(processDefault); + assertEquals(network, processDefault); + // TODO: open DatagramSockets, connect them to 192.0.2.1 and 2001:db8::, + // and ensure that the source address is in fact on this network as + // determined by mCM.getLinkProperties(network). + + mCM.setProcessDefaultNetwork(null); + } + + for (Network network : getTestableNetworks()) { + NetworkUtils.bindProcessToNetwork(0); + assertNull(mCM.getBoundNetworkForProcess()); + + int errno = runSetprocnetwork(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "setprocnetwork on " + mCM.getNetworkInfo(network), -errno); + } + assertEquals(network, new Network(mCM.getBoundNetworkForProcess())); + // TODO: open DatagramSockets, connect them to 192.0.2.1 and 2001:db8::, + // and ensure that the source address is in fact on this network as + // determined by mCM.getLinkProperties(network). + + NetworkUtils.bindProcessToNetwork(0); + } + } + + @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + public void testSetsocknetwork() throws ErrnoException { + for (Network network : getTestableNetworks()) { + int errno = runSetsocknetwork(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "setsocknetwork on " + mCM.getNetworkInfo(network), -errno); + } + } + } + + public void testNativeDatagramTransmission() throws ErrnoException { + for (Network network : getTestableNetworks()) { + int errno = runDatagramCheck(network.getNetworkHandle()); + if (errno != 0) { + throw new ErrnoException( + "DatagramCheck on " + mCM.getNetworkInfo(network), -errno); + } + } + } + + public void testNoSuchNetwork() { + final Network eNoNet = new Network(54321); + assertNull(mCM.getNetworkInfo(eNoNet)); + + final long eNoNetHandle = eNoNet.getNetworkHandle(); + assertEquals(-OsConstants.ENONET, runSetsocknetwork(eNoNetHandle)); + assertEquals(-OsConstants.ENONET, runSetprocnetwork(eNoNetHandle)); + // TODO: correct test permissions so this call is not silently re-mapped + // to query on the default network. + // assertEquals(-OsConstants.ENONET, runGetaddrinfoCheck(eNoNetHandle)); + } + + public void testNetworkHandle() { + // Test Network -> NetworkHandle -> Network results in the same Network. + for (Network network : getTestableNetworks()) { + long networkHandle = network.getNetworkHandle(); + Network newNetwork = Network.fromNetworkHandle(networkHandle); + assertEquals(newNetwork, network); + } + + // Test that only obfuscated handles are allowed. + try { + Network.fromNetworkHandle(100); + fail(); + } catch (IllegalArgumentException e) {} + try { + Network.fromNetworkHandle(-1); + fail(); + } catch (IllegalArgumentException e) {} + try { + Network.fromNetworkHandle(0); + fail(); + } catch (IllegalArgumentException e) {} + } + + public void testResNApi() throws Exception { + final Network[] testNetworks = getTestableNetworks(); + + for (Network network : testNetworks) { + // Throws AssertionError directly in jni function if test fail. + runResNqueryCheck(network.getNetworkHandle()); + runResNsendCheck(network.getNetworkHandle()); + runResNcancelCheck(network.getNetworkHandle()); + runResNapiMalformedCheck(network.getNetworkHandle()); + + final NetworkCapabilities nc = mCM.getNetworkCapabilities(network); + // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't + // test NXDOMAIN on these DNS servers. + // b/144521720 + if (nc != null && !nc.hasTransport(TRANSPORT_CELLULAR)) { + runResNnxDomainCheck(network.getNetworkHandle()); + } + } + } + + @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") + public void testResNApiNXDomainPrivateDns() throws InterruptedException { + mCtsNetUtils.storePrivateDnsSetting(); + // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. + // b/144521720 + try { + mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); + for (Network network : getTestableNetworks()) { + // Wait for private DNS setting to propagate. + mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", + network, GOOGLE_PRIVATE_DNS_SERVER, true); + runResNnxDomainCheck(network.getNetworkHandle()); + } + } finally { + mCtsNetUtils.restorePrivateDnsSetting(); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt new file mode 100644 index 0000000000..7508228734 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -0,0 +1,668 @@ +/* + * 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 android.app.Instrumentation +import android.content.Context +import android.net.ConnectivityManager +import android.net.KeepalivePacketData +import android.net.LinkAddress +import android.net.LinkProperties +import android.net.Network +import android.net.NetworkAgent +import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT +import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER +import android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS +import android.net.NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED +import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE +import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE +import android.net.NetworkAgent.INVALID_NETWORK +import android.net.NetworkAgent.VALID_NETWORK +import android.net.NetworkAgentConfig +import android.net.NetworkCapabilities +import android.net.NetworkInfo +import android.net.NetworkProvider +import android.net.NetworkRequest +import android.net.SocketKeepalive +import android.net.StringNetworkSpecifier +import android.net.Uri +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSignalStrengthThresholdsUpdated +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive +import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper +import android.os.Message +import android.os.Messenger +import androidx.test.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.AsyncChannel +import com.android.net.module.util.ArrayTrackRecord +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.RecorderCallback.CallbackEntry.Available +import com.android.testutils.RecorderCallback.CallbackEntry.Lost +import com.android.testutils.TestableNetworkCallback +import org.junit.After +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.fail +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.argThat +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import java.net.InetAddress +import java.time.Duration +import java.util.UUID +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue + +// This test doesn't really have a constraint on how fast the methods should return. If it's +// going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio +// without affecting the run time of successful runs. Thus, set a very high timeout. +private const val DEFAULT_TIMEOUT_MS = 5000L +// When waiting for a NetworkCallback to determine there was no timeout, waiting is the +// only possible thing (the relevant handler is the one in the real ConnectivityService, +// and then there is the Binder call), so have a short timeout for this as it will be +// exhausted every time. +private const val NO_CALLBACK_TIMEOUT = 200L +// Any legal score (0~99) for the test network would do, as it is going to be kept up by the +// requests filed by the test and should never match normal internet requests. 70 is the default +// score of Ethernet networks, it's as good a value as any other. +private const val TEST_NETWORK_SCORE = 70 +private const val BETTER_NETWORK_SCORE = 75 +private const val FAKE_NET_ID = 1098 +private val instrumentation: Instrumentation + get() = InstrumentationRegistry.getInstrumentation() +private val realContext: Context + get() = InstrumentationRegistry.getContext() +private fun Message(what: Int, arg1: Int, arg2: Int, obj: Any?) = Message.obtain().also { + it.what = what + it.arg1 = arg1 + it.arg2 = arg2 + it.obj = obj +} + +@RunWith(AndroidJUnit4::class) +class NetworkAgentTest { + @Rule @JvmField + val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) + + private val LOCAL_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.1") + private val REMOTE_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.2") + + private val mCM = realContext.getSystemService(ConnectivityManager::class.java) + private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") + private val mFakeConnectivityService by lazy { FakeConnectivityService(mHandlerThread.looper) } + + private class Provider(context: Context, looper: Looper) : + NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") + + private val agentsToCleanUp = mutableListOf() + private val callbacksToCleanUp = mutableListOf() + + @Before + fun setUp() { + instrumentation.getUiAutomation().adoptShellPermissionIdentity() + mHandlerThread.start() + } + + @After + fun tearDown() { + agentsToCleanUp.forEach { it.unregister() } + callbacksToCleanUp.forEach { mCM.unregisterNetworkCallback(it) } + mHandlerThread.quitSafely() + instrumentation.getUiAutomation().dropShellPermissionIdentity() + } + + /** + * A fake that helps simulating ConnectivityService talking to a harnessed agent. + * This fake only supports speaking to one harnessed agent at a time because it + * only keeps track of one async channel. + */ + private class FakeConnectivityService(looper: Looper) { + private val CMD_EXPECT_DISCONNECT = 1 + private var disconnectExpected = false + private val msgHistory = ArrayTrackRecord().newReadHead() + private val asyncChannel = AsyncChannel() + private val handler = object : Handler(looper) { + override fun handleMessage(msg: Message) { + msgHistory.add(Message.obtain(msg)) // make a copy as the original will be recycled + when (msg.what) { + CMD_EXPECT_DISCONNECT -> disconnectExpected = true + AsyncChannel.CMD_CHANNEL_HALF_CONNECTED -> + asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) + AsyncChannel.CMD_CHANNEL_DISCONNECTED -> + if (!disconnectExpected) { + fail("Agent unexpectedly disconnected") + } else { + disconnectExpected = false + } + } + } + } + + fun connect(agentMsngr: Messenger) = asyncChannel.connect(realContext, handler, agentMsngr) + + fun disconnect() = asyncChannel.disconnect() + + fun sendMessage(what: Int, arg1: Int = 0, arg2: Int = 0, obj: Any? = null) = + asyncChannel.sendMessage(Message(what, arg1, arg2, obj)) + + fun expectMessage(what: Int) = + assertNotNull(msgHistory.poll(DEFAULT_TIMEOUT_MS) { it.what == what }) + + fun willExpectDisconnectOnce() = handler.sendEmptyMessage(CMD_EXPECT_DISCONNECT) + } + + private open class TestableNetworkAgent( + context: Context, + looper: Looper, + val nc: NetworkCapabilities, + val lp: LinkProperties, + conf: NetworkAgentConfig + ) : NetworkAgent(context, looper, TestableNetworkAgent::class.java.simpleName /* tag */, + nc, lp, TEST_NETWORK_SCORE, conf, Provider(context, looper)) { + private val history = ArrayTrackRecord().newReadHead() + + sealed class CallbackEntry { + object OnBandwidthUpdateRequested : CallbackEntry() + object OnNetworkUnwanted : CallbackEntry() + data class OnAddKeepalivePacketFilter( + val slot: Int, + val packet: KeepalivePacketData + ) : CallbackEntry() + data class OnRemoveKeepalivePacketFilter(val slot: Int) : CallbackEntry() + data class OnStartSocketKeepalive( + val slot: Int, + val interval: Int, + val packet: KeepalivePacketData + ) : CallbackEntry() + data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry() + data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry() + object OnAutomaticReconnectDisabled : CallbackEntry() + data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry() + data class OnSignalStrengthThresholdsUpdated(val thresholds: IntArray) : CallbackEntry() + } + + fun getName(): String? = (nc.getNetworkSpecifier() as? StringNetworkSpecifier)?.specifier + + override fun onBandwidthUpdateRequested() { + history.add(OnBandwidthUpdateRequested) + } + + override fun onNetworkUnwanted() { + history.add(OnNetworkUnwanted) + } + + override fun onAddKeepalivePacketFilter(slot: Int, packet: KeepalivePacketData) { + history.add(OnAddKeepalivePacketFilter(slot, packet)) + } + + override fun onRemoveKeepalivePacketFilter(slot: Int) { + history.add(OnRemoveKeepalivePacketFilter(slot)) + } + + override fun onStartSocketKeepalive( + slot: Int, + interval: Duration, + packet: KeepalivePacketData + ) { + history.add(OnStartSocketKeepalive(slot, interval.seconds.toInt(), packet)) + } + + override fun onStopSocketKeepalive(slot: Int) { + history.add(OnStopSocketKeepalive(slot)) + } + + override fun onSaveAcceptUnvalidated(accept: Boolean) { + history.add(OnSaveAcceptUnvalidated(accept)) + } + + override fun onAutomaticReconnectDisabled() { + history.add(OnAutomaticReconnectDisabled) + } + + override fun onSignalStrengthThresholdsUpdated(thresholds: IntArray) { + history.add(OnSignalStrengthThresholdsUpdated(thresholds)) + } + + fun expectEmptySignalStrengths() { + expectCallback().let { + // intArrayOf() without arguments makes an empty array + assertArrayEquals(intArrayOf(), it.thresholds) + } + } + + override fun onValidationStatus(status: Int, uri: Uri?) { + history.add(OnValidationStatus(status, uri)) + } + + // Expects the initial validation event that always occurs immediately after registering + // a NetworkAgent whose network does not require validation (which test networks do + // not, since they lack the INTERNET capability). It always contains the default argument + // for the URI. + fun expectNoInternetValidationStatus() = expectCallback().let { + assertEquals(it.status, VALID_NETWORK) + // The returned Uri is parsed from the empty string, which means it's an + // instance of the (private) Uri.StringUri. There are no real good ways + // to check this, the least bad is to just convert it to a string and + // make sure it's empty. + assertEquals("", it.uri.toString()) + } + + inline fun expectCallback(): T { + val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) + assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") + return foundCallback + } + + fun assertNoCallback() { + assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS), + "Handler didn't became idle after ${DEFAULT_TIMEOUT_MS}ms") + assertNull(history.peek()) + } + } + + private fun requestNetwork(request: NetworkRequest, callback: TestableNetworkCallback) { + mCM.requestNetwork(request, callback) + callbacksToCleanUp.add(callback) + } + + private fun registerNetworkCallback( + request: NetworkRequest, + callback: TestableNetworkCallback + ) { + mCM.registerNetworkCallback(request, callback) + callbacksToCleanUp.add(callback) + } + + private fun createNetworkAgent( + context: Context = realContext, + name: String? = null + ): TestableNetworkAgent { + val nc = NetworkCapabilities().apply { + addTransportType(NetworkCapabilities.TRANSPORT_TEST) + removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + if (null != name) { + setNetworkSpecifier(StringNetworkSpecifier(name)) + } + } + val lp = LinkProperties().apply { + addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) + } + val config = NetworkAgentConfig.Builder().build() + return TestableNetworkAgent(context, mHandlerThread.looper, nc, lp, config).also { + agentsToCleanUp.add(it) + } + } + + private fun createConnectedNetworkAgent(context: Context = realContext, name: String? = null): + Pair { + val request: NetworkRequest = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) + requestNetwork(request, callback) + val agent = createNetworkAgent(context, name) + agent.register() + agent.markConnected() + return agent to callback + } + + private fun createNetworkAgentWithFakeCS() = createNetworkAgent().also { + mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID))) + } + + @Test + fun testConnectAndUnregister() { + val (agent, callback) = createConnectedNetworkAgent() + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() + agent.expectNoInternetValidationStatus() + agent.unregister() + callback.expectCallback(agent.network) + agent.expectCallback() + assertFailsWith("Must not be able to register an agent twice") { + agent.register() + } + } + + @Test + fun testOnBandwidthUpdateRequested() { + val (agent, callback) = createConnectedNetworkAgent() + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() + agent.expectNoInternetValidationStatus() + mCM.requestBandwidthUpdate(agent.network) + agent.expectCallback() + agent.unregister() + } + + @Test + fun testSignalStrengthThresholds() { + val thresholds = intArrayOf(30, 50, 65) + val callbacks = thresholds.map { strength -> + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setSignalStrength(strength) + .build() + TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also { + registerNetworkCallback(request, it) + } + } + createConnectedNetworkAgent().let { (agent, callback) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectCallback().let { + assertArrayEquals(it.thresholds, thresholds) + } + agent.expectNoInternetValidationStatus() + + // Send signal strength and check that the callbacks are called appropriately. + val nc = NetworkCapabilities(agent.nc) + nc.setSignalStrength(20) + agent.sendNetworkCapabilities(nc) + callbacks.forEach { it.assertNoCallback(NO_CALLBACK_TIMEOUT) } + + nc.setSignalStrength(40) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectAvailableCallbacks(agent.network) + callbacks[1].assertNoCallback(NO_CALLBACK_TIMEOUT) + callbacks[2].assertNoCallback(NO_CALLBACK_TIMEOUT) + + nc.setSignalStrength(80) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 80 } + callbacks[1].expectAvailableCallbacks(agent.network) + callbacks[2].expectAvailableCallbacks(agent.network) + + nc.setSignalStrength(55) + agent.sendNetworkCapabilities(nc) + callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 } + callbacks[1].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 } + callbacks[2].expectCallback(agent.network) + } + callbacks.forEach { + mCM.unregisterNetworkCallback(it) + } + } + + @Test + fun testSocketKeepalive(): Unit = createNetworkAgentWithFakeCS().let { agent -> + val packet = object : KeepalivePacketData( + LOCAL_IPV4_ADDRESS /* srcAddress */, 1234 /* srcPort */, + REMOTE_IPV4_ADDRESS /* dstAddress */, 4567 /* dstPort */, + ByteArray(100 /* size */) { it.toByte() /* init */ }) {} + val slot = 4 + val interval = 37 + + mFakeConnectivityService.sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + arg1 = slot, obj = packet) + mFakeConnectivityService.sendMessage(CMD_START_SOCKET_KEEPALIVE, + arg1 = slot, arg2 = interval, obj = packet) + + agent.expectCallback().let { + assertEquals(it.slot, slot) + assertEquals(it.packet, packet) + } + agent.expectCallback().let { + assertEquals(it.slot, slot) + assertEquals(it.interval, interval) + assertEquals(it.packet, packet) + } + + agent.assertNoCallback() + + // Check that when the agent sends a keepalive event, ConnectivityService receives the + // expected message. + agent.sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED) + mFakeConnectivityService.expectMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE).let() { + assertEquals(slot, it.arg1) + assertEquals(SocketKeepalive.ERROR_UNSUPPORTED, it.arg2) + } + + mFakeConnectivityService.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, arg1 = slot) + mFakeConnectivityService.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, arg1 = slot) + agent.expectCallback().let { + assertEquals(it.slot, slot) + } + agent.expectCallback().let { + assertEquals(it.slot, slot) + } + } + + @Test + fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + agent.expectEmptySignalStrengths() + agent.expectNoInternetValidationStatus() + val ifaceName = "adhocIface" + val lp = LinkProperties(agent.lp) + lp.setInterfaceName(ifaceName) + agent.sendLinkProperties(lp) + callback.expectLinkPropertiesThat(agent.network) { + it.getInterfaceName() == ifaceName + } + val nc = NetworkCapabilities(agent.nc) + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + agent.sendNetworkCapabilities(nc) + callback.expectCapabilitiesThat(agent.network) { + it.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + } + } + + @Test + fun testSendScore() { + // This test will create two networks and check that the one with the stronger + // score wins out for a request that matches them both. + // First create requests to make sure both networks are kept up, using the + // specifier so they are specific to each network + val name1 = UUID.randomUUID().toString() + val name2 = UUID.randomUUID().toString() + val request1 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setNetworkSpecifier(StringNetworkSpecifier(name1)) + .build() + val request2 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setNetworkSpecifier(StringNetworkSpecifier(name2)) + .build() + val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) + val callback2 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) + requestNetwork(request1, callback1) + requestNetwork(request2, callback2) + + // Then file the interesting request + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) + requestNetwork(request, callback) + + // Connect the first Network + createConnectedNetworkAgent(name = name1).let { (agent1, _) -> + callback.expectAvailableThenValidatedCallbacks(agent1.network) + // Upgrade agent1 to a better score so that there is no ambiguity when + // agent2 connects that agent1 is still better + agent1.sendNetworkScore(BETTER_NETWORK_SCORE - 1) + // Connect the second agent + createConnectedNetworkAgent(name = name2).let { (agent2, _) -> + agent2.markConnected() + // The callback should not see anything yet + callback.assertNoCallback(NO_CALLBACK_TIMEOUT) + // Now update the score and expect the callback now prefers agent2 + agent2.sendNetworkScore(BETTER_NETWORK_SCORE) + callback.expectCallback(agent2.network) + } + } + + // tearDown() will unregister the requests and agents + } + + @Test + fun testAgentStartsInConnecting() { + val mockContext = mock(Context::class.java) + val mockCm = mock(ConnectivityManager::class.java) + doReturn(mockCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE) + createConnectedNetworkAgent(mockContext) + verify(mockCm).registerNetworkAgent(any(Messenger::class.java), + argThat { it.detailedState == NetworkInfo.DetailedState.CONNECTING }, + any(LinkProperties::class.java), + any(NetworkCapabilities::class.java), + anyInt() /* score */, + any(NetworkAgentConfig::class.java), + eq(NetworkProvider.ID_NONE)) + } + + @Test + fun testSetAcceptUnvalidated() { + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 1) + agent.expectCallback().let { + assertTrue(it.accept) + } + agent.assertNoCallback() + } + } + + @Test + fun testSetAcceptUnvalidatedPreventAutomaticReconnect() { + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 0) + mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + agent.expectCallback().let { + assertFalse(it.accept) + } + agent.expectCallback() + agent.assertNoCallback() + // When automatic reconnect is turned off, the network is torn down and + // ConnectivityService sends a disconnect. This in turn causes the agent + // to send a DISCONNECTED message to CS. + mFakeConnectivityService.willExpectDisconnectOnce() + mFakeConnectivityService.disconnect() + mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) + agent.expectCallback() + } + } + + @Test + fun testPreventAutomaticReconnect() { + createNetworkAgentWithFakeCS().let { agent -> + mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + agent.expectCallback() + agent.assertNoCallback() + mFakeConnectivityService.willExpectDisconnectOnce() + mFakeConnectivityService.disconnect() + mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) + agent.expectCallback() + } + } + + @Test + fun testValidationStatus() = createNetworkAgentWithFakeCS().let { agent -> + val uri = Uri.parse("http://www.google.com") + val bundle = Bundle().apply { + putString(NetworkAgent.REDIRECT_URL_KEY, uri.toString()) + } + mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, + arg1 = VALID_NETWORK, obj = bundle) + agent.expectCallback().let { + assertEquals(it.status, VALID_NETWORK) + assertEquals(it.uri, uri) + } + + mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, + arg1 = INVALID_NETWORK, obj = Bundle()) + agent.expectCallback().let { + assertEquals(it.status, INVALID_NETWORK) + assertNull(it.uri) + } + } + + @Test + fun testTemporarilyUnmeteredCapability() { + // This test will create a networks with/without NET_CAPABILITY_TEMPORARILY_NOT_METERED + // and check that the callback reflects the capability changes. + // First create a request to make sure the network is kept up + val request1 = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS).also { + registerNetworkCallback(request1, it) + } + requestNetwork(request1, callback1) + + // Then file the interesting request + val request = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build() + val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) + requestNetwork(request, callback) + + // Connect the network + createConnectedNetworkAgent().let { (agent, _) -> + callback.expectAvailableThenValidatedCallbacks(agent.network) + + // Send TEMP_NOT_METERED and check that the callback is called appropriately. + val nc1 = NetworkCapabilities(agent.nc) + .addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + agent.sendNetworkCapabilities(nc1) + callback.expectCapabilitiesThat(agent.network) { + it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + } + + // Remove TEMP_NOT_METERED and check that the callback is called appropriately. + val nc2 = NetworkCapabilities(agent.nc) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + agent.sendNetworkCapabilities(nc2) + callback.expectCapabilitiesThat(agent.network) { + !it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + } + } + + // tearDown() will unregister the requests and agents + } +} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt new file mode 100644 index 0000000000..fa15e8f82c --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfoTest.kt @@ -0,0 +1,122 @@ +/* + * 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 android.os.Build +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkInfo +import android.net.NetworkInfo.DetailedState +import android.net.NetworkInfo.State +import android.telephony.TelephonyManager +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Rule +import org.junit.runner.RunWith +import org.junit.Test + +const val TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE +const val TYPE_WIFI = ConnectivityManager.TYPE_WIFI +const val MOBILE_TYPE_NAME = "mobile" +const val WIFI_TYPE_NAME = "WIFI" +const val LTE_SUBTYPE_NAME = "LTE" + +@SmallTest +@RunWith(AndroidJUnit4::class) +class NetworkInfoTest { + @Rule @JvmField + val ignoreRule = DevSdkIgnoreRule() + + @Test + fun testAccessNetworkInfoProperties() { + val cm = InstrumentationRegistry.getInstrumentation().context + .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val ni = cm.getAllNetworkInfo() + assertTrue(ni.isNotEmpty()) + + for (netInfo in ni) { + when (netInfo.getType()) { + TYPE_MOBILE -> assertNetworkInfo(netInfo, MOBILE_TYPE_NAME) + TYPE_WIFI -> assertNetworkInfo(netInfo, WIFI_TYPE_NAME) + // TODO: Add BLUETOOTH_TETHER testing + } + } + } + + private fun assertNetworkInfo(netInfo: NetworkInfo, expectedTypeName: String) { + assertTrue(expectedTypeName.equals(netInfo.getTypeName(), ignoreCase = true)) + assertNotNull(netInfo.toString()) + + if (!netInfo.isConnectedOrConnecting()) return + + assertTrue(netInfo.isAvailable()) + if (State.CONNECTED == netInfo.getState()) { + assertTrue(netInfo.isConnected()) + } + assertTrue(State.CONNECTING == netInfo.getState() || + State.CONNECTED == netInfo.getState()) + assertTrue(DetailedState.SCANNING == netInfo.getDetailedState() || + DetailedState.CONNECTING == netInfo.getDetailedState() || + DetailedState.AUTHENTICATING == netInfo.getDetailedState() || + DetailedState.CONNECTED == netInfo.getDetailedState()) + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testConstructor() { + val networkInfo = NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, + MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + + assertEquals(TYPE_MOBILE, networkInfo.type) + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, networkInfo.subtype) + assertEquals(MOBILE_TYPE_NAME, networkInfo.typeName) + assertEquals(LTE_SUBTYPE_NAME, networkInfo.subtypeName) + assertEquals(DetailedState.IDLE, networkInfo.detailedState) + assertEquals(State.UNKNOWN, networkInfo.state) + assertNull(networkInfo.reason) + assertNull(networkInfo.extraInfo) + + try { + NetworkInfo(ConnectivityManager.MAX_NETWORK_TYPE + 1, + TelephonyManager.NETWORK_TYPE_LTE, MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + fail("Unexpected behavior. Network type is invalid.") + } catch (e: IllegalArgumentException) { + // Expected behavior. + } + } + + @Test + fun testSetDetailedState() { + val networkInfo = NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, + MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME) + val reason = "TestNetworkInfo" + val extraReason = "setDetailedState test" + + networkInfo.setDetailedState(DetailedState.CONNECTED, reason, extraReason) + assertEquals(DetailedState.CONNECTED, networkInfo.detailedState) + assertEquals(State.CONNECTED, networkInfo.state) + assertEquals(reason, networkInfo.reason) + assertEquals(extraReason, networkInfo.extraInfo) + } +} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java new file mode 100644 index 0000000000..590ce89579 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 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 android.net.NetworkInfo.DetailedState; +import android.test.AndroidTestCase; + +public class NetworkInfo_DetailedStateTest extends AndroidTestCase { + + public void testValueOf() { + assertEquals(DetailedState.AUTHENTICATING, DetailedState.valueOf("AUTHENTICATING")); + assertEquals(DetailedState.CONNECTED, DetailedState.valueOf("CONNECTED")); + assertEquals(DetailedState.CONNECTING, DetailedState.valueOf("CONNECTING")); + assertEquals(DetailedState.DISCONNECTED, DetailedState.valueOf("DISCONNECTED")); + assertEquals(DetailedState.DISCONNECTING, DetailedState.valueOf("DISCONNECTING")); + assertEquals(DetailedState.FAILED, DetailedState.valueOf("FAILED")); + assertEquals(DetailedState.IDLE, DetailedState.valueOf("IDLE")); + assertEquals(DetailedState.OBTAINING_IPADDR, DetailedState.valueOf("OBTAINING_IPADDR")); + assertEquals(DetailedState.SCANNING, DetailedState.valueOf("SCANNING")); + assertEquals(DetailedState.SUSPENDED, DetailedState.valueOf("SUSPENDED")); + } + + public void testValues() { + DetailedState[] expected = DetailedState.values(); + assertEquals(13, expected.length); + assertEquals(DetailedState.IDLE, expected[0]); + assertEquals(DetailedState.SCANNING, expected[1]); + assertEquals(DetailedState.CONNECTING, expected[2]); + assertEquals(DetailedState.AUTHENTICATING, expected[3]); + assertEquals(DetailedState.OBTAINING_IPADDR, expected[4]); + assertEquals(DetailedState.CONNECTED, expected[5]); + assertEquals(DetailedState.SUSPENDED, expected[6]); + assertEquals(DetailedState.DISCONNECTING, expected[7]); + assertEquals(DetailedState.DISCONNECTED, expected[8]); + assertEquals(DetailedState.FAILED, expected[9]); + assertEquals(DetailedState.BLOCKED, expected[10]); + assertEquals(DetailedState.VERIFYING_POOR_LINK, expected[11]); + assertEquals(DetailedState.CAPTIVE_PORTAL_CHECK, expected[12]); + } + +} diff --git a/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java new file mode 100644 index 0000000000..5303ef1281 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkInfo_StateTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 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 android.net.NetworkInfo.State; +import android.test.AndroidTestCase; + +public class NetworkInfo_StateTest extends AndroidTestCase { + + public void testValueOf() { + assertEquals(State.CONNECTED, State.valueOf("CONNECTED")); + assertEquals(State.CONNECTING, State.valueOf("CONNECTING")); + assertEquals(State.DISCONNECTED, State.valueOf("DISCONNECTED")); + assertEquals(State.DISCONNECTING, State.valueOf("DISCONNECTING")); + assertEquals(State.SUSPENDED, State.valueOf("SUSPENDED")); + assertEquals(State.UNKNOWN, State.valueOf("UNKNOWN")); + } + + public void testValues() { + State[] expected = State.values(); + assertEquals(6, expected.length); + assertEquals(State.CONNECTING, expected[0]); + assertEquals(State.CONNECTED, expected[1]); + assertEquals(State.SUSPENDED, expected[2]); + assertEquals(State.DISCONNECTING, expected[3]); + assertEquals(State.DISCONNECTED, expected[4]); + assertEquals(State.UNKNOWN, expected[5]); + } +} diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java new file mode 100644 index 0000000000..d118c8a0ca --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2018 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.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.MacAddress; +import android.net.MatchAllNetworkSpecifier; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.NetworkSpecifier; +import android.net.UidRange; +import android.net.wifi.WifiNetworkSpecifier; +import android.os.Build; +import android.os.PatternMatcher; +import android.os.Process; +import android.util.ArraySet; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class NetworkRequestTest { + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + + private static final String TEST_SSID = "TestSSID"; + private static final String OTHER_SSID = "OtherSSID"; + private static final int TEST_UID = 2097; + private static final String TEST_PACKAGE_NAME = "test.package.name"; + private static final MacAddress ARBITRARY_ADDRESS = MacAddress.fromString("3:5:8:12:9:2"); + + private class LocalNetworkSpecifier extends NetworkSpecifier { + private final int mId; + + LocalNetworkSpecifier(int id) { + mId = id; + } + + @Override + public boolean canBeSatisfiedBy(NetworkSpecifier other) { + return other instanceof LocalNetworkSpecifier + && mId == ((LocalNetworkSpecifier) other).mId; + } + } + + @Test + public void testCapabilities() { + assertTrue(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build() + .hasCapability(NET_CAPABILITY_MMS)); + assertFalse(new NetworkRequest.Builder().removeCapability(NET_CAPABILITY_MMS).build() + .hasCapability(NET_CAPABILITY_MMS)); + + final NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build(); + // Verify request has no capabilities + verifyNoCapabilities(nr); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testTemporarilyNotMeteredCapability() { + assertTrue(new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build() + .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertFalse(new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build() + .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + } + + private void verifyNoCapabilities(NetworkRequest nr) { + // NetworkCapabilities.mNetworkCapabilities is defined as type long + final int MAX_POSSIBLE_CAPABILITY = Long.SIZE; + for(int bit = 0; bit < MAX_POSSIBLE_CAPABILITY; bit++) { + assertFalse(nr.hasCapability(bit)); + } + } + + @Test + public void testTransports() { + assertTrue(new NetworkRequest.Builder().addTransportType(TRANSPORT_BLUETOOTH).build() + .hasTransport(TRANSPORT_BLUETOOTH)); + assertFalse(new NetworkRequest.Builder().removeTransportType(TRANSPORT_BLUETOOTH).build() + .hasTransport(TRANSPORT_BLUETOOTH)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testSpecifier() { + assertNull(new NetworkRequest.Builder().build().getNetworkSpecifier()); + final WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL)) + .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + .build(); + final NetworkSpecifier obtainedSpecifier = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .setNetworkSpecifier(specifier) + .build() + .getNetworkSpecifier(); + assertEquals(obtainedSpecifier, specifier); + + assertNull(new NetworkRequest.Builder() + .clearCapabilities() + .build() + .getNetworkSpecifier()); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testRequestorPackageName() { + assertNull(new NetworkRequest.Builder().build().getRequestorPackageName()); + final String pkgName = "android.net.test"; + final NetworkCapabilities nc = new NetworkCapabilities.Builder() + .setRequestorPackageName(pkgName) + .build(); + final NetworkRequest nr = new NetworkRequest.Builder() + .setCapabilities(nc) + .build(); + assertEquals(pkgName, nr.getRequestorPackageName()); + assertNull(new NetworkRequest.Builder() + .clearCapabilities() + .build() + .getRequestorPackageName()); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testCanBeSatisfiedBy() { + final LocalNetworkSpecifier specifier1 = new LocalNetworkSpecifier(1234 /* id */); + final LocalNetworkSpecifier specifier2 = new LocalNetworkSpecifier(5678 /* id */); + + final NetworkCapabilities capCellularMmsInternet = new NetworkCapabilities() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_MMS) + .addCapability(NET_CAPABILITY_INTERNET); + final NetworkCapabilities capCellularVpnMmsInternet = + new NetworkCapabilities(capCellularMmsInternet).addTransportType(TRANSPORT_VPN); + final NetworkCapabilities capCellularMmsInternetSpecifier1 = + new NetworkCapabilities(capCellularMmsInternet).setNetworkSpecifier(specifier1); + final NetworkCapabilities capVpnInternetSpecifier1 = new NetworkCapabilities() + .addCapability(NET_CAPABILITY_INTERNET) + .addTransportType(TRANSPORT_VPN) + .setNetworkSpecifier(specifier1); + final NetworkCapabilities capCellularMmsInternetMatchallspecifier = + new NetworkCapabilities(capCellularMmsInternet) + .setNetworkSpecifier(new MatchAllNetworkSpecifier()); + final NetworkCapabilities capCellularMmsInternetSpecifier2 = + new NetworkCapabilities(capCellularMmsInternet).setNetworkSpecifier(specifier2); + + final NetworkRequest requestCellularInternetSpecifier1 = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .setNetworkSpecifier(specifier1) + .build(); + assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(null)); + assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(new NetworkCapabilities())); + assertTrue(requestCellularInternetSpecifier1.canBeSatisfiedBy( + capCellularMmsInternetMatchallspecifier)); + assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(capCellularMmsInternet)); + assertTrue(requestCellularInternetSpecifier1.canBeSatisfiedBy( + capCellularMmsInternetSpecifier1)); + assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(capCellularVpnMmsInternet)); + assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy( + capCellularMmsInternetSpecifier2)); + + final NetworkRequest requestCellularInternet = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternet)); + assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternetSpecifier1)); + assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternetSpecifier2)); + assertFalse(requestCellularInternet.canBeSatisfiedBy(capVpnInternetSpecifier1)); + assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularVpnMmsInternet)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testInvariantInCanBeSatisfiedBy() { + // Test invariant that result of NetworkRequest.canBeSatisfiedBy() should be the same with + // NetworkCapabilities.satisfiedByNetworkCapabilities(). + final LocalNetworkSpecifier specifier1 = new LocalNetworkSpecifier(1234 /* id */); + final int uid = Process.myUid(); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + final NetworkRequest requestCombination = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .setLinkUpstreamBandwidthKbps(1000) + .setNetworkSpecifier(specifier1) + .setSignalStrength(-123) + .setUids(ranges).build(); + final NetworkCapabilities capCell = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR).build(); + assertCorrectlySatisfies(false, requestCombination, capCell); + + final NetworkCapabilities capCellInternet = new NetworkCapabilities.Builder(capCell) + .addCapability(NET_CAPABILITY_INTERNET).build(); + assertCorrectlySatisfies(false, requestCombination, capCellInternet); + + final NetworkCapabilities capCellInternetBW = + new NetworkCapabilities.Builder(capCellInternet) + .setLinkUpstreamBandwidthKbps(1024).build(); + assertCorrectlySatisfies(false, requestCombination, capCellInternetBW); + + final NetworkCapabilities capCellInternetBWSpecifier1 = + new NetworkCapabilities.Builder(capCellInternetBW) + .setNetworkSpecifier(specifier1).build(); + assertCorrectlySatisfies(false, requestCombination, capCellInternetBWSpecifier1); + + final NetworkCapabilities capCellInternetBWSpecifier1Signal = + new NetworkCapabilities.Builder(capCellInternetBWSpecifier1) + .setSignalStrength(-123).build(); + assertCorrectlySatisfies(true, requestCombination, + capCellInternetBWSpecifier1Signal); + + final NetworkCapabilities capCellInternetBWSpecifier1SignalUid = + new NetworkCapabilities.Builder(capCellInternetBWSpecifier1Signal) + .setOwnerUid(uid) + .setAdministratorUids(new int [] {uid}).build(); + assertCorrectlySatisfies(true, requestCombination, + capCellInternetBWSpecifier1SignalUid); + } + + private void assertCorrectlySatisfies(boolean expect, NetworkRequest request, + NetworkCapabilities nc) { + assertEquals(expect, request.canBeSatisfiedBy(nc)); + assertEquals( + request.canBeSatisfiedBy(nc), + request.networkCapabilities.satisfiedByNetworkCapabilities(nc)); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testRequestorUid() { + final NetworkCapabilities nc = new NetworkCapabilities(); + // Verify default value is INVALID_UID + assertEquals(Process.INVALID_UID, new NetworkRequest.Builder() + .setCapabilities(nc).build().getRequestorUid()); + + nc.setRequestorUid(1314); + final NetworkRequest nr = new NetworkRequest.Builder().setCapabilities(nc).build(); + assertEquals(1314, nr.getRequestorUid()); + + assertEquals(Process.INVALID_UID, new NetworkRequest.Builder() + .clearCapabilities().build().getRequestorUid()); + } +} diff --git a/tests/cts/net/src/android/net/cts/NetworkStackDependenciesTest.kt b/tests/cts/net/src/android/net/cts/NetworkStackDependenciesTest.kt new file mode 100644 index 0000000000..1a7f9555f6 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkStackDependenciesTest.kt @@ -0,0 +1,53 @@ +/* + * 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 android.content.pm.PackageManager +import android.net.cts.util.CtsNetUtils +import android.net.wifi.WifiManager +import android.os.Build +import androidx.test.filters.SdkSuppress +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assume.assumeTrue +import org.junit.Test +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +/** + * Basic tests for APIs used by the network stack module. + */ +class NetworkStackDependenciesTest { + @Test + @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q) + fun testGetFrequency() { + // WifiInfo#getFrequency was missing a CTS test in Q: this test is run as part of MTS on Q + // devices to ensure it behaves correctly. + val context = InstrumentationRegistry.getInstrumentation().getContext() + assumeTrue("This test only applies to devices that support wifi", + context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) + val wifiManager = context.getSystemService(WifiManager::class.java) + assertNotNull(wifiManager, "Device supports wifi but there is no WifiManager") + + CtsNetUtils(context).ensureWifiConnected() + val wifiInfo = wifiManager.getConnectionInfo() + // The NetworkStack can handle any value of getFrequency; unknown frequencies will not be + // classified in metrics, but this is expected behavior. It is only important that the + // method does not crash. Still verify that the frequency is positive + val frequency = wifiInfo.getFrequency() + assertTrue(frequency > 0, "Frequency must be > 0") + } +} \ No newline at end of file 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 0000000000..1a48983028 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java @@ -0,0 +1,146 @@ +/* + * 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 static org.junit.Assert.assertEquals; + +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.Build; +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 androidx.test.runner.AndroidJUnit4; + +import com.android.internal.util.CollectionUtils; +import com.android.testutils.DevSdkIgnoreRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +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; + +@RunWith(AndroidJUnit4.class) +public class NetworkStatsBinderTest { + // 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; + + @Rule + public DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule( + Build.VERSION_CODES.Q /* ignoreClassUpTo */); + + private final SparseArray> mUidStatsQueryOpArray = new SparseArray<>(); + + @Before + public 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 predicate) { + PackageManager pm = InstrumentationRegistry.getContext().getPackageManager(); + List 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; + } + + @Test + public void testAccessUidStatsFromBinder() throws Exception { + final int myUid = Process.myUid(); + final List 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/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt new file mode 100644 index 0000000000..5290f0db28 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt @@ -0,0 +1,245 @@ +/* + * 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 android.Manifest.permission.MANAGE_TEST_NETWORKS +import android.Manifest.permission.NETWORK_SETTINGS +import android.content.Context +import android.content.pm.PackageManager +import android.net.ConnectivityManager +import android.net.EthernetManager +import android.net.InetAddresses +import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL +import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED +import android.net.NetworkCapabilities.TRANSPORT_ETHERNET +import android.net.NetworkCapabilities.TRANSPORT_TEST +import android.net.NetworkRequest +import android.net.TestNetworkInterface +import android.net.TestNetworkManager +import android.net.Uri +import android.net.dhcp.DhcpDiscoverPacket +import android.net.dhcp.DhcpPacket +import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE +import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_DISCOVER +import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_REQUEST +import android.net.dhcp.DhcpRequestPacket +import android.os.Build +import android.os.HandlerThread +import android.platform.test.annotations.AppModeFull +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress +import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address +import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DhcpClientPacketFilter +import com.android.testutils.DhcpOptionFilter +import com.android.testutils.RecorderCallback.CallbackEntry +import com.android.testutils.TapPacketReader +import com.android.testutils.TestHttpServer +import com.android.testutils.TestableNetworkCallback +import com.android.testutils.runAsShell +import fi.iki.elonen.NanoHTTPD.Response.Status +import org.junit.After +import org.junit.Assume.assumeFalse +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.net.Inet4Address +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import kotlin.test.fail + +private const val MAX_PACKET_LENGTH = 1500 +private const val TEST_TIMEOUT_MS = 10_000L + +private const val TEST_LEASE_TIMEOUT_SECS = 3600 * 12 +private const val TEST_PREFIX_LENGTH = 24 + +private const val TEST_LOGIN_URL = "https://login.capport.android.com" +private const val TEST_VENUE_INFO_URL = "https://venueinfo.capport.android.com" +private const val TEST_DOMAIN_NAME = "lan" +private const val TEST_MTU = 1500.toShort() + +@AppModeFull(reason = "Instant apps cannot create test networks") +@RunWith(AndroidJUnit4::class) +class NetworkValidationTest { + @JvmField + @Rule + val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) + + private val context by lazy { InstrumentationRegistry.getInstrumentation().context } + private val tnm by lazy { context.assertHasService(TestNetworkManager::class.java) } + private val eth by lazy { context.assertHasService(EthernetManager::class.java) } + private val cm by lazy { context.assertHasService(ConnectivityManager::class.java) } + + private val handlerThread = HandlerThread(NetworkValidationTest::class.java.simpleName) + private val serverIpAddr = InetAddresses.parseNumericAddress("192.0.2.222") as Inet4Address + private val clientIpAddr = InetAddresses.parseNumericAddress("192.0.2.111") as Inet4Address + private val httpServer = TestHttpServer() + private val ethRequest = NetworkRequest.Builder() + // ETHERNET|TEST transport networks do not have NET_CAPABILITY_TRUSTED + .removeCapability(NET_CAPABILITY_TRUSTED) + .addTransportType(TRANSPORT_ETHERNET) + .addTransportType(TRANSPORT_TEST).build() + private val ethRequestCb = TestableNetworkCallback() + + private lateinit var iface: TestNetworkInterface + private lateinit var reader: TapPacketReader + private lateinit var capportUrl: Uri + + private var testSkipped = false + + @Before + fun setUp() { + // This test requires using a tap interface as an ethernet interface. + val pm = context.getPackageManager() + testSkipped = !pm.hasSystemFeature(PackageManager.FEATURE_ETHERNET) && + context.getSystemService(EthernetManager::class.java) == null + assumeFalse(testSkipped) + + // Register a request so the network does not get torn down + cm.requestNetwork(ethRequest, ethRequestCb) + runAsShell(NETWORK_SETTINGS, MANAGE_TEST_NETWORKS) { + eth.setIncludeTestInterfaces(true) + // Keeping a reference to the test interface also makes sure the ParcelFileDescriptor + // does not go out of scope, which would cause it to close the underlying FileDescriptor + // in its finalizer. + iface = tnm.createTapInterface() + } + + handlerThread.start() + reader = TapPacketReader( + handlerThread.threadHandler, + iface.fileDescriptor.fileDescriptor, + MAX_PACKET_LENGTH) + reader.startAsyncForTest() + httpServer.start() + + // Pad the listening port to make sure it is always of length 5. This ensures the URL has + // always the same length so the test can use constant IP and UDP header lengths. + // The maximum port number is 65535 so a length of 5 is always enough. + capportUrl = Uri.parse("http://localhost:${httpServer.listeningPort}/testapi.html?par=val") + } + + @After + fun tearDown() { + if (testSkipped) return + cm.unregisterNetworkCallback(ethRequestCb) + + runAsShell(NETWORK_SETTINGS) { eth.setIncludeTestInterfaces(false) } + + httpServer.stop() + handlerThread.threadHandler.post { reader.stop() } + handlerThread.quitSafely() + + iface.fileDescriptor.close() + } + + @Test + fun testCapportApiCallbacks() { + httpServer.addResponse(capportUrl, Status.OK, content = """ + |{ + | "captive": true, + | "user-portal-url": "$TEST_LOGIN_URL", + | "venue-info-url": "$TEST_VENUE_INFO_URL" + |} + """.trimMargin()) + + // Handle the DHCP handshake that includes the capport API URL + val discover = reader.assertDhcpPacketReceived( + DhcpDiscoverPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER) + reader.sendResponse(makeOfferPacket(discover.clientMac, discover.transactionId)) + + val request = reader.assertDhcpPacketReceived( + DhcpRequestPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_REQUEST) + assertEquals(discover.transactionId, request.transactionId) + assertEquals(clientIpAddr, request.mRequestedIp) + reader.sendResponse(makeAckPacket(request.clientMac, request.transactionId)) + + // The first request received by the server should be for the portal API + assertTrue(httpServer.requestsRecord.poll(TEST_TIMEOUT_MS, 0)?.matches(capportUrl) ?: false, + "The device did not fetch captive portal API data within timeout") + + // Expect network callbacks with capport info + val testCb = TestableNetworkCallback(TEST_TIMEOUT_MS) + // LinkProperties do not contain captive portal info if the callback is registered without + // NETWORK_SETTINGS permissions. + val lp = runAsShell(NETWORK_SETTINGS) { + cm.registerNetworkCallback(ethRequest, testCb) + + try { + val ncCb = testCb.eventuallyExpect { + it.caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) + } + testCb.eventuallyExpect { + it.network == ncCb.network && it.lp.captivePortalData != null + }.lp + } finally { + cm.unregisterNetworkCallback(testCb) + } + } + + assertEquals(capportUrl, lp.captivePortalApiUrl) + with(lp.captivePortalData) { + assertNotNull(this) + assertTrue(isCaptive) + assertEquals(Uri.parse(TEST_LOGIN_URL), userPortalUrl) + assertEquals(Uri.parse(TEST_VENUE_INFO_URL), venueInfoUrl) + } + } + + private fun makeOfferPacket(clientMac: ByteArray, transactionId: Int) = + DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, transactionId, + false /* broadcast */, serverIpAddr, IPV4_ADDR_ANY /* relayIp */, clientIpAddr, + clientMac, TEST_LEASE_TIMEOUT_SECS, + getPrefixMaskAsInet4Address(TEST_PREFIX_LENGTH), + getBroadcastAddress(clientIpAddr, TEST_PREFIX_LENGTH), + listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */, + serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */, + TEST_MTU, capportUrl.toString()) + + private fun makeAckPacket(clientMac: ByteArray, transactionId: Int) = + DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, transactionId, + false /* broadcast */, serverIpAddr, IPV4_ADDR_ANY /* relayIp */, clientIpAddr, + clientIpAddr /* requestClientIp */, clientMac, TEST_LEASE_TIMEOUT_SECS, + getPrefixMaskAsInet4Address(TEST_PREFIX_LENGTH), + getBroadcastAddress(clientIpAddr, TEST_PREFIX_LENGTH), + listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */, + serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */, + TEST_MTU, false /* rapidCommit */, capportUrl.toString()) +} + +private fun TapPacketReader.assertDhcpPacketReceived( + packetType: Class, + timeoutMs: Long, + type: Byte +): T { + val packetBytes = poll(timeoutMs, DhcpClientPacketFilter() + .and(DhcpOptionFilter(DHCP_MESSAGE_TYPE, type))) + ?: fail("${packetType.simpleName} not received within timeout") + val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2) + assertTrue(packetType.isInstance(packet), + "Expected ${packetType.simpleName} but got ${packet.javaClass.simpleName}") + return packetType.cast(packet) +} + +private fun Context.assertHasService(manager: Class): T { + return getSystemService(manager) ?: fail("Service $manager not found") +} diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt new file mode 100644 index 0000000000..f6fc75b5f4 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -0,0 +1,68 @@ +/* + * 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 android.Manifest +import android.net.util.NetworkStackUtils +import android.provider.DeviceConfig +import com.android.testutils.runAsShell + +/** + * Collection of utility methods for configuring network validation. + */ +internal object NetworkValidationTestUtil { + + /** + * Clear the test network validation URLs. + */ + fun clearValidationTestUrlsDeviceConfig() { + setHttpsUrlDeviceConfig(null) + setHttpUrlDeviceConfig(null) + setUrlExpirationDeviceConfig(null) + } + + /** + * Set the test validation HTTPS URL. + * + * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL + */ + fun setHttpsUrlDeviceConfig(url: String?) = + setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL, url) + + /** + * Set the test validation HTTP URL. + * + * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL + */ + fun setHttpUrlDeviceConfig(url: String?) = + setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL, url) + + /** + * Set the test validation URL expiration. + * + * @see NetworkStackUtils.TEST_URL_EXPIRATION_TIME + */ + fun setUrlExpirationDeviceConfig(timestamp: Long?) = + setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString()) + + private fun setConfig(configKey: String, value: String?) { + runAsShell(Manifest.permission.WRITE_DEVICE_CONFIG) { + DeviceConfig.setProperty( + DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) + } + } +} \ No newline at end of file diff --git a/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java b/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java new file mode 100644 index 0000000000..81a9e30dd5 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2018 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 com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.platform.test.annotations.AppModeFull; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.compatibility.common.util.ApiLevelUtil; +import com.android.compatibility.common.util.SystemUtil; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Formatter; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class NetworkWatchlistTest { + + private static final String TEST_WATCHLIST_XML = "assets/network_watchlist_config_for_test.xml"; + private static final String TEST_EMPTY_WATCHLIST_XML = + "assets/network_watchlist_config_empty_for_test.xml"; + private static final String TMP_CONFIG_PATH = + "/data/local/tmp/network_watchlist_config_for_test.xml"; + // Generated from sha256sum network_watchlist_config_for_test.xml + private static final String TEST_WATCHLIST_CONFIG_HASH = + "B5FC4636994180D54E1E912F78178AB1D8BD2BE71D90CA9F5BBC3284E4D04ED4"; + + private ConnectivityManager mConnectivityManager; + private boolean mHasFeature; + + @Before + public void setUp() throws Exception { + mHasFeature = isAtLeastP(); + mConnectivityManager = + (ConnectivityManager) InstrumentationRegistry.getContext().getSystemService( + Context.CONNECTIVITY_SERVICE); + assumeTrue(mHasFeature); + // Set empty watchlist test config before testing + setWatchlistConfig(TEST_EMPTY_WATCHLIST_XML); + // Verify test watchlist config is not set before testing + byte[] result = mConnectivityManager.getNetworkWatchlistConfigHash(); + assertNotNull("Watchlist config does not exist", result); + assertNotEquals(TEST_WATCHLIST_CONFIG_HASH, byteArrayToHexString(result)); + } + + @After + public void tearDown() throws Exception { + if (mHasFeature) { + // Set empty watchlist test config after testing + setWatchlistConfig(TEST_EMPTY_WATCHLIST_XML); + } + } + + private void cleanup() throws IOException { + runCommand("rm " + TMP_CONFIG_PATH); + } + + private boolean isAtLeastP() throws Exception { + // TODO: replace with ApiLevelUtil.isAtLeast(Build.VERSION_CODES.P) when the P API level + // constant is defined. + return ApiLevelUtil.getCodename().compareToIgnoreCase("P") >= 0; + } + + /** + * Test if ConnectivityManager.getNetworkWatchlistConfigHash() correctly + * returns the hash of config we set. + */ + @Test + @AppModeFull(reason = "Cannot access resource file in instant app mode") + public void testGetWatchlistConfigHash() throws Exception { + // Set watchlist config file for test + setWatchlistConfig(TEST_WATCHLIST_XML); + // Test if watchlist config hash value is correct + byte[] result = mConnectivityManager.getNetworkWatchlistConfigHash(); + Assert.assertEquals(TEST_WATCHLIST_CONFIG_HASH, byteArrayToHexString(result)); + } + + private static String byteArrayToHexString(byte[] bytes) { + Formatter formatter = new Formatter(); + for (byte b : bytes) { + formatter.format("%02X", b); + } + return formatter.toString(); + } + + private void saveResourceToFile(String res, String filePath) throws IOException { + // App can't access /data/local/tmp directly, so we pipe resource to file through stdin. + ParcelFileDescriptor stdin = pipeFromStdin(filePath); + pipeResourceToFileDescriptor(res, stdin); + } + + /* Pipe stdin to a file in filePath. Returns PFD for stdin. */ + private ParcelFileDescriptor pipeFromStdin(String filePath) { + // Not all devices have symlink for /dev/stdin, so use /proc/self/fd/0 directly. + // /dev/stdin maps to /proc/self/fd/0. + return runRwCommand("cp /proc/self/fd/0 " + filePath)[1]; + } + + private void pipeResourceToFileDescriptor(String res, ParcelFileDescriptor pfd) + throws IOException { + InputStream resStream = getClass().getClassLoader().getResourceAsStream(res); + FileOutputStream fdStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd); + + FileUtils.copy(resStream, fdStream); + + try { + fdStream.close(); + } catch (IOException e) { + } + } + + private static String runCommand(String command) throws IOException { + return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command); + } + + private static ParcelFileDescriptor[] runRwCommand(String command) { + return InstrumentationRegistry.getInstrumentation() + .getUiAutomation().executeShellCommandRw(command); + } + + private void setWatchlistConfig(String watchlistConfigFile) throws Exception { + cleanup(); + saveResourceToFile(watchlistConfigFile, TMP_CONFIG_PATH); + final String cmdResult = runCommand( + "cmd network_watchlist set-test-config " + TMP_CONFIG_PATH).trim(); + assertThat(cmdResult).contains("Success"); + cleanup(); + } +} diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java new file mode 100644 index 0000000000..0aedecb5ad --- /dev/null +++ b/tests/cts/net/src/android/net/cts/PacketUtils.java @@ -0,0 +1,474 @@ +/* + * Copyright (C) 2018 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.system.OsConstants.IPPROTO_IPV6; +import static android.system.OsConstants.IPPROTO_UDP; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Arrays; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class PacketUtils { + private static final String TAG = PacketUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + + static final int IP4_HDRLEN = 20; + static final int IP6_HDRLEN = 40; + static final int UDP_HDRLEN = 8; + static final int TCP_HDRLEN = 20; + static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12; + + // Not defined in OsConstants + static final int IPPROTO_IPV4 = 4; + static final int IPPROTO_ESP = 50; + + // Encryption parameters + static final int AES_GCM_IV_LEN = 8; + static final int AES_CBC_IV_LEN = 16; + static final int AES_GCM_BLK_SIZE = 4; + static final int AES_CBC_BLK_SIZE = 16; + + // Encryption algorithms + static final String AES = "AES"; + static final String AES_CBC = "AES/CBC/NoPadding"; + static final String HMAC_SHA_256 = "HmacSHA256"; + + public interface Payload { + byte[] getPacketBytes(IpHeader header) throws Exception; + + void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception; + + short length(); + + int getProtocolId(); + } + + public abstract static class IpHeader { + + public final byte proto; + public final InetAddress srcAddr; + public final InetAddress dstAddr; + public final Payload payload; + + public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) { + this.proto = (byte) proto; + this.srcAddr = src; + this.dstAddr = dst; + this.payload = payload; + } + + public abstract byte[] getPacketBytes() throws Exception; + + public abstract int getProtocolId(); + } + + public static class Ip4Header extends IpHeader { + private short checksum; + + public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) { + super(proto, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer resultBuffer = buildHeader(); + payload.addPacketBytes(this, resultBuffer); + + return getByteArrayFromBuffer(resultBuffer); + } + + public ByteBuffer buildHeader() { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version, IHL + bb.put((byte) (0x45)); + + // DCSP, ECN + bb.put((byte) 0); + + // Total Length + bb.putShort((short) (IP4_HDRLEN + payload.length())); + + // Empty for Identification, Flags and Fragment Offset + bb.putShort((short) 0); + bb.put((byte) 0x40); + bb.put((byte) 0x00); + + // TTL + bb.put((byte) 64); + + // Protocol + bb.put(proto); + + // Header Checksum + final int ipChecksumOffset = bb.position(); + bb.putShort((short) 0); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + bb.putShort(ipChecksumOffset, calculateChecksum(bb)); + + return bb; + } + + private short calculateChecksum(ByteBuffer bb) { + int checksum = 0; + + // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit + // aligned, so no special cases needed for unaligned values. + ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer(); + while (shortBuffer.hasRemaining()) { + short val = shortBuffer.get(); + + // Wrap as needed + checksum = addAndWrapForChecksum(checksum, val); + } + + return onesComplement(checksum); + } + + public int getProtocolId() { + return IPPROTO_IPV4; + } + } + + public static class Ip6Header extends IpHeader { + public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) { + super(nextHeader, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version | Traffic Class (First 4 bits) + bb.put((byte) 0x60); + + // Traffic class (Last 4 bits), Flow Label + bb.put((byte) 0); + bb.put((byte) 0); + bb.put((byte) 0); + + // Payload Length + bb.putShort((short) payload.length()); + + // Next Header + bb.put(proto); + + // Hop Limit + bb.put((byte) 64); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + // Payload + payload.addPacketBytes(this, bb); + + return getByteArrayFromBuffer(bb); + } + + public int getProtocolId() { + return IPPROTO_IPV6; + } + } + + public static class BytePayload implements Payload { + public final byte[] payload; + + public BytePayload(byte[] payload) { + this.payload = payload; + } + + public int getProtocolId() { + return -1; + } + + public byte[] getPacketBytes(IpHeader header) { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) { + resultBuffer.put(payload); + } + + public short length() { + return (short) payload.length; + } + } + + public static class UdpHeader implements Payload { + + public final short srcPort; + public final short dstPort; + public final Payload payload; + + public UdpHeader(int srcPort, int dstPort, Payload payload) { + this.srcPort = (short) srcPort; + this.dstPort = (short) dstPort; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_UDP; + } + + public short length() { + return (short) (payload.length() + 8); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + // Source, Destination port + resultBuffer.putShort(srcPort); + resultBuffer.putShort(dstPort); + + // Payload Length + resultBuffer.putShort(length()); + + // Get payload bytes for checksum + payload + ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + payload.addPacketBytes(header, payloadBuffer); + byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer); + + // Checksum + resultBuffer.putShort(calculateChecksum(header, payloadBytes)); + + // Payload + resultBuffer.put(payloadBytes); + } + + private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception { + int newChecksum = 0; + ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer(); + ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer(); + + while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) { + short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get(); + + // Wrap as needed + newChecksum = addAndWrapForChecksum(newChecksum, val); + } + + // Add pseudo-header values. Proto is 0-padded, so just use the byte. + newChecksum = addAndWrapForChecksum(newChecksum, header.proto); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + newChecksum = addAndWrapForChecksum(newChecksum, srcPort); + newChecksum = addAndWrapForChecksum(newChecksum, dstPort); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + + ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer(); + while (payloadShortBuffer.hasRemaining()) { + newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get()); + } + if (payload.length() % 2 != 0) { + newChecksum = + addAndWrapForChecksum( + newChecksum, (payloadBytes[payloadBytes.length - 1] << 8)); + } + + return onesComplement(newChecksum); + } + } + + public static class EspHeader implements Payload { + public final int nextHeader; + public final int spi; + public final int seqNum; + public final byte[] key; + public final byte[] payload; + + /** + * Generic constructor for ESP headers. + * + *

    For Tunnel mode, payload will be a full IP header + attached payloads + * + *

    For Transport mode, payload will be only the attached payloads, but with the checksum + * calculated using the pre-encryption IP header + */ + public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) { + this.nextHeader = nextHeader; + this.spi = spi; + this.seqNum = seqNum; + this.key = key; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_ESP; + } + + public short length() { + // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len) + return (short) + calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + espPayloadBuffer.putInt(spi); + espPayloadBuffer.putInt(seqNum); + espPayloadBuffer.put(getCiphertext(key)); + + espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16); + resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer)); + } + + private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException { + Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256); + SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256); + sha256HMAC.init(authKey); + + return sha256HMAC.doFinal(authenticatedSection); + } + + /** + * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks + * + *

    The ciphertext does NOT include the SPI/Sequence numbers, or the ICV. + */ + private byte[] getCiphertext(byte[] key) throws GeneralSecurityException { + int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE); + ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen); + paddedPayload.put(payload); + + // Add padding - consecutive integers from 0x01 + int pad = 1; + while (paddedPayload.position() < paddedPayload.limit()) { + paddedPayload.put((byte) pad++); + } + + paddedPayload.position(paddedPayload.limit() - 2); + paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length + paddedPayload.put((byte) nextHeader); + + // Generate Initialization Vector + byte[] iv = new byte[AES_CBC_IV_LEN]; + new SecureRandom().nextBytes(iv); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); + + // Encrypt payload + Cipher cipher = Cipher.getInstance(AES_CBC); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload)); + + // Build ciphertext + ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length); + cipherText.put(iv); + cipherText.put(encrypted); + + return getByteArrayFromBuffer(cipherText); + } + } + + private static int addAndWrapForChecksum(int currentChecksum, int value) { + currentChecksum += value & 0x0000ffff; + + // Wrap anything beyond the first 16 bits, and add to lower order bits + return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff); + } + + private static short onesComplement(int val) { + val = (val >>> 16) + (val & 0xffff); + + if (val == 0) return 0; + return (short) ((~val) & 0xffff); + } + + public static int calculateEspPacketSize( + int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { + final int ESP_HDRLEN = 4 + 4; // SPI + Seq# + final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length + payloadLen += cryptIvLength; // Initialization Vector + + // Align to block size of encryption algorithm + payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize); + return payloadLen + ESP_HDRLEN + ICV_LEN; + } + + private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) { + payloadLen += 2; // ESP trailer + + // Align to block size of encryption algorithm + return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize); + } + + private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) { + return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; + } + + private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) { + return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); + } + + public static IpHeader getIpHeader( + int protocol, InetAddress src, InetAddress dst, Payload payload) { + if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { + throw new IllegalArgumentException("Invalid src/dst address combination"); + } + + if (src instanceof Inet6Address) { + return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); + } else { + return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); + } + } + + /* + * Debug printing + */ + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(hexArray[b >>> 4]); + sb.append(hexArray[b & 0x0F]); + sb.append(' '); + } + return sb.toString(); + } +} diff --git a/tests/cts/net/src/android/net/cts/ProxyInfoTest.java b/tests/cts/net/src/android/net/cts/ProxyInfoTest.java new file mode 100644 index 0000000000..1c5624ce38 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ProxyInfoTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2019 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 org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.ProxyInfo; +import android.net.Uri; +import android.os.Build; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +@RunWith(AndroidJUnit4.class) +public final class ProxyInfoTest { + private static final String TEST_HOST = "test.example.com"; + private static final int TEST_PORT = 5566; + private static final Uri TEST_URI = Uri.parse("https://test.example.com"); + // This matches android.net.ProxyInfo#LOCAL_EXCL_LIST + private static final String LOCAL_EXCL_LIST = ""; + // This matches android.net.ProxyInfo#LOCAL_HOST + private static final String LOCAL_HOST = "localhost"; + // This matches android.net.ProxyInfo#LOCAL_PORT + private static final int LOCAL_PORT = -1; + + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + + @Test + public void testConstructor() { + final ProxyInfo proxy = new ProxyInfo((ProxyInfo) null); + checkEmpty(proxy); + + assertEquals(proxy, new ProxyInfo(proxy)); + } + + @Test + public void testBuildDirectProxy() { + final ProxyInfo proxy1 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT); + + assertEquals(TEST_HOST, proxy1.getHost()); + assertEquals(TEST_PORT, proxy1.getPort()); + assertArrayEquals(new String[0], proxy1.getExclusionList()); + assertEquals(Uri.EMPTY, proxy1.getPacFileUrl()); + + final List exclList = new ArrayList<>(); + exclList.add("localhost"); + exclList.add("*.exclusion.com"); + final ProxyInfo proxy2 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT, exclList); + + assertEquals(TEST_HOST, proxy2.getHost()); + assertEquals(TEST_PORT, proxy2.getPort()); + assertArrayEquals(exclList.toArray(new String[0]), proxy2.getExclusionList()); + assertEquals(Uri.EMPTY, proxy2.getPacFileUrl()); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testBuildPacProxy() { + final ProxyInfo proxy1 = ProxyInfo.buildPacProxy(TEST_URI); + + assertEquals(LOCAL_HOST, proxy1.getHost()); + assertEquals(LOCAL_PORT, proxy1.getPort()); + assertArrayEquals(LOCAL_EXCL_LIST.toLowerCase(Locale.ROOT).split(","), + proxy1.getExclusionList()); + assertEquals(TEST_URI, proxy1.getPacFileUrl()); + + final ProxyInfo proxy2 = ProxyInfo.buildPacProxy(TEST_URI, TEST_PORT); + + assertEquals(LOCAL_HOST, proxy2.getHost()); + assertEquals(TEST_PORT, proxy2.getPort()); + assertArrayEquals(LOCAL_EXCL_LIST.toLowerCase(Locale.ROOT).split(","), + proxy2.getExclusionList()); + assertEquals(TEST_URI, proxy2.getPacFileUrl()); + } + + @Test + public void testIsValid() { + final ProxyInfo proxy1 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT); + assertTrue(proxy1.isValid()); + + // Given empty host + final ProxyInfo proxy2 = ProxyInfo.buildDirectProxy("", TEST_PORT); + assertFalse(proxy2.isValid()); + // Given invalid host + final ProxyInfo proxy3 = ProxyInfo.buildDirectProxy(".invalid.com", TEST_PORT); + assertFalse(proxy3.isValid()); + // Given invalid port. + final ProxyInfo proxy4 = ProxyInfo.buildDirectProxy(TEST_HOST, 0); + assertFalse(proxy4.isValid()); + // Given another invalid port + final ProxyInfo proxy5 = ProxyInfo.buildDirectProxy(TEST_HOST, 65536); + assertFalse(proxy5.isValid()); + // Given invalid exclusion list + final List exclList = new ArrayList<>(); + exclList.add(".invalid.com"); + exclList.add("%.test.net"); + final ProxyInfo proxy6 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT, exclList); + assertFalse(proxy6.isValid()); + } + + private void checkEmpty(ProxyInfo proxy) { + assertNull(proxy.getHost()); + assertEquals(0, proxy.getPort()); + assertNull(proxy.getExclusionList()); + assertEquals(Uri.EMPTY, proxy.getPacFileUrl()); + } +} diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java new file mode 100644 index 0000000000..467d12f9dc --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ProxyTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009 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 android.net.Proxy; +import android.test.AndroidTestCase; + +public class ProxyTest extends AndroidTestCase { + + public void testConstructor() { + new Proxy(); + } + + public void testAccessProperties() { + final int minValidPort = 0; + final int maxValidPort = 65535; + int defaultPort = Proxy.getDefaultPort(); + if(null == Proxy.getDefaultHost()) { + assertEquals(-1, defaultPort); + } else { + assertTrue(defaultPort >= minValidPort && defaultPort <= maxValidPort); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/RssiCurveTest.java b/tests/cts/net/src/android/net/cts/RssiCurveTest.java new file mode 100644 index 0000000000..d651b7186b --- /dev/null +++ b/tests/cts/net/src/android/net/cts/RssiCurveTest.java @@ -0,0 +1,102 @@ +/* + * 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 com.google.common.truth.Truth.assertThat; + +import android.net.RssiCurve; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** CTS tests for {@link RssiCurve}. */ +@RunWith(AndroidJUnit4.class) +public class RssiCurveTest { + + @Test + public void lookupScore_constantCurve() { + // One bucket from rssi=-100 to 100 with score 10. + RssiCurve curve = new RssiCurve(-100, 200, new byte[] { 10 }); + assertThat(curve.lookupScore(-200)).isEqualTo(10); + assertThat(curve.lookupScore(-100)).isEqualTo(10); + assertThat(curve.lookupScore(0)).isEqualTo(10); + assertThat(curve.lookupScore(100)).isEqualTo(10); + assertThat(curve.lookupScore(200)).isEqualTo(10); + } + + @Test + public void lookupScore_changingCurve() { + // One bucket from -100 to 0 with score -10, and one bucket from 0 to 100 with score 10. + RssiCurve curve = new RssiCurve(-100, 100, new byte[] { -10, 10 }); + assertThat(curve.lookupScore(-200)).isEqualTo(-10); + assertThat(curve.lookupScore(-100)).isEqualTo(-10); + assertThat(curve.lookupScore(-50)).isEqualTo(-10); + assertThat(curve.lookupScore(0)).isEqualTo(10); + assertThat(curve.lookupScore(50)).isEqualTo(10); + assertThat(curve.lookupScore(100)).isEqualTo(10); + assertThat(curve.lookupScore(200)).isEqualTo(10); + } + + @Test + public void lookupScore_linearCurve() { + // Curve starting at -110, with 15 buckets of width 10 whose scores increases by 10 with + // each bucket. The current active network gets a boost of 15 to its RSSI. + RssiCurve curve = new RssiCurve( + -110, + 10, + new byte[] { -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 }, + 15); + + assertThat(curve.lookupScore(-120)).isEqualTo(-20); + assertThat(curve.lookupScore(-120, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-120, true)).isEqualTo(-20); + + assertThat(curve.lookupScore(-111)).isEqualTo(-20); + assertThat(curve.lookupScore(-111, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-111, true)).isEqualTo(-10); + + assertThat(curve.lookupScore(-110)).isEqualTo(-20); + assertThat(curve.lookupScore(-110, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-110, true)).isEqualTo(-10); + + assertThat(curve.lookupScore(-105)).isEqualTo(-20); + assertThat(curve.lookupScore(-105, false)).isEqualTo(-20); + assertThat(curve.lookupScore(-105, true)).isEqualTo(0); + + assertThat(curve.lookupScore(-100)).isEqualTo(-10); + assertThat(curve.lookupScore(-100, false)).isEqualTo(-10); + assertThat(curve.lookupScore(-100, true)).isEqualTo(0); + + assertThat(curve.lookupScore(-50)).isEqualTo(40); + assertThat(curve.lookupScore(-50, false)).isEqualTo(40); + assertThat(curve.lookupScore(-50, true)).isEqualTo(50); + + assertThat(curve.lookupScore(0)).isEqualTo(90); + assertThat(curve.lookupScore(0, false)).isEqualTo(90); + assertThat(curve.lookupScore(0, true)).isEqualTo(100); + + assertThat(curve.lookupScore(30)).isEqualTo(120); + assertThat(curve.lookupScore(30, false)).isEqualTo(120); + assertThat(curve.lookupScore(30, true)).isEqualTo(120); + + assertThat(curve.lookupScore(40)).isEqualTo(120); + assertThat(curve.lookupScore(40, false)).isEqualTo(120); + assertThat(curve.lookupScore(40, true)).isEqualTo(120); + } +} diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java new file mode 100644 index 0000000000..cbe54f8036 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2008 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 org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.net.SSLCertificateSocketFactory; +import android.platform.test.annotations.AppModeFull; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import libcore.javax.net.ssl.SSLConfigurationAsserts; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class SSLCertificateSocketFactoryTest { + // TEST_HOST should point to a web server with a valid TLS certificate. + private static final String TEST_HOST = "www.google.com"; + private static final int HTTPS_PORT = 443; + private HostnameVerifier mDefaultVerifier; + private SSLCertificateSocketFactory mSocketFactory; + private InetAddress mLocalAddress; + // InetAddress obtained by resolving TEST_HOST. + private InetAddress mTestHostAddress; + // SocketAddress combining mTestHostAddress and HTTPS_PORT. + private List mTestSocketAddresses; + + @Before + public void setUp() { + // Expected state before each test method is that + // HttpsURLConnection.getDefaultHostnameVerifier() will return the system default. + mDefaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); + mSocketFactory = (SSLCertificateSocketFactory) + SSLCertificateSocketFactory.getDefault(1000 /* handshakeTimeoutMillis */); + assertNotNull(mSocketFactory); + InetAddress[] addresses; + try { + addresses = InetAddress.getAllByName(TEST_HOST); + mTestHostAddress = addresses[0]; + } catch (UnknownHostException uhe) { + throw new AssertionError( + "Unable to test SSLCertificateSocketFactory: cannot resolve " + TEST_HOST, uhe); + } + + mTestSocketAddresses = Arrays.stream(addresses) + .map(addr -> new InetSocketAddress(addr, HTTPS_PORT)) + .collect(Collectors.toList()); + + // Find the local IP address which will be used to connect to TEST_HOST. + try { + Socket testSocket = new Socket(TEST_HOST, HTTPS_PORT); + mLocalAddress = testSocket.getLocalAddress(); + testSocket.close(); + } catch (IOException ioe) { + throw new AssertionError("" + + "Unable to test SSLCertificateSocketFactory: cannot connect to " + + TEST_HOST, ioe); + } + } + + // Restore the system default hostname verifier after each test. + @After + public void restoreDefaultHostnameVerifier() { + HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier); + } + + @Test + public void testDefaultConfiguration() throws Exception { + SSLConfigurationAsserts.assertSSLSocketFactoryDefaultConfiguration(mSocketFactory); + } + + @Test + public void testAccessProperties() { + mSocketFactory.getSupportedCipherSuites(); + mSocketFactory.getDefaultCipherSuites(); + } + + /** + * Tests the {@code createSocket()} cases which are expected to fail with {@code IOException}. + */ + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void createSocket_io_error_expected() { + // Connect to the localhost HTTPS port. Should result in connection refused IOException + // because no service should be listening on that port. + InetAddress localhostAddress = InetAddress.getLoopbackAddress(); + try { + mSocketFactory.createSocket(localhostAddress, HTTPS_PORT); + fail(); + } catch (IOException e) { + // expected + } + + // Same, but also binding to a local address. + try { + mSocketFactory.createSocket(localhostAddress, HTTPS_PORT, localhostAddress, 0); + fail(); + } catch (IOException e) { + // expected + } + + // Same, wrapping an existing plain socket which is in an unconnected state. + try { + Socket socket = new Socket(); + mSocketFactory.createSocket(socket, "localhost", HTTPS_PORT, true); + fail(); + } catch (IOException e) { + // expected + } + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(String, int)}. + * + *

    This method should return a socket which is fully connected (i.e. TLS handshake complete) + * and whose peer TLS certificate has been verified to have the correct hostname. + * + *

    {@link SSLCertificateSocketFactory} is documented to verify hostnames using + * the {@link HostnameVerifier} returned by + * {@link HttpsURLConnection#getDefaultHostnameVerifier}, so this test connects twice, + * once with the system default {@link HostnameVerifier} which is expected to succeed, + * and once after installing a {@link NegativeHostnameVerifier} which will cause + * {@link SSLCertificateSocketFactory#verifyHostname} to throw a + * {@link SSLPeerUnverifiedException}. + * + *

    These tests only test the hostname verification logic in SSLCertificateSocketFactory, + * other TLS failure modes and the default HostnameVerifier are tested elsewhere, see + * {@link com.squareup.okhttp.internal.tls.HostnameVerifierTest} and + * https://android.googlesource.com/platform/external/boringssl/+/refs/heads/master/src/ssl/test + * + *

    Tests the following behaviour:- + *

      + *
    • TEST_SERVER is available and has a valid TLS certificate + *
    • {@code createSocket()} verifies the remote hostname is correct using + * {@link HttpsURLConnection#getDefaultHostnameVerifier} + *
    • {@link SSLPeerUnverifiedException} is thrown when the remote hostname is invalid + *
    + * + *

    See also http://b/2807618. + */ + @Test + public void createSocket_simple_with_hostname_verification() throws Exception { + Socket socket = mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT); + assertConnectedSocket(socket); + socket.close(); + + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + try { + mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(Socket, String, int, boolean)}. + * + *

    This method should return a socket which is fully connected (i.e. TLS handshake complete) + * and whose peer TLS certificate has been verified to have the correct hostname. + * + *

    The TLS socket returned is wrapped around the plain socket passed into + * {@code createSocket()}. + * + *

    See {@link #createSocket_simple_with_hostname_verification()} for test methodology. + */ + @Test + public void createSocket_wrapped_with_hostname_verification() throws Exception { + Socket underlying = new Socket(TEST_HOST, HTTPS_PORT); + Socket socket = mSocketFactory.createSocket(underlying, TEST_HOST, HTTPS_PORT, true); + assertConnectedSocket(socket); + socket.close(); + + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + try { + underlying = new Socket(TEST_HOST, HTTPS_PORT); + mSocketFactory.createSocket(underlying, TEST_HOST, HTTPS_PORT, true); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(String, int, InetAddress, int)}. + * + *

    This method should return a socket which is fully connected (i.e. TLS handshake complete) + * and whose peer TLS certificate has been verified to have the correct hostname. + * + *

    The TLS socket returned is also bound to the local address determined in {@link #setUp} to + * be used for connections to TEST_HOST, and a wildcard port. + * + *

    See {@link #createSocket_simple_with_hostname_verification()} for test methodology. + */ + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void createSocket_bound_with_hostname_verification() throws Exception { + Socket socket = mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT, mLocalAddress, 0); + assertConnectedSocket(socket); + socket.close(); + + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + try { + mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT, mLocalAddress, 0); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(InetAddress, int)}. + * + *

    This method should return a socket which the documentation describes as "unconnected", + * which actually means that the socket is fully connected at the TCP layer but TLS handshaking + * and hostname verification have not yet taken place. + * + *

    Behaviour is tested by installing a {@link NegativeHostnameVerifier} and by calling + * {@link #assertConnectedSocket} to ensure TLS handshaking but no hostname verification takes + * place. Next, {@link SSLCertificateSocketFactory#verifyHostname} is called to ensure + * that hostname verification is using the {@link HostnameVerifier} returned by + * {@link HttpsURLConnection#getDefaultHostnameVerifier} as documented. + * + *

    Tests the following behaviour:- + *

      + *
    • TEST_SERVER is available and has a valid TLS certificate + *
    • {@code createSocket()} does not verify the remote hostname + *
    • Calling {@link SSLCertificateSocketFactory#verifyHostname} on the returned socket + * throws {@link SSLPeerUnverifiedException} if the remote hostname is invalid + *
    + */ + @Test + public void createSocket_simple_no_hostname_verification() throws Exception{ + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + Socket socket = mSocketFactory.createSocket(mTestHostAddress, HTTPS_PORT); + // Need to provide the expected hostname here or the TLS handshake will + // be unable to supply SNI to the remote host. + mSocketFactory.setHostname(socket, TEST_HOST); + assertConnectedSocket(socket); + try { + SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier); + SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + socket.close(); + } + + /** + * Tests hostname verification for + * {@link SSLCertificateSocketFactory#createSocket(InetAddress, int, InetAddress, int)}. + * + *

    This method should return a socket which the documentation describes as "unconnected", + * which actually means that the socket is fully connected at the TCP layer but TLS handshaking + * and hostname verification have not yet taken place. + * + *

    The TLS socket returned is also bound to the local address determined in {@link #setUp} to + * be used for connections to TEST_HOST, and a wildcard port. + * + *

    See {@link #createSocket_simple_no_hostname_verification()} for test methodology. + */ + @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void createSocket_bound_no_hostname_verification() throws Exception{ + HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier()); + Socket socket = + mSocketFactory.createSocket(mTestHostAddress, HTTPS_PORT, mLocalAddress, 0); + // Need to provide the expected hostname here or the TLS handshake will + // be unable to supply SNI to the peer. + mSocketFactory.setHostname(socket, TEST_HOST); + assertConnectedSocket(socket); + try { + SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + fail(); + } catch (SSLPeerUnverifiedException expected) { + // expected + } + HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier); + SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + socket.close(); + } + + /** + * Asserts a socket is fully connected to the expected peer. + * + *

    For the variants of createSocket which verify the remote hostname, + * {@code socket} should already be fully connected. + * + *

    For the non-verifying variants, retrieving the input stream will trigger a TLS handshake + * and so may throw an exception, for example if the peer's certificate is invalid. + * + *

    Does no hostname verification. + */ + private void assertConnectedSocket(Socket socket) throws Exception { + assertNotNull(socket); + assertTrue(socket.isConnected()); + assertNotNull(socket.getInputStream()); + assertNotNull(socket.getOutputStream()); + assertTrue(mTestSocketAddresses.contains(socket.getRemoteSocketAddress())); + } + + /** + * A HostnameVerifier which always returns false to simulate a server returning a + * certificate which does not match the expected hostname. + */ + private static class NegativeHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(String hostname, SSLSession sslSession) { + return false; + } + } +} diff --git a/tests/cts/net/src/android/net/cts/TheaterModeTest.java b/tests/cts/net/src/android/net/cts/TheaterModeTest.java new file mode 100644 index 0000000000..d1ddeaa375 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/TheaterModeTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 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 android.content.ContentResolver; +import android.content.Context; +import android.platform.test.annotations.AppModeFull; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.util.Log; + +public class TheaterModeTest extends AndroidTestCase { + private static final String TAG = "TheaterModeTest"; + private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; + private static final String FEATURE_WIFI = "android.hardware.wifi"; + private static final int TIMEOUT_MS = 10 * 1000; + private boolean mHasFeature; + private Context mContext; + private ContentResolver resolver; + + public void setup() { + mContext= getContext(); + resolver = mContext.getContentResolver(); + mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH) + || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI)); + } + + @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") + public void testTheaterMode() { + setup(); + if (!mHasFeature) { + Log.i(TAG, "The device doesn't support network bluetooth or wifi feature"); + return; + } + + for (int testCount = 0; testCount < 2; testCount++) { + if (!doOneTest()) { + fail("Theater mode failed to change in " + TIMEOUT_MS + "msec"); + return; + } + } + } + + private boolean doOneTest() { + boolean theaterModeOn = isTheaterModeOn(); + + setTheaterModeOn(!theaterModeOn); + try { + Thread.sleep(TIMEOUT_MS); + } catch (InterruptedException e) { + Log.e(TAG, "Sleep time interrupted.", e); + } + + if (theaterModeOn == isTheaterModeOn()) { + return false; + } + return true; + } + + private void setTheaterModeOn(boolean enabling) { + // Change the system setting for theater mode + Settings.Global.putInt(resolver, Settings.Global.THEATER_MODE_ON, enabling ? 1 : 0); + } + + private boolean isTheaterModeOn() { + // Read the system setting for theater mode + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0) != 0; + } +} diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java new file mode 100755 index 0000000000..37bdd44fbf --- /dev/null +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2010 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 android.net.NetworkStats; +import android.net.TrafficStats; +import android.os.Process; +import android.platform.test.annotations.AppModeFull; +import android.test.AndroidTestCase; +import android.util.Log; +import android.util.Range; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class TrafficStatsTest extends AndroidTestCase { + private static final String LOG_TAG = "TrafficStatsTest"; + + /** Verify the given value is in range [lower, upper] */ + private void assertInRange(String tag, long value, long lower, long upper) { + final Range range = new Range(lower, upper); + assertTrue(tag + ": " + value + " is not within range [" + lower + ", " + upper + "]", + range.contains(value)); + } + + public void testValidMobileStats() { + // We can't assume a mobile network is even present in this test, so + // we simply assert that a valid value is returned. + + assertTrue(TrafficStats.getMobileTxPackets() >= 0); + assertTrue(TrafficStats.getMobileRxPackets() >= 0); + assertTrue(TrafficStats.getMobileTxBytes() >= 0); + assertTrue(TrafficStats.getMobileRxBytes() >= 0); + } + + public void testValidTotalStats() { + assertTrue(TrafficStats.getTotalTxPackets() >= 0); + assertTrue(TrafficStats.getTotalRxPackets() >= 0); + assertTrue(TrafficStats.getTotalTxBytes() >= 0); + assertTrue(TrafficStats.getTotalRxBytes() >= 0); + } + + public void testValidPacketStats() { + assertTrue(TrafficStats.getTxPackets("lo") >= 0); + assertTrue(TrafficStats.getRxPackets("lo") >= 0); + } + + public void testThreadStatsTag() throws Exception { + TrafficStats.setThreadStatsTag(0xf00d); + assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xf00d); + + final CountDownLatch latch = new CountDownLatch(1); + + new Thread("TrafficStatsTest.testThreadStatsTag") { + @Override + public void run() { + assertTrue("Tag leaked", TrafficStats.getThreadStatsTag() != 0xf00d); + TrafficStats.setThreadStatsTag(0xcafe); + assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xcafe); + latch.countDown(); + } + }.start(); + + latch.await(5, TimeUnit.SECONDS); + assertTrue("Tag lost", TrafficStats.getThreadStatsTag() == 0xf00d); + + TrafficStats.clearThreadStatsTag(); + assertTrue("Tag not cleared", TrafficStats.getThreadStatsTag() != 0xf00d); + } + + long tcpPacketToIpBytes(long packetCount, long bytes) { + // ip header + tcp header + data. + // Tcp header is mostly 32. Syn has different tcp options -> 40. Don't care. + return packetCount * (20 + 32 + bytes); + } + + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testTrafficStatsForLocalhost() throws IOException { + final long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets(); + final long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets(); + final long mobileTxBytesBefore = TrafficStats.getMobileTxBytes(); + final long mobileRxBytesBefore = TrafficStats.getMobileRxBytes(); + final long totalTxPacketsBefore = TrafficStats.getTotalTxPackets(); + final long totalRxPacketsBefore = TrafficStats.getTotalRxPackets(); + final long totalTxBytesBefore = TrafficStats.getTotalTxBytes(); + final long totalRxBytesBefore = TrafficStats.getTotalRxBytes(); + final long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid()); + final long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); + final long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid()); + final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid()); + final long ifaceTxPacketsBefore = TrafficStats.getTxPackets("lo"); + final long ifaceRxPacketsBefore = TrafficStats.getRxPackets("lo"); + + // Transfer 1MB of data across an explicitly localhost socket. + final int byteCount = 1024; + final int packetCount = 1024; + + TrafficStats.startDataProfiling(null); + final ServerSocket server = new ServerSocket(0); + new Thread("TrafficStatsTest.testTrafficStatsForLocalhost") { + @Override + public void run() { + try { + final Socket socket = new Socket("localhost", server.getLocalPort()); + // Make sure that each write()+flush() turns into a packet: + // disable Nagle. + socket.setTcpNoDelay(true); + final OutputStream out = socket.getOutputStream(); + final byte[] buf = new byte[byteCount]; + TrafficStats.setThreadStatsTag(0x42); + TrafficStats.tagSocket(socket); + for (int i = 0; i < packetCount; i++) { + out.write(buf); + out.flush(); + try { + // Bug: 10668088, Even with Nagle disabled, and flushing the 1024 bytes + // the kernel still regroups data into a larger packet. + Thread.sleep(5); + } catch (InterruptedException e) { + } + } + out.close(); + socket.close(); + } catch (IOException e) { + Log.i(LOG_TAG, "Badness during writes to socket: " + e); + } + } + }.start(); + + int read = 0; + try { + final Socket socket = server.accept(); + socket.setTcpNoDelay(true); + TrafficStats.setThreadStatsTag(0x43); + TrafficStats.tagSocket(socket); + final InputStream in = socket.getInputStream(); + final byte[] buf = new byte[byteCount]; + while (read < byteCount * packetCount) { + int n = in.read(buf); + assertTrue("Unexpected EOF", n > 0); + read += n; + } + } finally { + server.close(); + } + assertTrue("Not all data read back", read >= byteCount * packetCount); + + // It's too fast to call getUidTxBytes function. + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + final NetworkStats testStats = TrafficStats.stopDataProfiling(null); + + final long mobileTxPacketsAfter = TrafficStats.getMobileTxPackets(); + final long mobileRxPacketsAfter = TrafficStats.getMobileRxPackets(); + final long mobileTxBytesAfter = TrafficStats.getMobileTxBytes(); + final long mobileRxBytesAfter = TrafficStats.getMobileRxBytes(); + final long totalTxPacketsAfter = TrafficStats.getTotalTxPackets(); + final long totalRxPacketsAfter = TrafficStats.getTotalRxPackets(); + final long totalTxBytesAfter = TrafficStats.getTotalTxBytes(); + final long totalRxBytesAfter = TrafficStats.getTotalRxBytes(); + final long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid()); + final long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid()); + final long uidTxPacketsAfter = TrafficStats.getUidTxPackets(Process.myUid()); + final long uidRxPacketsAfter = TrafficStats.getUidRxPackets(Process.myUid()); + final long uidTxDeltaBytes = uidTxBytesAfter - uidTxBytesBefore; + final long uidTxDeltaPackets = uidTxPacketsAfter - uidTxPacketsBefore; + final long uidRxDeltaBytes = uidRxBytesAfter - uidRxBytesBefore; + final long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore; + final long ifaceTxPacketsAfter = TrafficStats.getTxPackets("lo"); + final long ifaceRxPacketsAfter = TrafficStats.getRxPackets("lo"); + final long ifaceTxDeltaPackets = ifaceTxPacketsAfter - ifaceTxPacketsBefore; + final long ifaceRxDeltaPackets = ifaceRxPacketsAfter - ifaceRxPacketsBefore; + + // Localhost traffic *does* count against per-UID stats. + /* + * Calculations: + * - bytes + * bytes is approx: packets * data + packets * acks; + * but sometimes there are less acks than packets, so we set a lower + * limit of 1 ack. + * - setup/teardown + * + 7 approx.: syn, syn-ack, ack, fin-ack, ack, fin-ack, ack; + * but sometimes the last find-acks just vanish, so we set a lower limit of +5. + */ + final int maxExpectedExtraPackets = 7; + final int minExpectedExtraPackets = 5; + + // Some other tests don't cleanup connections correctly. + // They have the same UID, so we discount their lingering traffic + // which happens only on non-localhost, such as TCP FIN retranmission packets + final long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore) + - uidTxDeltaPackets; + final long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) + - uidRxDeltaPackets; + if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { + Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + + deltaRxOtherPackets); + } + + // Check that the per-uid stats obtained from data profiling contain the expected values. + // The data profiling snapshot is generated from the readNetworkStatsDetail() method in + // networkStatsService, so it's possible to verify that the detailed stats for a given + // uid are correct. + final NetworkStats.Entry entry = testStats.getTotal(null, Process.myUid()); + final long pktBytes = tcpPacketToIpBytes(packetCount, byteCount); + final long pktWithNoDataBytes = tcpPacketToIpBytes(packetCount, 0); + final long minExpExtraPktBytes = tcpPacketToIpBytes(minExpectedExtraPackets, 0); + final long maxExpExtraPktBytes = tcpPacketToIpBytes(maxExpectedExtraPackets, 0); + final long deltaTxOtherPktBytes = tcpPacketToIpBytes(deltaTxOtherPackets, 0); + final long deltaRxOtherPktBytes = tcpPacketToIpBytes(deltaRxOtherPackets, 0); + assertInRange("txPackets detail", entry.txPackets, packetCount + minExpectedExtraPackets, + uidTxDeltaPackets); + assertInRange("rxPackets detail", entry.rxPackets, packetCount + minExpectedExtraPackets, + uidRxDeltaPackets); + assertInRange("txBytes detail", entry.txBytes, pktBytes + minExpExtraPktBytes, + uidTxDeltaBytes); + assertInRange("rxBytes detail", entry.rxBytes, pktBytes + minExpExtraPktBytes, + uidRxDeltaBytes); + assertInRange("uidtxp", uidTxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); + assertInRange("uidrxp", uidRxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); + assertInRange("uidtxb", uidTxDeltaBytes, pktBytes + minExpExtraPktBytes, + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaTxOtherPktBytes); + assertInRange("uidrxb", uidRxDeltaBytes, pktBytes + minExpExtraPktBytes, + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaRxOtherPktBytes); + assertInRange("iftxp", ifaceTxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); + assertInRange("ifrxp", ifaceRxDeltaPackets, packetCount + minExpectedExtraPackets, + packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); + + // Localhost traffic *does* count against total stats. + // Check the total stats increased after test data transfer over localhost has been made. + assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, + totalTxPacketsAfter >= totalTxPacketsBefore + uidTxDeltaPackets); + assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, + totalRxPacketsAfter >= totalRxPacketsBefore + uidRxDeltaPackets); + assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, + totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes); + assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, + totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes); + assertTrue("iftxp: " + ifaceTxPacketsBefore + " -> " + ifaceTxPacketsAfter, + totalTxPacketsAfter >= totalTxPacketsBefore + ifaceTxDeltaPackets); + assertTrue("ifrxp: " + ifaceRxPacketsBefore + " -> " + ifaceRxPacketsAfter, + totalRxPacketsAfter >= totalRxPacketsBefore + ifaceRxDeltaPackets); + + // Localhost traffic should *not* count against mobile stats, + // There might be some other traffic, but nowhere near 1MB. + assertInRange("mtxp", mobileTxPacketsAfter, mobileTxPacketsBefore, + mobileTxPacketsBefore + 500); + assertInRange("mrxp", mobileRxPacketsAfter, mobileRxPacketsBefore, + mobileRxPacketsBefore + 500); + assertInRange("mtxb", mobileTxBytesAfter, mobileTxBytesBefore, + mobileTxBytesBefore + 200000); + assertInRange("mrxb", mobileRxBytesAfter, mobileRxBytesBefore, + mobileRxBytesBefore + 200000); + } +} diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java new file mode 100644 index 0000000000..adaba9d398 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2018 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.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.IPPROTO_ESP; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.system.OsConstants.IPPROTO_UDP; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.os.ParcelFileDescriptor; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +public class TunUtils { + private static final String TAG = TunUtils.class.getSimpleName(); + + protected static final int IP4_ADDR_OFFSET = 12; + protected static final int IP4_ADDR_LEN = 4; + protected static final int IP6_ADDR_OFFSET = 8; + protected static final int IP6_ADDR_LEN = 16; + protected static final int IP4_PROTO_OFFSET = 9; + protected static final int IP6_PROTO_OFFSET = 6; + + private static final int DATA_BUFFER_LEN = 4096; + private static final int TIMEOUT = 1000; + + private final List mPackets = new ArrayList<>(); + private final ParcelFileDescriptor mTunFd; + private final Thread mReaderThread; + + public TunUtils(ParcelFileDescriptor tunFd) { + mTunFd = tunFd; + + // Start background reader thread + mReaderThread = + new Thread( + () -> { + try { + // Loop will exit and thread will quit when tunFd is closed. + // Receiving either EOF or an exception will exit this reader loop. + // FileInputStream in uninterruptable, so there's no good way to + // ensure that this thread shuts down except upon FD closure. + while (true) { + byte[] intercepted = receiveFromTun(); + if (intercepted == null) { + // Exit once we've hit EOF + return; + } else if (intercepted.length > 0) { + // Only save packet if we've received any bytes. + synchronized (mPackets) { + mPackets.add(intercepted); + mPackets.notifyAll(); + } + } + } + } catch (IOException ignored) { + // Simply exit this reader thread + return; + } + }); + mReaderThread.start(); + } + + private byte[] receiveFromTun() throws IOException { + FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor()); + byte[] inBytes = new byte[DATA_BUFFER_LEN]; + int bytesRead = in.read(inBytes); + + if (bytesRead < 0) { + return null; // return null for EOF + } else if (bytesRead >= DATA_BUFFER_LEN) { + throw new IllegalStateException("Too big packet. Fragmentation unsupported"); + } + return Arrays.copyOf(inBytes, bytesRead); + } + + private byte[] getFirstMatchingPacket(Predicate verifier, int startIndex) { + synchronized (mPackets) { + for (int i = startIndex; i < mPackets.size(); i++) { + byte[] pkt = mPackets.get(i); + if (verifier.test(pkt)) { + return pkt; + } + } + } + return null; + } + + protected byte[] awaitPacket(Predicate verifier) throws Exception { + long endTime = System.currentTimeMillis() + TIMEOUT; + int startIndex = 0; + + synchronized (mPackets) { + while (System.currentTimeMillis() < endTime) { + final byte[] pkt = getFirstMatchingPacket(verifier, startIndex); + if (pkt != null) { + return pkt; // We've found the packet we're looking for. + } + + startIndex = mPackets.size(); + + // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout + long waitTimeout = endTime - System.currentTimeMillis(); + if (waitTimeout > 0) { + mPackets.wait(waitTimeout); + } + } + } + + fail("No packet found matching verifier"); + throw new IllegalStateException("Impossible condition; should have thrown in fail()"); + } + + public byte[] awaitEspPacketNoPlaintext( + int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + final byte[] espPkt = awaitPacket( + (pkt) -> isEspFailIfSpecifiedPlaintextFound(pkt, spi, useEncap, plaintext)); + + // Validate packet size + assertEquals(expectedPacketSize, espPkt.length); + + return espPkt; // We've found the packet we're looking for. + } + + private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { + // Check SPI byte by byte. + return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) + && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) + && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) + && pkt[espOffset + 3] == (byte) (spi & 0xff); + } + + /** + * Variant of isEsp that also fails the test if the provided plaintext is found + * + * @param pkt the packet bytes to verify + * @param spi the expected SPI to look for + * @param encap whether encap was enabled, and the packet has a UDP header + * @param plaintext the plaintext packet before outbound encryption, which MUST not appear in + * the provided packet. + */ + private static boolean isEspFailIfSpecifiedPlaintextFound( + byte[] pkt, int spi, boolean encap, byte[] plaintext) { + if (Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) != -1) { + fail("Banned plaintext packet found"); + } + + return isEsp(pkt, spi, encap); + } + + private static boolean isEsp(byte[] pkt, int spi, boolean encap) { + if (isIpv6(pkt)) { + // IPv6 UDP encap not supported by kernels; assume non-encap. + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); + } else { + // Use default IPv4 header length (assuming no options) + if (encap) { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP + && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi); + } else { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi); + } + } + } + + public static boolean isIpv6(byte[] pkt) { + // First nibble shows IP version. 0x60 for IPv6 + return (pkt[0] & (byte) 0xF0) == (byte) 0x60; + } + + private static byte[] getReflectedPacket(byte[] pkt) { + byte[] reflected = Arrays.copyOf(pkt, pkt.length); + + if (isIpv6(pkt)) { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset + reflected, // dst + IP6_ADDR_OFFSET, // dst offset + IP6_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET, // src offset + reflected, // dst + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset + IP6_ADDR_LEN); // len + } else { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset + reflected, // dst + IP4_ADDR_OFFSET, // dst offset + IP4_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET, // src offset + reflected, // dst + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset + IP4_ADDR_LEN); // len + } + return reflected; + } + + /** Takes all captured packets, flips the src/dst, and re-injects them. */ + public void reflectPackets() throws IOException { + synchronized (mPackets) { + for (byte[] pkt : mPackets) { + injectPacket(getReflectedPacket(pkt)); + } + } + } + + public void injectPacket(byte[] pkt) throws IOException { + FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor()); + out.write(pkt); + out.flush(); + } + + /** Resets the intercepted packets. */ + public void reset() throws IOException { + synchronized (mPackets) { + mPackets.clear(); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/UriTest.java b/tests/cts/net/src/android/net/cts/UriTest.java new file mode 100644 index 0000000000..40b8fb7259 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UriTest.java @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2008 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 android.content.ContentUris; +import android.net.Uri; +import android.os.Parcel; +import android.test.AndroidTestCase; +import java.io.File; +import java.util.Arrays; +import java.util.ArrayList; + +public class UriTest extends AndroidTestCase { + public void testParcelling() { + parcelAndUnparcel(Uri.parse("foo:bob%20lee")); + parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment")); + parcelAndUnparcel(new Uri.Builder() + .scheme("http") + .authority("crazybob.org") + .path("/rss/") + .encodedQuery("a=b") + .fragment("foo") + .build()); + } + + private void parcelAndUnparcel(Uri u) { + Parcel p = Parcel.obtain(); + Uri.writeToParcel(p, u); + p.setDataPosition(0); + assertEquals(u, Uri.CREATOR.createFromParcel(p)); + + p.setDataPosition(0); + u = u.buildUpon().build(); + Uri.writeToParcel(p, u); + p.setDataPosition(0); + assertEquals(u, Uri.CREATOR.createFromParcel(p)); + } + + public void testBuildUpon() { + Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build(); + assertEquals("robert", u.getScheme()); + assertEquals("lee", u.getEncodedSchemeSpecificPart()); + assertEquals("lee", u.getSchemeSpecificPart()); + assertNull(u.getQuery()); + assertNull(u.getPath()); + assertNull(u.getAuthority()); + assertNull(u.getHost()); + + Uri a = Uri.fromParts("foo", "bar", "tee"); + Uri b = a.buildUpon().fragment("new").build(); + assertEquals("new", b.getFragment()); + assertEquals("bar", b.getSchemeSpecificPart()); + assertEquals("foo", b.getScheme()); + a = new Uri.Builder() + .scheme("foo") + .encodedOpaquePart("bar") + .fragment("tee") + .build(); + b = a.buildUpon().fragment("new").build(); + assertEquals("new", b.getFragment()); + assertEquals("bar", b.getSchemeSpecificPart()); + assertEquals("foo", b.getScheme()); + + a = Uri.fromParts("scheme", "[2001:db8::dead:e1f]/foo", "bar"); + b = a.buildUpon().fragment("qux").build(); + assertEquals("qux", b.getFragment()); + assertEquals("[2001:db8::dead:e1f]/foo", b.getSchemeSpecificPart()); + assertEquals("scheme", b.getScheme()); + } + + public void testStringUri() { + assertEquals("bob lee", + Uri.parse("foo:bob%20lee").getSchemeSpecificPart()); + assertEquals("bob%20lee", + Uri.parse("foo:bob%20lee").getEncodedSchemeSpecificPart()); + + assertEquals("/bob%20lee", + Uri.parse("foo:/bob%20lee").getEncodedPath()); + assertNull(Uri.parse("foo:bob%20lee").getPath()); + + assertEquals("bob%20lee", + Uri.parse("foo:?bob%20lee").getEncodedQuery()); + assertNull(Uri.parse("foo:bob%20lee").getEncodedQuery()); + assertNull(Uri.parse("foo:bar#?bob%20lee").getQuery()); + + assertEquals("bob%20lee", + Uri.parse("foo:#bob%20lee").getEncodedFragment()); + + Uri uri = Uri.parse("http://localhost:42"); + assertEquals("localhost", uri.getHost()); + assertEquals(42, uri.getPort()); + + uri = Uri.parse("http://bob@localhost:42"); + assertEquals("bob", uri.getUserInfo()); + assertEquals("localhost", uri.getHost()); + assertEquals(42, uri.getPort()); + + uri = Uri.parse("http://bob%20lee@localhost:42"); + assertEquals("bob lee", uri.getUserInfo()); + assertEquals("bob%20lee", uri.getEncodedUserInfo()); + + uri = Uri.parse("http://localhost"); + assertEquals("localhost", uri.getHost()); + assertEquals(-1, uri.getPort()); + + uri = Uri.parse("http://a:a@example.com:a@example2.com/path"); + assertEquals("a:a@example.com:a@example2.com", uri.getAuthority()); + assertEquals("example2.com", uri.getHost()); + assertEquals(-1, uri.getPort()); + assertEquals("/path", uri.getPath()); + + uri = Uri.parse("http://a.foo.com\\.example.com/path"); + assertEquals("a.foo.com", uri.getHost()); + assertEquals(-1, uri.getPort()); + assertEquals("\\.example.com/path", uri.getPath()); + + uri = Uri.parse("https://[2001:db8::dead:e1f]/foo"); + assertEquals("[2001:db8::dead:e1f]", uri.getAuthority()); + assertNull(uri.getUserInfo()); + assertEquals("[2001:db8::dead:e1f]", uri.getHost()); + assertEquals(-1, uri.getPort()); + assertEquals("/foo", uri.getPath()); + assertEquals(null, uri.getFragment()); + assertEquals("//[2001:db8::dead:e1f]/foo", uri.getSchemeSpecificPart()); + + uri = Uri.parse("https://[2001:db8::dead:e1f]/#foo"); + assertEquals("[2001:db8::dead:e1f]", uri.getAuthority()); + assertNull(uri.getUserInfo()); + assertEquals("[2001:db8::dead:e1f]", uri.getHost()); + assertEquals(-1, uri.getPort()); + assertEquals("/", uri.getPath()); + assertEquals("foo", uri.getFragment()); + assertEquals("//[2001:db8::dead:e1f]/", uri.getSchemeSpecificPart()); + + uri = Uri.parse( + "https://some:user@[2001:db8::dead:e1f]:1234/foo?corge=thud&corge=garp#bar"); + assertEquals("some:user@[2001:db8::dead:e1f]:1234", uri.getAuthority()); + assertEquals("some:user", uri.getUserInfo()); + assertEquals("[2001:db8::dead:e1f]", uri.getHost()); + assertEquals(1234, uri.getPort()); + assertEquals("/foo", uri.getPath()); + assertEquals("bar", uri.getFragment()); + assertEquals("//some:user@[2001:db8::dead:e1f]:1234/foo?corge=thud&corge=garp", + uri.getSchemeSpecificPart()); + assertEquals("corge=thud&corge=garp", uri.getQuery()); + assertEquals("thud", uri.getQueryParameter("corge")); + assertEquals(Arrays.asList("thud", "garp"), uri.getQueryParameters("corge")); + } + + public void testCompareTo() { + Uri a = Uri.parse("foo:a"); + Uri b = Uri.parse("foo:b"); + Uri b2 = Uri.parse("foo:b"); + + assertTrue(a.compareTo(b) < 0); + assertTrue(b.compareTo(a) > 0); + assertEquals(0, b.compareTo(b2)); + } + + public void testEqualsAndHashCode() { + Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee"); + + Uri b = new Uri.Builder() + .scheme("http") + .authority("crazybob.org") + .path("/test/") + .encodedQuery("foo=bar") + .fragment("tee") + .build(); + + // Try alternate builder methods. + Uri c = new Uri.Builder() + .scheme("http") + .encodedAuthority("crazybob.org") + .encodedPath("/test/") + .encodedQuery("foo=bar") + .encodedFragment("tee") + .build(); + + assertFalse(Uri.EMPTY.equals(null)); + assertEquals(a, b); + assertEquals(b, c); + assertEquals(c, a); + assertEquals(a.hashCode(), b.hashCode()); + assertEquals(b.hashCode(), c.hashCode()); + } + + public void testEncodeAndDecode() { + String encoded = Uri.encode("Bob:/", "/"); + assertEquals(-1, encoded.indexOf(':')); + assertTrue(encoded.indexOf('/') > -1); + assertEncodeDecodeRoundtripExact(null); + assertEncodeDecodeRoundtripExact(""); + assertEncodeDecodeRoundtripExact("Bob"); + assertEncodeDecodeRoundtripExact(":Bob"); + assertEncodeDecodeRoundtripExact("::Bob"); + assertEncodeDecodeRoundtripExact("Bob::Lee"); + assertEncodeDecodeRoundtripExact("Bob:Lee"); + assertEncodeDecodeRoundtripExact("Bob::"); + assertEncodeDecodeRoundtripExact("Bob:"); + assertEncodeDecodeRoundtripExact("::Bob::"); + assertEncodeDecodeRoundtripExact("https:/some:user@[2001:db8::dead:e1f]:1234/foo#bar"); + } + + private static void assertEncodeDecodeRoundtripExact(String s) { + assertEquals(s, Uri.decode(Uri.encode(s, null))); + } + + public void testDecode_emptyString_returnsEmptyString() { + assertEquals("", Uri.decode("")); + } + + public void testDecode_null_returnsNull() { + assertNull(Uri.decode(null)); + } + + public void testDecode_wrongHexDigit() { + // %p in the end. + assertEquals("ab/$\u0102%\u0840\uFFFD\u0000", Uri.decode("ab%2f$%C4%82%25%e0%a1%80%p")); + } + + public void testDecode_secondHexDigitWrong() { + // %1p in the end. + assertEquals("ab/$\u0102%\u0840\uFFFD\u0001", Uri.decode("ab%2f$%c4%82%25%e0%a1%80%1p")); + } + + public void testDecode_endsWithPercent_appendsUnknownCharacter() { + // % in the end. + assertEquals("ab/$\u0102%\u0840\uFFFD", Uri.decode("ab%2f$%c4%82%25%e0%a1%80%")); + } + + public void testDecode_plusNotConverted() { + assertEquals("ab/$\u0102%+\u0840", Uri.decode("ab%2f$%c4%82%25+%e0%a1%80")); + } + + // Last character needs decoding (make sure we are flushing the buffer with chars to decode). + public void testDecode_lastCharacter() { + assertEquals("ab/$\u0102%\u0840", Uri.decode("ab%2f$%c4%82%25%e0%a1%80")); + } + + // Check that a second row of encoded characters is decoded properly (internal buffers are + // reset properly). + public void testDecode_secondRowOfEncoded() { + assertEquals("ab/$\u0102%\u0840aa\u0840", + Uri.decode("ab%2f$%c4%82%25%e0%a1%80aa%e0%a1%80")); + } + + public void testFromFile() { + File f = new File("/tmp/bob"); + Uri uri = Uri.fromFile(f); + assertEquals("file:///tmp/bob", uri.toString()); + try { + Uri.fromFile(null); + fail("testFile fail"); + } catch (NullPointerException e) {} + } + + public void testQueryParameters() { + Uri uri = Uri.parse("content://user"); + assertEquals(null, uri.getQueryParameter("a")); + + uri = uri.buildUpon().appendQueryParameter("a", "b").build(); + assertEquals("b", uri.getQueryParameter("a")); + + uri = uri.buildUpon().appendQueryParameter("a", "b2").build(); + assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a")); + + uri = uri.buildUpon().appendQueryParameter("c", "d").build(); + assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a")); + assertEquals("d", uri.getQueryParameter("c")); + } + + public void testPathOperations() { + Uri uri = Uri.parse("content://user/a/b"); + + assertEquals(2, uri.getPathSegments().size()); + assertEquals("a", uri.getPathSegments().get(0)); + assertEquals("b", uri.getPathSegments().get(1)); + assertEquals("b", uri.getLastPathSegment()); + + Uri first = uri; + uri = uri.buildUpon().appendPath("c").build(); + assertEquals(3, uri.getPathSegments().size()); + assertEquals("c", uri.getPathSegments().get(2)); + assertEquals("c", uri.getLastPathSegment()); + assertEquals("content://user/a/b/c", uri.toString()); + + uri = ContentUris.withAppendedId(uri, 100); + assertEquals(4, uri.getPathSegments().size()); + assertEquals("100", uri.getPathSegments().get(3)); + assertEquals("100", uri.getLastPathSegment()); + assertEquals(100, ContentUris.parseId(uri)); + assertEquals("content://user/a/b/c/100", uri.toString()); + + // Make sure the original URI is still intact. + assertEquals(2, first.getPathSegments().size()); + assertEquals("b", first.getLastPathSegment()); + + try { + first.getPathSegments().get(2); + fail("test path operations"); + } catch (IndexOutOfBoundsException e) {} + + assertEquals(null, Uri.EMPTY.getLastPathSegment()); + + Uri withC = Uri.parse("foo:/a/b/").buildUpon().appendPath("c").build(); + assertEquals("/a/b/c", withC.getPath()); + } + + public void testOpaqueUri() { + Uri uri = Uri.parse("mailto:nobody"); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + + uri = Uri.fromParts("mailto", "nobody", null); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + + uri = new Uri.Builder() + .scheme("mailto") + .opaquePart("nobody") + .build(); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + } + + private void testOpaqueUri(Uri uri) { + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getSchemeSpecificPart()); + assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); + + assertNull(uri.getFragment()); + assertTrue(uri.isAbsolute()); + assertTrue(uri.isOpaque()); + assertFalse(uri.isRelative()); + assertFalse(uri.isHierarchical()); + + assertNull(uri.getAuthority()); + assertNull(uri.getEncodedAuthority()); + assertNull(uri.getPath()); + assertNull(uri.getEncodedPath()); + assertNull(uri.getUserInfo()); + assertNull(uri.getEncodedUserInfo()); + assertNull(uri.getQuery()); + assertNull(uri.getEncodedQuery()); + assertNull(uri.getHost()); + assertEquals(-1, uri.getPort()); + + assertTrue(uri.getPathSegments().isEmpty()); + assertNull(uri.getLastPathSegment()); + + assertEquals("mailto:nobody", uri.toString()); + + Uri withFragment = uri.buildUpon().fragment("top").build(); + assertEquals("mailto:nobody#top", withFragment.toString()); + } + + public void testHierarchicalUris() { + testHierarchical("http", "google.com", "/p1/p2", "query", "fragment"); + testHierarchical("file", null, "/p1/p2", null, null); + testHierarchical("content", "contact", "/p1/p2", null, null); + testHierarchical("http", "google.com", "/p1/p2", null, "fragment"); + testHierarchical("http", "google.com", "", null, "fragment"); + testHierarchical("http", "google.com", "", "query", "fragment"); + testHierarchical("http", "google.com", "", "query", null); + testHierarchical("http", null, "/", "query", null); + } + + private static void testHierarchical(String scheme, String authority, + String path, String query, String fragment) { + StringBuilder sb = new StringBuilder(); + + if (authority != null) { + sb.append("//").append(authority); + } + if (path != null) { + sb.append(path); + } + if (query != null) { + sb.append('?').append(query); + } + + String ssp = sb.toString(); + + if (scheme != null) { + sb.insert(0, scheme + ":"); + } + if (fragment != null) { + sb.append('#').append(fragment); + } + + String uriString = sb.toString(); + + Uri uri = Uri.parse(uriString); + + // Run these twice to test caching. + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + + // Test rebuilt version. + uri = uri.buildUpon().build(); + + // Run these twice to test caching. + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + + // The decoded and encoded versions of the inputs are all the same. + // We'll test the actual encoding decoding separately. + + // Test building with encoded versions. + Uri built = new Uri.Builder() + .scheme(scheme) + .encodedAuthority(authority) + .encodedPath(path) + .encodedQuery(query) + .encodedFragment(fragment) + .build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + + // Test building with decoded versions. + built = new Uri.Builder() + .scheme(scheme) + .authority(authority) + .path(path) + .query(query) + .fragment(fragment) + .build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + + // Rebuild. + built = built.buildUpon().build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + } + + private static void compareHierarchical(String uriString, String ssp, + Uri uri, + String scheme, String authority, String path, String query, + String fragment) { + assertEquals(scheme, uri.getScheme()); + assertEquals(authority, uri.getAuthority()); + assertEquals(authority, uri.getEncodedAuthority()); + assertEquals(path, uri.getPath()); + assertEquals(path, uri.getEncodedPath()); + assertEquals(query, uri.getQuery()); + assertEquals(query, uri.getEncodedQuery()); + assertEquals(fragment, uri.getFragment()); + assertEquals(fragment, uri.getEncodedFragment()); + assertEquals(ssp, uri.getSchemeSpecificPart()); + + if (scheme != null) { + assertTrue(uri.isAbsolute()); + assertFalse(uri.isRelative()); + } else { + assertFalse(uri.isAbsolute()); + assertTrue(uri.isRelative()); + } + + assertFalse(uri.isOpaque()); + assertTrue(uri.isHierarchical()); + assertEquals(uriString, uri.toString()); + } + + public void testNormalizeScheme() { + assertEquals(Uri.parse(""), Uri.parse("").normalizeScheme()); + assertEquals(Uri.parse("http://www.android.com"), + Uri.parse("http://www.android.com").normalizeScheme()); + assertEquals(Uri.parse("http://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c"), + Uri.parse("HTTP://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c") + .normalizeScheme()); + } + + public void testToSafeString_tel() { + checkToSafeString("tel:xxxxxx", "tel:Google"); + checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890"); + checkToSafeString("tEl:xxx.xxx-xxxx", "tEl:123.456-7890"); + } + + public void testToSafeString_sip() { + checkToSafeString("sip:xxxxxxx@xxxxxxx.xxxxxxxx", "sip:android@android.com:1234"); + checkToSafeString("sIp:xxxxxxx@xxxxxxx.xxx", "sIp:android@android.com"); + } + + public void testToSafeString_sms() { + checkToSafeString("sms:xxxxxx", "sms:123abc"); + checkToSafeString("smS:xxx.xxx-xxxx", "smS:123.456-7890"); + } + + public void testToSafeString_smsto() { + checkToSafeString("smsto:xxxxxx", "smsto:123abc"); + checkToSafeString("SMSTo:xxx.xxx-xxxx", "SMSTo:123.456-7890"); + } + + public void testToSafeString_mailto() { + checkToSafeString("mailto:xxxxxxx@xxxxxxx.xxx", "mailto:android@android.com"); + checkToSafeString("Mailto:xxxxxxx@xxxxxxx.xxxxxxxxxx", + "Mailto:android@android.com/secret"); + } + + public void testToSafeString_nfc() { + checkToSafeString("nfc:xxxxxx", "nfc:123abc"); + checkToSafeString("nfc:xxx.xxx-xxxx", "nfc:123.456-7890"); + checkToSafeString("nfc:xxxxxxx@xxxxxxx.xxx", "nfc:android@android.com"); + } + + public void testToSafeString_http() { + checkToSafeString("http://www.android.com/...", "http://www.android.com"); + checkToSafeString("HTTP://www.android.com/...", "HTTP://www.android.com"); + checkToSafeString("http://www.android.com/...", "http://www.android.com/"); + checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param"); + checkToSafeString("http://www.android.com/...", + "http://user:pwd@www.android.com/secretUrl?param"); + checkToSafeString("http://www.android.com/...", + "http://user@www.android.com/secretUrl?param"); + checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param"); + checkToSafeString("http:///...", "http:///path?param"); + checkToSafeString("http:///...", "http://"); + checkToSafeString("http://:12345/...", "http://:12345/"); + } + + public void testToSafeString_https() { + checkToSafeString("https://www.android.com/...", "https://www.android.com/secretUrl?param"); + checkToSafeString("https://www.android.com:8443/...", + "https://user:pwd@www.android.com:8443/secretUrl?param"); + checkToSafeString("https://www.android.com/...", "https://user:pwd@www.android.com"); + checkToSafeString("Https://www.android.com/...", "Https://user:pwd@www.android.com"); + } + + public void testToSafeString_ftp() { + checkToSafeString("ftp://ftp.android.com/...", "ftp://ftp.android.com/"); + checkToSafeString("ftP://ftp.android.com/...", "ftP://anonymous@ftp.android.com/"); + checkToSafeString("ftp://ftp.android.com:2121/...", + "ftp://root:love@ftp.android.com:2121/"); + } + + public void testToSafeString_rtsp() { + checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/"); + checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/video.mov"); + checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/video.mov?param"); + checkToSafeString("RtsP://rtsp.android.com/...", "RtsP://anonymous@rtsp.android.com/"); + checkToSafeString("rtsp://rtsp.android.com:2121/...", + "rtsp://username:password@rtsp.android.com:2121/"); + } + + public void testToSafeString_notSupport() { + checkToSafeString("unsupported://ajkakjah/askdha/secret?secret", + "unsupported://ajkakjah/askdha/secret?secret"); + checkToSafeString("unsupported:ajkakjah/askdha/secret?secret", + "unsupported:ajkakjah/askdha/secret?secret"); + } + + private void checkToSafeString(String expectedSafeString, String original) { + assertEquals(expectedSafeString, Uri.parse(original).toSafeString()); + } +} diff --git a/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java new file mode 100644 index 0000000000..4088d822cf --- /dev/null +++ b/tests/cts/net/src/android/net/cts/Uri_BuilderTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 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 junit.framework.TestCase; +import android.net.Uri.Builder; +import android.net.Uri; + +public class Uri_BuilderTest extends TestCase { + public void testBuilderOperations() { + Uri uri = Uri.parse("http://google.com/p1?query#fragment"); + Builder builder = uri.buildUpon(); + uri = builder.appendPath("p2").build(); + assertEquals("http", uri.getScheme()); + assertEquals("google.com", uri.getAuthority()); + assertEquals("/p1/p2", uri.getPath()); + assertEquals("query", uri.getQuery()); + assertEquals("fragment", uri.getFragment()); + assertEquals(uri.toString(), builder.toString()); + + uri = Uri.parse("mailto:nobody"); + builder = uri.buildUpon(); + uri = builder.build(); + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getSchemeSpecificPart()); + assertEquals(uri.toString(), builder.toString()); + + uri = new Uri.Builder() + .scheme("http") + .encodedAuthority("google.com") + .encodedPath("/p1") + .appendEncodedPath("p2") + .encodedQuery("query") + .appendQueryParameter("query2", null) + .encodedFragment("fragment") + .build(); + assertEquals("http", uri.getScheme()); + assertEquals("google.com", uri.getEncodedAuthority()); + assertEquals("/p1/p2", uri.getEncodedPath()); + assertEquals("query&query2=null", uri.getEncodedQuery()); + assertEquals("fragment", uri.getEncodedFragment()); + + uri = new Uri.Builder() + .scheme("mailto") + .encodedOpaquePart("nobody") + .build(); + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); + } +} diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java new file mode 100644 index 0000000000..5a70928e37 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2009 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.net.UrlQuerySanitizer.ParameterValuePair; +import android.net.UrlQuerySanitizer.ValueSanitizer; +import android.os.Build; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; +import java.util.Set; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class UrlQuerySanitizerTest { + @Rule + public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); + + private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; + + // URL for test. + private static final String TEST_URL = "http://example.com/?name=Joe+User&age=20&height=175"; + + // Default sanitizer's change when "+". + private static final String EXPECTED_UNDERLINE_NAME = "Joe_User"; + + // IllegalCharacterValueSanitizer sanitizer's change when "+". + private static final String EXPECTED_SPACE_NAME = "Joe User"; + private static final String EXPECTED_AGE = "20"; + private static final String EXPECTED_HEIGHT = "175"; + private static final String NAME = "name"; + private static final String AGE = "age"; + private static final String HEIGHT = "height"; + + @Test + public void testUrlQuerySanitizer() { + MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer(); + assertFalse(uqs.getAllowUnregisteredParamaters()); + + final String query = "book=thinking in java&price=108"; + final String book = "book"; + final String bookName = "thinking in java"; + final String price = "price"; + final String bookPrice = "108"; + final String notExistPar = "notExistParameter"; + uqs.registerParameters(new String[]{book, price}, UrlQuerySanitizer.getSpaceLegal()); + uqs.parseQuery(query); + assertTrue(uqs.hasParameter(book)); + assertTrue(uqs.hasParameter(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertEquals(bookName, uqs.getValue(book)); + assertEquals(bookPrice, uqs.getValue(price)); + assertNull(uqs.getValue(notExistPar)); + uqs.clear(); + assertFalse(uqs.hasParameter(book)); + assertFalse(uqs.hasParameter(price)); + + uqs.parseEntry(book, bookName); + assertTrue(uqs.hasParameter(book)); + assertEquals(bookName, uqs.getValue(book)); + uqs.parseEntry(price, bookPrice); + assertTrue(uqs.hasParameter(price)); + assertEquals(bookPrice, uqs.getValue(price)); + assertFalse(uqs.hasParameter(notExistPar)); + assertNull(uqs.getValue(notExistPar)); + + uqs = new MockUrlQuerySanitizer(TEST_URL); + assertTrue(uqs.getAllowUnregisteredParamaters()); + + assertTrue(uqs.hasParameter(NAME)); + assertTrue(uqs.hasParameter(AGE)); + assertTrue(uqs.hasParameter(HEIGHT)); + assertFalse(uqs.hasParameter(notExistPar)); + + assertEquals(EXPECTED_UNDERLINE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertEquals(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + assertNull(uqs.getValue(notExistPar)); + + final int ContainerLen = 3; + Set urlSet = uqs.getParameterSet(); + assertEquals(ContainerLen, urlSet.size()); + assertTrue(urlSet.contains(NAME)); + assertTrue(urlSet.contains(AGE)); + assertTrue(urlSet.contains(HEIGHT)); + assertFalse(urlSet.contains(notExistPar)); + + List urlList = uqs.getParameterList(); + assertEquals(ContainerLen, urlList.size()); + ParameterValuePair pvp = urlList.get(0); + assertEquals(NAME, pvp.mParameter); + assertEquals(EXPECTED_UNDERLINE_NAME, pvp.mValue); + pvp = urlList.get(1); + assertEquals(AGE, pvp.mParameter); + assertEquals(EXPECTED_AGE, pvp.mValue); + pvp = urlList.get(2); + assertEquals(HEIGHT, pvp.mParameter); + assertEquals(EXPECTED_HEIGHT, pvp.mValue); + + assertFalse(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT + 1); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 1, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.setPreferFirstRepeatedParameter(true); + assertTrue(uqs.getPreferFirstRepeatedParameter()); + uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT); + assertEquals(ContainerLen, urlSet.size()); + assertEquals(ContainerLen + 2, urlList.size()); + assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); + + uqs.registerParameter(NAME, null); + assertNull(uqs.getValueSanitizer(NAME)); + assertNotNull(uqs.getEffectiveValueSanitizer(NAME)); + + uqs.setAllowUnregisteredParamaters(false); + assertFalse(uqs.getAllowUnregisteredParamaters()); + uqs.registerParameter(NAME, null); + assertNull(uqs.getEffectiveValueSanitizer(NAME)); + + ValueSanitizer vs = new IllegalCharacterValueSanitizer(ALL_OK); + uqs.registerParameter(NAME, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertNotSame(EXPECTED_AGE, uqs.getValue(AGE)); + + String[] register = {NAME, AGE}; + uqs.registerParameters(register, vs); + uqs.parseUrl(TEST_URL); + assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); + assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); + assertNotSame(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); + + uqs.setUnregisteredParameterValueSanitizer(vs); + assertEquals(vs, uqs.getUnregisteredParameterValueSanitizer()); + + vs = UrlQuerySanitizer.getAllIllegal(); + assertEquals("Joe_User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButNulLegal(); + assertEquals("Joe User", vs.sanitize("Joe\0User")); + vs = UrlQuerySanitizer.getAllButWhitespaceLegal(); + assertEquals("Joe_User", vs.sanitize("Joe User")); + vs = UrlQuerySanitizer.getAmpAndSpaceLegal(); + assertEquals("Joe User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getAmpLegal(); + assertEquals("Joe_User&", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getSpaceLegal(); + assertEquals("Joe User ", vs.sanitize("Joe User&")); + vs = UrlQuerySanitizer.getUrlAndSpaceLegal(); + assertEquals("Joe User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + vs = UrlQuerySanitizer.getUrlLegal(); + assertEquals("Joe_User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); + + String escape = "Joe"; + assertEquals(escape, uqs.unescape(escape)); + String expectedPlus = "Joe User"; + String expectedPercentSignHex = "title=" + Character.toString((char)181); + String initialPlus = "Joe+User"; + String initialPercentSign = "title=%B5"; + assertEquals(expectedPlus, uqs.unescape(initialPlus)); + assertEquals(expectedPercentSignHex, uqs.unescape(initialPercentSign)); + String expectedPlusThenPercentSign = "Joe Random, User"; + String plusThenPercentSign = "Joe+Random%2C%20User"; + assertEquals(expectedPlusThenPercentSign, uqs.unescape(plusThenPercentSign)); + String expectedPercentSignThenPlus = "Joe, Random User"; + String percentSignThenPlus = "Joe%2C+Random+User"; + assertEquals(expectedPercentSignThenPlus, uqs.unescape(percentSignThenPlus)); + + assertTrue(uqs.decodeHexDigit('0') >= 0); + assertTrue(uqs.decodeHexDigit('b') >= 0); + assertTrue(uqs.decodeHexDigit('F') >= 0); + assertTrue(uqs.decodeHexDigit('$') < 0); + + assertTrue(uqs.isHexDigit('0')); + assertTrue(uqs.isHexDigit('b')); + assertTrue(uqs.isHexDigit('F')); + assertFalse(uqs.isHexDigit('$')); + + uqs.clear(); + assertEquals(0, urlSet.size()); + assertEquals(0, urlList.size()); + + uqs.setPreferFirstRepeatedParameter(true); + assertTrue(uqs.getPreferFirstRepeatedParameter()); + uqs.setPreferFirstRepeatedParameter(false); + assertFalse(uqs.getPreferFirstRepeatedParameter()); + + UrlQuerySanitizer uq = new UrlQuerySanitizer(); + uq.setPreferFirstRepeatedParameter(true); + final String PARA_ANSWER = "answer"; + uq.registerParameter(PARA_ANSWER, new MockValueSanitizer()); + uq.parseUrl("http://www.google.com/question?answer=13&answer=42"); + assertEquals("13", uq.getValue(PARA_ANSWER)); + + uq.setPreferFirstRepeatedParameter(false); + uq.parseQuery("http://www.google.com/question?answer=13&answer=42"); + assertEquals("42", uq.getValue(PARA_ANSWER)); + + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // Only fixed in R + public void testScriptUrlOk_73822755() { + ValueSanitizer sanitizer = new UrlQuerySanitizer.IllegalCharacterValueSanitizer( + UrlQuerySanitizer.IllegalCharacterValueSanitizer.SCRIPT_URL_OK); + assertEquals("javascript:alert()", sanitizer.sanitize("javascript:alert()")); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // Only fixed in R + public void testScriptUrlBlocked_73822755() { + ValueSanitizer sanitizer = UrlQuerySanitizer.getUrlAndSpaceLegal(); + assertEquals("", sanitizer.sanitize("javascript:alert()")); + } + + private static class MockValueSanitizer implements ValueSanitizer{ + + public String sanitize(String value) { + return value; + } + } + + class MockUrlQuerySanitizer extends UrlQuerySanitizer { + public MockUrlQuerySanitizer() { + super(); + } + + public MockUrlQuerySanitizer(String url) { + super(url); + } + + @Override + protected void addSanitizedEntry(String parameter, String value) { + super.addSanitizedEntry(parameter, value); + } + + @Override + protected void clear() { + super.clear(); + } + + @Override + protected int decodeHexDigit(char c) { + return super.decodeHexDigit(c); + } + + @Override + protected boolean isHexDigit(char c) { + return super.isHexDigit(c); + } + + @Override + protected void parseEntry(String parameter, String value) { + super.parseEntry(parameter, value); + } + } +} diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java new file mode 100644 index 0000000000..f86af3114e --- /dev/null +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009 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 android.net.UrlQuerySanitizer; +import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; +import android.test.AndroidTestCase; + +public class UrlQuerySanitizer_IllegalCharacterValueSanitizerTest extends AndroidTestCase { + static final int SPACE_OK = IllegalCharacterValueSanitizer.SPACE_OK; + public void testSanitize() { + IllegalCharacterValueSanitizer sanitizer = new IllegalCharacterValueSanitizer(SPACE_OK); + assertEquals("Joe User", sanitizer.sanitize("Joecommon/android-3.x kernel trees. If you are not running one of these kernels, the + * functionality can be obtained by cherry-picking the following patches from David Miller's + * net-next tree: + *

      + *
    • 6d0bfe2 net: ipv6: Add IPv6 support to the ping socket. + *
    • c26d6b4 ping: always initialize ->sin6_scope_id and ->sin6_flowinfo + *
    • fbfe80c net: ipv6: fix wrong ping_v6_sendmsg return value + *
    • a1bdc45 net: ipv6: add missing lock in ping_v6_sendmsg + *
    • cf970c0 ping: prevent NULL pointer dereference on write to msg_name + *
    + * or the equivalent backports to the common/android-3.x trees. + */ +public class PingTest extends AndroidTestCase { + /** Maximum size of the packets we're using to test. */ + private static final int MAX_SIZE = 4096; + + /** Size of the ICMPv6 header. */ + private static final int ICMP_HEADER_SIZE = 8; + + /** Number of packets to test. */ + private static final int NUM_PACKETS = 10; + + /** The beginning of an ICMPv6 echo request: type, code, and uninitialized checksum. */ + private static final byte[] PING_HEADER = new byte[] { + (byte) ICMP6_ECHO_REQUEST, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }; + + /** + * Returns a byte array containing an ICMPv6 echo request with the specified payload length. + */ + private byte[] pingPacket(int payloadLength) { + byte[] packet = new byte[payloadLength + ICMP_HEADER_SIZE]; + new Random().nextBytes(packet); + System.arraycopy(PING_HEADER, 0, packet, 0, PING_HEADER.length); + return packet; + } + + /** + * Checks that the first length bytes of two byte arrays are equal. + */ + private void assertArrayBytesEqual(byte[] expected, byte[] actual, int length) { + for (int i = 0; i < length; i++) { + assertEquals("Arrays differ at index " + i + ":", expected[i], actual[i]); + } + } + + /** + * Creates an IPv6 ping socket and sets a receive timeout of 100ms. + */ + private FileDescriptor createPingSocket() throws ErrnoException { + FileDescriptor s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); + Os.setsockoptTimeval(s, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(100)); + return s; + } + + /** + * Sends a ping packet to a random port on the specified address on the specified socket. + */ + private void sendPing(FileDescriptor s, + InetAddress address, byte[] packet) throws ErrnoException, IOException { + // Pick a random port. Choose a range that gives a reasonable chance of picking a low port. + int port = (int) (Math.random() * 2048); + + // Send the packet. + int ret = Os.sendto(s, ByteBuffer.wrap(packet), 0, address, port); + assertEquals(packet.length, ret); + } + + /** + * Checks that a socket has received a response appropriate to the specified packet. + */ + private void checkResponse(FileDescriptor s, InetAddress dest, + byte[] sent, boolean useRecvfrom) throws ErrnoException, IOException { + ByteBuffer responseBuffer = ByteBuffer.allocate(MAX_SIZE); + int bytesRead; + + // Receive the response. + if (useRecvfrom) { + InetSocketAddress from = new InetSocketAddress(); + bytesRead = Os.recvfrom(s, responseBuffer, 0, from); + + // Check the source address and scope ID. + assertTrue(from.getAddress() instanceof Inet6Address); + Inet6Address fromAddress = (Inet6Address) from.getAddress(); + assertEquals(0, fromAddress.getScopeId()); + assertNull(fromAddress.getScopedInterface()); + assertEquals(dest.getHostAddress(), fromAddress.getHostAddress()); + } else { + bytesRead = Os.read(s, responseBuffer); + } + + // Check the packet length. + assertEquals(sent.length, bytesRead); + + // Check the response is an echo reply. + byte[] response = new byte[bytesRead]; + responseBuffer.flip(); + responseBuffer.get(response, 0, bytesRead); + assertEquals((byte) ICMP6_ECHO_REPLY, response[0]); + + // Find out what ICMP ID was used in the packet that was sent. + int id = ((InetSocketAddress) Os.getsockname(s)).getPort(); + sent[4] = (byte) (id / 256); + sent[5] = (byte) (id % 256); + + // Ensure the response is the same as the packet, except for the type (which is 0x81) + // and the ID and checksum, which are set by the kernel. + response[0] = (byte) 0x80; // Type. + response[2] = response[3] = (byte) 0x00; // Checksum. + assertArrayBytesEqual(response, sent, bytesRead); + } + + /** + * Sends NUM_PACKETS random ping packets to ::1 and checks the replies. + */ + public void testLoopbackPing() throws ErrnoException, IOException { + // Generate a random ping packet and send it to localhost. + InetAddress ipv6Loopback = InetAddress.getByName(null); + assertEquals("::1", ipv6Loopback.getHostAddress()); + + for (int i = 0; i < NUM_PACKETS; i++) { + byte[] packet = pingPacket((int) (Math.random() * (MAX_SIZE - ICMP_HEADER_SIZE))); + FileDescriptor s = createPingSocket(); + // Use both recvfrom and read(). + sendPing(s, ipv6Loopback, packet); + checkResponse(s, ipv6Loopback, packet, true); + sendPing(s, ipv6Loopback, packet); + checkResponse(s, ipv6Loopback, packet, false); + // Check closing the socket doesn't raise an exception. + Os.close(s); + } + } +} diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioCodecTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioCodecTest.java new file mode 100644 index 0000000000..412498c309 --- /dev/null +++ b/tests/cts/net/src/android/net/rtp/cts/AudioCodecTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 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.rtp.cts; + +import android.net.rtp.AudioCodec; +import android.test.AndroidTestCase; + +public class AudioCodecTest extends AndroidTestCase { + + private void assertEquals(AudioCodec codec, int type, String rtpmap, String fmtp) { + if (type >= 0) { + assertEquals(codec.type, type); + } else { + assertTrue(codec.type >= 96 && codec.type <= 127); + } + assertEquals(codec.rtpmap.compareToIgnoreCase(rtpmap), 0); + assertEquals(codec.fmtp, fmtp); + } + + public void testConstants() throws Exception { + assertEquals(AudioCodec.PCMU, 0, "PCMU/8000", null); + assertEquals(AudioCodec.PCMA, 8, "PCMA/8000", null); + assertEquals(AudioCodec.GSM, 3, "GSM/8000", null); + assertEquals(AudioCodec.GSM_EFR, -1, "GSM-EFR/8000", null); + assertEquals(AudioCodec.AMR, -1, "AMR/8000", null); + + assertFalse(AudioCodec.AMR.type == AudioCodec.GSM_EFR.type); + } + + public void testGetCodec() throws Exception { + // Bad types. + assertNull(AudioCodec.getCodec(128, "PCMU/8000", null)); + assertNull(AudioCodec.getCodec(-1, "PCMU/8000", null)); + assertNull(AudioCodec.getCodec(96, null, null)); + + // Fixed types. + assertEquals(AudioCodec.getCodec(0, null, null), 0, "PCMU/8000", null); + assertEquals(AudioCodec.getCodec(8, null, null), 8, "PCMA/8000", null); + assertEquals(AudioCodec.getCodec(3, null, null), 3, "GSM/8000", null); + + // Dynamic types. + assertEquals(AudioCodec.getCodec(96, "pcmu/8000", null), 96, "PCMU/8000", null); + assertEquals(AudioCodec.getCodec(97, "pcma/8000", null), 97, "PCMA/8000", null); + assertEquals(AudioCodec.getCodec(98, "gsm/8000", null), 98, "GSM/8000", null); + assertEquals(AudioCodec.getCodec(99, "gsm-efr/8000", null), 99, "GSM-EFR/8000", null); + assertEquals(AudioCodec.getCodec(100, "amr/8000", null), 100, "AMR/8000", null); + } + + public void testGetCodecs() throws Exception { + AudioCodec[] codecs = AudioCodec.getCodecs(); + assertTrue(codecs.length >= 5); + + // The types of the codecs should be different. + boolean[] types = new boolean[128]; + for (AudioCodec codec : codecs) { + assertFalse(types[codec.type]); + types[codec.type] = true; + } + } +} diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java new file mode 100644 index 0000000000..fc78e96e11 --- /dev/null +++ b/tests/cts/net/src/android/net/rtp/cts/AudioGroupTest.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2012 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.rtp.cts; + +import android.content.Context; +import android.media.AudioManager; +import android.net.rtp.AudioCodec; +import android.net.rtp.AudioGroup; +import android.net.rtp.AudioStream; +import android.net.rtp.RtpStream; +import android.os.Build; +import android.platform.test.annotations.AppModeFull; +import android.test.AndroidTestCase; + +import androidx.core.os.BuildCompat; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; + +@AppModeFull(reason = "RtpStream cannot create in instant app mode") +public class AudioGroupTest extends AndroidTestCase { + + private static final String TAG = AudioGroupTest.class.getSimpleName(); + + private AudioManager mAudioManager; + + private AudioStream mStreamA; + private DatagramSocket mSocketA; + private AudioStream mStreamB; + private DatagramSocket mSocketB; + private AudioGroup mGroup; + + @Override + public void setUp() throws Exception { + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); + + InetAddress local = InetAddress.getByName("::1"); + + mStreamA = new AudioStream(local); + mStreamA.setMode(RtpStream.MODE_NORMAL); + mStreamA.setCodec(AudioCodec.PCMU); + mSocketA = new DatagramSocket(); + mSocketA.connect(mStreamA.getLocalAddress(), mStreamA.getLocalPort()); + mStreamA.associate(mSocketA.getLocalAddress(), mSocketA.getLocalPort()); + + mStreamB = new AudioStream(local); + mStreamB.setMode(RtpStream.MODE_NORMAL); + mStreamB.setCodec(AudioCodec.PCMU); + mSocketB = new DatagramSocket(); + mSocketB.connect(mStreamB.getLocalAddress(), mStreamB.getLocalPort()); + mStreamB.associate(mSocketB.getLocalAddress(), mSocketB.getLocalPort()); + + // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R) + mGroup = Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR() + ? new AudioGroup(mContext) + : new AudioGroup(); // Constructor with context argument was introduced in R + } + + @Override + public void tearDown() throws Exception { + mGroup.clear(); + mStreamA.release(); + mSocketA.close(); + mStreamB.release(); + mSocketB.close(); + mAudioManager.setMode(AudioManager.MODE_NORMAL); + } + + private void assertPacket(DatagramSocket socket, int length) throws Exception { + DatagramPacket packet = new DatagramPacket(new byte[length + 1], length + 1); + socket.setSoTimeout(3000); + socket.receive(packet); + assertEquals(packet.getLength(), length); + } + + private void drain(DatagramSocket socket) throws Exception { + DatagramPacket packet = new DatagramPacket(new byte[1], 1); + socket.setSoTimeout(1); + try { + // Drain the socket by retrieving all the packets queued on it. + // A SocketTimeoutException will be thrown when it becomes empty. + while (true) { + socket.receive(packet); + } + } catch (Exception e) { + // ignore. + } + } + + public void testTraffic() throws Exception { + mStreamA.join(mGroup); + assertPacket(mSocketA, 12 + 160); + + mStreamB.join(mGroup); + assertPacket(mSocketB, 12 + 160); + + mStreamA.join(null); + drain(mSocketA); + + drain(mSocketB); + assertPacket(mSocketB, 12 + 160); + + mStreamA.join(mGroup); + assertPacket(mSocketA, 12 + 160); + } + + public void testSetMode() throws Exception { + mGroup.setMode(AudioGroup.MODE_NORMAL); + assertEquals(mGroup.getMode(), AudioGroup.MODE_NORMAL); + + mGroup.setMode(AudioGroup.MODE_MUTED); + assertEquals(mGroup.getMode(), AudioGroup.MODE_MUTED); + + mStreamA.join(mGroup); + mStreamB.join(mGroup); + + mGroup.setMode(AudioGroup.MODE_NORMAL); + assertEquals(mGroup.getMode(), AudioGroup.MODE_NORMAL); + + mGroup.setMode(AudioGroup.MODE_MUTED); + assertEquals(mGroup.getMode(), AudioGroup.MODE_MUTED); + } + + public void testAdd() throws Exception { + mStreamA.join(mGroup); + assertEquals(mGroup.getStreams().length, 1); + + mStreamB.join(mGroup); + assertEquals(mGroup.getStreams().length, 2); + + mStreamA.join(mGroup); + assertEquals(mGroup.getStreams().length, 2); + } + + public void testRemove() throws Exception { + mStreamA.join(mGroup); + assertEquals(mGroup.getStreams().length, 1); + + mStreamA.join(null); + assertEquals(mGroup.getStreams().length, 0); + + mStreamA.join(mGroup); + assertEquals(mGroup.getStreams().length, 1); + } + + public void testClear() throws Exception { + mStreamA.join(mGroup); + mStreamB.join(mGroup); + mGroup.clear(); + + assertEquals(mGroup.getStreams().length, 0); + assertFalse(mStreamA.isBusy()); + assertFalse(mStreamB.isBusy()); + } + + public void testDoubleClear() throws Exception { + mStreamA.join(mGroup); + mStreamB.join(mGroup); + mGroup.clear(); + mGroup.clear(); + } +} diff --git a/tests/cts/net/src/android/net/rtp/cts/AudioStreamTest.java b/tests/cts/net/src/android/net/rtp/cts/AudioStreamTest.java new file mode 100644 index 0000000000..f2db6ee9c4 --- /dev/null +++ b/tests/cts/net/src/android/net/rtp/cts/AudioStreamTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 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.rtp.cts; + +import android.net.rtp.AudioCodec; +import android.net.rtp.AudioStream; +import android.platform.test.annotations.AppModeFull; +import android.test.AndroidTestCase; + +import java.net.InetAddress; + +@AppModeFull(reason = "RtpStream cannot create in instant app mode") +public class AudioStreamTest extends AndroidTestCase { + + private void testRtpStream(InetAddress address) throws Exception { + AudioStream stream = new AudioStream(address); + assertEquals(stream.getLocalAddress(), address); + assertEquals(stream.getLocalPort() % 2, 0); + + assertNull(stream.getRemoteAddress()); + assertEquals(stream.getRemotePort(), -1); + stream.associate(address, 1000); + assertEquals(stream.getRemoteAddress(), address); + assertEquals(stream.getRemotePort(), 1000); + + assertFalse(stream.isBusy()); + stream.release(); + } + + public void testV4Stream() throws Exception { + testRtpStream(InetAddress.getByName("127.0.0.1")); + } + + public void testV6Stream() throws Exception { + testRtpStream(InetAddress.getByName("::1")); + } + + public void testSetDtmfType() throws Exception { + AudioStream stream = new AudioStream(InetAddress.getByName("::1")); + + assertEquals(stream.getDtmfType(), -1); + try { + stream.setDtmfType(0); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // ignore + } + stream.setDtmfType(96); + assertEquals(stream.getDtmfType(), 96); + + stream.setCodec(AudioCodec.getCodec(97, "PCMU/8000", null)); + try { + stream.setDtmfType(97); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // ignore + } + stream.release(); + } + + public void testSetCodec() throws Exception { + AudioStream stream = new AudioStream(InetAddress.getByName("::1")); + + assertNull(stream.getCodec()); + stream.setCodec(AudioCodec.getCodec(97, "PCMU/8000", null)); + assertNotNull(stream.getCodec()); + + stream.setDtmfType(96); + try { + stream.setCodec(AudioCodec.getCodec(96, "PCMU/8000", null)); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // ignore + } + stream.release(); + } + + public void testDoubleRelease() throws Exception { + AudioStream stream = new AudioStream(InetAddress.getByName("::1")); + stream.release(); + stream.release(); + } +} diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp new file mode 100644 index 0000000000..c36d976423 --- /dev/null +++ b/tests/cts/net/util/Android.bp @@ -0,0 +1,26 @@ +// +// Copyright (C) 2019 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. +// + +// Common utilities for cts net tests. +java_library { + name: "cts-net-utils", + srcs: ["java/**/*.java", "java/**/*.kt"], + static_libs: [ + "compatibility-device-util-axt", + "junit", + "net-tests-utils", + ], +} \ No newline at end of file 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 new file mode 100644 index 0000000000..be0daae8dc --- /dev/null +++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2019 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.util; + +import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.wifi.WifiManager.SCAN_RESULTS_AVAILABLE_ACTION; + +import static com.android.testutils.TestPermissionUtil.runAsShell; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.annotation.NonNull; +import android.app.AppOpsManager; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkInfo.State; +import android.net.NetworkRequest; +import android.net.TestNetworkManager; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Binder; +import android.os.Build; +import android.os.IBinder; +import android.os.SystemProperties; +import android.provider.Settings; +import android.system.Os; +import android.system.OsConstants; +import android.util.Log; + +import com.android.compatibility.common.util.SystemUtil; + +import junit.framework.AssertionFailedError; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public final class CtsNetUtils { + private static final String TAG = CtsNetUtils.class.getSimpleName(); + private static final int DURATION = 10000; + private static final int SOCKET_TIMEOUT_MS = 2000; + private static final int PRIVATE_DNS_PROBE_MS = 1_000; + + private static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000; + private static final int CONNECTIVITY_CHANGE_TIMEOUT_SECS = 30; + public static final int HTTP_PORT = 80; + public static final String TEST_HOST = "connectivitycheck.gstatic.com"; + public static final String HTTP_REQUEST = + "GET /generate_204 HTTP/1.0\r\n" + + "Host: " + TEST_HOST + "\r\n" + + "Connection: keep-alive\r\n\r\n"; + // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. + public static final String NETWORK_CALLBACK_ACTION = + "ConnectivityManagerTest.NetworkCallbackAction"; + + private final IBinder mBinder = new Binder(); + private final Context mContext; + private final ConnectivityManager mCm; + private final ContentResolver mCR; + private final WifiManager mWifiManager; + private TestNetworkCallback mCellNetworkCallback; + private String mOldPrivateDnsMode; + private String mOldPrivateDnsSpecifier; + + public CtsNetUtils(Context context) { + mContext = context; + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mCR = context.getContentResolver(); + } + + /** Checks if FEATURE_IPSEC_TUNNELS is enabled on the device */ + public boolean hasIpsecTunnelsFeature() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + || SystemProperties.getInt("ro.product.first_api_level", 0) + >= Build.VERSION_CODES.Q; + } + + /** + * Sets the given appop using shell commands + * + *

    Expects caller to hold the shell permission identity. + */ + public void setAppopPrivileged(int appop, boolean allow) { + final String opName = AppOpsManager.opToName(appop); + for (final String pkg : new String[] {"com.android.shell", mContext.getPackageName()}) { + final String cmd = + String.format( + "appops set %s %s %s", + pkg, // Package name + opName, // Appop + (allow ? "allow" : "deny")); // Action + SystemUtil.runShellCommand(cmd); + } + } + + /** Sets up a test network using the provided interface name */ + public TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception { + // Build a network request + final NetworkRequest nr = + new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(TRANSPORT_TEST) + .setNetworkSpecifier(ifname) + .build(); + + final TestNetworkCallback cb = new TestNetworkCallback(); + mCm.requestNetwork(nr, cb); + + // Setup the test network after network request is filed to prevent Network from being + // reaped due to no requests matching it. + mContext.getSystemService(TestNetworkManager.class).setupTestNetwork(ifname, mBinder); + + return cb; + } + + // Toggle WiFi twice, leaving it in the state it started in + public void toggleWifi() { + if (mWifiManager.isWifiEnabled()) { + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); + connectToWifi(); + } else { + connectToWifi(); + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); + } + } + + /** + * Enable WiFi and wait for it to become connected to a network. + * + * This method expects to receive a legacy broadcast on connect, which may not be sent if the + * network does not become default or if it is not the first network. + */ + public Network connectToWifi() { + return connectToWifi(true /* expectLegacyBroadcast */); + } + + /** + * Enable WiFi and wait for it to become connected to a network. + * + * A network is considered connected when a {@link NetworkRequest} with TRANSPORT_WIFI + * receives a {@link NetworkCallback#onAvailable(Network)} callback. + */ + public Network ensureWifiConnected() { + return connectToWifi(false /* expectLegacyBroadcast */); + } + + /** + * Enable WiFi and wait for it to become connected to a network. + * + * @param expectLegacyBroadcast Whether to check for a legacy CONNECTIVITY_ACTION connected + * broadcast. The broadcast is typically not sent if the network + * does not become the default network, and is not the first + * network to appear. + * @return The network that was newly connected. + */ + private Network connectToWifi(boolean expectLegacyBroadcast) { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network wifiNetwork = null; + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + boolean connected = false; + final String err = "Wifi must be configured to connect to an access point for this test."; + try { + clearWifiBlacklist(); + SystemUtil.runShellCommand("svc wifi enable"); + final WifiConfiguration config = maybeAddVirtualWifiConfiguration(); + if (config == null) { + // TODO: this may not clear the BSSID blacklist, as opposed to + // mWifiManager.connect(config) + assertTrue("Error reconnecting wifi", runAsShell(NETWORK_SETTINGS, + mWifiManager::reconnect)); + } else { + // When running CTS, devices are expected to have wifi networks pre-configured. + // This condition is only hit on virtual devices. + final Integer error = runAsShell(NETWORK_SETTINGS, () -> { + final ConnectWifiListener listener = new ConnectWifiListener(); + mWifiManager.connect(config, listener); + return listener.connectFuture.get( + CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS); + }); + assertNull("Error connecting to wifi: " + error, error); + } + // Ensure we get an onAvailable callback and possibly a CONNECTIVITY_ACTION. + wifiNetwork = callback.waitForAvailable(); + assertNotNull(err, wifiNetwork); + connected = !expectLegacyBroadcast || receiver.waitForState(); + } catch (InterruptedException ex) { + fail("connectToWifi was interrupted"); + } finally { + mCm.unregisterNetworkCallback(callback); + mContext.unregisterReceiver(receiver); + } + + assertTrue(err, connected); + return wifiNetwork; + } + + private static class ConnectWifiListener implements WifiManager.ActionListener { + /** + * Future completed when the connect process ends. Provides the error code or null if none. + */ + final CompletableFuture connectFuture = new CompletableFuture<>(); + @Override + public void onSuccess() { + connectFuture.complete(null); + } + + @Override + public void onFailure(int reason) { + connectFuture.complete(reason); + } + } + + private WifiConfiguration maybeAddVirtualWifiConfiguration() { + final List configs = runAsShell(NETWORK_SETTINGS, + mWifiManager::getConfiguredNetworks); + // If no network is configured, add a config for virtual access points if applicable + if (configs.size() == 0) { + final List scanResults = getWifiScanResults(); + final WifiConfiguration virtualConfig = maybeConfigureVirtualNetwork(scanResults); + assertNotNull("The device has no configured wifi network", virtualConfig); + + return virtualConfig; + } + // No need to add a configuration: there is already one + return null; + } + + private List getWifiScanResults() { + final CompletableFuture> scanResultsFuture = new CompletableFuture<>(); + runAsShell(NETWORK_SETTINGS, () -> { + final BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + scanResultsFuture.complete(mWifiManager.getScanResults()); + } + }; + mContext.registerReceiver(receiver, new IntentFilter(SCAN_RESULTS_AVAILABLE_ACTION)); + mWifiManager.startScan(); + }); + + try { + return scanResultsFuture.get(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS); + } catch (ExecutionException | InterruptedException | TimeoutException e) { + throw new AssertionFailedError("Wifi scan results not received within timeout"); + } + } + + /** + * If a virtual wifi network is detected, add a configuration for that network. + * TODO(b/158150376): have the test infrastructure add virtual wifi networks when appropriate. + */ + private WifiConfiguration maybeConfigureVirtualNetwork(List scanResults) { + // Virtual wifi networks used on the emulator and cloud testing infrastructure + final List virtualSsids = Arrays.asList("VirtWifi", "AndroidWifi"); + Log.d(TAG, "Wifi scan results: " + scanResults); + final ScanResult virtualScanResult = scanResults.stream().filter( + s -> virtualSsids.contains(s.SSID)).findFirst().orElse(null); + + // Only add the virtual configuration if the virtual AP is detected in scans + if (virtualScanResult == null) return null; + + final WifiConfiguration virtualConfig = new WifiConfiguration(); + // ASCII SSIDs need to be surrounded by double quotes + virtualConfig.SSID = "\"" + virtualScanResult.SSID + "\""; + virtualConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + + runAsShell(NETWORK_SETTINGS, () -> { + final int networkId = mWifiManager.addNetwork(virtualConfig); + assertTrue(networkId >= 0); + assertTrue(mWifiManager.enableNetwork(networkId, false /* attemptConnect */)); + }); + return virtualConfig; + } + + /** + * Re-enable wifi networks that were blacklisted, typically because no internet connection was + * detected the last time they were connected. This is necessary to make sure wifi can reconnect + * to them. + */ + private void clearWifiBlacklist() { + runAsShell(NETWORK_SETTINGS, () -> { + for (WifiConfiguration cfg : mWifiManager.getConfiguredNetworks()) { + assertTrue(mWifiManager.enableNetwork(cfg.networkId, false /* attemptConnect */)); + } + }); + } + + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * This method expects to receive a legacy broadcast on disconnect, which may not be sent if the + * network was not default, or was not the first network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + */ + public void disconnectFromWifi(Network wifiNetworkToCheck) { + disconnectFromWifi(wifiNetworkToCheck, true /* expectLegacyBroadcast */); + } + + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + */ + public void ensureWifiDisconnected(Network wifiNetworkToCheck) { + disconnectFromWifi(wifiNetworkToCheck, false /* expectLegacyBroadcast */); + } + + /** + * Disable WiFi and wait for it to become disconnected from the network. + * + * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network + * is expected to be able to establish a TCP connection to a remote + * server before disconnecting, and to have that connection closed in + * the process. + * @param expectLegacyBroadcast Whether to check for a legacy CONNECTIVITY_ACTION disconnected + * broadcast. The broadcast is typically not sent if the network + * was not the default network and not the first network to appear. + * The check will always be skipped if the device was not connected + * to wifi in the first place. + */ + private void disconnectFromWifi(Network wifiNetworkToCheck, boolean expectLegacyBroadcast) { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + final boolean wasWifiConnected = wifiInfo != null && wifiInfo.getNetworkId() != -1; + // Assert that we can establish a TCP connection on wifi. + Socket wifiBoundSocket = null; + if (wifiNetworkToCheck != null) { + assertTrue("Cannot check network " + wifiNetworkToCheck + ": wifi is not connected", + wasWifiConnected); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(wifiNetworkToCheck); + assertNotNull("Network " + wifiNetworkToCheck + " is not connected", nc); + try { + wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); + testHttpRequest(wifiBoundSocket); + } catch (IOException e) { + fail("HTTP request before wifi disconnected failed with: " + e); + } + } + + try { + SystemUtil.runShellCommand("svc wifi disable"); + if (wasWifiConnected) { + // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. + assertNotNull("Did not receive onLost callback after disabling wifi", + callback.waitForLost()); + } + if (wasWifiConnected && expectLegacyBroadcast) { + assertTrue("Wifi failed to reach DISCONNECTED state.", receiver.waitForState()); + } + } catch (InterruptedException ex) { + fail("disconnectFromWifi was interrupted"); + } finally { + mCm.unregisterNetworkCallback(callback); + mContext.unregisterReceiver(receiver); + } + + // Check that the socket is closed when wifi disconnects. + if (wifiBoundSocket != null) { + try { + testHttpRequest(wifiBoundSocket); + fail("HTTP request should not succeed after wifi disconnects"); + } catch (IOException expected) { + assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); + } + } + } + + public Network getWifiNetwork() { + TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network network = null; + try { + network = callback.waitForAvailable(); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + } + assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); + return network; + } + + public Network connectToCell() throws InterruptedException { + if (cellConnectAttempted()) { + throw new IllegalStateException("Already connected"); + } + NetworkRequest cellRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + mCellNetworkCallback = new TestNetworkCallback(); + mCm.requestNetwork(cellRequest, mCellNetworkCallback); + final Network cellNetwork = mCellNetworkCallback.waitForAvailable(); + assertNotNull("Cell network not available. " + + "Please ensure the device has working mobile data.", cellNetwork); + return cellNetwork; + } + + public void disconnectFromCell() { + if (!cellConnectAttempted()) { + throw new IllegalStateException("Cell connection not attempted"); + } + mCm.unregisterNetworkCallback(mCellNetworkCallback); + mCellNetworkCallback = null; + } + + public boolean cellConnectAttempted() { + return mCellNetworkCallback != null; + } + + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + + private void testHttpRequest(Socket s) throws IOException { + OutputStream out = s.getOutputStream(); + InputStream in = s.getInputStream(); + + final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + byte[] responseBytes = new byte[4096]; + out.write(requestBytes); + in.read(responseBytes); + assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); + } + + private Socket getBoundSocket(Network network, String host, int port) throws IOException { + InetSocketAddress addr = new InetSocketAddress(host, port); + Socket s = network.getSocketFactory().createSocket(); + try { + s.setSoTimeout(SOCKET_TIMEOUT_MS); + s.connect(addr, SOCKET_TIMEOUT_MS); + } catch (IOException e) { + s.close(); + throw e; + } + return s; + } + + public void storePrivateDnsSetting() { + // Store private DNS setting + mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + mOldPrivateDnsSpecifier = Settings.Global.getString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER); + // It's possible that there is no private DNS default value in Settings. + // Give it a proper default mode which is opportunistic mode. + if (mOldPrivateDnsMode == null) { + mOldPrivateDnsSpecifier = ""; + mOldPrivateDnsMode = PRIVATE_DNS_MODE_OPPORTUNISTIC; + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, mOldPrivateDnsSpecifier); + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + } + } + + public void restorePrivateDnsSetting() throws InterruptedException { + if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) { + return; + } + // restore private DNS setting + if ("hostname".equals(mOldPrivateDnsMode)) { + setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); + awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", + mCm.getActiveNetwork(), + mOldPrivateDnsSpecifier, true); + } else { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + } + } + + public void setPrivateDnsStrictMode(String server) { + // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures + // that if the previous private DNS mode was not "hostname", the system only sees one + // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two. + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server); + final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER. + if (!"hostname".equals(mode)) { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + } + } + + public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, + @NonNull String server, boolean requiresValidatedServers) throws InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); + NetworkCallback callback = new NetworkCallback() { + @Override + public void onLinkPropertiesChanged(Network n, LinkProperties lp) { + if (requiresValidatedServers && lp.getValidatedPrivateDnsServers().isEmpty()) { + return; + } + if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) { + latch.countDown(); + } + } + }; + mCm.registerNetworkCallback(request, callback); + assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + mCm.unregisterNetworkCallback(callback); + // Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do + // this, then the test could complete before the NetworkMonitor private DNS probe + // completes. This would result in tearDown disabling private DNS, and the NetworkMonitor + // private DNS probe getting stuck because there are no longer any private DNS servers to + // query. This then results in the next test not being able to change the private DNS + // setting within the timeout, because the NetworkMonitor thread is blocked in the + // private DNS probe. There is no way to know when the probe has completed: because the + // network is likely already validated, there is no callback that we can listen to, so + // just sleep. + if (requiresValidatedServers) { + Thread.sleep(PRIVATE_DNS_PROBE_MS); + } + } + + /** + * Receiver that captures the last connectivity change's network type and state. Recognizes + * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. + */ + public static class ConnectivityActionReceiver extends BroadcastReceiver { + + private final CountDownLatch mReceiveLatch = new CountDownLatch(1); + + private final int mNetworkType; + private final NetworkInfo.State mNetState; + private final ConnectivityManager mCm; + + public ConnectivityActionReceiver(ConnectivityManager cm, int networkType, + NetworkInfo.State netState) { + this.mCm = cm; + mNetworkType = networkType; + mNetState = netState; + } + + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + NetworkInfo networkInfo = null; + + // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable + // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is + // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { + networkInfo = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", + networkInfo); + } else if (NETWORK_CALLBACK_ACTION.equals(action)) { + Network network = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); + networkInfo = this.mCm.getNetworkInfo(network); + if (networkInfo == null) { + // When disconnecting, it seems like we get an intent sent with an invalid + // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), + // it is invalid. Ignore these. + Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " + + "invalid network"); + return; + } + } else { + fail("ConnectivityActionReceiver received unxpected intent action: " + action); + } + + assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); + int networkType = networkInfo.getType(); + State networkState = networkInfo.getState(); + Log.i(TAG, "Network type: " + networkType + " state: " + networkState); + if (networkType == mNetworkType && networkInfo.getState() == mNetState) { + mReceiveLatch.countDown(); + } + } + + public boolean waitForState() throws InterruptedException { + return mReceiveLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS); + } + } + + /** + * Callback used in testRegisterNetworkCallback that allows caller to block on + * {@code onAvailable}. + */ + public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CountDownLatch mAvailableLatch = new CountDownLatch(1); + private final CountDownLatch mLostLatch = new CountDownLatch(1); + private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); + + public Network currentNetwork; + public Network lastLostNetwork; + + public Network waitForAvailable() throws InterruptedException { + return mAvailableLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS) + ? currentNetwork : null; + } + + public Network waitForLost() throws InterruptedException { + return mLostLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS) + ? lastLostNetwork : null; + } + + public boolean waitForUnavailable() throws InterruptedException { + return mUnavailableLatch.await(2, TimeUnit.SECONDS); + } + + + @Override + public void onAvailable(Network network) { + currentNetwork = network; + mAvailableLatch.countDown(); + } + + @Override + public void onLost(Network network) { + lastLostNetwork = network; + if (network.equals(currentNetwork)) { + currentNetwork = null; + } + mLostLatch.countDown(); + } + + @Override + public void onUnavailable() { + mUnavailableLatch.countDown(); + } + } +} diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java new file mode 100644 index 0000000000..c95dc28dd1 --- /dev/null +++ b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java @@ -0,0 +1,447 @@ +/* + * 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.util; + +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.Network; +import android.net.TetheredClient; +import android.net.TetheringManager; +import android.net.TetheringManager.TetheringEventCallback; +import android.net.TetheringManager.TetheringInterfaceRegexps; +import android.net.TetheringManager.TetheringRequest; +import android.net.wifi.WifiClient; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.SoftApCallback; +import android.os.ConditionVariable; + +import androidx.annotation.NonNull; + +import com.android.compatibility.common.util.SystemUtil; +import com.android.net.module.util.ArrayTrackRecord; + +import java.util.Collection; +import java.util.List; + +public final class CtsTetheringUtils { + private TetheringManager mTm; + private WifiManager mWm; + private Context mContext; + + private static final int DEFAULT_TIMEOUT_MS = 60_000; + + public CtsTetheringUtils(Context ctx) { + mContext = ctx; + mTm = mContext.getSystemService(TetheringManager.class); + mWm = mContext.getSystemService(WifiManager.class); + } + + public static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static int TIMEOUT_MS = 30_000; + public static class CallbackValue { + public final int error; + + private CallbackValue(final int e) { + error = e; + } + + public static class OnTetheringStarted extends CallbackValue { + OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); } + } + + public static class OnTetheringFailed extends CallbackValue { + OnTetheringFailed(final int error) { super(error); } + } + + @Override + public String toString() { + return String.format("%s(%d)", getClass().getSimpleName(), error); + } + } + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + + @Override + public void onTetheringStarted() { + mHistory.add(new CallbackValue.OnTetheringStarted()); + } + + @Override + public void onTetheringFailed(final int error) { + mHistory.add(new CallbackValue.OnTetheringFailed(error)); + } + + public void verifyTetheringStarted() { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv); + assertTrue("Fail start tethering:" + cv, + cv instanceof CallbackValue.OnTetheringStarted); + } + + public void expectTetheringFailed(final int expected) throws InterruptedException { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv); + assertTrue("Expect fail with error code " + expected + ", but received: " + cv, + (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected)); + } + } + + public static boolean isIfaceMatch(final List ifaceRegexs, final List ifaces) { + return isIfaceMatch(ifaceRegexs.toArray(new String[0]), ifaces); + } + + public static boolean isIfaceMatch(final String[] ifaceRegexs, final List ifaces) { + if (ifaceRegexs == null) fail("ifaceRegexs should not be null"); + + if (ifaces == null) return false; + + for (String s : ifaces) { + for (String regex : ifaceRegexs) { + if (s.matches(regex)) { + return true; + } + } + } + return false; + } + + // Must poll the callback before looking at the member. + public static class TestTetheringEventCallback implements TetheringEventCallback { + private static final int TIMEOUT_MS = 30_000; + + public enum CallbackType { + ON_SUPPORTED, + ON_UPSTREAM, + ON_TETHERABLE_REGEX, + ON_TETHERABLE_IFACES, + ON_TETHERED_IFACES, + ON_ERROR, + ON_CLIENTS, + ON_OFFLOAD_STATUS, + }; + + public static class CallbackValue { + public final CallbackType callbackType; + public final Object callbackParam; + public final int callbackParam2; + + private CallbackValue(final CallbackType type, final Object param, final int param2) { + this.callbackType = type; + this.callbackParam = param; + this.callbackParam2 = param2; + } + } + + private final ArrayTrackRecord mHistory = + new ArrayTrackRecord(); + + private final ArrayTrackRecord.ReadHead mCurrent = + mHistory.newReadHead(); + + private TetheringInterfaceRegexps mTetherableRegex; + private List mTetherableIfaces; + private List mTetheredIfaces; + + @Override + public void onTetheringSupported(boolean supported) { + mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, (supported ? 1 : 0))); + } + + @Override + public void onUpstreamChanged(Network network) { + mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); + } + + @Override + public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { + mTetherableRegex = reg; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); + } + + @Override + public void onTetherableInterfacesChanged(List interfaces) { + mTetherableIfaces = interfaces; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); + } + + @Override + public void onTetheredInterfacesChanged(List interfaces) { + mTetheredIfaces = interfaces; + mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); + } + + @Override + public void onError(String ifName, int error) { + mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); + } + + @Override + public void onClientsChanged(Collection clients) { + mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); + } + + @Override + public void onOffloadStatusChanged(int status) { + mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); + } + + public void expectTetherableInterfacesChanged(@NonNull List regexs) { + assertNotNull("No expected tetherable ifaces callback", mCurrent.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; + final List interfaces = (List) cv.callbackParam; + return isIfaceMatch(regexs, interfaces); + })); + } + + public void expectTetheredInterfacesChanged(@NonNull List regexs) { + assertNotNull("No expected tethered ifaces callback", mCurrent.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; + + final List interfaces = (List) cv.callbackParam; + + // Null regexs means no active tethering. + if (regexs == null) return interfaces.isEmpty(); + + return isIfaceMatch(regexs, interfaces); + })); + } + + public void expectCallbackStarted() { + int receivedBitMap = 0; + // The each bit represent a type from CallbackType.ON_*. + // Expect all of callbacks except for ON_ERROR. + final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal()); + // Receive ON_ERROR on started callback is not matter. It just means tethering is + // failed last time, should able to continue the test this time. + while ((receivedBitMap & expectedBitMap) != expectedBitMap) { + final CallbackValue cv = mCurrent.poll(TIMEOUT_MS, c -> true); + if (cv == null) { + fail("No expected callbacks, " + "expected bitmap: " + + expectedBitMap + ", actual: " + receivedBitMap); + } + + receivedBitMap |= (1 << cv.callbackType.ordinal()); + } + } + + public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { + assertNotNull("No offload status changed", mCurrent.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; + + final int status = (int) cv.callbackParam; + for (int offloadStatus : offloadStatuses) { + if (offloadStatus == status) return true; + } + + return false; + })); + } + + public void expectErrorOrTethered(final String iface) { + assertNotNull("No expected callback", mCurrent.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType == CallbackType.ON_ERROR + && iface.equals((String) cv.callbackParam)) { + return true; + } + if (cv.callbackType == CallbackType.ON_TETHERED_IFACES + && ((List) cv.callbackParam).contains(iface)) { + return true; + } + + return false; + })); + } + + public Network getCurrentValidUpstream() { + final CallbackValue result = mCurrent.poll(TIMEOUT_MS, (cv) -> { + return (cv.callbackType == CallbackType.ON_UPSTREAM) + && cv.callbackParam != null; + }); + + assertNotNull("No valid upstream", result); + return (Network) result.callbackParam; + } + + public void assumeTetheringSupported() { + final ArrayTrackRecord.ReadHead history = + mHistory.newReadHead(); + assertNotNull("No onSupported callback", history.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_SUPPORTED) return false; + + assumeTrue(cv.callbackParam2 == 1 /* supported */); + return true; + })); + } + + public void assumeWifiTetheringSupported(final Context ctx) throws Exception { + assumeTetheringSupported(); + + assumeTrue(!getTetheringInterfaceRegexps().getTetherableWifiRegexs().isEmpty()); + + final PackageManager pm = ctx.getPackageManager(); + assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_WIFI)); + + WifiManager wm = ctx.getSystemService(WifiManager.class); + // Wifi feature flags only work when wifi is on. + final boolean previousWifiEnabledState = wm.isWifiEnabled(); + try { + if (!previousWifiEnabledState) SystemUtil.runShellCommand("svc wifi enable"); + waitForWifiEnabled(ctx); + assumeTrue(wm.isPortableHotspotSupported()); + } finally { + if (!previousWifiEnabledState) SystemUtil.runShellCommand("svc wifi disable"); + } + } + + public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { + return mTetherableRegex; + } + + public List getTetherableInterfaces() { + return mTetherableIfaces; + } + + public List getTetheredInterfaces() { + return mTetheredIfaces; + } + } + + private static void waitForWifiEnabled(final Context ctx) throws Exception { + WifiManager wm = ctx.getSystemService(WifiManager.class); + if (wm.isWifiEnabled()) return; + + final ConditionVariable mWaiting = new ConditionVariable(); + final BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { + if (wm.isWifiEnabled()) mWaiting.open(); + } + } + }; + try { + ctx.registerReceiver(receiver, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); + if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { + assertTrue("Wifi did not become enabled after " + DEFAULT_TIMEOUT_MS + "ms", + wm.isWifiEnabled()); + } + } finally { + ctx.unregisterReceiver(receiver); + } + } + + public TestTetheringEventCallback registerTetheringEventCallback() { + final TestTetheringEventCallback tetherEventCallback = + new TestTetheringEventCallback(); + + mTm.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); + tetherEventCallback.expectCallbackStarted(); + + return tetherEventCallback; + } + + public void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) { + mTm.unregisterTetheringEventCallback(callback); + } + + private static List getWifiTetherableInterfaceRegexps( + final TestTetheringEventCallback callback) { + return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); + } + + public static boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) { + return !getWifiTetherableInterfaceRegexps(callback).isEmpty(); + } + + public void startWifiTethering(final TestTetheringEventCallback callback) + throws InterruptedException { + final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); + assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces())); + + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) + .setShouldShowEntitlementUi(false).build(); + mTm.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); + + callback.expectTetheredInterfacesChanged(wifiRegexs); + + callback.expectOneOfOffloadStatusChanged( + TETHER_HARDWARE_OFFLOAD_STARTED, + TETHER_HARDWARE_OFFLOAD_FAILED); + } + + private static class StopSoftApCallback implements SoftApCallback { + private final ConditionVariable mWaiting = new ConditionVariable(); + @Override + public void onStateChanged(int state, int failureReason) { + if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open(); + } + + @Override + public void onConnectedClientsChanged(List clients) { } + + public void waitForSoftApStopped() { + if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { + fail("stopSoftAp Timeout"); + } + } + } + + // Wait for softAp to be disabled. This is necessary on devices where stopping softAp + // deletes the interface. On these devices, tethering immediately stops when the softAp + // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be + // fully disabled, because otherwise the next test might fail because it attempts to + // start softAp before it's fully stopped. + public void expectSoftApDisabled() { + final StopSoftApCallback callback = new StopSoftApCallback(); + try { + mWm.registerSoftApCallback(c -> c.run(), callback); + // registerSoftApCallback will immediately call the callback with the current state, so + // this callback will fire even if softAp is already disabled. + callback.waitForSoftApStopped(); + } finally { + mWm.unregisterSoftApCallback(callback); + } + } + + public void stopWifiTethering(final TestTetheringEventCallback callback) { + mTm.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); + callback.expectTetheredInterfacesChanged(null); + callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + } +} diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp new file mode 100644 index 0000000000..b1d4a6052b --- /dev/null +++ b/tests/cts/tethering/Android.bp @@ -0,0 +1,56 @@ +// Copyright (C) 2019 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. + +android_test { + name: "CtsTetheringTest", + defaults: ["cts_defaults"], + + libs: [ + "android.test.base", + ], + + srcs: [ + "src/**/*.java", + ], + + static_libs: [ + "TetheringCommonTests", + "TetheringIntegrationTestsLib", + "compatibility-device-util-axt", + "cts-net-utils", + "net-tests-utils", + "ctstestrunner-axt", + "junit", + "junit-params", + ], + + jni_libs: [ + // For mockito extended + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], + + // Change to system current when TetheringManager move to bootclass path. + platform_apis: true, + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "general-tests", + "mts", + ], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", +} diff --git a/tests/cts/tethering/AndroidManifest.xml b/tests/cts/tethering/AndroidManifest.xml new file mode 100644 index 0000000000..911dbf2ffb --- /dev/null +++ b/tests/cts/tethering/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + diff --git a/tests/cts/tethering/AndroidTest.xml b/tests/cts/tethering/AndroidTest.xml new file mode 100644 index 0000000000..e752e3a82a --- /dev/null +++ b/tests/cts/tethering/AndroidTest.xml @@ -0,0 +1,35 @@ + + + + diff --git a/tests/cts/tethering/OWNERS b/tests/cts/tethering/OWNERS new file mode 100644 index 0000000000..cd6abeb6e8 --- /dev/null +++ b/tests/cts/tethering/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 31808 +lorenzo@google.com +satk@google.com + diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java new file mode 100644 index 0000000000..71a81ff621 --- /dev/null +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2019 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.tethering.test; + +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; +import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.cts.util.CtsTetheringUtils.isIfaceMatch; +import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + +import android.app.UiAutomation; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.LinkAddress; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.TetheringManager; +import android.net.TetheringManager.OnTetheringEntitlementResultListener; +import android.net.TetheringManager.TetheringInterfaceRegexps; +import android.net.TetheringManager.TetheringRequest; +import android.net.cts.util.CtsNetUtils; +import android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import android.net.cts.util.CtsTetheringUtils; +import android.net.cts.util.CtsTetheringUtils.StartTetheringCallback; +import android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.PersistableBundle; +import android.os.ResultReceiver; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +@RunWith(AndroidJUnit4.class) +public class TetheringManagerTest { + + private Context mContext; + + private ConnectivityManager mCm; + private TetheringManager mTM; + private WifiManager mWm; + private PackageManager mPm; + + private TetherChangeReceiver mTetherChangeReceiver; + private CtsNetUtils mCtsNetUtils; + private CtsTetheringUtils mCtsTetheringUtils; + + private static final int DEFAULT_TIMEOUT_MS = 60_000; + + private void adoptShellPermissionIdentity() { + final UiAutomation uiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uiAutomation.adoptShellPermissionIdentity(); + } + + private void dropShellPermissionIdentity() { + final UiAutomation uiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uiAutomation.dropShellPermissionIdentity(); + } + + @Before + public void setUp() throws Exception { + adoptShellPermissionIdentity(); + mContext = InstrumentationRegistry.getContext(); + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); + mWm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mPm = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); + mCtsTetheringUtils = new CtsTetheringUtils(mContext); + mTetherChangeReceiver = new TetherChangeReceiver(); + final IntentFilter filter = new IntentFilter( + TetheringManager.ACTION_TETHER_STATE_CHANGED); + final Intent intent = mContext.registerReceiver(mTetherChangeReceiver, filter); + if (intent != null) mTetherChangeReceiver.onReceive(null, intent); + } + + @After + public void tearDown() throws Exception { + mTM.stopAllTethering(); + mContext.unregisterReceiver(mTetherChangeReceiver); + dropShellPermissionIdentity(); + } + + private class TetherChangeReceiver extends BroadcastReceiver { + private class TetherState { + final ArrayList mAvailable; + final ArrayList mActive; + final ArrayList mErrored; + + TetherState(Intent intent) { + mAvailable = intent.getStringArrayListExtra( + TetheringManager.EXTRA_AVAILABLE_TETHER); + mActive = intent.getStringArrayListExtra( + TetheringManager.EXTRA_ACTIVE_TETHER); + mErrored = intent.getStringArrayListExtra( + TetheringManager.EXTRA_ERRORED_TETHER); + } + } + + @Override + public void onReceive(Context content, Intent intent) { + String action = intent.getAction(); + if (action.equals(TetheringManager.ACTION_TETHER_STATE_CHANGED)) { + mResult.add(new TetherState(intent)); + } + } + + public final LinkedBlockingQueue mResult = new LinkedBlockingQueue<>(); + + // Expects that tethering reaches the desired state. + // - If active is true, expects that tethering is enabled on at least one interface + // matching ifaceRegexs. + // - If active is false, expects that tethering is disabled on all the interfaces matching + // ifaceRegexs. + // Fails if any interface matching ifaceRegexs becomes errored. + public void expectTethering(final boolean active, final String[] ifaceRegexs) { + while (true) { + final TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS, ifaceRegexs); + assertNotNull("Did not receive expected state change, active: " + active, state); + + if (isIfaceActive(ifaceRegexs, state) == active) return; + } + } + + private TetherState pollAndAssertNoError(final int timeout, final String[] ifaceRegexs) { + final TetherState state = pollTetherState(timeout); + assertNoErroredIfaces(state, ifaceRegexs); + return state; + } + + private TetherState pollTetherState(final int timeout) { + try { + return mResult.poll(timeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + fail("No result after " + timeout + " ms"); + return null; + } + } + + private boolean isIfaceActive(final String[] ifaceRegexs, final TetherState state) { + return isIfaceMatch(ifaceRegexs, state.mActive); + } + + private void assertNoErroredIfaces(final TetherState state, final String[] ifaceRegexs) { + if (state == null || state.mErrored == null) return; + + if (isIfaceMatch(ifaceRegexs, state.mErrored)) { + fail("Found failed tethering interfaces: " + Arrays.toString(state.mErrored.toArray())); + } + } + } + + @Test + public void testStartTetheringWithStateChangeBroadcast() throws Exception { + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); + try { + tetherEventCallback.assumeWifiTetheringSupported(mContext); + } finally { + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); + } + + final String[] wifiRegexs = mTM.getTetherableWifiRegexs(); + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) + .setShouldShowEntitlementUi(false).build(); + mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); + + mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); + + mTM.stopTethering(TETHERING_WIFI); + mCtsTetheringUtils.expectSoftApDisabled(); + mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); + } + + @Test + public void testTetheringRequest() { + final TetheringRequest tr = new TetheringRequest.Builder(TETHERING_WIFI).build(); + assertEquals(TETHERING_WIFI, tr.getTetheringType()); + assertNull(tr.getLocalIpv4Address()); + assertNull(tr.getClientStaticIpv4Address()); + assertFalse(tr.isExemptFromEntitlementCheck()); + assertTrue(tr.getShouldShowEntitlementUi()); + + final LinkAddress localAddr = new LinkAddress("192.168.24.5/24"); + final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24"); + final TetheringRequest tr2 = new TetheringRequest.Builder(TETHERING_USB) + .setStaticIpv4Addresses(localAddr, clientAddr) + .setExemptFromEntitlementCheck(true) + .setShouldShowEntitlementUi(false).build(); + + assertEquals(localAddr, tr2.getLocalIpv4Address()); + assertEquals(clientAddr, tr2.getClientStaticIpv4Address()); + assertEquals(TETHERING_USB, tr2.getTetheringType()); + assertTrue(tr2.isExemptFromEntitlementCheck()); + assertFalse(tr2.getShouldShowEntitlementUi()); + } + + @Test + public void testRegisterTetheringEventCallback() throws Exception { + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); + + try { + tetherEventCallback.assumeWifiTetheringSupported(mContext); + + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); + + final List tetheredIfaces = tetherEventCallback.getTetheredInterfaces(); + assertEquals(1, tetheredIfaces.size()); + final String wifiTetheringIface = tetheredIfaces.get(0); + + mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); + + try { + final int ret = mTM.tether(wifiTetheringIface); + // There is no guarantee that the wifi interface will be available after disabling + // the hotspot, so don't fail the test if the call to tether() fails. + if (ret == TETHER_ERROR_NO_ERROR) { + // If calling #tether successful, there is a callback to tell the result of + // tethering setup. + tetherEventCallback.expectErrorOrTethered(wifiTetheringIface); + } + } finally { + mTM.untether(wifiTetheringIface); + } + } finally { + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); + } + } + + @Test + public void testGetTetherableInterfaceRegexps() { + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); + tetherEventCallback.assumeTetheringSupported(); + + final TetheringInterfaceRegexps tetherableRegexs = + tetherEventCallback.getTetheringInterfaceRegexps(); + final List wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); + final List usbRegexs = tetherableRegexs.getTetherableUsbRegexs(); + final List btRegexs = tetherableRegexs.getTetherableBluetoothRegexs(); + + assertEquals(wifiRegexs, Arrays.asList(mTM.getTetherableWifiRegexs())); + assertEquals(usbRegexs, Arrays.asList(mTM.getTetherableUsbRegexs())); + assertEquals(btRegexs, Arrays.asList(mTM.getTetherableBluetoothRegexs())); + + //Verify that any regex name should only contain in one array. + wifiRegexs.forEach(s -> assertFalse(usbRegexs.contains(s))); + wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); + usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); + + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); + } + + @Test + public void testStopAllTethering() throws Exception { + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); + try { + tetherEventCallback.assumeWifiTetheringSupported(mContext); + + // TODO: start ethernet tethering here when TetheringManagerTest is moved to + // TetheringIntegrationTest. + + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); + + mTM.stopAllTethering(); + tetherEventCallback.expectTetheredInterfacesChanged(null); + } finally { + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); + } + } + + @Test + public void testEnableTetheringPermission() throws Exception { + dropShellPermissionIdentity(); + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + } + + private class EntitlementResultListener implements OnTetheringEntitlementResultListener { + private final CompletableFuture future = new CompletableFuture<>(); + + @Override + public void onTetheringEntitlementResult(int result) { + future.complete(result); + } + + public int get(long timeout, TimeUnit unit) throws Exception { + return future.get(timeout, unit); + } + + } + + private void assertEntitlementResult(final Consumer functor, + final int expect) throws Exception { + final EntitlementResultListener listener = new EntitlementResultListener(); + functor.accept(listener); + + assertEquals(expect, listener.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + + @Test + public void testRequestLatestEntitlementResult() throws Exception { + assumeTrue(mTM.isTetheringSupported()); + // Verify that requestLatestTetheringEntitlementResult() can get entitlement + // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener. + assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI_P2P, false, c -> c.run(), listener), + TETHER_ERROR_ENTITLEMENT_UNKNOWN); + + // Verify that requestLatestTetheringEntitlementResult() can get entitlement + // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via receiver. + assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI_P2P, + new ResultReceiver(null /* handler */) { + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + listener.onTetheringEntitlementResult(resultCode); + } + }, false), + TETHER_ERROR_ENTITLEMENT_UNKNOWN); + + // Do not request TETHERING_WIFI entitlement result if TETHERING_WIFI is not available. + assumeTrue(mTM.getTetherableWifiRegexs().length > 0); + + // Verify that null listener will cause IllegalArgumentException. + try { + mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI, false, c -> c.run(), null); + } catch (IllegalArgumentException expect) { } + + // Override carrier config to ignore entitlement check. + final PersistableBundle bundle = new PersistableBundle(); + bundle.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, false); + overrideCarrierConfig(bundle); + + // Verify that requestLatestTetheringEntitlementResult() can get entitlement + // result TETHER_ERROR_NO_ERROR due to provisioning bypassed. + assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( + TETHERING_WIFI, false, c -> c.run(), listener), TETHER_ERROR_NO_ERROR); + + // Reset carrier config. + overrideCarrierConfig(null); + } + + private void overrideCarrierConfig(PersistableBundle bundle) { + final CarrierConfigManager configManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + configManager.overrideConfig(subId, bundle); + } + + @Test + public void testTetheringUpstream() throws Exception { + assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY)); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); + + boolean previousWifiEnabledState = false; + + try { + tetherEventCallback.assumeWifiTetheringSupported(mContext); + + previousWifiEnabledState = mWm.isWifiEnabled(); + if (previousWifiEnabledState) { + mCtsNetUtils.ensureWifiDisconnected(null); + } + + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + Network activeNetwork = null; + try { + mCm.registerDefaultNetworkCallback(networkCallback); + activeNetwork = networkCallback.waitForAvailable(); + } finally { + mCm.unregisterNetworkCallback(networkCallback); + } + + assertNotNull("No active network. Please ensure the device has working mobile data.", + activeNetwork); + final NetworkCapabilities activeNetCap = mCm.getNetworkCapabilities(activeNetwork); + + // If active nework is ETHERNET, tethering may not use cell network as upstream. + assumeFalse(activeNetCap.hasTransport(TRANSPORT_ETHERNET)); + + assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR)); + + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); + + final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + final boolean dunRequired = telephonyManager.isTetheringApnRequired(); + final int expectedCap = dunRequired ? NET_CAPABILITY_DUN : NET_CAPABILITY_INTERNET; + final Network network = tetherEventCallback.getCurrentValidUpstream(); + final NetworkCapabilities netCap = mCm.getNetworkCapabilities(network); + assertTrue(netCap.hasTransport(TRANSPORT_CELLULAR)); + assertTrue(netCap.hasCapability(expectedCap)); + + mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); + } finally { + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); + if (previousWifiEnabledState) { + mCtsNetUtils.connectToWifi(); + } + } + } +} From 549cc56731fcf27a40d4b0b4aeee10210301c60d Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 29 Sep 2020 14:39:25 +0800 Subject: [PATCH 1378/1415] Add CTS for getTx/RxBytes in TrafficStats Test: atest TrafficStatsTest Bug: 164965653 Change-Id: Ic3d253bbd036f40781d4f2706a67fb145ab4a575 --- .../src/android/net/cts/TrafficStatsTest.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index 37bdd44fbf..c92755ebbf 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -59,9 +59,11 @@ public class TrafficStatsTest extends AndroidTestCase { assertTrue(TrafficStats.getTotalRxBytes() >= 0); } - public void testValidPacketStats() { + public void testValidIfaceStats() { assertTrue(TrafficStats.getTxPackets("lo") >= 0); assertTrue(TrafficStats.getRxPackets("lo") >= 0); + assertTrue(TrafficStats.getTxBytes("lo") >= 0); + assertTrue(TrafficStats.getRxBytes("lo") >= 0); } public void testThreadStatsTag() throws Exception { @@ -109,6 +111,8 @@ public class TrafficStatsTest extends AndroidTestCase { final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid()); final long ifaceTxPacketsBefore = TrafficStats.getTxPackets("lo"); final long ifaceRxPacketsBefore = TrafficStats.getRxPackets("lo"); + final long ifaceTxBytesBefore = TrafficStats.getTxBytes("lo"); + final long ifaceRxBytesBefore = TrafficStats.getRxBytes("lo"); // Transfer 1MB of data across an explicitly localhost socket. final int byteCount = 1024; @@ -189,8 +193,12 @@ public class TrafficStatsTest extends AndroidTestCase { final long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore; final long ifaceTxPacketsAfter = TrafficStats.getTxPackets("lo"); final long ifaceRxPacketsAfter = TrafficStats.getRxPackets("lo"); + final long ifaceTxBytesAfter = TrafficStats.getTxBytes("lo"); + final long ifaceRxBytesAfter = TrafficStats.getRxBytes("lo"); final long ifaceTxDeltaPackets = ifaceTxPacketsAfter - ifaceTxPacketsBefore; final long ifaceRxDeltaPackets = ifaceRxPacketsAfter - ifaceRxPacketsBefore; + final long ifaceTxDeltaBytes = ifaceTxBytesAfter - ifaceTxBytesBefore; + final long ifaceRxDeltaBytes = ifaceRxBytesAfter - ifaceRxBytesBefore; // Localhost traffic *does* count against per-UID stats. /* @@ -249,6 +257,10 @@ public class TrafficStatsTest extends AndroidTestCase { packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); assertInRange("ifrxp", ifaceRxDeltaPackets, packetCount + minExpectedExtraPackets, packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); + assertInRange("iftxb", ifaceTxDeltaBytes, pktBytes + minExpExtraPktBytes, + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaTxOtherPktBytes); + assertInRange("ifrxb", ifaceRxDeltaBytes, pktBytes + minExpExtraPktBytes, + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaRxOtherPktBytes); // Localhost traffic *does* count against total stats. // Check the total stats increased after test data transfer over localhost has been made. @@ -264,6 +276,10 @@ public class TrafficStatsTest extends AndroidTestCase { totalTxPacketsAfter >= totalTxPacketsBefore + ifaceTxDeltaPackets); assertTrue("ifrxp: " + ifaceRxPacketsBefore + " -> " + ifaceRxPacketsAfter, totalRxPacketsAfter >= totalRxPacketsBefore + ifaceRxDeltaPackets); + assertTrue("iftxb: " + ifaceTxBytesBefore + " -> " + ifaceTxBytesAfter, + totalTxBytesAfter >= totalTxBytesBefore + ifaceTxDeltaBytes); + assertTrue("ifrxb: " + ifaceRxBytesBefore + " -> " + ifaceRxBytesAfter, + totalRxBytesAfter >= totalRxBytesBefore + ifaceRxDeltaBytes); // Localhost traffic should *not* count against mobile stats, // There might be some other traffic, but nowhere near 1MB. From 42ea4318f7f99c3d1a5294f17a2206c6e65ad796 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 27 Oct 2020 15:57:19 +0800 Subject: [PATCH 1379/1415] Exclude lingering traffic from loopback iface stats check Lingering traffic from previous tests are only happens in non-loopback interface. Stats gets from loopback interface would not see them. Thus, exclude them from in-range check. Test: atest TrafficStatsTest --rerun-until-failure 100 Bug: 164965653 Change-Id: Ic15c4c2e27f86b5711ada904c22734206c67d671 --- tests/cts/net/src/android/net/cts/TrafficStatsTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java index c92755ebbf..1d9268ae11 100755 --- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java +++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java @@ -254,13 +254,13 @@ public class TrafficStatsTest extends AndroidTestCase { assertInRange("uidrxb", uidRxDeltaBytes, pktBytes + minExpExtraPktBytes, pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaRxOtherPktBytes); assertInRange("iftxp", ifaceTxDeltaPackets, packetCount + minExpectedExtraPackets, - packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); + packetCount + packetCount + maxExpectedExtraPackets); assertInRange("ifrxp", ifaceRxDeltaPackets, packetCount + minExpectedExtraPackets, - packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); + packetCount + packetCount + maxExpectedExtraPackets); assertInRange("iftxb", ifaceTxDeltaBytes, pktBytes + minExpExtraPktBytes, - pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaTxOtherPktBytes); + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes); assertInRange("ifrxb", ifaceRxDeltaBytes, pktBytes + minExpExtraPktBytes, - pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaRxOtherPktBytes); + pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes); // Localhost traffic *does* count against total stats. // Check the total stats increased after test data transfer over localhost has been made. From 862c8a1ea0367f9e6b5ef93fd45f9c3e0762de29 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 2 Nov 2020 18:33:32 +0800 Subject: [PATCH 1380/1415] Fix tethering doesn't turn off issue When user restriction turns on, all tethering functions should be disabled. But tethering functions still work after restrication is on. Because tethering request would be removed from mActiveTetheringRequests after starting tethering that will result in Tethering#isTetheringActive() always returns false. Thus, update the design to check tethered interface to ensure that any of tethering function is working. Bug: 169596583 Test: atest TetheringTests Test: Manually test that tethering function would be disabled and notification would show to user after restriction was on. Change-Id: Icb9649a5ecdec2d029ac763b5b9b80042ad50eb9 --- .../networkstack/tethering/Tethering.java | 7 ++- .../networkstack/tethering/TetheringTest.java | 49 +++++++++++++++---- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 5a0c5b0cff..2c91d100ec 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -1079,9 +1079,14 @@ public class Tethering { } } + @VisibleForTesting + SparseArray getActiveTetheringRequests() { + return mActiveTetheringRequests; + } + @VisibleForTesting boolean isTetheringActive() { - return mActiveTetheringRequests.size() > 0; + return getTetheredIfaces().length > 0; } @VisibleForTesting diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 37a4d90a72..0a37f54aaa 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -52,6 +52,7 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static com.android.networkstack.tethering.Tethering.UserRestrictionActionListener; import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES; @@ -735,9 +736,12 @@ public class TetheringTest { initTetheringUpstream(upstreamState); // Emulate pressing the USB tethering button in Settings UI. - mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null); + final TetheringRequestParcel request = createTetheringRequestParcel(TETHERING_USB); + mTethering.startTethering(request, null); mLooper.dispatchAll(); verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); + assertEquals(1, mTethering.getActiveTetheringRequests().size()); + assertEquals(request, mTethering.getActiveTetheringRequests().get(TETHERING_USB)); mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true); } @@ -1174,20 +1178,26 @@ public class TetheringTest { verifyNoMoreInteractions(mNetd); } + private UserRestrictionActionListener makeUserRestrictionActionListener( + final Tethering tethering, final boolean currentDisallow, final boolean nextDisallow) { + final Bundle newRestrictions = new Bundle(); + newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow); + when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions); + + final UserRestrictionActionListener ural = + new UserRestrictionActionListener(mUserManager, tethering, mNotificationUpdater); + ural.mDisallowTethering = currentDisallow; + return ural; + } + private void runUserRestrictionsChange( boolean currentDisallow, boolean nextDisallow, boolean isTetheringActive, int expectedInteractionsWithShowNotification) throws Exception { - final Bundle newRestrictions = new Bundle(); - newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow); final Tethering mockTethering = mock(Tethering.class); when(mockTethering.isTetheringActive()).thenReturn(isTetheringActive); - when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions); - - final Tethering.UserRestrictionActionListener ural = - new Tethering.UserRestrictionActionListener( - mUserManager, mockTethering, mNotificationUpdater); - ural.mDisallowTethering = currentDisallow; + final UserRestrictionActionListener ural = + makeUserRestrictionActionListener(mockTethering, currentDisallow, nextDisallow); ural.onUserRestrictionsChanged(); verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification)) @@ -1256,6 +1266,27 @@ public class TetheringTest { expectedInteractionsWithShowNotification); } + @Test + public void testUntetherUsbWhenRestrictionIsOn() { + // Start usb tethering and check that usb interface is tethered. + final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); + runUsbTethering(upstreamState); + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + assertTrue(mTethering.isTetheringActive()); + assertEquals(0, mTethering.getActiveTetheringRequests().size()); + + final Tethering.UserRestrictionActionListener ural = makeUserRestrictionActionListener( + mTethering, false /* currentDisallow */, true /* nextDisallow */); + + ural.onUserRestrictionsChanged(); + mLooper.dispatchAll(); + + // Verify that restriction notification has showed to user. + verify(mNotificationUpdater, times(1)).notifyTetheringDisabledByRestriction(); + // Verify that usb tethering has been disabled. + verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE); + } + private class TestTetheringEventCallback extends ITetheringEventCallback.Stub { private final ArrayList mActualUpstreams = new ArrayList<>(); private final ArrayList mTetheringConfigs = From 108f82b463e844e36e64f02d61e24bfbeac1407c Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Tue, 10 Nov 2020 11:34:18 +0000 Subject: [PATCH 1381/1415] Add an owner for NetworkWatchlistTest. Test: N/A Change-Id: Icfbeaf60e1ff98d29c449b9fcc43c0e5ce39a20e --- tests/cts/net/OWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/OWNERS b/tests/cts/net/OWNERS index d55855650f..7722bb37b6 100644 --- a/tests/cts/net/OWNERS +++ b/tests/cts/net/OWNERS @@ -1,3 +1,5 @@ # Bug component: 31808 lorenzo@google.com satk@google.com + +per-file src/android/net/cts/NetworkWatchlistTest.java=alanstokes@google.com From 5c39147e5af6d84df72145331f49aa59aca10482 Mon Sep 17 00:00:00 2001 From: Yintang Gu Date: Tue, 10 Nov 2020 11:37:32 +0800 Subject: [PATCH 1382/1415] Tune up TIMEOUTs of IPSec CTS for low end devices Ikev2VpnTest#testStartStopVpnProfileV4 and testStartStopVpnProfileV6 contains the IKE sequences and requires the phone to send and receive the required packet in 1000ms. On some low end devices, the response time may exceeds this TIMEOUT sometimes. So we need to use larger timeouts. Bug: 171176723 Change-Id: I005b83ffecd8ade5063000690bfd4136d82f1a07 --- tests/cts/net/src/android/net/cts/TunUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index adaba9d398..7887385234 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -47,7 +47,7 @@ public class TunUtils { protected static final int IP6_PROTO_OFFSET = 6; private static final int DATA_BUFFER_LEN = 4096; - private static final int TIMEOUT = 1000; + private static final int TIMEOUT = 2000; private final List mPackets = new ArrayList<>(); private final ParcelFileDescriptor mTunFd; From e90c48c9aadc62a746748918ed6dad179be869a6 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 19 Nov 2020 17:26:15 +0900 Subject: [PATCH 1383/1415] This bug was fixed in S, don't test for it in R Bug: 172401665 Test: CtsNetTestCasesLatestSdk Change-Id: Ib9fb3ec09eeaebbb4ac1b1b458cfcc5c4f506cff --- tests/cts/net/src/android/net/cts/NetworkAgentTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 7508228734..45a84f8985 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -62,6 +62,7 @@ import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.AsyncChannel import com.android.net.module.util.ArrayTrackRecord import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback @@ -541,6 +542,7 @@ class NetworkAgentTest { } @Test + @IgnoreUpTo(android.os.Build.VERSION_CODES.R) fun testAgentStartsInConnecting() { val mockContext = mock(Context::class.java) val mockCm = mock(ConnectivityManager::class.java) From 1bc62872499283e482dee4fab67ac6567bc79d30 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 25 Nov 2020 07:35:21 +0000 Subject: [PATCH 1384/1415] Add TEST_MAPPING config for CTS postsubmit The new configuration runs tests on physical devices with SIM cards. This is only done in postsubmit, as such tests can only run a few (~2) times a day due to availability of the devices. This configuration allows running all tests, so there is no annotation filter. Change-Id: If95e4deeed8098327023f99e6e610331b8e86a0f Test: TH validates TEST_MAPPING configurations --- tests/cts/net/TEST_MAPPING | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/cts/net/TEST_MAPPING b/tests/cts/net/TEST_MAPPING index 7545cb0c30..8f65b655dc 100644 --- a/tests/cts/net/TEST_MAPPING +++ b/tests/cts/net/TEST_MAPPING @@ -19,5 +19,12 @@ } ] } + ], + // Tests on physical devices with SIM cards: postsubmit only for capacity constraints + "mainline-postsubmit": [ + { + "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]", + "keywords": ["sim"] + } ] } From 29e0258707f283ae3d3eb70db891d133e9f10e52 Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Thu, 26 Nov 2020 12:30:05 +0000 Subject: [PATCH 1385/1415] Revert "Tweak NetworkWatchListTests." This reverts commit 17b1001282e59fd770f211caa7faf5feb80afb13. Reason for revert: I'll resubmit in AOSP, with the fix for the test included. Change-Id: I5bd63a5341a9b67ce63ec34080de13ed9203eba6 --- .../android/net/cts/NetworkWatchlistTest.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java b/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java index 63b3f711c5..81a9e30dd5 100644 --- a/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java @@ -24,10 +24,9 @@ import static org.junit.Assume.assumeTrue; import android.content.Context; import android.net.ConnectivityManager; +import android.platform.test.annotations.AppModeFull; import android.os.FileUtils; import android.os.ParcelFileDescriptor; -import android.platform.test.annotations.AppModeFull; -import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -133,9 +132,14 @@ public class NetworkWatchlistTest { private void pipeResourceToFileDescriptor(String res, ParcelFileDescriptor pfd) throws IOException { - try (InputStream resStream = getClass().getClassLoader().getResourceAsStream(res); - FileOutputStream fdStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd)) { - FileUtils.copy(resStream, fdStream); + InputStream resStream = getClass().getClassLoader().getResourceAsStream(res); + FileOutputStream fdStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd); + + FileUtils.copy(resStream, fdStream); + + try { + fdStream.close(); + } catch (IOException e) { } } @@ -149,8 +153,6 @@ public class NetworkWatchlistTest { } private void setWatchlistConfig(String watchlistConfigFile) throws Exception { - Log.w("NetworkWatchlistTest", "Setting watchlist config " + watchlistConfigFile - + " in " + Thread.currentThread().getName()); cleanup(); saveResourceToFile(watchlistConfigFile, TMP_CONFIG_PATH); final String cmdResult = runCommand( From 36529b250a74a93e3040dc0d94d33951e380c61c Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Fri, 6 Nov 2020 16:57:53 +0000 Subject: [PATCH 1386/1415] Fix race condition in NetworkWatchListTest We were running cp to create a file and then running a command to read the file. However were weren't waiting for the cp to finish (or, indeed, start), so occasionally the read would fail saying the file didn't exist. Also added some logging, because diagnosing failure without it is painful. Also simplify & improve file closing logic. Some of this was previously submitted on internal master as change I1c875102f0cce32cbbe2e3b36de913741c9abb92, but I've reverted that in favor of this. Bug: 168216494 Test: atest CtsNetTestCases:android.net.cts.NetworkWatchlistTest Change-Id: I46a9db8b7a1885a9829f00bbd3233b863cfd1f5d --- .../android/net/cts/NetworkWatchlistTest.java | 81 ++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java b/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java index 81a9e30dd5..6833c70994 100644 --- a/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkWatchlistTest.java @@ -22,11 +22,13 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeTrue; +import android.app.UiAutomation; import android.content.Context; import android.net.ConnectivityManager; -import android.platform.test.annotations.AppModeFull; import android.os.FileUtils; import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.AppModeFull; +import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -117,42 +119,9 @@ public class NetworkWatchlistTest { return formatter.toString(); } - private void saveResourceToFile(String res, String filePath) throws IOException { - // App can't access /data/local/tmp directly, so we pipe resource to file through stdin. - ParcelFileDescriptor stdin = pipeFromStdin(filePath); - pipeResourceToFileDescriptor(res, stdin); - } - - /* Pipe stdin to a file in filePath. Returns PFD for stdin. */ - private ParcelFileDescriptor pipeFromStdin(String filePath) { - // Not all devices have symlink for /dev/stdin, so use /proc/self/fd/0 directly. - // /dev/stdin maps to /proc/self/fd/0. - return runRwCommand("cp /proc/self/fd/0 " + filePath)[1]; - } - - private void pipeResourceToFileDescriptor(String res, ParcelFileDescriptor pfd) - throws IOException { - InputStream resStream = getClass().getClassLoader().getResourceAsStream(res); - FileOutputStream fdStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd); - - FileUtils.copy(resStream, fdStream); - - try { - fdStream.close(); - } catch (IOException e) { - } - } - - private static String runCommand(String command) throws IOException { - return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command); - } - - private static ParcelFileDescriptor[] runRwCommand(String command) { - return InstrumentationRegistry.getInstrumentation() - .getUiAutomation().executeShellCommandRw(command); - } - private void setWatchlistConfig(String watchlistConfigFile) throws Exception { + Log.w("NetworkWatchlistTest", "Setting watchlist config " + watchlistConfigFile + + " in " + Thread.currentThread().getName()); cleanup(); saveResourceToFile(watchlistConfigFile, TMP_CONFIG_PATH); final String cmdResult = runCommand( @@ -160,4 +129,44 @@ public class NetworkWatchlistTest { assertThat(cmdResult).contains("Success"); cleanup(); } + + private void saveResourceToFile(String res, String filePath) throws IOException { + final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation() + .getUiAutomation(); + // App can't access /data/local/tmp directly, so we pipe resource to file through stdin. + // Not all devices have symlink for /dev/stdin, so use /proc/self/fd/0 directly. + // /dev/stdin maps to /proc/self/fd/0. + final ParcelFileDescriptor[] fileDescriptors = uiAutomation.executeShellCommandRw( + "cp /proc/self/fd/0 " + filePath); + + ParcelFileDescriptor stdin = fileDescriptors[1]; + ParcelFileDescriptor stdout = fileDescriptors[0]; + + pipeResourceToFileDescriptor(res, stdin); + + // Wait for the process to close its stdout - which should mean it has completed. + consumeFile(stdout); + } + + private void consumeFile(ParcelFileDescriptor pfd) throws IOException { + try (InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + for (;;) { + if (stream.read() == -1) { + return; + } + } + } + } + + private void pipeResourceToFileDescriptor(String res, ParcelFileDescriptor pfd) + throws IOException { + try (InputStream resStream = getClass().getClassLoader().getResourceAsStream(res); + FileOutputStream fdStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd)) { + FileUtils.copy(resStream, fdStream); + } + } + + private static String runCommand(String command) throws IOException { + return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command); + } } From 1fb77ae003ce89fb001e291b032bc7a42f40b37e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 26 Nov 2020 18:13:41 +0900 Subject: [PATCH 1387/1415] Add a .gitignore in packages/modules/Connectivity. Test: None Change-Id: I23ca7980db01b3f32e94876fa9a0b3952cf29914 --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..ccff05290a --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Eclipse project +**/.classpath +**/.project + +# IntelliJ project +**/.idea +**/*.iml +**/*.ipr From a7d3c79a7669d439866cfe1532f44584387f185a Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 27 Nov 2020 17:11:56 +0900 Subject: [PATCH 1388/1415] Add repo hooks for packages/modules/Connectivity. This adds the Java and Kotlin linters. Test: repo upload Change-Id: Ic508b17ed0b4e33c41debbbeb7a6c0406c46a973 --- PREUPLOAD.cfg | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 PREUPLOAD.cfg diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg new file mode 100644 index 0000000000..ebc1264c7a --- /dev/null +++ b/PREUPLOAD.cfg @@ -0,0 +1,4 @@ +[Hook Scripts] +checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} + +ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES} From 99fcd0bbf86de453915437b833b1fb1f604d09e9 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 27 Nov 2020 18:06:29 +0900 Subject: [PATCH 1389/1415] Add OWNERS for packages/modules/Connectivity. Specify the owners here instead of including them from other places (e.g., frameworks/base, NetworkStack) because we hope that this project will eventually contain all the code. Test: none Change-Id: I82811a9758480f16654145c4d55ef784be09de2b --- OWNERS | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 OWNERS diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000000..0e1e65df81 --- /dev/null +++ b/OWNERS @@ -0,0 +1,6 @@ +codewiz@google.com +jchalard@google.com +junyulai@google.com +lorenzo@google.com +reminv@google.com +satk@google.com From 3657ce9cdacb9d1b134336e2f94c710aad42a1da Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 26 Nov 2020 18:09:20 +0900 Subject: [PATCH 1390/1415] Add a CTS test for NetworkAgent#setUnderlyingNetworks. Bug: 173331190 Test: atest CtsNetTestCases:NetworkAgentTest#testSetUnderlyingNetworks Change-Id: I442a618d2d50eb15dbcb8926b60fc6fd0d5b2f3e --- .../src/android/net/cts/NetworkAgentTest.kt | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 45a84f8985..85d0a2e7eb 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -82,6 +82,7 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.verify import java.net.InetAddress import java.time.Duration +import java.util.Arrays import java.util.UUID import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -312,9 +313,11 @@ class NetworkAgentTest { private fun createNetworkAgent( context: Context = realContext, - name: String? = null + name: String? = null, + nc: NetworkCapabilities = NetworkCapabilities(), + lp: LinkProperties = LinkProperties() ): TestableNetworkAgent { - val nc = NetworkCapabilities().apply { + nc.apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) @@ -325,7 +328,7 @@ class NetworkAgentTest { setNetworkSpecifier(StringNetworkSpecifier(name)) } } - val lp = LinkProperties().apply { + lp.apply { addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) } val config = NetworkAgentConfig.Builder().build() @@ -541,8 +544,63 @@ class NetworkAgentTest { // tearDown() will unregister the requests and agents } + private fun hasAllTransports(nc: NetworkCapabilities?, transports: IntArray) = + nc != null && transports.all { nc.hasTransport(it) } + @Test - @IgnoreUpTo(android.os.Build.VERSION_CODES.R) + @IgnoreUpTo(Build.VERSION_CODES.R) + fun testSetUnderlyingNetworks() { + val request = NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addTransportType(NetworkCapabilities.TRANSPORT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) // TODO: add to VPN! + .build() + val callback = TestableNetworkCallback() + mCM.registerNetworkCallback(request, callback) + + val nc = NetworkCapabilities().apply { + addTransportType(NetworkCapabilities.TRANSPORT_TEST) + addTransportType(NetworkCapabilities.TRANSPORT_VPN) + removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + } + val defaultNetwork = mCM.activeNetwork + assertNotNull(defaultNetwork) + val defaultNetworkTransports = mCM.getNetworkCapabilities(defaultNetwork).transportTypes + + val agent = createNetworkAgent(nc = nc) + agent.register() + agent.markConnected() + callback.expectAvailableThenValidatedCallbacks(agent.network!!) + + var vpnNc = mCM.getNetworkCapabilities(agent.network) + assertNotNull(vpnNc) + assertTrue(NetworkCapabilities.TRANSPORT_VPN in vpnNc.transportTypes) + assertTrue(hasAllTransports(vpnNc, defaultNetworkTransports), + "VPN transports ${Arrays.toString(vpnNc.transportTypes)}" + + " lacking transports from ${Arrays.toString(defaultNetworkTransports)}") + + agent.setUnderlyingNetworks(listOf()) + callback.expectCapabilitiesThat(agent.network!!) { + it.transportTypes.size == 1 && it.hasTransport(NetworkCapabilities.TRANSPORT_VPN) + } + + val expectedTransports = (defaultNetworkTransports.toSet() + + NetworkCapabilities.TRANSPORT_VPN).toIntArray() + agent.setUnderlyingNetworks(null) + callback.expectCapabilitiesThat(agent.network!!) { + it.transportTypes.size == expectedTransports.size && + hasAllTransports(it, expectedTransports) + } + + agent.unregister() + callback.expectCallback(agent.network) + + mCM.unregisterNetworkCallback(callback) + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.R) fun testAgentStartsInConnecting() { val mockContext = mock(Context::class.java) val mockCm = mock(ConnectivityManager::class.java) From d01761e07f80bbfc13b1a5d7ed3bcd31e4743794 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 3 Dec 2020 08:06:32 +0000 Subject: [PATCH 1391/1415] Set noparent in connectivity CTS owners Also reorganize the files to have one toplevel CTS owners file, and only additional owners in subdirectories. Change-Id: I28ce193896e1ade2034589327805870774a4d608 Test: m --- tests/cts/{tethering => }/OWNERS | 4 ++-- tests/cts/hostside/OWNERS | 2 +- tests/cts/net/OWNERS | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) rename tests/cts/{tethering => }/OWNERS (60%) diff --git a/tests/cts/tethering/OWNERS b/tests/cts/OWNERS similarity index 60% rename from tests/cts/tethering/OWNERS rename to tests/cts/OWNERS index cd6abeb6e8..426434508a 100644 --- a/tests/cts/tethering/OWNERS +++ b/tests/cts/OWNERS @@ -1,4 +1,4 @@ # Bug component: 31808 +set noparent lorenzo@google.com -satk@google.com - +satk@google.com \ No newline at end of file diff --git a/tests/cts/hostside/OWNERS b/tests/cts/hostside/OWNERS index 52c8053323..20bc55e8bd 100644 --- a/tests/cts/hostside/OWNERS +++ b/tests/cts/hostside/OWNERS @@ -1,4 +1,4 @@ # Bug component: 61373 +# Inherits parent owners sudheersai@google.com -lorenzo@google.com jchalard@google.com diff --git a/tests/cts/net/OWNERS b/tests/cts/net/OWNERS index 7722bb37b6..432bd9b27f 100644 --- a/tests/cts/net/OWNERS +++ b/tests/cts/net/OWNERS @@ -1,5 +1,3 @@ # Bug component: 31808 -lorenzo@google.com -satk@google.com - +# Inherits parent owners per-file src/android/net/cts/NetworkWatchlistTest.java=alanstokes@google.com From 977464ef5a9832cccb4d1e5c60600c2efc528c83 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 7 Dec 2020 14:00:05 +0900 Subject: [PATCH 1392/1415] Pass in proper NetworkCapabilities in testSetUnderlyingNetworks. The CL that introduced testSetUnderlyingNetworks allowed tests to pass in NetworkCapabilities when registering an agent, but incorrectly always set the agent's capabilities anyway. This resulted in testSetUnderlyingNetworks registering an agent with TRANSPORT_VPN and NET_CAPABILITY_NOT_VPN. Fix this by ensuring that createNetworkAgent either uses the passed-in capabilities unmodified, or creates its own. Assert that the test VPN network does not have NET_CAPABILITY_NOT_VPN. While I'm at it, remove the manual unregistration of the callback by using the registerNetworkCallback helper method. Also add a little bit of extra test coverage. Bug: 173331190 Test: test-only change Change-Id: I114d876a1b2bf5344dd7c6fa23862df1c0a412c3 --- .../src/android/net/cts/NetworkAgentTest.kt | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 85d0a2e7eb..38002365ca 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -57,6 +57,7 @@ import android.os.HandlerThread import android.os.Looper import android.os.Message import android.os.Messenger +import android.util.DebugUtils.valueToString import androidx.test.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.AsyncChannel @@ -314,10 +315,10 @@ class NetworkAgentTest { private fun createNetworkAgent( context: Context = realContext, name: String? = null, - nc: NetworkCapabilities = NetworkCapabilities(), - lp: LinkProperties = LinkProperties() + initialNc: NetworkCapabilities? = null, + initialLp: LinkProperties? = null ): TestableNetworkAgent { - nc.apply { + val nc = initialNc ?: NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) @@ -328,7 +329,7 @@ class NetworkAgentTest { setNetworkSpecifier(StringNetworkSpecifier(name)) } } - lp.apply { + val lp = initialLp ?: LinkProperties().apply { addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) } val config = NetworkAgentConfig.Builder().build() @@ -557,7 +558,7 @@ class NetworkAgentTest { .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) // TODO: add to VPN! .build() val callback = TestableNetworkCallback() - mCM.registerNetworkCallback(request, callback) + registerNetworkCallback(request, callback) val nc = NetworkCapabilities().apply { addTransportType(NetworkCapabilities.TRANSPORT_TEST) @@ -566,25 +567,30 @@ class NetworkAgentTest { } val defaultNetwork = mCM.activeNetwork assertNotNull(defaultNetwork) - val defaultNetworkTransports = mCM.getNetworkCapabilities(defaultNetwork).transportTypes + val defaultNetworkCapabilities = mCM.getNetworkCapabilities(defaultNetwork) + val defaultNetworkTransports = defaultNetworkCapabilities.transportTypes - val agent = createNetworkAgent(nc = nc) + val agent = createNetworkAgent(initialNc = nc) agent.register() agent.markConnected() callback.expectAvailableThenValidatedCallbacks(agent.network!!) + // Check that the default network's transport is propagated to the VPN. var vpnNc = mCM.getNetworkCapabilities(agent.network) assertNotNull(vpnNc) assertTrue(NetworkCapabilities.TRANSPORT_VPN in vpnNc.transportTypes) + assertFalse(vpnNc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)) assertTrue(hasAllTransports(vpnNc, defaultNetworkTransports), "VPN transports ${Arrays.toString(vpnNc.transportTypes)}" + " lacking transports from ${Arrays.toString(defaultNetworkTransports)}") + // Check that when no underlying networks are announced the underlying transport disappears. agent.setUnderlyingNetworks(listOf()) callback.expectCapabilitiesThat(agent.network!!) { it.transportTypes.size == 1 && it.hasTransport(NetworkCapabilities.TRANSPORT_VPN) } + // Put the underlying network back and check that the underlying transport reappears. val expectedTransports = (defaultNetworkTransports.toSet() + NetworkCapabilities.TRANSPORT_VPN).toIntArray() agent.setUnderlyingNetworks(null) @@ -593,10 +599,22 @@ class NetworkAgentTest { hasAllTransports(it, expectedTransports) } + // Check that some underlying capabilities are propagated. + // This is not very accurate because the test does not control the capabilities of the + // underlying networks, and because not congested, not roaming, and not suspended are the + // default anyway. It's still useful as an extra check though. + vpnNc = mCM.getNetworkCapabilities(agent.network) + for (cap in listOf(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED, + NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, + NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) { + val capStr = valueToString(NetworkCapabilities::class.java, "NET_CAPABILITY_", cap) + if (defaultNetworkCapabilities.hasCapability(cap) && !vpnNc.hasCapability(cap)) { + fail("$capStr not propagated from underlying: $defaultNetworkCapabilities") + } + } + agent.unregister() callback.expectCallback(agent.network) - - mCM.unregisterNetworkCallback(callback) } @Test From e5bd0dba21413062121e162e162722ba3224c5ef Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Tue, 8 Dec 2020 09:57:42 +0000 Subject: [PATCH 1393/1415] Use libnetjniutils for JNI File Descriptor info Drops use of deprecated API in libnativehelper and uses a common helper that will be stable across releases. Bug: 158749603 Test: m Change-Id: Ic1a1811ffb9a1c207f562a180417e99df31e3502 --- Tethering/Android.bp | 3 +++ Tethering/jni/android_net_util_TetheringUtils.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 23aa7f8d51..d8557adc61 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -67,6 +67,9 @@ cc_library { "liblog", "libnativehelper_compat_libc++", ], + static_libs: [ + "libnetjniutils", + ], // We cannot use plain "libc++" here to link libc++ dynamically because it results in: // java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp index 94c871d8a3..7bfb6dab4a 100644 --- a/Tethering/jni/android_net_util_TetheringUtils.cpp +++ b/Tethering/jni/android_net_util_TetheringUtils.cpp @@ -19,8 +19,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -57,7 +57,7 @@ static void android_net_util_setupIcmpFilter(JNIEnv *env, jobject javaFd, uint32 filter_code, }; - int fd = jniGetFDFromFileDescriptor(env, javaFd); + int fd = netjniutils::GetNativeFileDescriptor(env, javaFd); if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) { jniThrowExceptionFmt(env, "java/net/SocketException", "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno)); @@ -79,7 +79,7 @@ static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject j { static const int kLinkLocalHopLimit = 255; - int fd = jniGetFDFromFileDescriptor(env, javaFd); + int fd = netjniutils::GetNativeFileDescriptor(env, javaFd); // Set an ICMPv6 filter that only passes Router Solicitations. struct icmp6_filter rs_only; From cc3e994f162cf876e7f794b7ff545c07d170f197 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 12 Dec 2020 22:42:58 +0900 Subject: [PATCH 1394/1415] Minor fixes to NetworkAgentTest. - Use a more realistic routing config (instead of a LinkAddress with prefix length 0, an address with a mask of 32 and a default route). - Use InetAddresses to parse IP addresses since it's a public API. - Import the NET_CAPABILITY_xxx and TRANSPORT_xxx constants for readability. Bug: 173331190 Test: test-only change Change-Id: I9703d7dd5781f60fb3d531267d3f5370cbccd64f --- .../src/android/net/cts/NetworkAgentTest.kt | 83 +++++++++++-------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 38002365ca..bb66129cdf 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -18,6 +18,8 @@ package android.net.cts import android.app.Instrumentation import android.content.Context import android.net.ConnectivityManager +import android.net.InetAddresses +import android.net.IpPrefix import android.net.KeepalivePacketData import android.net.LinkAddress import android.net.LinkProperties @@ -34,9 +36,20 @@ import android.net.NetworkAgent.INVALID_NETWORK import android.net.NetworkAgent.VALID_NETWORK import android.net.NetworkAgentConfig import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN +import android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED +import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED +import android.net.NetworkCapabilities.TRANSPORT_TEST +import android.net.NetworkCapabilities.TRANSPORT_VPN import android.net.NetworkInfo import android.net.NetworkProvider import android.net.NetworkRequest +import android.net.RouteInfo import android.net.SocketKeepalive import android.net.StringNetworkSpecifier import android.net.Uri @@ -81,7 +94,6 @@ import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock import org.mockito.Mockito.verify -import java.net.InetAddress import java.time.Duration import java.util.Arrays import java.util.UUID @@ -123,8 +135,8 @@ class NetworkAgentTest { @Rule @JvmField val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) - private val LOCAL_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.1") - private val REMOTE_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.2") + private val LOCAL_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1") + private val REMOTE_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.2") private val mCM = realContext.getSystemService(ConnectivityManager::class.java) private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") @@ -319,18 +331,19 @@ class NetworkAgentTest { initialLp: LinkProperties? = null ): TestableNetworkAgent { val nc = initialNc ?: NetworkCapabilities().apply { - addTransportType(NetworkCapabilities.TRANSPORT_TEST) - removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) - addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) - addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + addTransportType(TRANSPORT_TEST) + removeCapability(NET_CAPABILITY_TRUSTED) + removeCapability(NET_CAPABILITY_INTERNET) + addCapability(NET_CAPABILITY_NOT_SUSPENDED) + addCapability(NET_CAPABILITY_NOT_ROAMING) + addCapability(NET_CAPABILITY_NOT_VPN) if (null != name) { setNetworkSpecifier(StringNetworkSpecifier(name)) } } val lp = initialLp ?: LinkProperties().apply { - addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0)) + addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 32)) + addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null)) } val config = NetworkAgentConfig.Builder().build() return TestableNetworkAgent(context, mHandlerThread.looper, nc, lp, config).also { @@ -342,7 +355,7 @@ class NetworkAgentTest { Pair { val request: NetworkRequest = NetworkRequest.Builder() .clearCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addTransportType(TRANSPORT_TEST) .build() val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) requestNetwork(request, callback) @@ -387,7 +400,7 @@ class NetworkAgentTest { val callbacks = thresholds.map { strength -> val request = NetworkRequest.Builder() .clearCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addTransportType(TRANSPORT_TEST) .setSignalStrength(strength) .build() TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also { @@ -487,10 +500,10 @@ class NetworkAgentTest { it.getInterfaceName() == ifaceName } val nc = NetworkCapabilities(agent.nc) - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + nc.addCapability(NET_CAPABILITY_NOT_METERED) agent.sendNetworkCapabilities(nc) callback.expectCapabilitiesThat(agent.network) { - it.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + it.hasCapability(NET_CAPABILITY_NOT_METERED) } } @@ -504,12 +517,12 @@ class NetworkAgentTest { val name2 = UUID.randomUUID().toString() val request1 = NetworkRequest.Builder() .clearCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addTransportType(TRANSPORT_TEST) .setNetworkSpecifier(StringNetworkSpecifier(name1)) .build() val request2 = NetworkRequest.Builder() .clearCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addTransportType(TRANSPORT_TEST) .setNetworkSpecifier(StringNetworkSpecifier(name2)) .build() val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) @@ -520,7 +533,7 @@ class NetworkAgentTest { // Then file the interesting request val request = NetworkRequest.Builder() .clearCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addTransportType(TRANSPORT_TEST) .build() val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) requestNetwork(request, callback) @@ -552,18 +565,18 @@ class NetworkAgentTest { @IgnoreUpTo(Build.VERSION_CODES.R) fun testSetUnderlyingNetworks() { val request = NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_TEST) - .addTransportType(NetworkCapabilities.TRANSPORT_VPN) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) // TODO: add to VPN! + .addTransportType(TRANSPORT_TEST) + .addTransportType(TRANSPORT_VPN) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .removeCapability(NET_CAPABILITY_TRUSTED) // TODO: add to VPN! .build() val callback = TestableNetworkCallback() registerNetworkCallback(request, callback) val nc = NetworkCapabilities().apply { - addTransportType(NetworkCapabilities.TRANSPORT_TEST) - addTransportType(NetworkCapabilities.TRANSPORT_VPN) - removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + addTransportType(TRANSPORT_TEST) + addTransportType(TRANSPORT_VPN) + removeCapability(NET_CAPABILITY_NOT_VPN) } val defaultNetwork = mCM.activeNetwork assertNotNull(defaultNetwork) @@ -591,8 +604,8 @@ class NetworkAgentTest { } // Put the underlying network back and check that the underlying transport reappears. - val expectedTransports = (defaultNetworkTransports.toSet() + - NetworkCapabilities.TRANSPORT_VPN).toIntArray() + val expectedTransports = (defaultNetworkTransports.toSet() + TRANSPORT_VPN) + .toIntArray() agent.setUnderlyingNetworks(null) callback.expectCapabilitiesThat(agent.network!!) { it.transportTypes.size == expectedTransports.size && @@ -604,9 +617,9 @@ class NetworkAgentTest { // underlying networks, and because not congested, not roaming, and not suspended are the // default anyway. It's still useful as an extra check though. vpnNc = mCM.getNetworkCapabilities(agent.network) - for (cap in listOf(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED, - NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, - NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) { + for (cap in listOf(NET_CAPABILITY_NOT_CONGESTED, + NET_CAPABILITY_NOT_ROAMING, + NET_CAPABILITY_NOT_SUSPENDED)) { val capStr = valueToString(NetworkCapabilities::class.java, "NET_CAPABILITY_", cap) if (defaultNetworkCapabilities.hasCapability(cap) && !vpnNc.hasCapability(cap)) { fail("$capStr not propagated from underlying: $defaultNetworkCapabilities") @@ -705,7 +718,7 @@ class NetworkAgentTest { // First create a request to make sure the network is kept up val request1 = NetworkRequest.Builder() .clearCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addTransportType(TRANSPORT_TEST) .build() val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS).also { registerNetworkCallback(request1, it) @@ -715,7 +728,7 @@ class NetworkAgentTest { // Then file the interesting request val request = NetworkRequest.Builder() .clearCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addTransportType(TRANSPORT_TEST) .build() val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) requestNetwork(request, callback) @@ -726,18 +739,18 @@ class NetworkAgentTest { // Send TEMP_NOT_METERED and check that the callback is called appropriately. val nc1 = NetworkCapabilities(agent.nc) - .addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) agent.sendNetworkCapabilities(nc1) callback.expectCapabilitiesThat(agent.network) { - it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) } // Remove TEMP_NOT_METERED and check that the callback is called appropriately. val nc2 = NetworkCapabilities(agent.nc) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) agent.sendNetworkCapabilities(nc2) callback.expectCapabilitiesThat(agent.network) { - !it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + !it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) } } From ed1211d2d82a02ae6ce9c94f55852e045b755c0f Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 12 Dec 2020 22:49:03 +0900 Subject: [PATCH 1395/1415] Update NetworkAgentTest to support generalized underlying networks. Currently, when an agent calls setUnderlyingNetworks, the transports of the network are hardcoded to TRANSPORT_VPN only. This is being fixed in another CL in this topic. The new code reports the same transports sent by the agent. This test registers an agent with TRANSPORT_TEST|TRANSPORT_VPN. Update the test to expect both transports in the callbacks it receives. Bug: 173331190 Test: passes when run with other CL in topic Change-Id: Iede61d74fa02a4fec1f345f6d18835c1acab7337 --- tests/cts/net/src/android/net/cts/NetworkAgentTest.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index bb66129cdf..1d2f19a579 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -591,8 +591,10 @@ class NetworkAgentTest { // Check that the default network's transport is propagated to the VPN. var vpnNc = mCM.getNetworkCapabilities(agent.network) assertNotNull(vpnNc) - assertTrue(NetworkCapabilities.TRANSPORT_VPN in vpnNc.transportTypes) - assertFalse(vpnNc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)) + + val testAndVpn = intArrayOf(TRANSPORT_TEST, TRANSPORT_VPN) + assertTrue(hasAllTransports(vpnNc, testAndVpn)) + assertFalse(vpnNc.hasCapability(NET_CAPABILITY_NOT_VPN)) assertTrue(hasAllTransports(vpnNc, defaultNetworkTransports), "VPN transports ${Arrays.toString(vpnNc.transportTypes)}" + " lacking transports from ${Arrays.toString(defaultNetworkTransports)}") @@ -600,11 +602,11 @@ class NetworkAgentTest { // Check that when no underlying networks are announced the underlying transport disappears. agent.setUnderlyingNetworks(listOf()) callback.expectCapabilitiesThat(agent.network!!) { - it.transportTypes.size == 1 && it.hasTransport(NetworkCapabilities.TRANSPORT_VPN) + it.transportTypes.size == 2 && hasAllTransports(it, testAndVpn) } // Put the underlying network back and check that the underlying transport reappears. - val expectedTransports = (defaultNetworkTransports.toSet() + TRANSPORT_VPN) + val expectedTransports = (defaultNetworkTransports.toSet() + TRANSPORT_TEST + TRANSPORT_VPN) .toIntArray() agent.setUnderlyingNetworks(null) callback.expectCapabilitiesThat(agent.network!!) { From 9b6b353b5d3e4f8bcf3a20a19ea853754597d504 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 15 Dec 2020 09:39:52 +0000 Subject: [PATCH 1396/1415] Move cts/net/TEST_MAPPING to toplevel The tests should just be run on any change in packages/modules/Connectivity, not just changes in the CTS package. Change-Id: I1c86c402f39a8a9b84e7422445df289c3ea7842f Test: TEST_MAPPING needs to be verified by TH --- tests/cts/net/TEST_MAPPING => TEST_MAPPING | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename tests/cts/net/TEST_MAPPING => TEST_MAPPING (88%) diff --git a/tests/cts/net/TEST_MAPPING b/TEST_MAPPING similarity index 88% rename from tests/cts/net/TEST_MAPPING rename to TEST_MAPPING index 8f65b655dc..1db4baaf4c 100644 --- a/tests/cts/net/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,5 +1,6 @@ { - // TODO: move to mainline-presubmit once supported + // Run in addition to mainline-presubmit as mainline-presubmit is not + // supported in every branch. "presubmit": [ { "name": "CtsNetTestCasesLatestSdk", From d2df5729f657fb51ab7b1c88067931135d54e598 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 10 Dec 2020 16:37:15 +0900 Subject: [PATCH 1397/1415] Move module utils to the module package. Test: FrameworksWifiTest FrameworksNetTest Merged-In: Ib04bebb061dc64d6d685116b596fb3179d5b959a Change-Id: I9118da3898d864c7bf0ed7bc9d94b94343c4a084 --- Tethering/src/android/net/ip/NeighborPacketForwarder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/Tethering/src/android/net/ip/NeighborPacketForwarder.java index 73fc833fab..084743db03 100644 --- a/Tethering/src/android/net/ip/NeighborPacketForwarder.java +++ b/Tethering/src/android/net/ip/NeighborPacketForwarder.java @@ -25,7 +25,6 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOCK_RAW; import android.net.util.InterfaceParams; -import android.net.util.PacketReader; import android.net.util.SocketUtils; import android.net.util.TetheringUtils; import android.os.Handler; @@ -33,6 +32,8 @@ import android.system.ErrnoException; import android.system.Os; import android.util.Log; +import com.android.net.module.util.PacketReader; + import java.io.FileDescriptor; import java.io.IOException; import java.net.Inet6Address; From abb46bef36c255744a42885763267d44905ea157 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 16 Dec 2020 06:27:48 +0000 Subject: [PATCH 1398/1415] Fix timeout on NetworkAgentTest callback All callbacks in the class use the DEFAULT_TIMEOUT_MS, except for this recently added test. The test is currently flaky in various branches. Fixes: 174716714 Fixes: 174691729 Change-Id: I9f4446bb83eb4402c912292ac31d46e1d2cb6a52 Test: TH --- tests/cts/net/src/android/net/cts/NetworkAgentTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 1d2f19a579..87aa2a3110 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -570,7 +570,7 @@ class NetworkAgentTest { .removeCapability(NET_CAPABILITY_NOT_VPN) .removeCapability(NET_CAPABILITY_TRUSTED) // TODO: add to VPN! .build() - val callback = TestableNetworkCallback() + val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) registerNetworkCallback(request, callback) val nc = NetworkCapabilities().apply { From f50f05ebcb6a5fcbfd09810d887965df15b0b678 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 16 Dec 2020 16:38:51 +0800 Subject: [PATCH 1399/1415] Also update connected clients for local only tethering mForwardedDownstreams is the set of downstreams who wanted upstream. In other word, it don't contains localOnly tethering(e.g. local only hotspot, wifi p2p tethering). Changing the list from mForwardedDownstreams to mNotifyList make both tethered and localOnly tethering have connected clients callback. Bug: 172290164 Test: atest TetheringTests Change-Id: I58fdb28efc616b00d63a1c237ea93aee4d8f2dcd --- .../networkstack/tethering/Tethering.java | 22 ++- .../networkstack/tethering/TetheringTest.java | 140 +++++++++++++++++- 2 files changed, 154 insertions(+), 8 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 2c91d100ec..62ae88c24b 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -140,8 +140,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Executor; @@ -216,13 +216,12 @@ public class Tethering { private final ArrayMap mTetherStates; private final BroadcastReceiver mStateReceiver; private final Looper mLooper; - private final StateMachine mTetherMainSM; + private final TetherMainSM mTetherMainSM; private final OffloadController mOffloadController; private final UpstreamNetworkMonitor mUpstreamNetworkMonitor; // TODO: Figure out how to merge this and other downstream-tracking objects // into a single coherent structure. - // Use LinkedHashSet for predictable ordering order for ConnectedClientsTracker. - private final LinkedHashSet mForwardedDownstreams; + private final HashSet mForwardedDownstreams; private final VersionedBroadcastListener mCarrierConfigChange; private final TetheringDependencies mDeps; private final EntitlementManager mEntitlementMgr; @@ -287,7 +286,7 @@ public class Tethering { }); mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMainSM, mLog, TetherMainSM.EVENT_UPSTREAM_CALLBACK); - mForwardedDownstreams = new LinkedHashSet<>(); + mForwardedDownstreams = new HashSet<>(); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); @@ -1423,6 +1422,7 @@ public class Tethering { // interfaces. // 2) mNotifyList contains all state machines that may have outstanding tethering state // that needs to be torn down. + // 3) Use mNotifyList for predictable ordering order for ConnectedClientsTracker. // // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList // so that the garbage collector does not clean up the state machine before it has a chance @@ -1459,6 +1459,15 @@ public class Tethering { setInitialState(mInitialState); } + /** + * Returns all downstreams that are serving clients, regardless of they are actually + * tethered or localOnly. This must be called on the tethering thread (not thread-safe). + */ + @NonNull + public List getAllDownstreams() { + return mNotifyList; + } + class InitialState extends State { @Override public boolean processMessage(Message message) { @@ -2300,7 +2309,8 @@ public class Tethering { } private void updateConnectedClients(final List wifiClients) { - if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, wifiClients)) { + if (mConnectedClientsTracker.updateConnectedClients(mTetherMainSM.getAllDownstreams(), + wifiClients)) { reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients()); } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 0a37f54aaa..f4b3749132 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -16,6 +16,7 @@ package com.android.networkstack.tethering; +import static android.Manifest.permission.NETWORK_SETTINGS; import static android.content.pm.PackageManager.GET_ACTIVITIES; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; @@ -36,6 +37,7 @@ import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; @@ -49,12 +51,15 @@ import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; +import static android.system.OsConstants.RT_SCOPE_UNIVERSE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; import static com.android.networkstack.tethering.Tethering.UserRestrictionActionListener; import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES; +import static com.android.testutils.TestPermissionUtil.runAsShell; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -108,11 +113,14 @@ import android.net.NetworkRequest; import android.net.RouteInfo; import android.net.TetherStatesParcel; import android.net.TetheredClient; +import android.net.TetheredClient.AddressInfo; import android.net.TetheringCallbackStartedParcel; import android.net.TetheringConfigurationParcel; import android.net.TetheringRequestParcel; +import android.net.dhcp.DhcpLeaseParcelable; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpEventCallbacks; import android.net.dhcp.IDhcpServer; import android.net.ip.DadProxy; import android.net.ip.IpNeighborMonitor; @@ -122,7 +130,9 @@ import android.net.util.InterfaceParams; import android.net.util.NetworkConstants; import android.net.util.SharedLog; import android.net.wifi.SoftApConfiguration; +import android.net.wifi.WifiClient; import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.SoftApCallback; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pInfo; import android.net.wifi.p2p.WifiP2pManager; @@ -168,6 +178,7 @@ import java.net.Inet6Address; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Vector; @@ -237,6 +248,7 @@ public class TetheringTest { private EntitlementManager mEntitleMgr; private OffloadController mOffloadCtrl; private PrivateAddressCoordinator mPrivateAddressCoordinator; + private SoftApCallback mSoftApCallback; private class TestContext extends BroadcastInterceptingContext { TestContext(Context base) { @@ -568,8 +580,12 @@ public class TetheringTest { ArgumentCaptor.forClass(PhoneStateListener.class); verify(mTelephonyManager).listen(phoneListenerCaptor.capture(), eq(PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE)); - verify(mWifiManager).registerSoftApCallback(any(), any()); mPhoneStateListener = phoneListenerCaptor.getValue(); + + final ArgumentCaptor softApCallbackCaptor = + ArgumentCaptor.forClass(SoftApCallback.class); + verify(mWifiManager).registerSoftApCallback(any(), softApCallbackCaptor.capture()); + mSoftApCallback = softApCallbackCaptor.getValue(); } private void setTetheringSupported(final boolean supported) { @@ -1293,6 +1309,7 @@ public class TetheringTest { new ArrayList<>(); private final ArrayList mTetherStates = new ArrayList<>(); private final ArrayList mOffloadStatus = new ArrayList<>(); + private final ArrayList> mTetheredClients = new ArrayList<>(); // This function will remove the recorded callbacks, so it must be called once for // each callback. If this is called after multiple callback, the order matters. @@ -1338,6 +1355,13 @@ public class TetheringTest { return mTetherStates.remove(0); } + public void expectTetheredClientChanged(List leases) { + assertFalse(mTetheredClients.isEmpty()); + final List result = mTetheredClients.remove(0); + assertEquals(leases.size(), result.size()); + assertTrue(leases.containsAll(result)); + } + @Override public void onUpstreamChanged(Network network) { mActualUpstreams.add(network); @@ -1355,7 +1379,7 @@ public class TetheringTest { @Override public void onTetherClientsChanged(List clients) { - // TODO: check this + mTetheredClients.add(clients); } @Override @@ -1369,6 +1393,7 @@ public class TetheringTest { mTetheringConfigs.add(parcel.config); mTetherStates.add(parcel.states); mOffloadStatus.add(parcel.offloadStatus); + mTetheredClients.add(parcel.tetheredClients); } @Override @@ -1398,6 +1423,7 @@ public class TetheringTest { assertNoUpstreamChangeCallback(); assertNoConfigChangeCallback(); assertNoStateChangeCallback(); + assertTrue(mTetheredClients.isEmpty()); } private void assertTetherConfigParcelEqual(@NonNull TetheringConfigurationParcel actual, @@ -1437,6 +1463,7 @@ public class TetheringTest { // 1. Register one callback before running any tethering. mTethering.registerTetheringEventCallback(callback); mLooper.dispatchAll(); + callback.expectTetheredClientChanged(Collections.emptyList()); callback.expectUpstreamChanged(new Network[] {null}); callback.expectConfigurationChanged( mTethering.getTetheringConfiguration().toStableParcelable()); @@ -1463,6 +1490,7 @@ public class TetheringTest { // 3. Register second callback. mTethering.registerTetheringEventCallback(callback2); mLooper.dispatchAll(); + callback2.expectTetheredClientChanged(Collections.emptyList()); callback2.expectUpstreamChanged(upstreamState.network); callback2.expectConfigurationChanged( mTethering.getTetheringConfiguration().toStableParcelable()); @@ -2054,6 +2082,114 @@ public class TetheringTest { verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES); } + @Test + public void testUpdateConnectedClients() throws Exception { + TestTetheringEventCallback callback = new TestTetheringEventCallback(); + runAsShell(NETWORK_SETTINGS, () -> { + mTethering.registerTetheringEventCallback(callback); + mLooper.dispatchAll(); + }); + callback.expectTetheredClientChanged(Collections.emptyList()); + + IDhcpEventCallbacks eventCallbacks; + final ArgumentCaptor dhcpEventCbsCaptor = + ArgumentCaptor.forClass(IDhcpEventCallbacks.class); + // Run local only tethering. + mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true); + sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME); + mLooper.dispatchAll(); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS)).startWithCallbacks( + any(), dhcpEventCbsCaptor.capture()); + eventCallbacks = dhcpEventCbsCaptor.getValue(); + // Update lease for local only tethering. + final MacAddress testMac1 = MacAddress.fromString("11:11:11:11:11:11"); + final ArrayList p2pLeases = new ArrayList<>(); + p2pLeases.add(createDhcpLeaseParcelable("clientId1", testMac1, "192.168.50.24", 24, + Long.MAX_VALUE, "test1")); + notifyDhcpLeasesChanged(p2pLeases, eventCallbacks); + final List clients = toTetheredClients(p2pLeases, TETHERING_WIFI_P2P); + callback.expectTetheredClientChanged(clients); + reset(mDhcpServer); + + // Run wifi tethering. + mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true); + sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); + mLooper.dispatchAll(); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS)).startWithCallbacks( + any(), dhcpEventCbsCaptor.capture()); + eventCallbacks = dhcpEventCbsCaptor.getValue(); + // Update mac address from softAp callback before getting dhcp lease. + final ArrayList wifiClients = new ArrayList<>(); + final MacAddress testMac2 = MacAddress.fromString("22:22:22:22:22:22"); + final WifiClient testClient = mock(WifiClient.class); + when(testClient.getMacAddress()).thenReturn(testMac2); + wifiClients.add(testClient); + mSoftApCallback.onConnectedClientsChanged(wifiClients); + final TetheredClient noAddrClient = new TetheredClient(testMac2, + Collections.emptyList() /* addresses */, TETHERING_WIFI); + clients.add(noAddrClient); + callback.expectTetheredClientChanged(clients); + + // Update dhcp lease for wifi tethering. + clients.remove(noAddrClient); + final ArrayList wifiLeases = new ArrayList<>(); + wifiLeases.add(createDhcpLeaseParcelable("clientId2", testMac2, "192.168.43.24", 24, + Long.MAX_VALUE, "test2")); + notifyDhcpLeasesChanged(wifiLeases, eventCallbacks); + clients.addAll(toTetheredClients(wifiLeases, TETHERING_WIFI)); + callback.expectTetheredClientChanged(clients); + + // Test onStarted callback that register second callback when tethering is running. + TestTetheringEventCallback callback2 = new TestTetheringEventCallback(); + runAsShell(NETWORK_SETTINGS, () -> { + mTethering.registerTetheringEventCallback(callback2); + mLooper.dispatchAll(); + }); + callback2.expectTetheredClientChanged(clients); + } + + private void notifyDhcpLeasesChanged(List leaseParcelables, + IDhcpEventCallbacks callback) throws Exception { + callback.onLeasesChanged(leaseParcelables); + mLooper.dispatchAll(); + } + + private List toTetheredClients(List leaseParcelables, + int type) throws Exception { + final ArrayList leases = new ArrayList<>(); + for (DhcpLeaseParcelable lease : leaseParcelables) { + final LinkAddress address = new LinkAddress( + intToInet4AddressHTH(lease.netAddr), lease.prefixLength, + 0 /* flags */, RT_SCOPE_UNIVERSE /* as per RFC6724#3.2 */, + lease.expTime /* deprecationTime */, lease.expTime /* expirationTime */); + + final MacAddress macAddress = MacAddress.fromBytes(lease.hwAddr); + + final AddressInfo addressInfo = new TetheredClient.AddressInfo(address, lease.hostname); + leases.add(new TetheredClient( + macAddress, + Collections.singletonList(addressInfo), + type)); + } + + return leases; + } + + private DhcpLeaseParcelable createDhcpLeaseParcelable(final String clientId, + final MacAddress hwAddr, final String netAddr, final int prefixLength, + final long expTime, final String hostname) throws Exception { + final DhcpLeaseParcelable lease = new DhcpLeaseParcelable(); + lease.clientId = clientId.getBytes(); + lease.hwAddr = hwAddr.toByteArray(); + lease.netAddr = inet4AddressToIntHTH( + (Inet4Address) InetAddresses.parseNumericAddress(netAddr)); + lease.prefixLength = prefixLength; + lease.expTime = expTime; + lease.hostname = hostname; + + return lease; + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } From afe26600fb0c6a5e3bc1cfcbd0428784761b7a59 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 2 Nov 2020 17:41:17 +0900 Subject: [PATCH 1400/1415] Migrate away from AsyncChannel in NetworkAgent Use two oneway binder interfaces instead. The interfaces post messages to handlers as was implemented before, but provide a more strictly defined interface, with less hops between NetworkAgent, AsyncChannel, and ConnectivityService. Exempt-From-Owner-Approval: Owners OOO, change approved by team members Ignore-AOSP-First: merge conflicts in dependent changes Test: atest FrameworksNetTests CtsNetTestCasesLatestSdk Change-Id: Ica51d0179bcb3b4e314d2c3e85709aead6ca5657 --- framework/Android.bp | 29 +++++ .../connectivity/aidl/INetworkAgent.aidl | 46 +++++++ .../aidl/INetworkAgentRegistry.aidl | 36 ++++++ .../src/android/net/cts/NetworkAgentTest.kt | 117 +++++++----------- 4 files changed, 156 insertions(+), 72 deletions(-) create mode 100644 framework/Android.bp create mode 100644 framework/src/com/android/connectivity/aidl/INetworkAgent.aidl create mode 100644 framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl diff --git a/framework/Android.bp b/framework/Android.bp new file mode 100644 index 0000000000..8db8d7699a --- /dev/null +++ b/framework/Android.bp @@ -0,0 +1,29 @@ +// +// 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. +// + +// TODO: use a java_library in the bootclasspath instead +filegroup { + name: "framework-connectivity-sources", + srcs: [ + "src/**/*.java", + "src/**/*.aidl", + ], + path: "src", + visibility: [ + "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", + ], +} \ No newline at end of file diff --git a/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl new file mode 100644 index 0000000000..1af9e769b7 --- /dev/null +++ b/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl @@ -0,0 +1,46 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package com.android.connectivity.aidl; + +import android.net.NattKeepalivePacketData; +import android.net.TcpKeepalivePacketData; + +import com.android.connectivity.aidl.INetworkAgentRegistry; + +/** + * Interface to notify NetworkAgent of connectivity events. + * @hide + */ +oneway interface INetworkAgent { + void onRegistered(in INetworkAgentRegistry registry); + void onDisconnected(); + void onBandwidthUpdateRequested(); + void onValidationStatusChanged(int validationStatus, + in @nullable String captivePortalUrl); + void onSaveAcceptUnvalidated(boolean acceptUnvalidated); + void onStartNattSocketKeepalive(int slot, int intervalDurationMs, + in NattKeepalivePacketData packetData); + void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, + in TcpKeepalivePacketData packetData); + void onStopSocketKeepalive(int slot); + void onSignalStrengthThresholdsUpdated(in int[] thresholds); + void onPreventAutomaticReconnect(); + void onAddNattKeepalivePacketFilter(int slot, + in NattKeepalivePacketData packetData); + void onAddTcpKeepalivePacketFilter(int slot, + in TcpKeepalivePacketData packetData); + void onRemoveKeepalivePacketFilter(int slot); +} diff --git a/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl new file mode 100644 index 0000000000..d42a34055c --- /dev/null +++ b/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl @@ -0,0 +1,36 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package com.android.connectivity.aidl; + +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; + +/** + * Interface for NetworkAgents to send network network properties. + * @hide + */ +oneway interface INetworkAgentRegistry { + void sendNetworkCapabilities(in NetworkCapabilities nc); + void sendLinkProperties(in LinkProperties lp); + // TODO: consider replacing this by "markConnected()" and removing + void sendNetworkInfo(in NetworkInfo info); + void sendScore(int score); + void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial); + void sendSocketKeepaliveEvent(int slot, int reason); + void sendUnderlyingNetworks(in @nullable List networks); +} diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 87aa2a3110..803c9d804f 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -23,15 +23,9 @@ import android.net.IpPrefix import android.net.KeepalivePacketData import android.net.LinkAddress import android.net.LinkProperties +import android.net.NattKeepalivePacketData import android.net.Network import android.net.NetworkAgent -import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER -import android.net.NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT -import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER -import android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS -import android.net.NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED -import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE -import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE import android.net.NetworkAgent.INVALID_NETWORK import android.net.NetworkAgent.VALID_NETWORK import android.net.NetworkAgentConfig @@ -64,16 +58,14 @@ import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSta import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus import android.os.Build -import android.os.Bundle -import android.os.Handler import android.os.HandlerThread import android.os.Looper import android.os.Message -import android.os.Messenger import android.util.DebugUtils.valueToString import androidx.test.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 -import com.android.internal.util.AsyncChannel +import com.android.connectivity.aidl.INetworkAgent +import com.android.connectivity.aidl.INetworkAgentRegistry import com.android.net.module.util.ArrayTrackRecord import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo @@ -82,7 +74,6 @@ import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback import org.junit.After import org.junit.Assert.assertArrayEquals -import org.junit.Assert.fail import org.junit.Before import org.junit.Rule import org.junit.Test @@ -93,6 +84,7 @@ import org.mockito.ArgumentMatchers.argThat import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock +import org.mockito.Mockito.timeout import org.mockito.Mockito.verify import java.time.Duration import java.util.Arrays @@ -103,6 +95,7 @@ import kotlin.test.assertFalse import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue +import kotlin.test.fail // This test doesn't really have a constraint on how fast the methods should return. If it's // going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio @@ -140,7 +133,7 @@ class NetworkAgentTest { private val mCM = realContext.getSystemService(ConnectivityManager::class.java) private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") - private val mFakeConnectivityService by lazy { FakeConnectivityService(mHandlerThread.looper) } + private val mFakeConnectivityService = FakeConnectivityService() private class Provider(context: Context, looper: Looper) : NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") @@ -167,39 +160,30 @@ class NetworkAgentTest { * This fake only supports speaking to one harnessed agent at a time because it * only keeps track of one async channel. */ - private class FakeConnectivityService(looper: Looper) { - private val CMD_EXPECT_DISCONNECT = 1 - private var disconnectExpected = false - private val msgHistory = ArrayTrackRecord().newReadHead() - private val asyncChannel = AsyncChannel() - private val handler = object : Handler(looper) { - override fun handleMessage(msg: Message) { - msgHistory.add(Message.obtain(msg)) // make a copy as the original will be recycled - when (msg.what) { - CMD_EXPECT_DISCONNECT -> disconnectExpected = true - AsyncChannel.CMD_CHANNEL_HALF_CONNECTED -> - asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) - AsyncChannel.CMD_CHANNEL_DISCONNECTED -> - if (!disconnectExpected) { - fail("Agent unexpectedly disconnected") - } else { - disconnectExpected = false - } - } - } + private class FakeConnectivityService { + val mockRegistry = mock(INetworkAgentRegistry::class.java) + private var agentField: INetworkAgent? = null + private val registry = object : INetworkAgentRegistry.Stub(), + INetworkAgentRegistry by mockRegistry { + // asBinder has implementations in both INetworkAgentRegistry.Stub and mockRegistry, so + // it needs to be disambiguated. Just fail the test as it should be unused here. + // asBinder is used when sending the registry in binder transactions, so not in this + // test (the test just uses in-process direct calls). If it were used across processes, + // using the Stub super.asBinder() implementation would allow sending the registry in + // binder transactions, while recording incoming calls on the other mockito-generated + // methods. + override fun asBinder() = fail("asBinder should be unused in this test") } - fun connect(agentMsngr: Messenger) = asyncChannel.connect(realContext, handler, agentMsngr) + val agent: INetworkAgent + get() = agentField ?: fail("No INetworkAgent") - fun disconnect() = asyncChannel.disconnect() + fun connect(agent: INetworkAgent) { + this.agentField = agent + agent.onRegistered(registry) + } - fun sendMessage(what: Int, arg1: Int = 0, arg2: Int = 0, obj: Any? = null) = - asyncChannel.sendMessage(Message(what, arg1, arg2, obj)) - - fun expectMessage(what: Int) = - assertNotNull(msgHistory.poll(DEFAULT_TIMEOUT_MS) { it.what == what }) - - fun willExpectDisconnectOnce() = handler.sendEmptyMessage(CMD_EXPECT_DISCONNECT) + fun disconnect() = agent.onDisconnected() } private open class TestableNetworkAgent( @@ -445,17 +429,15 @@ class NetworkAgentTest { @Test fun testSocketKeepalive(): Unit = createNetworkAgentWithFakeCS().let { agent -> - val packet = object : KeepalivePacketData( + val packet = NattKeepalivePacketData( LOCAL_IPV4_ADDRESS /* srcAddress */, 1234 /* srcPort */, REMOTE_IPV4_ADDRESS /* dstAddress */, 4567 /* dstPort */, - ByteArray(100 /* size */) { it.toByte() /* init */ }) {} + ByteArray(100 /* size */)) val slot = 4 val interval = 37 - mFakeConnectivityService.sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, - arg1 = slot, obj = packet) - mFakeConnectivityService.sendMessage(CMD_START_SOCKET_KEEPALIVE, - arg1 = slot, arg2 = interval, obj = packet) + mFakeConnectivityService.agent.onAddNattKeepalivePacketFilter(slot, packet) + mFakeConnectivityService.agent.onStartNattSocketKeepalive(slot, interval, packet) agent.expectCallback().let { assertEquals(it.slot, slot) @@ -472,13 +454,11 @@ class NetworkAgentTest { // Check that when the agent sends a keepalive event, ConnectivityService receives the // expected message. agent.sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED) - mFakeConnectivityService.expectMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE).let() { - assertEquals(slot, it.arg1) - assertEquals(SocketKeepalive.ERROR_UNSUPPORTED, it.arg2) - } + verify(mFakeConnectivityService.mockRegistry, timeout(DEFAULT_TIMEOUT_MS)) + .sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED) - mFakeConnectivityService.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, arg1 = slot) - mFakeConnectivityService.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, arg1 = slot) + mFakeConnectivityService.agent.onStopSocketKeepalive(slot) + mFakeConnectivityService.agent.onRemoveKeepalivePacketFilter(slot) agent.expectCallback().let { assertEquals(it.slot, slot) } @@ -639,7 +619,7 @@ class NetworkAgentTest { val mockCm = mock(ConnectivityManager::class.java) doReturn(mockCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE) createConnectedNetworkAgent(mockContext) - verify(mockCm).registerNetworkAgent(any(Messenger::class.java), + verify(mockCm).registerNetworkAgent(any(), argThat { it.detailedState == NetworkInfo.DetailedState.CONNECTING }, any(LinkProperties::class.java), any(NetworkCapabilities::class.java), @@ -651,7 +631,7 @@ class NetworkAgentTest { @Test fun testSetAcceptUnvalidated() { createNetworkAgentWithFakeCS().let { agent -> - mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 1) + mFakeConnectivityService.agent.onSaveAcceptUnvalidated(true) agent.expectCallback().let { assertTrue(it.accept) } @@ -662,19 +642,18 @@ class NetworkAgentTest { @Test fun testSetAcceptUnvalidatedPreventAutomaticReconnect() { createNetworkAgentWithFakeCS().let { agent -> - mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 0) - mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + mFakeConnectivityService.agent.onSaveAcceptUnvalidated(false) + mFakeConnectivityService.agent.onPreventAutomaticReconnect() agent.expectCallback().let { assertFalse(it.accept) } agent.expectCallback() agent.assertNoCallback() // When automatic reconnect is turned off, the network is torn down and - // ConnectivityService sends a disconnect. This in turn causes the agent - // to send a DISCONNECTED message to CS. - mFakeConnectivityService.willExpectDisconnectOnce() + // ConnectivityService disconnects. As part of the disconnect, ConnectivityService will + // also send itself a message to unregister the NetworkAgent from its internal + // structure. mFakeConnectivityService.disconnect() - mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) agent.expectCallback() } } @@ -682,12 +661,10 @@ class NetworkAgentTest { @Test fun testPreventAutomaticReconnect() { createNetworkAgentWithFakeCS().let { agent -> - mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + mFakeConnectivityService.agent.onPreventAutomaticReconnect() agent.expectCallback() agent.assertNoCallback() - mFakeConnectivityService.willExpectDisconnectOnce() mFakeConnectivityService.disconnect() - mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) agent.expectCallback() } } @@ -695,18 +672,14 @@ class NetworkAgentTest { @Test fun testValidationStatus() = createNetworkAgentWithFakeCS().let { agent -> val uri = Uri.parse("http://www.google.com") - val bundle = Bundle().apply { - putString(NetworkAgent.REDIRECT_URL_KEY, uri.toString()) - } - mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, - arg1 = VALID_NETWORK, obj = bundle) + mFakeConnectivityService.agent.onValidationStatusChanged(VALID_NETWORK, + uri.toString()) agent.expectCallback().let { assertEquals(it.status, VALID_NETWORK) assertEquals(it.uri, uri) } - mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, - arg1 = INVALID_NETWORK, obj = Bundle()) + mFakeConnectivityService.agent.onValidationStatusChanged(INVALID_NETWORK, null) agent.expectCallback().let { assertEquals(it.status, INVALID_NETWORK) assertNull(it.uri) From 4f896db6fff69bd5e53f2b7292a87c75b5148b01 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 2 Nov 2020 17:41:17 +0900 Subject: [PATCH 1401/1415] Migrate away from AsyncChannel in NetworkAgent Use two oneway binder interfaces instead. The interfaces post messages to handlers as was implemented before, but provide a more strictly defined interface, with less hops between NetworkAgent, AsyncChannel, and ConnectivityService. Test: atest FrameworksNetTests CtsNetTestCasesLatestSdk Merged-In: Ica51d0179bcb3b4e314d2c3e85709aead6ca5657 Change-Id: Ica51d0179bcb3b4e314d2c3e85709aead6ca5657 --- framework/Android.bp | 29 +++++ .../connectivity/aidl/INetworkAgent.aidl | 46 +++++++ .../aidl/INetworkAgentRegistry.aidl | 36 ++++++ .../src/android/net/cts/NetworkAgentTest.kt | 117 +++++++----------- 4 files changed, 156 insertions(+), 72 deletions(-) create mode 100644 framework/Android.bp create mode 100644 framework/src/com/android/connectivity/aidl/INetworkAgent.aidl create mode 100644 framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl diff --git a/framework/Android.bp b/framework/Android.bp new file mode 100644 index 0000000000..8db8d7699a --- /dev/null +++ b/framework/Android.bp @@ -0,0 +1,29 @@ +// +// 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. +// + +// TODO: use a java_library in the bootclasspath instead +filegroup { + name: "framework-connectivity-sources", + srcs: [ + "src/**/*.java", + "src/**/*.aidl", + ], + path: "src", + visibility: [ + "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", + ], +} \ No newline at end of file diff --git a/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl new file mode 100644 index 0000000000..1af9e769b7 --- /dev/null +++ b/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl @@ -0,0 +1,46 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package com.android.connectivity.aidl; + +import android.net.NattKeepalivePacketData; +import android.net.TcpKeepalivePacketData; + +import com.android.connectivity.aidl.INetworkAgentRegistry; + +/** + * Interface to notify NetworkAgent of connectivity events. + * @hide + */ +oneway interface INetworkAgent { + void onRegistered(in INetworkAgentRegistry registry); + void onDisconnected(); + void onBandwidthUpdateRequested(); + void onValidationStatusChanged(int validationStatus, + in @nullable String captivePortalUrl); + void onSaveAcceptUnvalidated(boolean acceptUnvalidated); + void onStartNattSocketKeepalive(int slot, int intervalDurationMs, + in NattKeepalivePacketData packetData); + void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, + in TcpKeepalivePacketData packetData); + void onStopSocketKeepalive(int slot); + void onSignalStrengthThresholdsUpdated(in int[] thresholds); + void onPreventAutomaticReconnect(); + void onAddNattKeepalivePacketFilter(int slot, + in NattKeepalivePacketData packetData); + void onAddTcpKeepalivePacketFilter(int slot, + in TcpKeepalivePacketData packetData); + void onRemoveKeepalivePacketFilter(int slot); +} diff --git a/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl new file mode 100644 index 0000000000..d42a34055c --- /dev/null +++ b/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl @@ -0,0 +1,36 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package com.android.connectivity.aidl; + +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; + +/** + * Interface for NetworkAgents to send network network properties. + * @hide + */ +oneway interface INetworkAgentRegistry { + void sendNetworkCapabilities(in NetworkCapabilities nc); + void sendLinkProperties(in LinkProperties lp); + // TODO: consider replacing this by "markConnected()" and removing + void sendNetworkInfo(in NetworkInfo info); + void sendScore(int score); + void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial); + void sendSocketKeepaliveEvent(int slot, int reason); + void sendUnderlyingNetworks(in @nullable List networks); +} diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 87aa2a3110..803c9d804f 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -23,15 +23,9 @@ import android.net.IpPrefix import android.net.KeepalivePacketData import android.net.LinkAddress import android.net.LinkProperties +import android.net.NattKeepalivePacketData import android.net.Network import android.net.NetworkAgent -import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER -import android.net.NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT -import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER -import android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS -import android.net.NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED -import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE -import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE import android.net.NetworkAgent.INVALID_NETWORK import android.net.NetworkAgent.VALID_NETWORK import android.net.NetworkAgentConfig @@ -64,16 +58,14 @@ import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSta import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus import android.os.Build -import android.os.Bundle -import android.os.Handler import android.os.HandlerThread import android.os.Looper import android.os.Message -import android.os.Messenger import android.util.DebugUtils.valueToString import androidx.test.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 -import com.android.internal.util.AsyncChannel +import com.android.connectivity.aidl.INetworkAgent +import com.android.connectivity.aidl.INetworkAgentRegistry import com.android.net.module.util.ArrayTrackRecord import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo @@ -82,7 +74,6 @@ import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback import org.junit.After import org.junit.Assert.assertArrayEquals -import org.junit.Assert.fail import org.junit.Before import org.junit.Rule import org.junit.Test @@ -93,6 +84,7 @@ import org.mockito.ArgumentMatchers.argThat import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock +import org.mockito.Mockito.timeout import org.mockito.Mockito.verify import java.time.Duration import java.util.Arrays @@ -103,6 +95,7 @@ import kotlin.test.assertFalse import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue +import kotlin.test.fail // This test doesn't really have a constraint on how fast the methods should return. If it's // going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio @@ -140,7 +133,7 @@ class NetworkAgentTest { private val mCM = realContext.getSystemService(ConnectivityManager::class.java) private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") - private val mFakeConnectivityService by lazy { FakeConnectivityService(mHandlerThread.looper) } + private val mFakeConnectivityService = FakeConnectivityService() private class Provider(context: Context, looper: Looper) : NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") @@ -167,39 +160,30 @@ class NetworkAgentTest { * This fake only supports speaking to one harnessed agent at a time because it * only keeps track of one async channel. */ - private class FakeConnectivityService(looper: Looper) { - private val CMD_EXPECT_DISCONNECT = 1 - private var disconnectExpected = false - private val msgHistory = ArrayTrackRecord().newReadHead() - private val asyncChannel = AsyncChannel() - private val handler = object : Handler(looper) { - override fun handleMessage(msg: Message) { - msgHistory.add(Message.obtain(msg)) // make a copy as the original will be recycled - when (msg.what) { - CMD_EXPECT_DISCONNECT -> disconnectExpected = true - AsyncChannel.CMD_CHANNEL_HALF_CONNECTED -> - asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) - AsyncChannel.CMD_CHANNEL_DISCONNECTED -> - if (!disconnectExpected) { - fail("Agent unexpectedly disconnected") - } else { - disconnectExpected = false - } - } - } + private class FakeConnectivityService { + val mockRegistry = mock(INetworkAgentRegistry::class.java) + private var agentField: INetworkAgent? = null + private val registry = object : INetworkAgentRegistry.Stub(), + INetworkAgentRegistry by mockRegistry { + // asBinder has implementations in both INetworkAgentRegistry.Stub and mockRegistry, so + // it needs to be disambiguated. Just fail the test as it should be unused here. + // asBinder is used when sending the registry in binder transactions, so not in this + // test (the test just uses in-process direct calls). If it were used across processes, + // using the Stub super.asBinder() implementation would allow sending the registry in + // binder transactions, while recording incoming calls on the other mockito-generated + // methods. + override fun asBinder() = fail("asBinder should be unused in this test") } - fun connect(agentMsngr: Messenger) = asyncChannel.connect(realContext, handler, agentMsngr) + val agent: INetworkAgent + get() = agentField ?: fail("No INetworkAgent") - fun disconnect() = asyncChannel.disconnect() + fun connect(agent: INetworkAgent) { + this.agentField = agent + agent.onRegistered(registry) + } - fun sendMessage(what: Int, arg1: Int = 0, arg2: Int = 0, obj: Any? = null) = - asyncChannel.sendMessage(Message(what, arg1, arg2, obj)) - - fun expectMessage(what: Int) = - assertNotNull(msgHistory.poll(DEFAULT_TIMEOUT_MS) { it.what == what }) - - fun willExpectDisconnectOnce() = handler.sendEmptyMessage(CMD_EXPECT_DISCONNECT) + fun disconnect() = agent.onDisconnected() } private open class TestableNetworkAgent( @@ -445,17 +429,15 @@ class NetworkAgentTest { @Test fun testSocketKeepalive(): Unit = createNetworkAgentWithFakeCS().let { agent -> - val packet = object : KeepalivePacketData( + val packet = NattKeepalivePacketData( LOCAL_IPV4_ADDRESS /* srcAddress */, 1234 /* srcPort */, REMOTE_IPV4_ADDRESS /* dstAddress */, 4567 /* dstPort */, - ByteArray(100 /* size */) { it.toByte() /* init */ }) {} + ByteArray(100 /* size */)) val slot = 4 val interval = 37 - mFakeConnectivityService.sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, - arg1 = slot, obj = packet) - mFakeConnectivityService.sendMessage(CMD_START_SOCKET_KEEPALIVE, - arg1 = slot, arg2 = interval, obj = packet) + mFakeConnectivityService.agent.onAddNattKeepalivePacketFilter(slot, packet) + mFakeConnectivityService.agent.onStartNattSocketKeepalive(slot, interval, packet) agent.expectCallback().let { assertEquals(it.slot, slot) @@ -472,13 +454,11 @@ class NetworkAgentTest { // Check that when the agent sends a keepalive event, ConnectivityService receives the // expected message. agent.sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED) - mFakeConnectivityService.expectMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE).let() { - assertEquals(slot, it.arg1) - assertEquals(SocketKeepalive.ERROR_UNSUPPORTED, it.arg2) - } + verify(mFakeConnectivityService.mockRegistry, timeout(DEFAULT_TIMEOUT_MS)) + .sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED) - mFakeConnectivityService.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, arg1 = slot) - mFakeConnectivityService.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, arg1 = slot) + mFakeConnectivityService.agent.onStopSocketKeepalive(slot) + mFakeConnectivityService.agent.onRemoveKeepalivePacketFilter(slot) agent.expectCallback().let { assertEquals(it.slot, slot) } @@ -639,7 +619,7 @@ class NetworkAgentTest { val mockCm = mock(ConnectivityManager::class.java) doReturn(mockCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE) createConnectedNetworkAgent(mockContext) - verify(mockCm).registerNetworkAgent(any(Messenger::class.java), + verify(mockCm).registerNetworkAgent(any(), argThat { it.detailedState == NetworkInfo.DetailedState.CONNECTING }, any(LinkProperties::class.java), any(NetworkCapabilities::class.java), @@ -651,7 +631,7 @@ class NetworkAgentTest { @Test fun testSetAcceptUnvalidated() { createNetworkAgentWithFakeCS().let { agent -> - mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 1) + mFakeConnectivityService.agent.onSaveAcceptUnvalidated(true) agent.expectCallback().let { assertTrue(it.accept) } @@ -662,19 +642,18 @@ class NetworkAgentTest { @Test fun testSetAcceptUnvalidatedPreventAutomaticReconnect() { createNetworkAgentWithFakeCS().let { agent -> - mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 0) - mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + mFakeConnectivityService.agent.onSaveAcceptUnvalidated(false) + mFakeConnectivityService.agent.onPreventAutomaticReconnect() agent.expectCallback().let { assertFalse(it.accept) } agent.expectCallback() agent.assertNoCallback() // When automatic reconnect is turned off, the network is torn down and - // ConnectivityService sends a disconnect. This in turn causes the agent - // to send a DISCONNECTED message to CS. - mFakeConnectivityService.willExpectDisconnectOnce() + // ConnectivityService disconnects. As part of the disconnect, ConnectivityService will + // also send itself a message to unregister the NetworkAgent from its internal + // structure. mFakeConnectivityService.disconnect() - mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) agent.expectCallback() } } @@ -682,12 +661,10 @@ class NetworkAgentTest { @Test fun testPreventAutomaticReconnect() { createNetworkAgentWithFakeCS().let { agent -> - mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT) + mFakeConnectivityService.agent.onPreventAutomaticReconnect() agent.expectCallback() agent.assertNoCallback() - mFakeConnectivityService.willExpectDisconnectOnce() mFakeConnectivityService.disconnect() - mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED) agent.expectCallback() } } @@ -695,18 +672,14 @@ class NetworkAgentTest { @Test fun testValidationStatus() = createNetworkAgentWithFakeCS().let { agent -> val uri = Uri.parse("http://www.google.com") - val bundle = Bundle().apply { - putString(NetworkAgent.REDIRECT_URL_KEY, uri.toString()) - } - mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, - arg1 = VALID_NETWORK, obj = bundle) + mFakeConnectivityService.agent.onValidationStatusChanged(VALID_NETWORK, + uri.toString()) agent.expectCallback().let { assertEquals(it.status, VALID_NETWORK) assertEquals(it.uri, uri) } - mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS, - arg1 = INVALID_NETWORK, obj = Bundle()) + mFakeConnectivityService.agent.onValidationStatusChanged(INVALID_NETWORK, null) agent.expectCallback().let { assertEquals(it.status, INVALID_NETWORK) assertNull(it.uri) From 796f29c09ebb148a9857c40e539228f2e64cc97b Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 5 Jan 2021 06:37:56 +0000 Subject: [PATCH 1402/1415] Increase the wait timeout for meteredness to change. Bug: 170241174 Bug: 174808291 Test: atest CtsHostsideNetworkTests:HostsideRestrictBackgroundNetworkTests Change-Id: I3af17819a403958d88a30af7f6346e5bb96b2828 --- .../com/android/cts/net/hostside/NetworkPolicyTestUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java index 3807d79c35..3041dfa76b 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java @@ -55,7 +55,7 @@ import androidx.test.platform.app.InstrumentationRegistry; public class NetworkPolicyTestUtils { - private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 5000; + private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 10_000; private static ConnectivityManager mCm; private static WifiManager mWm; From bd5cc4231d68e6e5d87a6341c74fd97a3cfac316 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 2 Nov 2020 19:00:34 +0900 Subject: [PATCH 1403/1415] Add service-connectivity to tethering APEX Add the connectivity service JAR to the tethering APEX. This change should not be released in monthly updates until the modularization work is done, so will be reverted in module release branches. Test: Boot, wifi connects and has internet access Bug: 171540887 Merged-In: Ic496cd62be8c90928ccc619519ebe517beea78f0 Change-Id: Ia7cb83834b854e8c495c4ef17ec69ad032509208 --- Tethering/apex/Android.bp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp index a1e7fd218d..c99121cae7 100644 --- a/Tethering/apex/Android.bp +++ b/Tethering/apex/Android.bp @@ -16,9 +16,17 @@ apex { name: "com.android.tethering", - updatable: true, - min_sdk_version: "30", - java_libs: ["framework-tethering"], + // TODO: make updatable again once this contains only updatable artifacts (in particular, this + // cannot build as updatable unless service-connectivity builds against stable API). + // updatable: true, + // min_sdk_version: "30", + java_libs: [ + "framework-tethering", + "service-connectivity", + ], + jni_libs: [ + "libservice-connectivity", + ], bpfs: ["offload.o"], apps: ["Tethering"], manifest: "manifest.json", From 850ca6f6b421b98f0aabeec6f1ca8dba4acebc1d Mon Sep 17 00:00:00 2001 From: Pete Bentley Date: Thu, 7 Jan 2021 13:51:18 +0000 Subject: [PATCH 1404/1415] Revert "Add service-connectivity to tethering APEX" Revert "Set setCurrentProxyScriptUrl as public" Revert submission 1532910-connectivity_jar_in_apex Reason for revert: Breaks boot tests: b/176969905 Reverted Changes: Ie41a5b569:Set setCurrentProxyScriptUrl as public Id7b6a4664:Move service-connectivity to the tethering APEX Ia7cb83834:Add service-connectivity to tethering APEX Change-Id: I9f31d4810a92e620f02cc8d24bdf18fe28001a2b --- Tethering/apex/Android.bp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp index c99121cae7..a1e7fd218d 100644 --- a/Tethering/apex/Android.bp +++ b/Tethering/apex/Android.bp @@ -16,17 +16,9 @@ apex { name: "com.android.tethering", - // TODO: make updatable again once this contains only updatable artifacts (in particular, this - // cannot build as updatable unless service-connectivity builds against stable API). - // updatable: true, - // min_sdk_version: "30", - java_libs: [ - "framework-tethering", - "service-connectivity", - ], - jni_libs: [ - "libservice-connectivity", - ], + updatable: true, + min_sdk_version: "30", + java_libs: ["framework-tethering"], bpfs: ["offload.o"], apps: ["Tethering"], manifest: "manifest.json", From 2812f607a0cf9ea18f6b2658d73d2396f6ad95ce Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 8 Jan 2021 01:19:44 +0000 Subject: [PATCH 1405/1415] Revert^2 "Add service-connectivity to tethering APEX" Add the connectivity service JAR to the tethering APEX. This change should not be released in monthly updates until the modularization work is done, so will be reverted in module release branches. This rolls forward the change. The original topic was reverted because of a bad merged-in clause; this is fixed and re-verified in this topic. Test: Boot, wifi connects and has internet access Bug: 171540887 Change-Id: Ib0ac49609e444a53a6fee4575f5078e15f364eef --- Tethering/apex/Android.bp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp index a1e7fd218d..c99121cae7 100644 --- a/Tethering/apex/Android.bp +++ b/Tethering/apex/Android.bp @@ -16,9 +16,17 @@ apex { name: "com.android.tethering", - updatable: true, - min_sdk_version: "30", - java_libs: ["framework-tethering"], + // TODO: make updatable again once this contains only updatable artifacts (in particular, this + // cannot build as updatable unless service-connectivity builds against stable API). + // updatable: true, + // min_sdk_version: "30", + java_libs: [ + "framework-tethering", + "service-connectivity", + ], + jni_libs: [ + "libservice-connectivity", + ], bpfs: ["offload.o"], apps: ["Tethering"], manifest: "manifest.json", From ee661dfb59719333b51f226fef80af7e25972f18 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Mon, 28 Dec 2020 16:44:49 +0800 Subject: [PATCH 1406/1415] Move BaseNetdUnsolicitedEventListener to frameworks/libs/net Move BaseNetdUnsolicitedEventListener to frameworks/libs/net and create a new library - netd-client for using. Also remove netd_aidl_interface-unstable-java since netd-client links to the stable one. Bug: 174837473 Test: Manual test and check the log. Change-Id: Id65142b8c13a6cccbfe387d4ab757967497546e6 --- Tethering/Android.bp | 2 +- .../BaseNetdUnsolicitedEventListener.java | 75 ------------------- .../networkstack/tethering/Tethering.java | 2 +- 3 files changed, 2 insertions(+), 77 deletions(-) delete mode 100644 Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java diff --git a/Tethering/Android.bp b/Tethering/Android.bp index d8557adc61..272b4b9084 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -26,7 +26,6 @@ java_defaults { ], static_libs: [ "androidx.annotation_annotation", - "netd_aidl_interface-unstable-java", "netlink-client", // TODO: use networkstack-client instead of just including the AIDL interface "networkstack-aidl-interfaces-unstable-java", @@ -34,6 +33,7 @@ java_defaults { "android.hardware.tetheroffload.control-V1.0-java", "net-utils-framework-common", "net-utils-device-common", + "netd-client", ], libs: [ "framework-statsd.stubs.module_lib", diff --git a/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java b/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java deleted file mode 100644 index b1ffdb01f5..0000000000 --- a/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2019 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.util; - -import android.net.INetdUnsolicitedEventListener; - -import androidx.annotation.NonNull; - -/** - * Base {@link INetdUnsolicitedEventListener} that provides no-op implementations which can be - * overridden. - */ -public class BaseNetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub { - - @Override - public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, - int uid) { } - - @Override - public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { } - - @Override - public void onInterfaceDnsServerInfo(@NonNull String ifName, long lifetimeS, - @NonNull String[] servers) { } - - @Override - public void onInterfaceAddressUpdated(@NonNull String addr, String ifName, int flags, - int scope) { } - - @Override - public void onInterfaceAddressRemoved(@NonNull String addr, @NonNull String ifName, int flags, - int scope) { } - - @Override - public void onInterfaceAdded(@NonNull String ifName) { } - - @Override - public void onInterfaceRemoved(@NonNull String ifName) { } - - @Override - public void onInterfaceChanged(@NonNull String ifName, boolean up) { } - - @Override - public void onInterfaceLinkStateChanged(@NonNull String ifName, boolean up) { } - - @Override - public void onRouteChanged(boolean updated, @NonNull String route, @NonNull String gateway, - @NonNull String ifName) { } - - @Override - public void onStrictCleartextDetected(int uid, @NonNull String hex) { } - - @Override - public int getInterfaceVersion() { - return INetdUnsolicitedEventListener.VERSION; - } - - @Override - public String getInterfaceHash() { - return INetdUnsolicitedEventListener.HASH; - } -} diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 62ae88c24b..fdd1c40949 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -93,7 +93,6 @@ import android.net.TetheringConfigurationParcel; import android.net.TetheringRequestParcel; import android.net.ip.IpServer; import android.net.shared.NetdUtils; -import android.net.util.BaseNetdUnsolicitedEventListener; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; import android.net.util.SharedLog; @@ -132,6 +131,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.net.module.util.BaseNetdUnsolicitedEventListener; import java.io.FileDescriptor; import java.io.PrintWriter; From 4df8a7aef18e44089838f94fa51afe2a74af3b5e Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 11 Jan 2021 09:47:04 +0100 Subject: [PATCH 1407/1415] Add CTS test for Restricted Networking Mode Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests Bug: 175281879 Bug: 170323671 Change-Id: Ic69e7e029debeea1f131242fb2baad2796d4768c --- ...ractRestrictBackgroundNetworkTestCase.java | 6 +- .../cts/net/hostside/RestrictedModeTest.java | 68 +++++++++++++++++++ ...ostsideRestrictBackgroundNetworkTests.java | 8 +++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 71f6f2f5f0..f423503c56 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -234,12 +234,16 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { } protected void assertForegroundNetworkAccess() throws Exception { + assertForegroundNetworkAccess(true); + } + + protected void assertForegroundNetworkAccess(boolean expectAllowed) throws Exception { assertForegroundState(); // We verified that app is in foreground state but if the screen turns-off while // verifying for network access, the app will go into background state (in case app's // foreground status was due to top activity). So, turn the screen on when verifying // network connectivity. - assertNetworkAccess(true /* expectAvailable */, true /* needScreenOn */); + assertNetworkAccess(expectAllowed /* expectAvailable */, true /* needScreenOn */); } protected void assertForegroundServiceNetworkAccess() throws Exception { diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java new file mode 100644 index 0000000000..29d3c6e1ba --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 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 com.android.cts.net.hostside; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public final class RestrictedModeTest extends AbstractRestrictBackgroundNetworkTestCase { + @Before + public void setUp() throws Exception { + super.setUp(); + } + + @After + public void tearDown() throws Exception { + setRestrictedMode(false); + super.tearDown(); + } + + private void setRestrictedMode(boolean enabled) throws Exception { + executeSilentShellCommand( + "settings put global restricted_networking_mode " + (enabled ? 1 : 0)); + assertRestrictedModeState(enabled); + } + + private void assertRestrictedModeState(boolean enabled) throws Exception { + assertDelayedShellCommand("cmd netpolicy get restricted-mode", + "Restricted mode status: " + (enabled ? "enabled" : "disabled")); + } + + @Test + public void testNetworkAccess() throws Exception { + setRestrictedMode(false); + + // go to foreground state and enable restricted mode + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); + setRestrictedMode(true); + assertForegroundNetworkAccess(false); + + // go to background state + finishActivity(); + assertBackgroundNetworkAccess(false); + + // disable restricted mode and assert network access in foreground and background states + setRestrictedMode(false); + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); + assertForegroundNetworkAccess(true); + + // go to background state + finishActivity(); + assertBackgroundNetworkAccess(true); + } +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index ac28c7ab63..a629ccf65e 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -311,6 +311,14 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists"); } + /************************** + * Restricted mode tests. * + **************************/ + public void testRestrictedMode_networkAccess() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".RestrictedModeTest", + "testNetworkAccess"); + } + /******************* * Helper methods. * *******************/ From 7052688dde014de45315c368287e07049b32cfc4 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 12 Nov 2020 00:17:15 +0800 Subject: [PATCH 1408/1415] Provide a easy way to access bpf maps from java A wrapper for bpf map opening, reading/writing, and iteration. Bug: 173167302 Test: atest BpfMapTest Change-Id: I792b41978b322c9e4969cd7b6c35d6978ab86bc4 --- Tethering/Android.bp | 6 +- Tethering/bpf_progs/offload.c | 4 + Tethering/jarjar-rules.txt | 5 +- .../jni/android_net_util_TetheringUtils.cpp | 17 - ..._android_networkstack_tethering_BpfMap.cpp | 176 +++++++++ Tethering/jni/onload.cpp | 42 +++ Tethering/proguard.flags | 8 + .../networkstack/tethering/BpfMap.java | 222 +++++++++++ .../tethering/TetherIngressKey.java | 72 ++++ .../tethering/TetherIngressValue.java | 80 ++++ .../networkstack/tethering/BpfMapTest.java | 356 ++++++++++++++++++ 11 files changed, 969 insertions(+), 19 deletions(-) create mode 100644 Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp create mode 100644 Tethering/jni/onload.cpp create mode 100644 Tethering/src/com/android/networkstack/tethering/BpfMap.java create mode 100644 Tethering/src/com/android/networkstack/tethering/TetherIngressKey.java create mode 100644 Tethering/src/com/android/networkstack/tethering/TetherIngressValue.java create mode 100644 Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java diff --git a/Tethering/Android.bp b/Tethering/Android.bp index d8557adc61..0c9801c4fe 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -60,8 +60,12 @@ cc_library { "com.android.tethering", ], min_sdk_version: "30", + include_dirs: [ + // TODO: use the libbpf_android_headers instead of just including the header files. + "system/bpf/libbpf_android/include/", + ], srcs: [ - "jni/android_net_util_TetheringUtils.cpp", + "jni/*.cpp", ], shared_libs: [ "liblog", diff --git a/Tethering/bpf_progs/offload.c b/Tethering/bpf_progs/offload.c index cc5af3127b..d8dc60dc1a 100644 --- a/Tethering/bpf_progs/offload.c +++ b/Tethering/bpf_progs/offload.c @@ -34,6 +34,10 @@ DEFINE_BPF_MAP_GRW(tether_stats_map, HASH, uint32_t, TetherStatsValue, 16, AID_N // (tethering allowed when stats[iif].rxBytes + stats[iif].txBytes < limit[iif]) DEFINE_BPF_MAP_GRW(tether_limit_map, HASH, uint32_t, uint64_t, 16, AID_NETWORK_STACK) +// Used only by TetheringPrivilegedTests, not by production code. +DEFINE_BPF_MAP_GRW(tether_ingress_map_TEST, HASH, TetherIngressKey, TetherIngressValue, 16, + AID_NETWORK_STACK) + static inline __always_inline int do_forward(struct __sk_buff* skb, bool is_ethernet) { int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0; void* data = (void*)(long)skb->data; diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt index 591861f5b8..d1ad569e0d 100644 --- a/Tethering/jarjar-rules.txt +++ b/Tethering/jarjar-rules.txt @@ -8,4 +8,7 @@ rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1 rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1 # Classes from net-utils-framework-common -rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1 \ No newline at end of file +rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1 + +# Classes from net-utils-device-common +rule com.android.net.module.util.Struct* com.android.networkstack.tethering.util.Struct@1 diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp index 7bfb6dab4a..27c84cf280 100644 --- a/Tethering/jni/android_net_util_TetheringUtils.cpp +++ b/Tethering/jni/android_net_util_TetheringUtils.cpp @@ -28,9 +28,6 @@ #include #include -#define LOG_TAG "TetheringUtils" -#include - namespace android { static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt); @@ -184,18 +181,4 @@ int register_android_net_util_TetheringUtils(JNIEnv* env) { gMethods, NELEM(gMethods)); } -extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { - JNIEnv *env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { - __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); - return JNI_ERR; - } - - if (register_android_net_util_TetheringUtils(env) < 0) { - return JNI_ERR; - } - - return JNI_VERSION_1_6; -} - }; // namespace android diff --git a/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp b/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp new file mode 100644 index 0000000000..64f7dcfa3c --- /dev/null +++ b/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp @@ -0,0 +1,176 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include + +#include "nativehelper/scoped_primitive_array.h" +#include "nativehelper/scoped_utf_chars.h" + +#define BPF_FD_JUST_USE_INT +#include "bpf/BpfUtils.h" + +namespace android { + +static jclass sErrnoExceptionClass; +static jmethodID sErrnoExceptionCtor2; +static jmethodID sErrnoExceptionCtor3; + +static void throwErrnoException(JNIEnv* env, const char* functionName, int error) { + if (sErrnoExceptionClass == nullptr || sErrnoExceptionClass == nullptr) return; + + jthrowable cause = nullptr; + if (env->ExceptionCheck()) { + cause = env->ExceptionOccurred(); + env->ExceptionClear(); + } + + ScopedLocalRef msg(env, env->NewStringUTF(functionName)); + + // Not really much we can do here if msg is null, let's try to stumble on... + if (msg.get() == nullptr) env->ExceptionClear(); + + jobject errnoException; + if (cause != nullptr) { + errnoException = env->NewObject(sErrnoExceptionClass, sErrnoExceptionCtor3, msg.get(), + error, cause); + } else { + errnoException = env->NewObject(sErrnoExceptionClass, sErrnoExceptionCtor2, msg.get(), + error); + } + env->Throw(static_cast(errnoException)); +} + +static jint com_android_networkstack_tethering_BpfMap_closeMap(JNIEnv *env, jobject clazz, + jint fd) { + int ret = close(fd); + + if (ret) throwErrnoException(env, "closeMap", errno); + + return ret; +} + +static jint com_android_networkstack_tethering_BpfMap_bpfFdGet(JNIEnv *env, jobject clazz, + jstring path, jint mode) { + ScopedUtfChars pathname(env, path); + + jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast(mode)); + + return fd; +} + +static void com_android_networkstack_tethering_BpfMap_writeToMapEntry(JNIEnv *env, jobject clazz, + jint fd, jbyteArray key, jbyteArray value, jint flags) { + ScopedByteArrayRO keyRO(env, key); + ScopedByteArrayRO valueRO(env, value); + + int ret = bpf::writeToMapEntry(static_cast(fd), keyRO.get(), valueRO.get(), + static_cast(flags)); + + if (ret) throwErrnoException(env, "writeToMapEntry", errno); +} + +static jboolean throwIfNotEnoent(JNIEnv *env, const char* functionName, int ret, int err) { + if (ret == 0) return true; + + if (err != ENOENT) throwErrnoException(env, functionName, err); + return false; +} + +static jboolean com_android_networkstack_tethering_BpfMap_deleteMapEntry(JNIEnv *env, jobject clazz, + jint fd, jbyteArray key) { + ScopedByteArrayRO keyRO(env, key); + + // On success, zero is returned. If the element is not found, -1 is returned and errno is set + // to ENOENT. + int ret = bpf::deleteMapEntry(static_cast(fd), keyRO.get()); + + return throwIfNotEnoent(env, "deleteMapEntry", ret, errno); +} + +static jboolean com_android_networkstack_tethering_BpfMap_getNextMapKey(JNIEnv *env, jobject clazz, + jint fd, jbyteArray key, jbyteArray nextKey) { + // If key is found, the operation returns zero and sets the next key pointer to the key of the + // next element. If key is not found, the operation returns zero and sets the next key pointer + // to the key of the first element. If key is the last element, -1 is returned and errno is + // set to ENOENT. Other possible errno values are ENOMEM, EFAULT, EPERM, and EINVAL. + ScopedByteArrayRW nextKeyRW(env, nextKey); + int ret; + if (key == nullptr) { + // Called by getFirstKey. Find the first key in the map. + ret = bpf::getNextMapKey(static_cast(fd), nullptr, nextKeyRW.get()); + } else { + ScopedByteArrayRO keyRO(env, key); + ret = bpf::getNextMapKey(static_cast(fd), keyRO.get(), nextKeyRW.get()); + } + + return throwIfNotEnoent(env, "getNextMapKey", ret, errno); +} + +static jboolean com_android_networkstack_tethering_BpfMap_findMapEntry(JNIEnv *env, jobject clazz, + jint fd, jbyteArray key, jbyteArray value) { + ScopedByteArrayRO keyRO(env, key); + ScopedByteArrayRW valueRW(env, value); + + // If an element is found, the operation returns zero and stores the element's value into + // "value". If no element is found, the operation returns -1 and sets errno to ENOENT. + int ret = bpf::findMapEntry(static_cast(fd), keyRO.get(), valueRW.get()); + + return throwIfNotEnoent(env, "findMapEntry", ret, errno); +} + +/* + * JNI registration. + */ +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "closeMap", "(I)I", + (void*) com_android_networkstack_tethering_BpfMap_closeMap }, + { "bpfFdGet", "(Ljava/lang/String;I)I", + (void*) com_android_networkstack_tethering_BpfMap_bpfFdGet }, + { "writeToMapEntry", "(I[B[BI)V", + (void*) com_android_networkstack_tethering_BpfMap_writeToMapEntry }, + { "deleteMapEntry", "(I[B)Z", + (void*) com_android_networkstack_tethering_BpfMap_deleteMapEntry }, + { "getNextMapKey", "(I[B[B)Z", + (void*) com_android_networkstack_tethering_BpfMap_getNextMapKey }, + { "findMapEntry", "(I[B[B)Z", + (void*) com_android_networkstack_tethering_BpfMap_findMapEntry }, + +}; + +int register_com_android_networkstack_tethering_BpfMap(JNIEnv* env) { + sErrnoExceptionClass = static_cast(env->NewGlobalRef( + env->FindClass("android/system/ErrnoException"))); + if (sErrnoExceptionClass == nullptr) return JNI_ERR; + + sErrnoExceptionCtor2 = env->GetMethodID(sErrnoExceptionClass, "", + "(Ljava/lang/String;I)V"); + if (sErrnoExceptionCtor2 == nullptr) return JNI_ERR; + + sErrnoExceptionCtor3 = env->GetMethodID(sErrnoExceptionClass, "", + "(Ljava/lang/String;ILjava/lang/Throwable;)V"); + if (sErrnoExceptionCtor3 == nullptr) return JNI_ERR; + + return jniRegisterNativeMethods(env, + "com/android/networkstack/tethering/BpfMap", + gMethods, NELEM(gMethods)); +} + +}; // namespace android diff --git a/Tethering/jni/onload.cpp b/Tethering/jni/onload.cpp new file mode 100644 index 0000000000..3766de9076 --- /dev/null +++ b/Tethering/jni/onload.cpp @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#include +#include "jni.h" + +#define LOG_TAG "TetheringJni" +#include + +namespace android { + +int register_android_net_util_TetheringUtils(JNIEnv* env); +int register_com_android_networkstack_tethering_BpfMap(JNIEnv* env); + +extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "ERROR: GetEnv failed"); + return JNI_ERR; + } + + if (register_android_net_util_TetheringUtils(env) < 0) return JNI_ERR; + + if (register_com_android_networkstack_tethering_BpfMap(env) < 0) return JNI_ERR; + + return JNI_VERSION_1_6; +} + +}; // namespace android diff --git a/Tethering/proguard.flags b/Tethering/proguard.flags index 86b903353c..9ab56c2b61 100644 --- a/Tethering/proguard.flags +++ b/Tethering/proguard.flags @@ -4,6 +4,14 @@ static final int EVENT_*; } +-keep class com.android.networkstack.tethering.BpfMap { + native ; +} + +-keepclassmembers public class * extends com.android.networkstack.tethering.util.Struct { + public (...); +} + -keepclassmembers class android.net.ip.IpServer { static final int CMD_*; } diff --git a/Tethering/src/com/android/networkstack/tethering/BpfMap.java b/Tethering/src/com/android/networkstack/tethering/BpfMap.java new file mode 100644 index 0000000000..9505709655 --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/BpfMap.java @@ -0,0 +1,222 @@ +/* + * 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 com.android.networkstack.tethering; + +import static android.system.OsConstants.EEXIST; +import static android.system.OsConstants.ENOENT; + +import android.system.ErrnoException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.net.module.util.Struct; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * BpfMap is a key -> value mapping structure that is designed to maintained the bpf map entries. + * This is a wrapper class of in-kernel data structure. The in-kernel data can be read/written by + * passing syscalls with map file descriptor. + * + * @param the key of the map. + * @param the value of the map. + */ +public class BpfMap implements AutoCloseable { + // Following definitions from kernel include/uapi/linux/bpf.h + public static final int BPF_F_RDWR = 0; + public static final int BPF_F_RDONLY = 1 << 3; + public static final int BPF_F_WRONLY = 1 << 4; + + public static final int BPF_MAP_TYPE_HASH = 1; + + private static final int BPF_F_NO_PREALLOC = 1; + + private static final int BPF_ANY = 0; + private static final int BPF_NOEXIST = 1; + private static final int BPF_EXIST = 2; + + private final int mMapFd; + private final Class mKeyClass; + private final Class mValueClass; + private final int mKeySize; + private final int mValueSize; + + /** + * Create a BpfMap map wrapper with "path" of filesystem. + * + * @param flag the access mode, one of BPF_F_RDWR, BPF_F_RDONLY, or BPF_F_WRONLY. + * @throws ErrnoException if the BPF map associated with {@code path} cannot be retrieved. + * @throws NullPointerException if {@code path} is null. + */ + public BpfMap(@NonNull final String path, final int flag, final Class key, + final Class value) throws ErrnoException, NullPointerException { + mMapFd = bpfFdGet(path, flag); + + mKeyClass = key; + mValueClass = value; + mKeySize = Struct.getSize(key); + mValueSize = Struct.getSize(value); + } + + /** + * Update an existing or create a new key -> value entry in an eBbpf map. + */ + public void updateEntry(K key, V value) throws ErrnoException { + writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_ANY); + } + + /** + * If the key does not exist in the map, insert key -> value entry into eBpf map. + * Otherwise IllegalStateException will be thrown. + */ + public void insertEntry(K key, V value) + throws ErrnoException, IllegalStateException { + try { + writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + } catch (ErrnoException e) { + if (e.errno == EEXIST) throw new IllegalStateException(key + " already exists"); + + throw e; + } + } + + /** + * If the key already exists in the map, replace its value. Otherwise NoSuchElementException + * will be thrown. + */ + public void replaceEntry(K key, V value) + throws ErrnoException, NoSuchElementException { + try { + writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + } catch (ErrnoException e) { + if (e.errno == ENOENT) throw new NoSuchElementException(key + " not found"); + + throw e; + } + } + + /** Remove existing key from eBpf map. Return false if map was not modified. */ + public boolean deleteEntry(K key) throws ErrnoException { + return deleteMapEntry(mMapFd, key.writeToBytes()); + } + + private K getNextKeyInternal(@Nullable K key) throws ErrnoException { + final byte[] rawKey = getNextRawKey( + key == null ? null : key.writeToBytes()); + if (rawKey == null) return null; + + final ByteBuffer buffer = ByteBuffer.wrap(rawKey); + buffer.order(ByteOrder.nativeOrder()); + return Struct.parse(mKeyClass, buffer); + } + + /** + * Get the next key of the passed-in key. If the passed-in key is not found, return the first + * key. If the passed-in key is the last one, return null. + * + * TODO: consider allowing null passed-in key. + */ + public K getNextKey(@Nullable K key) throws ErrnoException { + Objects.requireNonNull(key); + return getNextKeyInternal(key); + } + + private byte[] getNextRawKey(@Nullable final byte[] key) throws ErrnoException { + byte[] nextKey = new byte[mKeySize]; + if (getNextMapKey(mMapFd, key, nextKey)) return nextKey; + + return null; + } + + /** Get the first key of eBpf map. */ + public K getFirstKey() throws ErrnoException { + return getNextKeyInternal(null); + } + + /** Check whether a key exists in the map. */ + public boolean containsKey(@NonNull K key) throws ErrnoException { + Objects.requireNonNull(key); + + final byte[] rawValue = getRawValue(key.writeToBytes()); + return rawValue != null; + } + + /** Retrieve a value from the map. Return null if there is no such key. */ + public V getValue(@NonNull K key) throws ErrnoException { + Objects.requireNonNull(key); + final byte[] rawValue = getRawValue(key.writeToBytes()); + + if (rawValue == null) return null; + + final ByteBuffer buffer = ByteBuffer.wrap(rawValue); + buffer.order(ByteOrder.nativeOrder()); + return Struct.parse(mValueClass, buffer); + } + + private byte[] getRawValue(final byte[] key) throws ErrnoException { + byte[] value = new byte[mValueSize]; + if (findMapEntry(mMapFd, key, value)) return value; + + return null; + } + + /** + * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer. + * The given BiConsumer may to delete the passed-in entry, but is not allowed to perform any + * other structural modifications to the map, such as adding entries or deleting other entries. + * Otherwise, iteration will result in undefined behaviour. + */ + public void forEach(BiConsumer action) throws ErrnoException { + @Nullable + K nextKey = getFirstKey(); + + while (nextKey != null) { + @NonNull + final K curKey = nextKey; + @NonNull + final V value = getValue(curKey); + + nextKey = getNextKey(curKey); + action.accept(curKey, value); + } + } + + @Override + public void close() throws Exception { + closeMap(mMapFd); + } + + private static native int closeMap(int fd) throws ErrnoException; + + private native int bpfFdGet(String path, int mode) throws ErrnoException, NullPointerException; + + private native void writeToMapEntry(int fd, byte[] key, byte[] value, int flags) + throws ErrnoException; + + private native boolean deleteMapEntry(int fd, byte[] key) throws ErrnoException; + + // If key is found, the operation returns true and the nextKey would reference to the next + // element. If key is not found, the operation returns true and the nextKey would reference to + // the first element. If key is the last element, false is returned. + private native boolean getNextMapKey(int fd, byte[] key, byte[] nextKey) throws ErrnoException; + + private native boolean findMapEntry(int fd, byte[] key, byte[] value) throws ErrnoException; +} diff --git a/Tethering/src/com/android/networkstack/tethering/TetherIngressKey.java b/Tethering/src/com/android/networkstack/tethering/TetherIngressKey.java new file mode 100644 index 0000000000..78683c5e1c --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/TetherIngressKey.java @@ -0,0 +1,72 @@ +/* + * 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 com.android.networkstack.tethering; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; + +/** The key of BpfMap which is used for bpf offload. */ +public class TetherIngressKey extends Struct { + @Field(order = 0, type = Type.U32) + public final long iif; // The input interface index. + + @Field(order = 1, type = Type.ByteArray, arraysize = 16) + public final byte[] neigh6; // The destination IPv6 address. + + public TetherIngressKey(final long iif, final byte[] neigh6) { + try { + final Inet6Address unused = (Inet6Address) InetAddress.getByAddress(neigh6); + } catch (ClassCastException | UnknownHostException e) { + throw new IllegalArgumentException("Invalid IPv6 address: " + + Arrays.toString(neigh6)); + } + this.iif = iif; + this.neigh6 = neigh6; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + + if (!(obj instanceof TetherIngressKey)) return false; + + final TetherIngressKey that = (TetherIngressKey) obj; + + return iif == that.iif && Arrays.equals(neigh6, that.neigh6); + } + + @Override + public int hashCode() { + return Long.hashCode(iif) ^ Arrays.hashCode(neigh6); + } + + @Override + public String toString() { + try { + return String.format("iif: %d, neigh: %s", iif, Inet6Address.getByAddress(neigh6)); + } catch (UnknownHostException e) { + // Should not happen because construtor already verify neigh6. + throw new IllegalStateException("Invalid TetherIngressKey"); + } + } +} diff --git a/Tethering/src/com/android/networkstack/tethering/TetherIngressValue.java b/Tethering/src/com/android/networkstack/tethering/TetherIngressValue.java new file mode 100644 index 0000000000..e2116fc2d5 --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/TetherIngressValue.java @@ -0,0 +1,80 @@ +/* + * 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 com.android.networkstack.tethering; + +import android.net.MacAddress; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.util.Objects; + +/** The value of BpfMap which is used for bpf offload. */ +public class TetherIngressValue extends Struct { + @Field(order = 0, type = Type.U32) + public final long oif; // The output interface index. + + // The ethhdr struct which is defined in uapi/linux/if_ether.h + @Field(order = 1, type = Type.EUI48) + public final MacAddress ethDstMac; // The destination mac address. + @Field(order = 2, type = Type.EUI48) + public final MacAddress ethSrcMac; // The source mac address. + @Field(order = 3, type = Type.UBE16) + public final int ethProto; // Packet type ID field. + + @Field(order = 4, type = Type.U16) + public final int pmtu; // The maximum L3 output path/route mtu. + + public TetherIngressValue(final long oif, @NonNull final MacAddress ethDstMac, + @NonNull final MacAddress ethSrcMac, final int ethProto, final int pmtu) { + Objects.requireNonNull(ethSrcMac); + Objects.requireNonNull(ethDstMac); + + this.oif = oif; + this.ethDstMac = ethDstMac; + this.ethSrcMac = ethSrcMac; + this.ethProto = ethProto; + this.pmtu = pmtu; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + + if (!(obj instanceof TetherIngressValue)) return false; + + final TetherIngressValue that = (TetherIngressValue) obj; + + return oif == that.oif && ethDstMac.equals(that.ethDstMac) + && ethSrcMac.equals(that.ethSrcMac) && ethProto == that.ethProto + && pmtu == that.pmtu; + } + + @Override + public int hashCode() { + return Objects.hash(oif, ethDstMac, ethSrcMac, ethProto, pmtu); + } + + @Override + public String toString() { + return String.format("oif: %d, dstMac: %s, srcMac: %s, proto: %d, pmtu: %d", oif, + ethDstMac, ethSrcMac, ethProto, pmtu); + } +} diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java new file mode 100644 index 0000000000..77c0961ba8 --- /dev/null +++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java @@ -0,0 +1,356 @@ +/* + * 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 com.android.networkstack.tethering; + +import static android.system.OsConstants.ETH_P_IPV6; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.net.MacAddress; +import android.os.Build; +import android.system.ErrnoException; +import android.system.OsConstants; +import android.util.ArrayMap; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.NoSuchElementException; + + +@RunWith(AndroidJUnit4.class) +@IgnoreUpTo(Build.VERSION_CODES.R) +public final class BpfMapTest { + // Sync from packages/modules/Connectivity/Tethering/bpf_progs/offload.c. + private static final int TEST_MAP_SIZE = 16; + private static final String TETHER_INGRESS_FS_PATH = + "/sys/fs/bpf/map_offload_tether_ingress_map_TEST"; + + private ArrayMap mTestData; + + @BeforeClass + public static void setupOnce() { + System.loadLibrary("tetherutilsjni"); + } + + @Before + public void setUp() throws Exception { + // TODO: Simply the test map creation and deletion. + // - Make the map a class member (mTestMap) + // - Open the test map RW in setUp + // - Close the test map in tearDown. + cleanTestMap(); + + mTestData = new ArrayMap<>(); + mTestData.put(createTetherIngressKey(101, "2001:db8::1"), + createTetherIngressValue(11, "00:00:00:00:00:0a", "11:11:11:00:00:0b", ETH_P_IPV6, + 1280)); + mTestData.put(createTetherIngressKey(102, "2001:db8::2"), + createTetherIngressValue(22, "00:00:00:00:00:0c", "22:22:22:00:00:0d", ETH_P_IPV6, + 1400)); + mTestData.put(createTetherIngressKey(103, "2001:db8::3"), + createTetherIngressValue(33, "00:00:00:00:00:0e", "33:33:33:00:00:0f", ETH_P_IPV6, + 1500)); + } + + @After + public void tearDown() throws Exception { + cleanTestMap(); + } + + private BpfMap getTestMap() throws Exception { + return new BpfMap<>( + TETHER_INGRESS_FS_PATH, BpfMap.BPF_F_RDWR, + TetherIngressKey.class, TetherIngressValue.class); + } + + private void cleanTestMap() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + bpfMap.forEach((key, value) -> { + try { + assertTrue(bpfMap.deleteEntry(key)); + } catch (ErrnoException ignored) { } + }); + assertNull(bpfMap.getFirstKey()); + } + } + + private TetherIngressKey createTetherIngressKey(long iif, String address) throws Exception { + final InetAddress ipv6Address = InetAddress.getByName(address); + + return new TetherIngressKey(iif, ipv6Address.getAddress()); + } + + private TetherIngressValue createTetherIngressValue(long oif, String src, String dst, int proto, + int pmtu) throws Exception { + final MacAddress srcMac = MacAddress.fromString(src); + final MacAddress dstMac = MacAddress.fromString(dst); + + return new TetherIngressValue(oif, dstMac, srcMac, proto, pmtu); + } + + @Test + public void testGetFd() throws Exception { + try (BpfMap readOnlyMap = new BpfMap<>(TETHER_INGRESS_FS_PATH, BpfMap.BPF_F_RDONLY, + TetherIngressKey.class, TetherIngressValue.class)) { + assertNotNull(readOnlyMap); + try { + readOnlyMap.insertEntry(mTestData.keyAt(0), mTestData.valueAt(0)); + fail("Writing RO map should throw ErrnoException"); + } catch (ErrnoException expected) { + assertEquals(OsConstants.EPERM, expected.errno); + } + } + try (BpfMap writeOnlyMap = new BpfMap<>(TETHER_INGRESS_FS_PATH, BpfMap.BPF_F_WRONLY, + TetherIngressKey.class, TetherIngressValue.class)) { + assertNotNull(writeOnlyMap); + try { + writeOnlyMap.getFirstKey(); + fail("Reading WO map should throw ErrnoException"); + } catch (ErrnoException expected) { + assertEquals(OsConstants.EPERM, expected.errno); + } + } + try (BpfMap readWriteMap = new BpfMap<>(TETHER_INGRESS_FS_PATH, BpfMap.BPF_F_RDWR, + TetherIngressKey.class, TetherIngressValue.class)) { + assertNotNull(readWriteMap); + } + } + + @Test + public void testGetFirstKey() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + // getFirstKey on an empty map returns null. + assertFalse(bpfMap.containsKey(mTestData.keyAt(0))); + assertNull(bpfMap.getFirstKey()); + assertNull(bpfMap.getValue(mTestData.keyAt(0))); + + // getFirstKey on a non-empty map returns the first key. + bpfMap.insertEntry(mTestData.keyAt(0), mTestData.valueAt(0)); + assertEquals(mTestData.keyAt(0), bpfMap.getFirstKey()); + } + } + + @Test + public void testGetNextKey() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + // [1] If the passed-in key is not found on empty map, return null. + final TetherIngressKey nonexistentKey = createTetherIngressKey(1234, "2001:db8::10"); + assertNull(bpfMap.getNextKey(nonexistentKey)); + + // [2] If the passed-in key is null on empty map, throw NullPointerException. + try { + bpfMap.getNextKey(null); + fail("Getting next key with null key should throw NullPointerException"); + } catch (NullPointerException expected) { } + + // The BPF map has one entry now. + final ArrayMap resultMap = new ArrayMap<>(); + bpfMap.insertEntry(mTestData.keyAt(0), mTestData.valueAt(0)); + resultMap.put(mTestData.keyAt(0), mTestData.valueAt(0)); + + // [3] If the passed-in key is the last key, return null. + // Because there is only one entry in the map, the first key equals the last key. + final TetherIngressKey lastKey = bpfMap.getFirstKey(); + assertNull(bpfMap.getNextKey(lastKey)); + + // The BPF map has two entries now. + bpfMap.insertEntry(mTestData.keyAt(1), mTestData.valueAt(1)); + resultMap.put(mTestData.keyAt(1), mTestData.valueAt(1)); + + // [4] If the passed-in key is found, return the next key. + TetherIngressKey nextKey = bpfMap.getFirstKey(); + while (nextKey != null) { + if (resultMap.remove(nextKey).equals(nextKey)) { + fail("Unexpected result: " + nextKey); + } + nextKey = bpfMap.getNextKey(nextKey); + } + assertTrue(resultMap.isEmpty()); + + // [5] If the passed-in key is not found on non-empty map, return the first key. + assertEquals(bpfMap.getFirstKey(), bpfMap.getNextKey(nonexistentKey)); + + // [6] If the passed-in key is null on non-empty map, throw NullPointerException. + try { + bpfMap.getNextKey(null); + fail("Getting next key with null key should throw NullPointerException"); + } catch (NullPointerException expected) { } + } + } + + @Test + public void testUpdateBpfMap() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + + final TetherIngressKey key = mTestData.keyAt(0); + final TetherIngressValue value = mTestData.valueAt(0); + final TetherIngressValue value2 = mTestData.valueAt(1); + assertFalse(bpfMap.deleteEntry(key)); + + // updateEntry will create an entry if it does not exist already. + bpfMap.updateEntry(key, value); + assertTrue(bpfMap.containsKey(key)); + final TetherIngressValue result = bpfMap.getValue(key); + assertEquals(value, result); + + // updateEntry will update an entry that already exists. + bpfMap.updateEntry(key, value2); + assertTrue(bpfMap.containsKey(key)); + final TetherIngressValue result2 = bpfMap.getValue(key); + assertEquals(value2, result2); + + assertTrue(bpfMap.deleteEntry(key)); + assertFalse(bpfMap.containsKey(key)); + } + } + + @Test + public void testInsertReplaceEntry() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + + final TetherIngressKey key = mTestData.keyAt(0); + final TetherIngressValue value = mTestData.valueAt(0); + final TetherIngressValue value2 = mTestData.valueAt(1); + + try { + bpfMap.replaceEntry(key, value); + fail("Replacing non-existent key " + key + " should throw NoSuchElementException"); + } catch (NoSuchElementException expected) { } + assertFalse(bpfMap.containsKey(key)); + + bpfMap.insertEntry(key, value); + assertTrue(bpfMap.containsKey(key)); + final TetherIngressValue result = bpfMap.getValue(key); + assertEquals(value, result); + try { + bpfMap.insertEntry(key, value); + fail("Inserting existing key " + key + " should throw IllegalStateException"); + } catch (IllegalStateException expected) { } + + bpfMap.replaceEntry(key, value2); + assertTrue(bpfMap.containsKey(key)); + final TetherIngressValue result2 = bpfMap.getValue(key); + assertEquals(value2, result2); + } + } + + @Test + public void testIterateBpfMap() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + final ArrayMap resultMap = + new ArrayMap<>(mTestData); + + for (int i = 0; i < resultMap.size(); i++) { + bpfMap.insertEntry(resultMap.keyAt(i), resultMap.valueAt(i)); + } + + bpfMap.forEach((key, value) -> { + if (!value.equals(resultMap.remove(key))) { + fail("Unexpected result: " + key + ", value: " + value); + } + }); + assertTrue(resultMap.isEmpty()); + } + } + + @Test + public void testIterateEmptyMap() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + // Use an one element array to be a trick for a counter because local variables + // referenced from a lambda expression must be final. + final int[] count = {0}; + bpfMap.forEach((key, value) -> { + count[0]++; + }); + + // Expect that consumer has never be called. + assertEquals(0, count[0]); + } + } + + @Test + public void testIterateDeletion() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + final ArrayMap resultMap = + new ArrayMap<>(mTestData); + + for (int i = 0; i < resultMap.size(); i++) { + bpfMap.insertEntry(resultMap.keyAt(i), resultMap.valueAt(i)); + } + + // Use an one element array to be a trick for a counter because local variables + // referenced from a lambda expression must be final. + final int[] count = {0}; + bpfMap.forEach((key, value) -> { + try { + assertTrue(bpfMap.deleteEntry(key)); + } catch (ErrnoException e) { + fail("Fail to delete key " + key + ": " + e); + } + if (!value.equals(resultMap.remove(key))) { + fail("Unexpected result: " + key + ", value: " + value); + } + count[0]++; + }); + assertEquals(3, count[0]); + assertTrue(resultMap.isEmpty()); + assertNull(bpfMap.getFirstKey()); + } + } + + @Test + public void testInsertOverflow() throws Exception { + try (BpfMap bpfMap = getTestMap()) { + final ArrayMap testData = new ArrayMap<>(); + + // Build test data for TEST_MAP_SIZE + 1 entries. + for (int i = 1; i <= TEST_MAP_SIZE + 1; i++) { + testData.put(createTetherIngressKey(i, "2001:db8::1"), createTetherIngressValue( + 100, "de:ad:be:ef:00:01", "de:ad:be:ef:00:02", ETH_P_IPV6, 1500)); + } + + // Insert #TEST_MAP_SIZE test entries to the map. The map has reached the limit. + for (int i = 0; i < TEST_MAP_SIZE; i++) { + bpfMap.insertEntry(testData.keyAt(i), testData.valueAt(i)); + } + + // The map won't allow inserting any more entries. + try { + bpfMap.insertEntry(testData.keyAt(TEST_MAP_SIZE), testData.valueAt(TEST_MAP_SIZE)); + fail("Writing too many entries should throw ErrnoException"); + } catch (ErrnoException expected) { + // Expect that can't insert the entry anymore because the number of elements in the + // map reached the limit. See man-pages/bpf. + assertEquals(OsConstants.E2BIG, expected.errno); + } + } + } +} From 7d05e6fdddd067e416f1ed6104df2b1887616d2b Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 12 Jan 2021 18:55:14 +0800 Subject: [PATCH 1409/1415] Follow-up CL to the change at aosp/1498277 1. Correct the API annotation. 2. The entry deletion failure causes the exception in cleanTestMap(). 3. Use AtomicInteger to be the counter in the lambda. Test: atest BpfMapTest Change-Id: I4a56038881a38bda993ef5303b71f0e2a99f03d1 --- .../networkstack/tethering/BpfMap.java | 11 +++----- .../networkstack/tethering/BpfMapTest.java | 28 +++++++++---------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/BpfMap.java b/Tethering/src/com/android/networkstack/tethering/BpfMap.java index 9505709655..69ad1b60eb 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfMap.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfMap.java @@ -134,7 +134,7 @@ public class BpfMap implements AutoCloseable * * TODO: consider allowing null passed-in key. */ - public K getNextKey(@Nullable K key) throws ErrnoException { + public K getNextKey(@NonNull K key) throws ErrnoException { Objects.requireNonNull(key); return getNextKeyInternal(key); } @@ -185,14 +185,11 @@ public class BpfMap implements AutoCloseable * Otherwise, iteration will result in undefined behaviour. */ public void forEach(BiConsumer action) throws ErrnoException { - @Nullable - K nextKey = getFirstKey(); + @Nullable K nextKey = getFirstKey(); while (nextKey != null) { - @NonNull - final K curKey = nextKey; - @NonNull - final V value = getValue(curKey); + @NonNull final K curKey = nextKey; + @NonNull final V value = getValue(curKey); nextKey = getNextKey(curKey); action.accept(curKey, value); diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java index 77c0961ba8..1ddbaa9a20 100644 --- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java +++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java @@ -43,6 +43,7 @@ import org.junit.runner.RunWith; import java.net.InetAddress; import java.util.NoSuchElementException; +import java.util.concurrent.atomic.AtomicInteger; @RunWith(AndroidJUnit4.class) @@ -96,7 +97,9 @@ public final class BpfMapTest { bpfMap.forEach((key, value) -> { try { assertTrue(bpfMap.deleteEntry(key)); - } catch (ErrnoException ignored) { } + } catch (ErrnoException e) { + fail("Fail to delete the key " + key + ": " + e); + } }); assertNull(bpfMap.getFirstKey()); } @@ -284,15 +287,11 @@ public final class BpfMapTest { @Test public void testIterateEmptyMap() throws Exception { try (BpfMap bpfMap = getTestMap()) { - // Use an one element array to be a trick for a counter because local variables - // referenced from a lambda expression must be final. - final int[] count = {0}; - bpfMap.forEach((key, value) -> { - count[0]++; - }); - - // Expect that consumer has never be called. - assertEquals(0, count[0]); + // Can't use an int because variables used in a lambda must be final. + final AtomicInteger count = new AtomicInteger(); + bpfMap.forEach((key, value) -> count.incrementAndGet()); + // Expect that the consumer was never called. + assertEquals(0, count.get()); } } @@ -306,9 +305,8 @@ public final class BpfMapTest { bpfMap.insertEntry(resultMap.keyAt(i), resultMap.valueAt(i)); } - // Use an one element array to be a trick for a counter because local variables - // referenced from a lambda expression must be final. - final int[] count = {0}; + // Can't use an int because variables used in a lambda must be final. + final AtomicInteger count = new AtomicInteger(); bpfMap.forEach((key, value) -> { try { assertTrue(bpfMap.deleteEntry(key)); @@ -318,9 +316,9 @@ public final class BpfMapTest { if (!value.equals(resultMap.remove(key))) { fail("Unexpected result: " + key + ", value: " + value); } - count[0]++; + count.incrementAndGet(); }); - assertEquals(3, count[0]); + assertEquals(3, count.get()); assertTrue(resultMap.isEmpty()); assertNull(bpfMap.getFirstKey()); } From 400702b6bbbc3e7ec0949d6ab21fcf3a10e1989e Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 13 Jan 2021 13:47:48 +0800 Subject: [PATCH 1410/1415] Use header module bpf_syscall_wrappers Use the versioned header library instead of just including the header files. Test: atest BpfMapTest Change-Id: Icf23dcdc051a4ead6a7c6e925159cdc27f49eac2 --- Tethering/Android.bp | 5 +---- Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 5edcfe38bd..761e098586 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -60,10 +60,7 @@ cc_library { "com.android.tethering", ], min_sdk_version: "30", - include_dirs: [ - // TODO: use the libbpf_android_headers instead of just including the header files. - "system/bpf/libbpf_android/include/", - ], + header_libs: ["bpf_syscall_wrappers"], srcs: [ "jni/*.cpp", ], diff --git a/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp b/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp index 64f7dcfa3c..eadc210e31 100644 --- a/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp +++ b/Tethering/jni/com_android_networkstack_tethering_BpfMap.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -24,7 +23,7 @@ #include "nativehelper/scoped_utf_chars.h" #define BPF_FD_JUST_USE_INT -#include "bpf/BpfUtils.h" +#include "BpfSyscallWrappers.h" namespace android { From c2858740c144378c74f592143a6dbeeb1ad2f04d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 12 Jan 2021 21:01:52 +0900 Subject: [PATCH 1411/1415] Do not install tethering in TEST_MAPPING The current tethering module has in-progress changes in non-mainline branches, so it cannot be installed. Disable the tests in non-mainline branches, considering that they are still run in mainline branches, which will contain the same tethering code, but without the connectivity artifacts added to the tethering apex. Bug: 177290955 Test: TEST_MAPPING needs to be tested on the infra Ignore-AOSP-First: This change must not go into AOSP Change-Id: I39dd011a8baa16c9b8eb33ec2a2e4dcaedf25b76 --- TEST_MAPPING | 6 ++++-- tests/cts/net/AndroidTestTemplate.xml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/TEST_MAPPING b/TEST_MAPPING index 1db4baaf4c..512851905d 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -13,7 +13,8 @@ ], "mainline-presubmit": [ { - "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]", + // TODO: add back the tethering modules when updatable in this branch + "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex]", "options": [ { "exclude-annotation": "com.android.testutils.SkipPresubmit" @@ -24,7 +25,8 @@ // Tests on physical devices with SIM cards: postsubmit only for capacity constraints "mainline-postsubmit": [ { - "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]", + // TODO: add back the tethering module when updatable in this branch + "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex]", "keywords": ["sim"] } ] diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml index 78a01e29c1..474eefe7bf 100644 --- a/tests/cts/net/AndroidTestTemplate.xml +++ b/tests/cts/net/AndroidTestTemplate.xml @@ -21,6 +21,7 @@